Commit baaca49f authored by Gautham R Shenoy's avatar Gautham R Shenoy Committed by Linus Torvalds

Define and use new events,CPU_LOCK_ACQUIRE and CPU_LOCK_RELEASE

This is an attempt to provide an alternate mechanism for postponing
a hotplug event instead of using a global mechanism like lock_cpu_hotplug.

The proposal is to add two new events namely CPU_LOCK_ACQUIRE and
CPU_LOCK_RELEASE. The notification for these two events would be sent
out before and after a cpu_hotplug event respectively.

During the CPU_LOCK_ACQUIRE event, a cpu-hotplug-aware subsystem is
supposed to acquire any per-subsystem hotcpu mutex ( Eg. workqueue_mutex
in kernel/workqueue.c ).

During the CPU_LOCK_RELEASE release event the cpu-hotplug-aware subsystem
is supposed to release the per-subsystem hotcpu mutex.

The reasons for defining new events as opposed to reusing the existing events
like CPU_UP_PREPARE/CPU_UP_FAILED/CPU_ONLINE for locking/unlocking of
per-subsystem hotcpu mutexes are as follow:

	- CPU_LOCK_ACQUIRE: All hotcpu mutexes are taken before subsystems
	start handling pre-hotplug events like CPU_UP_PREPARE/CPU_DOWN_PREPARE
	etc, thus ensuring a clean handling of these events.

	- CPU_LOCK_RELEASE: The hotcpu mutexes will be released only after
	all subsystems have handled post-hotplug events like CPU_DOWN_FAILED,
	CPU_DEAD,CPU_ONLINE etc thereby ensuring that there are no subsequent
	clashes amongst the interdependent subsystems after a cpu hotplugs.

This patch also uses __raw_notifier_call chain in _cpu_up to take care
of the dependency between the two consequetive calls to
raw_notifier_call_chain.

[akpm@linux-foundation.org: fix a bug]
Signed-off-by: default avatarGautham R Shenoy <ego@in.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6f7cc11a
...@@ -194,6 +194,8 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh, ...@@ -194,6 +194,8 @@ extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ #define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */
#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ #define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */
#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ #define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */
#define CPU_LOCK_ACQUIRE 0x0008 /* Acquire all hotcpu locks */
#define CPU_LOCK_RELEASE 0x0009 /* Release all hotcpu locks */
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _LINUX_NOTIFIER_H */ #endif /* _LINUX_NOTIFIER_H */
...@@ -132,12 +132,15 @@ static int _cpu_down(unsigned int cpu) ...@@ -132,12 +132,15 @@ static int _cpu_down(unsigned int cpu)
if (!cpu_online(cpu)) if (!cpu_online(cpu))
return -EINVAL; return -EINVAL;
raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE,
(void *)(long)cpu);
err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
(void *)(long)cpu); (void *)(long)cpu);
if (err == NOTIFY_BAD) { if (err == NOTIFY_BAD) {
printk("%s: attempt to take down CPU %u failed\n", printk("%s: attempt to take down CPU %u failed\n",
__FUNCTION__, cpu); __FUNCTION__, cpu);
return -EINVAL; err = -EINVAL;
goto out_release;
} }
/* Ensure that we are not runnable on dying cpu */ /* Ensure that we are not runnable on dying cpu */
...@@ -185,6 +188,9 @@ out_thread: ...@@ -185,6 +188,9 @@ out_thread:
err = kthread_stop(p); err = kthread_stop(p);
out_allowed: out_allowed:
set_cpus_allowed(current, old_allowed); set_cpus_allowed(current, old_allowed);
out_release:
raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE,
(void *)(long)cpu);
return err; return err;
} }
...@@ -206,13 +212,15 @@ int cpu_down(unsigned int cpu) ...@@ -206,13 +212,15 @@ int cpu_down(unsigned int cpu)
/* Requires cpu_add_remove_lock to be held */ /* Requires cpu_add_remove_lock to be held */
static int __cpuinit _cpu_up(unsigned int cpu) static int __cpuinit _cpu_up(unsigned int cpu)
{ {
int ret; int ret, nr_calls = 0;
void *hcpu = (void *)(long)cpu; void *hcpu = (void *)(long)cpu;
if (cpu_online(cpu) || !cpu_present(cpu)) if (cpu_online(cpu) || !cpu_present(cpu))
return -EINVAL; return -EINVAL;
ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); raw_notifier_call_chain(&cpu_chain, CPU_LOCK_ACQUIRE, hcpu);
ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu,
-1, &nr_calls);
if (ret == NOTIFY_BAD) { if (ret == NOTIFY_BAD) {
printk("%s: attempt to bring up CPU %u failed\n", printk("%s: attempt to bring up CPU %u failed\n",
__FUNCTION__, cpu); __FUNCTION__, cpu);
...@@ -233,8 +241,9 @@ static int __cpuinit _cpu_up(unsigned int cpu) ...@@ -233,8 +241,9 @@ static int __cpuinit _cpu_up(unsigned int cpu)
out_notify: out_notify:
if (ret != 0) if (ret != 0)
raw_notifier_call_chain(&cpu_chain, __raw_notifier_call_chain(&cpu_chain,
CPU_UP_CANCELED, hcpu); CPU_UP_CANCELED, hcpu, nr_calls, NULL);
raw_notifier_call_chain(&cpu_chain, CPU_LOCK_RELEASE, hcpu);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment