Skip to contentSkip to conversation

acpi : cpu hot-remove returns error when cpu_down() fails

PATCH Superseded Yasuaki Ishimatsu 4 participants 16 messages Jul 12, 2012 – Oct 9, 2012

Subsystems (3)

v3 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v3 1/3 acpi : cpu hot-remove returns error when cpu_down() fails

Even if cpu_down() fails, acpi_processor_remove() continues to remove the cpu. But in this case, it should return error number since some process may run on the cpu. If the cpu has a running process and the cpu is turned the power off, the system may not work well.

---
 drivers/acpi/processor_driver.c |   18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/acpi/processor_driver.c +12 -6
Index: linux-3.5-rc4/drivers/acpi/processor_driver.c
===================================================================
@@ -610,7 +610,7 @@ err_free_pr:
 static int acpi_processor_remove(struct acpi_device *device, int type)
 {
 	struct acpi_processor *pr = NULL;
-
+	int ret;
 
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
@@ -621,8 +621,9 @@ static int acpi_processor_remove(struct
 		goto free;
 
 	if (type == ACPI_BUS_REMOVAL_EJECT) {
-		if (acpi_processor_handle_eject(pr))
-			return -EINVAL;
+		ret = acpi_processor_handle_eject(pr);
+		if (ret)
+			return ret;
 	}
 
 	acpi_processor_power_exit(pr, device);
@@ -841,12 +842,17 @@ static acpi_status acpi_processor_hotadd
 
 static int acpi_processor_handle_eject(struct acpi_processor *pr)
 {
-	if (cpu_online(pr->id))
-		cpu_down(pr->id);
+	int ret;
+
+	if (cpu_online(pr->id)) {
+		ret = cpu_down(pr->id);
+		if (ret)
+			return ret;
+	}
 
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
-	return (0);
+	return ret;
 }
 #else
 static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
#1 lore raw

PATCH v3 2/3 acpi : prevent cpu from becoming online

Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus().

Why does the patch change _cpu_up() logic?

The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race.

hot-remove cpu | _cpu_up()
------------------------------------- ------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
     call put_online_cpus()            |
                                       | start and continue _cpu_up()
     return acpi_processor_remove()    |
continue hot-remove the cpu            |

So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below:

hot-remove cpu | _cpu_up()
-----------------------------------------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
          cpu's cpu_present is set     |
          to false by set_cpu_present()|
     call put_online_cpus()            |
                                       | start _cpu_up()
                                       | check cpu_present() and return -EINVAL
     return acpi_processor_remove()    |
continue hot-remove the cpu            |
---
 drivers/acpi/processor_driver.c |   14 ++++++++++++++
 kernel/cpu.c                    |    8 +++++---
 2 files changed, 19 insertions(+), 3 deletions(-)
drivers/acpi/processor_driver.c +14 -0
Index: linux-3.5-rc6/drivers/acpi/processor_driver.c
===================================================================
@@ -850,8 +850,22 @@ static int acpi_processor_handle_eject(s
 			return ret;
 	}
 
+	get_online_cpus();
+	/*
+	 * The cpu might become online again at this point. So we check whether
+	 * the cpu has been onlined or not. If the cpu became online, it means
+	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
+	 * returns -EAGAIN.
+	 */
+	if (unlikely(cpu_online(pr->id))) {
+		put_online_cpus();
+		printk("Failed to remove CPU %d, since someone onlines it\n"
+			, pr->id);
+		return -EAGAIN;
+	}
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
+	put_online_cpus();
 	return ret;
 }
 #else
kernel/cpu.c +5 -3
Index: linux-3.5-rc6/kernel/cpu.c
===================================================================
@@ -343,11 +343,13 @@ static int __cpuinit _cpu_up(unsigned in
 	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 	struct task_struct *idle;
 
-	if (cpu_online(cpu) || !cpu_present(cpu))
-		return -EINVAL;
-
 	cpu_hotplug_begin();
 
+	if (cpu_online(cpu) || !cpu_present(cpu)) {
+		ret =  -EINVAL;
+		goto out;
+	}
+
 	idle = idle_thread_get(cpu);
 	if (IS_ERR(idle)) {
 		ret = PTR_ERR(idle);
#2 lore raw

PATCH RESEND v3 2/3 acpi : prevent cpu from becoming online

Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus().

Why does the patch change _cpu_up() logic?

The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race.

hot-remove cpu | _cpu_up()
------------------------------------- ------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
     call put_online_cpus()            |
                                       | start and continue _cpu_up()
     return acpi_processor_remove()    |
continue hot-remove the cpu            |

So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below:

hot-remove cpu | _cpu_up()
-----------------------------------------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
          cpu's cpu_present is set     |
          to false by set_cpu_present()|
     call put_online_cpus()            |
                                       | start _cpu_up()
                                       | check cpu_present() and return -EINVAL
     return acpi_processor_remove()    |
continue hot-remove the cpu            |
---
 drivers/acpi/processor_driver.c |   14 ++++++++++++++
 kernel/cpu.c                    |    8 +++++---
 2 files changed, 19 insertions(+), 3 deletions(-)
drivers/acpi/processor_driver.c +14 -0
Index: linux-3.5-rc6/drivers/acpi/processor_driver.c
===================================================================
@@ -850,8 +850,22 @@ static int acpi_processor_handle_eject(s
 			return ret;
 	}
 
+	get_online_cpus();
+	/*
+	 * The cpu might become online again at this point. So we check whether
+	 * the cpu has been onlined or not. If the cpu became online, it means
+	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
+	 * returns -EAGAIN.
+	 */
+	if (unlikely(cpu_online(pr->id))) {
+		put_online_cpus();
+		printk(KERN_WARNING "Failed to remove CPU %d, "
+		       "since someone onlines the cpu\n" , pr->id);
+		return -EAGAIN;
+	}
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
+	put_online_cpus();
 	return ret;
 }
 #else
kernel/cpu.c +5 -3
Index: linux-3.5-rc6/kernel/cpu.c
===================================================================
@@ -343,11 +343,13 @@ static int __cpuinit _cpu_up(unsigned in
 	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 	struct task_struct *idle;
 
-	if (cpu_online(cpu) || !cpu_present(cpu))
-		return -EINVAL;
-
 	cpu_hotplug_begin();
 
+	if (cpu_online(cpu) || !cpu_present(cpu)) {
+		ret =  -EINVAL;
+		goto out;
+	}
+
 	idle = idle_thread_get(cpu);
 	if (IS_ERR(idle)) {
 		ret = PTR_ERR(idle);
Reviewed-by on v3 2/3
#3 lore raw

Re: [PATCH v3 2/3 RESEND] acpi : prevent cpu from becoming online

Quoted 41 lines · Yasuaki Ishimatsu

Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus().

Why does the patch change _cpu_up() logic?

The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race.

hot-remove cpu | _cpu_up()
------------------------------------- ------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
     call put_online_cpus()            |
                                       | start and continue _cpu_up()
     return acpi_processor_remove()    |
continue hot-remove the cpu            |

So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below:

hot-remove cpu | _cpu_up()
-----------------------------------------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
          cpu's cpu_present is set     |
          to false by set_cpu_present()|
     call put_online_cpus()            |
                                       | start _cpu_up()
                                       | check cpu_present() and return -EINVAL
     return acpi_processor_remove()    |
continue hot-remove the cpu            |
Quoted 2 lines

Please consider fixing the grammar issue below (since it is a user-visible print statement). Other than that, everything looks fine.

Quoted 14 lines
---
 drivers/acpi/processor_driver.c |   14 ++++++++++++++
 kernel/cpu.c                    |    8 +++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +1 -0
@@ -850,8 +850,22 @@ static int acpi_processor_handle_eject(s
 			return ret;
 	}
 
+	get_online_cpus();

drivers/acpi/processor_driver.c static int acpi_processor_handle_eject(s · line 863

Quoted 10 lines
drivers/acpi/processor_driver.c +10 -0
+	/*
+	 * The cpu might become online again at this point. So we check whether
+	 * the cpu has been onlined or not. If the cpu became online, it means
+	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
+	 * returns -EAGAIN.
+	 */
+	if (unlikely(cpu_online(pr->id))) {
+		put_online_cpus();
+		printk(KERN_WARNING "Failed to remove CPU %d, "
+		       "since someone onlines the cpu\n" , pr->id);

How about:
"Failed to remove CPU %d, because some other task brought the CPU back online\n"

Regards,
Srivatsa S. Bhat

Quoted 30 lines
drivers/acpi/processor_driver.c +3 -0
+		return -EAGAIN;
+	}
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
+	put_online_cpus();
 	return ret;
 }
 #else

Index: linux-3.5-rc6/kernel/cpu.c
===================================================================

kernel/cpu.c +5 -3
@@ -343,11 +343,13 @@ static int __cpuinit _cpu_up(unsigned in
 	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 	struct task_struct *idle;
 
-	if (cpu_online(cpu) || !cpu_present(cpu))
-		return -EINVAL;
-
 	cpu_hotplug_begin();
 
+	if (cpu_online(cpu) || !cpu_present(cpu)) {
+		ret =  -EINVAL;
+		goto out;
+	}
+
 	idle = idle_thread_get(cpu);
 	if (IS_ERR(idle)) {
 		ret = PTR_ERR(idle);
#4 lore raw

Re: [PATCH v3 2/3 RESEND] acpi : prevent cpu from becoming online

Quoted 63 lines · Srivatsa S. Bhat
Quoted 39 lines · Yasuaki Ishimatsu

Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus().

Why does the patch change _cpu_up() logic?

The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race.

hot-remove cpu | _cpu_up()
------------------------------------- ------------------------------------
call acpi_processor_handle_eject() |

      call cpu_down()                   |
      call get_online_cpus()            |
                                        | call cpu_hotplug_begin() and stop here
      call arch_unregister_cpu()        |
      call acpi_unmap_lsapic()          |
      call put_online_cpus()            |
                                        | start and continue _cpu_up()
      return acpi_processor_remove()    |

continue hot-remove the cpu |

So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below:

hot-remove cpu | _cpu_up()
-----------------------------------------------------------------------
call acpi_processor_handle_eject() |

      call cpu_down()                   |
      call get_online_cpus()            |
                                        | call cpu_hotplug_begin() and stop here
      call arch_unregister_cpu()        |
      call acpi_unmap_lsapic()          |
           cpu's cpu_present is set     |
           to false by set_cpu_present()|
      call put_online_cpus()            |
                                        | start _cpu_up()
                                        | check cpu_present() and return -EINVAL
      return acpi_processor_remove()    |
Quoted 4 lines

continue hot-remove the cpu |

Please consider fixing the grammar issue below (since it is a user-visible print statement). Other than that, everything looks fine.

Quoted 13 lines
---
  drivers/acpi/processor_driver.c |   14 ++++++++++++++
  kernel/cpu.c                    |    8 +++++---
  2 files changed, 19 insertions(+), 3 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +0 -0
@@ -850,8 +850,22 @@ static int acpi_processor_handle_eject(s
  			return ret;
  	}
 
Quoted 14 lines

drivers/acpi/processor_driver.c static int acpi_processor_handle_eject(s · line 863

Quoted 11 lines
drivers/acpi/processor_driver.c +11 -0
+	get_online_cpus();
+	/*
+	 * The cpu might become online again at this point. So we check whether
+	 * the cpu has been onlined or not. If the cpu became online, it means
+	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
+	 * returns -EAGAIN.
+	 */
+	if (unlikely(cpu_online(pr->id))) {
+		put_online_cpus();
+		printk(KERN_WARNING "Failed to remove CPU %d, "
+		       "since someone onlines the cpu\n" , pr->id);

How about:
"Failed to remove CPU %d, because some other task brought the CPU back online\n"

Looks good to me. I'll update it.

Thanks,
Yasuaki Ishimatsu

Quoted 40 lines

Regards,
Srivatsa S. Bhat

Quoted 20 lines
drivers/acpi/processor_driver.c +3 -0
+		return -EAGAIN;
+	}
  	arch_unregister_cpu(pr->id);
  	acpi_unmap_lsapic(pr->id);
+	put_online_cpus();
  	return ret;
  }
  #else

Index: linux-3.5-rc6/kernel/cpu.c
===================================================================

kernel/cpu.c +0 -3
@@ -343,11 +343,13 @@ static int __cpuinit _cpu_up(unsigned in
  	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
  	struct task_struct *idle;
 
-	if (cpu_online(cpu) || !cpu_present(cpu))
-		return -EINVAL;
-

kernel/cpu.c static int __cpuinit _cpu_up(unsigned in · line 355

Quoted 10 lines
kernel/cpu.c +5 -0
  	cpu_hotplug_begin();
 
+	if (cpu_online(cpu) || !cpu_present(cpu)) {
+		ret =  -EINVAL;
+		goto out;
+	}
+
  	idle = idle_thread_get(cpu);
  	if (IS_ERR(idle)) {
  		ret = PTR_ERR(idle);

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#5 lore raw

Re: [PATCH v3 2/3 RESEND] acpi : prevent cpu from becoming online

In reply to Yasuaki Ishimatsu
Quoted 57 lines · Yasuaki Ishimatsu

Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus().

Why does the patch change _cpu_up() logic?

The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race.

hot-remove cpu | _cpu_up()
------------------------------------- ------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
     call put_online_cpus()            |
                                       | start and continue _cpu_up()
     return acpi_processor_remove()    |
continue hot-remove the cpu            |

So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below:

hot-remove cpu | _cpu_up()
-----------------------------------------------------------------------

call acpi_processor_handle_eject()     |
     call cpu_down()                   |
     call get_online_cpus()            |
                                       | call cpu_hotplug_begin() and stop here
     call arch_unregister_cpu()        |
     call acpi_unmap_lsapic()          |
          cpu's cpu_present is set     |
          to false by set_cpu_present()|
     call put_online_cpus()            |
                                       | start _cpu_up()
                                       | check cpu_present() and return -EINVAL
     return acpi_processor_remove()    |
continue hot-remove the cpu            |
---
 drivers/acpi/processor_driver.c |   14 ++++++++++++++
 kernel/cpu.c                    |    8 +++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +1 -0
@@ -850,8 +850,22 @@ static int acpi_processor_handle_eject(s
 			return ret;
 	}
 
+	get_online_cpus();

drivers/acpi/processor_driver.c static int acpi_processor_handle_eject(s · line 863

Quoted 10 lines
drivers/acpi/processor_driver.c +10 -0
+	/*
+	 * The cpu might become online again at this point. So we check whether
+	 * the cpu has been onlined or not. If the cpu became online, it means
+	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
+	 * returns -EAGAIN.
+	 */
+	if (unlikely(cpu_online(pr->id))) {
+		put_online_cpus();
+		printk(KERN_WARNING "Failed to remove CPU %d, "
+		       "since someone onlines the cpu\n" , pr->id);

pr_warn() should be used per the recent checkpatch change.

Thanks,
-Toshi

Quoted 30 lines
drivers/acpi/processor_driver.c +3 -0
+		return -EAGAIN;
+	}
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
+	put_online_cpus();
 	return ret;
 }
 #else

Index: linux-3.5-rc6/kernel/cpu.c
===================================================================

kernel/cpu.c +5 -3
@@ -343,11 +343,13 @@ static int __cpuinit _cpu_up(unsigned in
 	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
 	struct task_struct *idle;
 
-	if (cpu_online(cpu) || !cpu_present(cpu))
-		return -EINVAL;
-
 	cpu_hotplug_begin();
 
+	if (cpu_online(cpu) || !cpu_present(cpu)) {
+		ret =  -EINVAL;
+		goto out;
+	}
+
 	idle = idle_thread_get(cpu);
 	if (IS_ERR(idle)) {
 		ret = PTR_ERR(idle);
#6 lore raw

Re: [PATCH v3 2/3 RESEND] acpi : prevent cpu from becoming online

Hi Toshi,

Quoted 57 lines · Toshi Kani
Quoted 56 lines · Yasuaki Ishimatsu

Even if acpi_processor_handle_eject() offlines cpu, there is a chance to online the cpu after that. So the patch closes the window by using get/put_online_cpus().

Why does the patch change _cpu_up() logic?

The patch cares the race of hot-remove cpu and _cpu_up(). If the patch does not change it, there is the following race.

hot-remove cpu | _cpu_up()
------------------------------------- ------------------------------------
call acpi_processor_handle_eject() |

      call cpu_down()                   |
      call get_online_cpus()            |
                                        | call cpu_hotplug_begin() and stop here
      call arch_unregister_cpu()        |
      call acpi_unmap_lsapic()          |
      call put_online_cpus()            |
                                        | start and continue _cpu_up()
      return acpi_processor_remove()    |

continue hot-remove the cpu |

So _cpu_up() can continue to itself. And hot-remove cpu can also continue itself. If the patch changes _cpu_up() logic, the race disappears as below:

hot-remove cpu | _cpu_up()
-----------------------------------------------------------------------
call acpi_processor_handle_eject() |

      call cpu_down()                   |
      call get_online_cpus()            |
                                        | call cpu_hotplug_begin() and stop here
      call arch_unregister_cpu()        |
      call acpi_unmap_lsapic()          |
           cpu's cpu_present is set     |
           to false by set_cpu_present()|
      call put_online_cpus()            |
                                        | start _cpu_up()
                                        | check cpu_present() and return -EINVAL
      return acpi_processor_remove()    |

continue hot-remove the cpu |

---
  drivers/acpi/processor_driver.c |   14 ++++++++++++++
  kernel/cpu.c                    |    8 +++++---
  2 files changed, 19 insertions(+), 3 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +0 -0
@@ -850,8 +850,22 @@ static int acpi_processor_handle_eject(s
  			return ret;
  	}
 
Quoted 13 lines

drivers/acpi/processor_driver.c static int acpi_processor_handle_eject(s · line 863

Quoted 11 lines
drivers/acpi/processor_driver.c +11 -0
+	get_online_cpus();
+	/*
+	 * The cpu might become online again at this point. So we check whether
+	 * the cpu has been onlined or not. If the cpu became online, it means
+	 * that someone wants to use the cpu. So acpi_processor_handle_eject()
+	 * returns -EAGAIN.
+	 */
+	if (unlikely(cpu_online(pr->id))) {
+		put_online_cpus();
+		printk(KERN_WARNING "Failed to remove CPU %d, "
+		       "since someone onlines the cpu\n" , pr->id);

pr_warn() should be used per the recent checkpatch change.

O.K. I'll update it.

Thanks,
Yasuaki Ishimatsu

Quoted 40 lines

Thanks,
-Toshi

Quoted 20 lines
drivers/acpi/processor_driver.c +3 -0
+		return -EAGAIN;
+	}
  	arch_unregister_cpu(pr->id);
  	acpi_unmap_lsapic(pr->id);
+	put_online_cpus();
  	return ret;
  }
  #else

Index: linux-3.5-rc6/kernel/cpu.c
===================================================================

kernel/cpu.c +0 -3
@@ -343,11 +343,13 @@ static int __cpuinit _cpu_up(unsigned in
  	unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
  	struct task_struct *idle;
 
-	if (cpu_online(cpu) || !cpu_present(cpu))
-		return -EINVAL;
-

kernel/cpu.c static int __cpuinit _cpu_up(unsigned in · line 355

Quoted 10 lines
kernel/cpu.c +5 -0
  	cpu_hotplug_begin();
 
+	if (cpu_online(cpu) || !cpu_present(cpu)) {
+		ret =  -EINVAL;
+		goto out;
+	}
+
  	idle = idle_thread_get(cpu);
  	if (IS_ERR(idle)) {
  		ret = PTR_ERR(idle);

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#7 lore raw

PATCH v3 3/3 acpi : acpi_bus_trim() stops removing devices when failing to remove the device

In reply to Yasuaki Ishimatsu

acpi_bus_trim() stops removing devices, when acpi_bus_remove() return error number. But acpi_bus_remove() cannot return error number correctly. acpi_bus_remove() only return -EINVAL, when dev argument is NULL. Thus even if device cannot be removed correctly, acpi_bus_trim() ignores and continues to remove devices. acpi_bus_hot_remove_device() uses acpi_bus_trim() for removing devices. Therefore acpi_bus_hot_remove_device() can send "_EJ0" to firmware, even if the device is running on the system. In this case, the system cannot work well. So acpi_bus_trim() should check whether device was removed or not correctly. The patch adds error check into some functions to remove the device.

---
 drivers/acpi/scan.c    |   15 ++++++++++++---
 drivers/base/dd.c      |   22 +++++++++++++++++-----
 include/linux/device.h |    2 +-
 3 files changed, 30 insertions(+), 9 deletions(-)
drivers/acpi/scan.c +12 -3
Index: linux-3.5-rc6/drivers/acpi/scan.c
===================================================================
@@ -425,12 +425,17 @@ static int acpi_device_remove(struct dev
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	struct acpi_driver *acpi_drv = acpi_dev->driver;
+	int ret;
 
 	if (acpi_drv) {
 		if (acpi_drv->ops.notify)
 			acpi_device_remove_notify_handler(acpi_dev);
-		if (acpi_drv->ops.remove)
-			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+		if (acpi_drv->ops.remove) {
+			ret = acpi_drv->ops.remove(acpi_dev,
+						   acpi_dev->removal_type);
+			if (ret)
+				return ret;
+		}
 	}
 	acpi_dev->driver = NULL;
 	acpi_dev->driver_data = NULL;
@@ -1208,11 +1213,15 @@ static int acpi_device_set_context(struc
 
 static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
 {
+	int ret;
+
 	if (!dev)
 		return -EINVAL;
 
 	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
-	device_release_driver(&dev->dev);
+	ret = device_release_driver(&dev->dev);
+	if (ret)
+		return ret;
 
 	if (!rmdevice)
 		return 0;
drivers/base/dd.c +17 -5
Index: linux-3.5-rc6/drivers/base/dd.c
===================================================================
@@ -464,9 +464,10 @@ EXPORT_SYMBOL_GPL(driver_attach);
  * __device_release_driver() must be called with @dev lock held.
  * When called for a USB interface, @dev->parent lock must be held as well.
  */
-static void __device_release_driver(struct device *dev)
+static int __device_release_driver(struct device *dev)
 {
 	struct device_driver *drv;
+	int ret;
 
 	drv = dev->driver;
 	if (drv) {
@@ -482,9 +483,11 @@ static void __device_release_driver(stru
 		pm_runtime_put_sync(dev);
 
 		if (dev->bus && dev->bus->remove)
-			dev->bus->remove(dev);
+			ret = dev->bus->remove(dev);
 		else if (drv->remove)
-			drv->remove(dev);
+			ret = drv->remove(dev);
+		if (ret)
+			goto rollback;
 		devres_release_all(dev);
 		dev->driver = NULL;
 		klist_remove(&dev->p->knode_driver);
@@ -494,6 +497,12 @@ static void __device_release_driver(stru
 						     dev);
 
 	}
+
+	return ret;
+
+rollback:
+	driver_sysfs_add(dev);
+	return ret;
 }
 
 /**
@@ -503,16 +512,19 @@ static void __device_release_driver(stru
  * Manually detach device from driver.
  * When called for a USB interface, @dev->parent lock must be held.
  */
-void device_release_driver(struct device *dev)
+int device_release_driver(struct device *dev)
 {
+	int ret;
 	/*
 	 * If anyone calls device_release_driver() recursively from
 	 * within their ->remove callback for the same device, they
 	 * will deadlock right here.
 	 */
 	device_lock(dev);
-	__device_release_driver(dev);
+	ret = __device_release_driver(dev);
 	device_unlock(dev);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(device_release_driver);
 
include/linux/device.h +1 -1
Index: linux-3.5-rc6/include/linux/device.h
===================================================================
@@ -827,7 +827,7 @@ static inline void *dev_get_platdata(con
  * for information on use.
  */
 extern int __must_check device_bind_driver(struct device *dev);
-extern void device_release_driver(struct device *dev);
+extern int device_release_driver(struct device *dev);
 extern int  __must_check device_attach(struct device *dev);
 extern int __must_check driver_attach(struct device_driver *drv);
 extern int __must_check device_reprobe(struct device *dev);
#8 lore raw

Re: [PATCH v3 3/3] acpi : acpi_bus_trim() stops removing devices when failing to remove the device

Quoted 90 lines · Yasuaki Ishimatsu

acpi_bus_trim() stops removing devices, when acpi_bus_remove() return error number. But acpi_bus_remove() cannot return error number correctly. acpi_bus_remove() only return -EINVAL, when dev argument is NULL. Thus even if device cannot be removed correctly, acpi_bus_trim() ignores and continues to remove devices. acpi_bus_hot_remove_device() uses acpi_bus_trim() for removing devices. Therefore acpi_bus_hot_remove_device() can send "_EJ0" to firmware, even if the device is running on the system. In this case, the system cannot work well. So acpi_bus_trim() should check whether device was removed or not correctly. The patch adds error check into some functions to remove the device.

---
 drivers/acpi/scan.c    |   15 ++++++++++++---
 drivers/base/dd.c      |   22 +++++++++++++++++-----
 include/linux/device.h |    2 +-
 3 files changed, 30 insertions(+), 9 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/scan.c
===================================================================

drivers/acpi/scan.c +12 -3
@@ -425,12 +425,17 @@ static int acpi_device_remove(struct dev
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	struct acpi_driver *acpi_drv = acpi_dev->driver;
+	int ret;
 
 	if (acpi_drv) {
 		if (acpi_drv->ops.notify)
 			acpi_device_remove_notify_handler(acpi_dev);
-		if (acpi_drv->ops.remove)
-			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+		if (acpi_drv->ops.remove) {
+			ret = acpi_drv->ops.remove(acpi_dev,
+						   acpi_dev->removal_type);
+			if (ret)
+				return ret;
+		}
 	}
 	acpi_dev->driver = NULL;
 	acpi_dev->driver_data = NULL;
@@ -1208,11 +1213,15 @@ static int acpi_device_set_context(struc
 
 static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
 {
+	int ret;
+
 	if (!dev)
 		return -EINVAL;
 
 	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
-	device_release_driver(&dev->dev);
+	ret = device_release_driver(&dev->dev);
+	if (ret)
+		return ret;
 
 	if (!rmdevice)
 		return 0;

Index: linux-3.5-rc6/drivers/base/dd.c
===================================================================

drivers/base/dd.c +6 -3
@@ -464,9 +464,10 @@ EXPORT_SYMBOL_GPL(driver_attach);
  * __device_release_driver() must be called with @dev lock held.
  * When called for a USB interface, @dev->parent lock must be held as well.
  */
-static void __device_release_driver(struct device *dev)
+static int __device_release_driver(struct device *dev)
 {
 	struct device_driver *drv;
+	int ret;
 
 	drv = dev->driver;
 	if (drv) {
@@ -482,9 +483,11 @@ static void __device_release_driver(stru
 		pm_runtime_put_sync(dev);
 
 		if (dev->bus && dev->bus->remove)
-			dev->bus->remove(dev);
+			ret = dev->bus->remove(dev);
 		else if (drv->remove)
-			drv->remove(dev);
+			ret = drv->remove(dev);
+		if (ret)
+			goto rollback;
 		devres_release_all(dev);
 		dev->driver = NULL;
 		klist_remove(&dev->p->knode_driver);

drivers/base/dd.c static void __device_release_driver(stru · line 501

Quoted 5 lines
drivers/base/dd.c +2 -0
@@ -494,6 +497,12 @@ static void __device_release_driver(stru
 						     dev);
 
 	}
+
+	return ret;

ret is uninitialized when !drv.

drivers/base/dd.c static void __device_release_driver(stru · line 515

Quoted 13 lines
drivers/base/dd.c +5 -1
+
+rollback:
+	driver_sysfs_add(dev);
+	return ret;
 }
 
 /**
@@ -503,16 +512,19 @@ static void __device_release_driver(stru
  * Manually detach device from driver.
  * When called for a USB interface, @dev->parent lock must be held.
  */
-void device_release_driver(struct device *dev)
+int device_release_driver(struct device *dev)

I agree with this change as driver's remove interface can fail. However, there are other callers to this function, which do not check the return value. I suppose there is no impact to the other paths since you only changed the CPU hotplug path to fail properly, but please confirm this is the case. I recommend documenting this change to the change log.

Thanks,
-Toshi

Quoted 30 lines
drivers/base/dd.c +4 -1
 {
+	int ret;
 	/*
 	 * If anyone calls device_release_driver() recursively from
 	 * within their ->remove callback for the same device, they
 	 * will deadlock right here.
 	 */
 	device_lock(dev);
-	__device_release_driver(dev);
+	ret = __device_release_driver(dev);
 	device_unlock(dev);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(device_release_driver);
 

Index: linux-3.5-rc6/include/linux/device.h
===================================================================

include/linux/device.h +1 -1
@@ -827,7 +827,7 @@ static inline void *dev_get_platdata(con
  * for information on use.
  */
 extern int __must_check device_bind_driver(struct device *dev);
-extern void device_release_driver(struct device *dev);
+extern int device_release_driver(struct device *dev);
 extern int  __must_check device_attach(struct device *dev);
 extern int __must_check driver_attach(struct device_driver *drv);
 extern int __must_check device_reprobe(struct device *dev);
#9 lore raw

Re: [PATCH v3 3/3] acpi : acpi_bus_trim() stops removing devices when failing to remove the device

Quoted 93 lines · Toshi Kani
Quoted 92 lines · Yasuaki Ishimatsu

acpi_bus_trim() stops removing devices, when acpi_bus_remove() return error number. But acpi_bus_remove() cannot return error number correctly. acpi_bus_remove() only return -EINVAL, when dev argument is NULL. Thus even if device cannot be removed correctly, acpi_bus_trim() ignores and continues to remove devices. acpi_bus_hot_remove_device() uses acpi_bus_trim() for removing devices. Therefore acpi_bus_hot_remove_device() can send "_EJ0" to firmware, even if the device is running on the system. In this case, the system cannot work well. So acpi_bus_trim() should check whether device was removed or not correctly. The patch adds error check into some functions to remove the device.

---
  drivers/acpi/scan.c    |   15 ++++++++++++---
  drivers/base/dd.c      |   22 +++++++++++++++++-----
  include/linux/device.h |    2 +-
  3 files changed, 30 insertions(+), 9 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/scan.c
===================================================================

drivers/acpi/scan.c +12 -3
@@ -425,12 +425,17 @@ static int acpi_device_remove(struct dev
  {
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = acpi_dev->driver;
+	int ret;
 
  	if (acpi_drv) {
  		if (acpi_drv->ops.notify)
  			acpi_device_remove_notify_handler(acpi_dev);
-		if (acpi_drv->ops.remove)
-			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+		if (acpi_drv->ops.remove) {
+			ret = acpi_drv->ops.remove(acpi_dev,
+						   acpi_dev->removal_type);
+			if (ret)
+				return ret;
+		}
  	}
  	acpi_dev->driver = NULL;
  	acpi_dev->driver_data = NULL;
@@ -1208,11 +1213,15 @@ static int acpi_device_set_context(struc
 
  static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
  {
+	int ret;
+
  	if (!dev)
  		return -EINVAL;
 
  	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
-	device_release_driver(&dev->dev);
+	ret = device_release_driver(&dev->dev);
+	if (ret)
+		return ret;
 
  	if (!rmdevice)
  		return 0;

Index: linux-3.5-rc6/drivers/base/dd.c
===================================================================

drivers/base/dd.c +6 -3
@@ -464,9 +464,10 @@ EXPORT_SYMBOL_GPL(driver_attach);
   * __device_release_driver() must be called with @dev lock held.
   * When called for a USB interface, @dev->parent lock must be held as well.
   */
-static void __device_release_driver(struct device *dev)
+static int __device_release_driver(struct device *dev)
  {
  	struct device_driver *drv;
+	int ret;
 
  	drv = dev->driver;
  	if (drv) {
@@ -482,9 +483,11 @@ static void __device_release_driver(stru
  		pm_runtime_put_sync(dev);
 
  		if (dev->bus && dev->bus->remove)
-			dev->bus->remove(dev);
+			ret = dev->bus->remove(dev);
  		else if (drv->remove)
-			drv->remove(dev);
+			ret = drv->remove(dev);
+		if (ret)
+			goto rollback;
  		devres_release_all(dev);
  		dev->driver = NULL;
  		klist_remove(&dev->p->knode_driver);
@@ -494,6 +497,12 @@ static void __device_release_driver(stru
  						     dev);
 
Quoted 5 lines

drivers/base/dd.c static void __device_release_driver(stru · line 501

Quoted 3 lines
drivers/base/dd.c +2 -0
  	}
+
+	return ret;

ret is uninitialized when !drv.

Thanks! I'll update it.

Quoted 7 lines
Quoted 7 lines
drivers/base/dd.c +4 -0
+
+rollback:
+	driver_sysfs_add(dev);
+	return ret;
  }
 
Quoted 14 lines

drivers/base/dd.c static void __device_release_driver(stru · line 515

Quoted 7 lines
drivers/base/dd.c +1 -1
  /**
@@ -503,16 +512,19 @@ static void __device_release_driver(stru
   * Manually detach device from driver.
   * When called for a USB interface, @dev->parent lock must be held.
   */
-void device_release_driver(struct device *dev)
+int device_release_driver(struct device *dev)

I agree with this change as driver's remove interface can fail. However, there are other callers to this function, which do not check the return value. I suppose there is no impact to the other paths since you only changed the CPU hotplug path to fail properly, but please confirm this is the case. I recommend documenting this change to the change log.

Thank you for your agreement. As you know, there are other callers. I believe the patch does not impact to them, since all of them does not check return value of device_release_driver().

I will write it to the patch.

Thanks,
Yasuaki Ishimatsu

Quoted 41 lines

Thanks,
-Toshi

Quoted 22 lines
drivers/base/dd.c +4 -1
  {
+	int ret;
  	/*
  	 * If anyone calls device_release_driver() recursively from
  	 * within their ->remove callback for the same device, they
  	 * will deadlock right here.
  	 */
  	device_lock(dev);
-	__device_release_driver(dev);
+	ret = __device_release_driver(dev);
  	device_unlock(dev);
+
+	return ret;
  }
  EXPORT_SYMBOL_GPL(device_release_driver);
 

Index: linux-3.5-rc6/include/linux/device.h
===================================================================

include/linux/device.h static inline void *dev_get_platdata(con · line 833

Quoted 8 lines
include/linux/device.h +1 -1
@@ -827,7 +827,7 @@ static inline void *dev_get_platdata(con
   * for information on use.
   */
  extern int __must_check device_bind_driver(struct device *dev);
-extern void device_release_driver(struct device *dev);
+extern int device_release_driver(struct device *dev);
  extern int  __must_check device_attach(struct device *dev);
  extern int __must_check driver_attach(struct device_driver *drv);
  extern int __must_check device_reprobe(struct device *dev);

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw

Re: [PATCH v3 3/3] acpi : acpi_bus_trim() stops removing devices when failing to remove the device

In reply to Yasuaki Ishimatsu

Hi, ishimatsu:

At 07/12/2012 07:28 PM, Yasuaki Ishimatsu Wrote:

Quoted 9 lines

acpi_bus_trim() stops removing devices, when acpi_bus_remove() return error number. But acpi_bus_remove() cannot return error number correctly. acpi_bus_remove() only return -EINVAL, when dev argument is NULL. Thus even if device cannot be removed correctly, acpi_bus_trim() ignores and continues to remove devices. acpi_bus_hot_remove_device() uses acpi_bus_trim() for removing devices. Therefore acpi_bus_hot_remove_device() can send "_EJ0" to firmware, even if the device is running on the system. In this case, the system cannot work well. So acpi_bus_trim() should check whether device was removed or not correctly. The patch adds error check into some functions to remove the device.

What is the status about this patch?

Vasilis Liaskovitis found a similar bug about the memory hotplug, and this patch can fix this problem:
https://lkml.org/lkml/2012/9/26/318

Thanks
Wen Congyang

Quoted 135 lines
---
 drivers/acpi/scan.c    |   15 ++++++++++++---
 drivers/base/dd.c      |   22 +++++++++++++++++-----
 include/linux/device.h |    2 +-
 3 files changed, 30 insertions(+), 9 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/scan.c
===================================================================

drivers/acpi/scan.c +12 -3
@@ -425,12 +425,17 @@ static int acpi_device_remove(struct dev
 {
 	struct acpi_device *acpi_dev = to_acpi_device(dev);
 	struct acpi_driver *acpi_drv = acpi_dev->driver;
+	int ret;
 
 	if (acpi_drv) {
 		if (acpi_drv->ops.notify)
 			acpi_device_remove_notify_handler(acpi_dev);
-		if (acpi_drv->ops.remove)
-			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+		if (acpi_drv->ops.remove) {
+			ret = acpi_drv->ops.remove(acpi_dev,
+						   acpi_dev->removal_type);
+			if (ret)
+				return ret;
+		}
 	}
 	acpi_dev->driver = NULL;
 	acpi_dev->driver_data = NULL;
@@ -1208,11 +1213,15 @@ static int acpi_device_set_context(struc
 
 static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
 {
+	int ret;
+
 	if (!dev)
 		return -EINVAL;
 
 	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
-	device_release_driver(&dev->dev);
+	ret = device_release_driver(&dev->dev);
+	if (ret)
+		return ret;
 
 	if (!rmdevice)
 		return 0;

Index: linux-3.5-rc6/drivers/base/dd.c
===================================================================

drivers/base/dd.c +17 -5
@@ -464,9 +464,10 @@ EXPORT_SYMBOL_GPL(driver_attach);
  * __device_release_driver() must be called with @dev lock held.
  * When called for a USB interface, @dev->parent lock must be held as well.
  */
-static void __device_release_driver(struct device *dev)
+static int __device_release_driver(struct device *dev)
 {
 	struct device_driver *drv;
+	int ret;
 
 	drv = dev->driver;
 	if (drv) {
@@ -482,9 +483,11 @@ static void __device_release_driver(stru
 		pm_runtime_put_sync(dev);
 
 		if (dev->bus && dev->bus->remove)
-			dev->bus->remove(dev);
+			ret = dev->bus->remove(dev);
 		else if (drv->remove)
-			drv->remove(dev);
+			ret = drv->remove(dev);
+		if (ret)
+			goto rollback;
 		devres_release_all(dev);
 		dev->driver = NULL;
 		klist_remove(&dev->p->knode_driver);
@@ -494,6 +497,12 @@ static void __device_release_driver(stru
 						     dev);
 
 	}
+
+	return ret;
+
+rollback:
+	driver_sysfs_add(dev);
+	return ret;
 }
 
 /**
@@ -503,16 +512,19 @@ static void __device_release_driver(stru
  * Manually detach device from driver.
  * When called for a USB interface, @dev->parent lock must be held.
  */
-void device_release_driver(struct device *dev)
+int device_release_driver(struct device *dev)
 {
+	int ret;
 	/*
 	 * If anyone calls device_release_driver() recursively from
 	 * within their ->remove callback for the same device, they
 	 * will deadlock right here.
 	 */
 	device_lock(dev);
-	__device_release_driver(dev);
+	ret = __device_release_driver(dev);
 	device_unlock(dev);
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(device_release_driver);
 

Index: linux-3.5-rc6/include/linux/device.h
===================================================================

include/linux/device.h +1 -2
@@ -827,7 +827,7 @@ static inline void *dev_get_platdata(con
  * for information on use.
  */
 extern int __must_check device_bind_driver(struct device *dev);
-extern void device_release_driver(struct device *dev);
+extern int device_release_driver(struct device *dev);
 extern int  __must_check device_attach(struct device *dev);
 extern int __must_check driver_attach(struct device_driver *drv);
 extern int __must_check device_reprobe(struct device *dev);
 
--

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

#11 lore raw

Re: [PATCH v3 3/3] acpi : acpi_bus_trim() stops removing devices when failing to remove the device

Hi Wen,

Quoted 13 lines · Wen Congyang

Hi, ishimatsu:

At 07/12/2012 07:28 PM, Yasuaki Ishimatsu Wrote:

Quoted 9 lines

acpi_bus_trim() stops removing devices, when acpi_bus_remove() return error number. But acpi_bus_remove() cannot return error number correctly. acpi_bus_remove() only return -EINVAL, when dev argument is NULL. Thus even if device cannot be removed correctly, acpi_bus_trim() ignores and continues to remove devices. acpi_bus_hot_remove_device() uses acpi_bus_trim() for removing devices. Therefore acpi_bus_hot_remove_device() can send "_EJ0" to firmware, even if the device is running on the system. In this case, the system cannot work well. So acpi_bus_trim() should check whether device was removed or not correctly. The patch adds error check into some functions to remove the device.

Quoted 1 line

What is the status about this patch?

I need to update the description against Toshi's comment as follows:

"I agree with this change as driver's remove interface can fail. However, there are other callers to this function, which do not check the return value. I suppose there is no impact to the other paths since you only changed the CPU hotplug path to fail properly, but please confirm this is the case. I recommend documenting this change to the change log."

I have already checked that the patch does not impact the other path with the exception of CPU and Memory hotplug path. So I will adds the result of investigation and following Vasislis's problem into the patch and resend to lklml.

Quoted 3 lines

Vasilis Liaskovitis found a similar bug about the memory hotplug, and this patch can fix this problem:
https://lkml.org/lkml/2012/9/26/318

Thanks,
Yasuaki Ishimatsu

Quoted 139 lines

Thanks
Wen Congyang

Quoted 135 lines
---
  drivers/acpi/scan.c    |   15 ++++++++++++---
  drivers/base/dd.c      |   22 +++++++++++++++++-----
  include/linux/device.h |    2 +-
  3 files changed, 30 insertions(+), 9 deletions(-)

Index: linux-3.5-rc6/drivers/acpi/scan.c
===================================================================

drivers/acpi/scan.c +12 -3
@@ -425,12 +425,17 @@ static int acpi_device_remove(struct dev
  {
  	struct acpi_device *acpi_dev = to_acpi_device(dev);
  	struct acpi_driver *acpi_drv = acpi_dev->driver;
+	int ret;
 
  	if (acpi_drv) {
  		if (acpi_drv->ops.notify)
  			acpi_device_remove_notify_handler(acpi_dev);
-		if (acpi_drv->ops.remove)
-			acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+		if (acpi_drv->ops.remove) {
+			ret = acpi_drv->ops.remove(acpi_dev,
+						   acpi_dev->removal_type);
+			if (ret)
+				return ret;
+		}
  	}
  	acpi_dev->driver = NULL;
  	acpi_dev->driver_data = NULL;
@@ -1208,11 +1213,15 @@ static int acpi_device_set_context(struc
 
  static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
  {
+	int ret;
+
  	if (!dev)
  		return -EINVAL;
 
  	dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
-	device_release_driver(&dev->dev);
+	ret = device_release_driver(&dev->dev);
+	if (ret)
+		return ret;
 
  	if (!rmdevice)
  		return 0;

Index: linux-3.5-rc6/drivers/base/dd.c
===================================================================

drivers/base/dd.c +17 -5
@@ -464,9 +464,10 @@ EXPORT_SYMBOL_GPL(driver_attach);
   * __device_release_driver() must be called with @dev lock held.
   * When called for a USB interface, @dev->parent lock must be held as well.
   */
-static void __device_release_driver(struct device *dev)
+static int __device_release_driver(struct device *dev)
  {
  	struct device_driver *drv;
+	int ret;
 
  	drv = dev->driver;
  	if (drv) {
@@ -482,9 +483,11 @@ static void __device_release_driver(stru
  		pm_runtime_put_sync(dev);
 
  		if (dev->bus && dev->bus->remove)
-			dev->bus->remove(dev);
+			ret = dev->bus->remove(dev);
  		else if (drv->remove)
-			drv->remove(dev);
+			ret = drv->remove(dev);
+		if (ret)
+			goto rollback;
  		devres_release_all(dev);
  		dev->driver = NULL;
  		klist_remove(&dev->p->knode_driver);
@@ -494,6 +497,12 @@ static void __device_release_driver(stru
  						     dev);
 
  	}
+
+	return ret;
+
+rollback:
+	driver_sysfs_add(dev);
+	return ret;
  }
 
  /**
@@ -503,16 +512,19 @@ static void __device_release_driver(stru
   * Manually detach device from driver.
   * When called for a USB interface, @dev->parent lock must be held.
   */
-void device_release_driver(struct device *dev)
+int device_release_driver(struct device *dev)
  {
+	int ret;
  	/*
  	 * If anyone calls device_release_driver() recursively from
  	 * within their ->remove callback for the same device, they
  	 * will deadlock right here.
  	 */
  	device_lock(dev);
-	__device_release_driver(dev);
+	ret = __device_release_driver(dev);
  	device_unlock(dev);
+
+	return ret;
  }
  EXPORT_SYMBOL_GPL(device_release_driver);
 

Index: linux-3.5-rc6/include/linux/device.h
===================================================================

include/linux/device.h +1 -2
@@ -827,7 +827,7 @@ static inline void *dev_get_platdata(con
   * for information on use.
   */
  extern int __must_check device_bind_driver(struct device *dev);
-extern void device_release_driver(struct device *dev);
+extern int device_release_driver(struct device *dev);
  extern int  __must_check device_attach(struct device *dev);
  extern int __must_check driver_attach(struct device_driver *drv);
  extern int __must_check device_reprobe(struct device *dev);
 
--

To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Reviewed-by on v3 1/3
#12 lore raw
In reply to Yasuaki Ishimatsu
Quoted 7 lines · Yasuaki Ishimatsu

Even if cpu_down() fails, acpi_processor_remove() continues to remove the cpu. But in this case, it should return error number since some process may run on the cpu. If the cpu has a running process and the cpu is turned the power off, the system may not work well.

Regards,
Srivatsa S. Bhat

Quoted 51 lines
---
 drivers/acpi/processor_driver.c |   18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Index: linux-3.5-rc4/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +12 -6
@@ -610,7 +610,7 @@ err_free_pr:
 static int acpi_processor_remove(struct acpi_device *device, int type)
 {
 	struct acpi_processor *pr = NULL;
-
+	int ret;
 
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
@@ -621,8 +621,9 @@ static int acpi_processor_remove(struct
 		goto free;
 
 	if (type == ACPI_BUS_REMOVAL_EJECT) {
-		if (acpi_processor_handle_eject(pr))
-			return -EINVAL;
+		ret = acpi_processor_handle_eject(pr);
+		if (ret)
+			return ret;
 	}
 
 	acpi_processor_power_exit(pr, device);
@@ -841,12 +842,17 @@ static acpi_status acpi_processor_hotadd
 
 static int acpi_processor_handle_eject(struct acpi_processor *pr)
 {
-	if (cpu_online(pr->id))
-		cpu_down(pr->id);
+	int ret;
+
+	if (cpu_online(pr->id)) {
+		ret = cpu_down(pr->id);
+		if (ret)
+			return ret;
+	}
 
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
-	return (0);
+	return ret;
 }
 #else
 static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
#13 lore raw

Hi Srivatsa,

Quoted 10 lines · Srivatsa S. Bhat
Quoted 7 lines · Yasuaki Ishimatsu

Even if cpu_down() fails, acpi_processor_remove() continues to remove the cpu. But in this case, it should return error number since some process may run on the cpu. If the cpu has a running process and the cpu is turned the power off, the system may not work well.

Thank you for reviewing.

Thanks,
Yasuaki Ishimatsu

Quoted 60 lines

Regards,
Srivatsa S. Bhat

Quoted 41 lines
---
  drivers/acpi/processor_driver.c |   18 ++++++++++++------
  1 file changed, 12 insertions(+), 6 deletions(-)

Index: linux-3.5-rc4/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +9 -5
@@ -610,7 +610,7 @@ err_free_pr:
  static int acpi_processor_remove(struct acpi_device *device, int type)
  {
  	struct acpi_processor *pr = NULL;
-
+	int ret;
 
  	if (!device || !acpi_driver_data(device))
  		return -EINVAL;
@@ -621,8 +621,9 @@ static int acpi_processor_remove(struct
  		goto free;
 
  	if (type == ACPI_BUS_REMOVAL_EJECT) {
-		if (acpi_processor_handle_eject(pr))
-			return -EINVAL;
+		ret = acpi_processor_handle_eject(pr);
+		if (ret)
+			return ret;
  	}
 
  	acpi_processor_power_exit(pr, device);
@@ -841,12 +842,17 @@ static acpi_status acpi_processor_hotadd
 
  static int acpi_processor_handle_eject(struct acpi_processor *pr)
  {
-	if (cpu_online(pr->id))
-		cpu_down(pr->id);
+	int ret;
+
+	if (cpu_online(pr->id)) {
+		ret = cpu_down(pr->id);
+		if (ret)

drivers/acpi/processor_driver.c static acpi_status acpi_processor_hotadd · line 858

Quoted 10 lines
drivers/acpi/processor_driver.c +3 -1
+			return ret;
+	}
 
  	arch_unregister_cpu(pr->id);
  	acpi_unmap_lsapic(pr->id);
-	return (0);
+	return ret;
  }
  #else
  static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#14 lore raw
In reply to Yasuaki Ishimatsu
Quoted 44 lines · Yasuaki Ishimatsu

Even if cpu_down() fails, acpi_processor_remove() continues to remove the cpu. But in this case, it should return error number since some process may run on the cpu. If the cpu has a running process and the cpu is turned the power off, the system may not work well.

---
 drivers/acpi/processor_driver.c |   18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Index: linux-3.5-rc4/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +6 -5
@@ -610,7 +610,7 @@ err_free_pr:
 static int acpi_processor_remove(struct acpi_device *device, int type)
 {
 	struct acpi_processor *pr = NULL;
-
+	int ret;
 
 	if (!device || !acpi_driver_data(device))
 		return -EINVAL;
@@ -621,8 +621,9 @@ static int acpi_processor_remove(struct
 		goto free;
 
 	if (type == ACPI_BUS_REMOVAL_EJECT) {
-		if (acpi_processor_handle_eject(pr))
-			return -EINVAL;
+		ret = acpi_processor_handle_eject(pr);
+		if (ret)
+			return ret;
 	}
 
 	acpi_processor_power_exit(pr, device);
@@ -841,12 +842,17 @@ static acpi_status acpi_processor_hotadd
 
 static int acpi_processor_handle_eject(struct acpi_processor *pr)
 {
-	if (cpu_online(pr->id))
-		cpu_down(pr->id);
+	int ret;
+

drivers/acpi/processor_driver.c static acpi_status acpi_processor_hotadd · line 855

Quoted 10 lines
drivers/acpi/processor_driver.c +6 -1
+	if (cpu_online(pr->id)) {
+		ret = cpu_down(pr->id);
+		if (ret)
+			return ret;
+	}
 
 	arch_unregister_cpu(pr->id);
 	acpi_unmap_lsapic(pr->id);
-	return (0);
+	return ret;

ret is uninitialized when !cpu_online().

Thanks,
-Toshi

Quoted 8 lines
drivers/acpi/processor_driver.c +0 -1
 }
 #else
 static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
 
--

To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#15 lore raw

Hi Toshi,

Quoted 51 lines · Toshi Kani
Quoted 50 lines · Yasuaki Ishimatsu

Even if cpu_down() fails, acpi_processor_remove() continues to remove the cpu. But in this case, it should return error number since some process may run on the cpu. If the cpu has a running process and the cpu is turned the power off, the system may not work well.

---
  drivers/acpi/processor_driver.c |   18 ++++++++++++------
  1 file changed, 12 insertions(+), 6 deletions(-)

Index: linux-3.5-rc4/drivers/acpi/processor_driver.c
===================================================================

drivers/acpi/processor_driver.c +11 -5
@@ -610,7 +610,7 @@ err_free_pr:
  static int acpi_processor_remove(struct acpi_device *device, int type)
  {
  	struct acpi_processor *pr = NULL;
-
+	int ret;
 
  	if (!device || !acpi_driver_data(device))
  		return -EINVAL;
@@ -621,8 +621,9 @@ static int acpi_processor_remove(struct
  		goto free;
 
  	if (type == ACPI_BUS_REMOVAL_EJECT) {
-		if (acpi_processor_handle_eject(pr))
-			return -EINVAL;
+		ret = acpi_processor_handle_eject(pr);
+		if (ret)
+			return ret;
  	}
 
  	acpi_processor_power_exit(pr, device);
@@ -841,12 +842,17 @@ static acpi_status acpi_processor_hotadd
 
  static int acpi_processor_handle_eject(struct acpi_processor *pr)
  {
-	if (cpu_online(pr->id))
-		cpu_down(pr->id);
+	int ret;
+
+	if (cpu_online(pr->id)) {
+		ret = cpu_down(pr->id);
+		if (ret)
+			return ret;
+	}
 
Quoted 6 lines

drivers/acpi/processor_driver.c static acpi_status acpi_processor_hotadd · line 855

Quoted 4 lines
drivers/acpi/processor_driver.c +1 -1
  	arch_unregister_cpu(pr->id);
  	acpi_unmap_lsapic(pr->id);
-	return (0);
+	return ret;

ret is uninitialized when !cpu_online().

Oops! I'll update it.

Thanks,
Yasuaki Ishimatsu

Quoted 18 lines

Thanks,
-Toshi

Quoted 8 lines
drivers/acpi/processor_driver.c +0 -1
  }
  #else
  static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr)
 
--

To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html