diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/cpu.c | 29 | ||||
-rw-r--r-- | kernel/module.c | 20 | ||||
-rw-r--r-- | kernel/panic.c | 4 | ||||
-rw-r--r-- | kernel/profile.c | 53 | ||||
-rw-r--r-- | kernel/softlockup.c | 2 | ||||
-rw-r--r-- | kernel/sys.c | 327 |
6 files changed, 301 insertions, 134 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c index 8be22bd80933..fe2b8d0bfe4c 100644 --- a/kernel/cpu.c +++ b/kernel/cpu.c | |||
@@ -18,7 +18,7 @@ | |||
18 | /* This protects CPUs going up and down... */ | 18 | /* This protects CPUs going up and down... */ |
19 | static DECLARE_MUTEX(cpucontrol); | 19 | static DECLARE_MUTEX(cpucontrol); |
20 | 20 | ||
21 | static struct notifier_block *cpu_chain; | 21 | static BLOCKING_NOTIFIER_HEAD(cpu_chain); |
22 | 22 | ||
23 | #ifdef CONFIG_HOTPLUG_CPU | 23 | #ifdef CONFIG_HOTPLUG_CPU |
24 | static struct task_struct *lock_cpu_hotplug_owner; | 24 | static struct task_struct *lock_cpu_hotplug_owner; |
@@ -71,21 +71,13 @@ EXPORT_SYMBOL_GPL(lock_cpu_hotplug_interruptible); | |||
71 | /* Need to know about CPUs going up/down? */ | 71 | /* Need to know about CPUs going up/down? */ |
72 | int register_cpu_notifier(struct notifier_block *nb) | 72 | int register_cpu_notifier(struct notifier_block *nb) |
73 | { | 73 | { |
74 | int ret; | 74 | return blocking_notifier_chain_register(&cpu_chain, nb); |
75 | |||
76 | if ((ret = lock_cpu_hotplug_interruptible()) != 0) | ||
77 | return ret; | ||
78 | ret = notifier_chain_register(&cpu_chain, nb); | ||
79 | unlock_cpu_hotplug(); | ||
80 | return ret; | ||
81 | } | 75 | } |
82 | EXPORT_SYMBOL(register_cpu_notifier); | 76 | EXPORT_SYMBOL(register_cpu_notifier); |
83 | 77 | ||
84 | void unregister_cpu_notifier(struct notifier_block *nb) | 78 | void unregister_cpu_notifier(struct notifier_block *nb) |
85 | { | 79 | { |
86 | lock_cpu_hotplug(); | 80 | blocking_notifier_chain_unregister(&cpu_chain, nb); |
87 | notifier_chain_unregister(&cpu_chain, nb); | ||
88 | unlock_cpu_hotplug(); | ||
89 | } | 81 | } |
90 | EXPORT_SYMBOL(unregister_cpu_notifier); | 82 | EXPORT_SYMBOL(unregister_cpu_notifier); |
91 | 83 | ||
@@ -141,7 +133,7 @@ int cpu_down(unsigned int cpu) | |||
141 | goto out; | 133 | goto out; |
142 | } | 134 | } |
143 | 135 | ||
144 | err = notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, | 136 | err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE, |
145 | (void *)(long)cpu); | 137 | (void *)(long)cpu); |
146 | if (err == NOTIFY_BAD) { | 138 | if (err == NOTIFY_BAD) { |
147 | printk("%s: attempt to take down CPU %u failed\n", | 139 | printk("%s: attempt to take down CPU %u failed\n", |
@@ -159,7 +151,7 @@ int cpu_down(unsigned int cpu) | |||
159 | p = __stop_machine_run(take_cpu_down, NULL, cpu); | 151 | p = __stop_machine_run(take_cpu_down, NULL, cpu); |
160 | if (IS_ERR(p)) { | 152 | if (IS_ERR(p)) { |
161 | /* CPU didn't die: tell everyone. Can't complain. */ | 153 | /* CPU didn't die: tell everyone. Can't complain. */ |
162 | if (notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, | 154 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED, |
163 | (void *)(long)cpu) == NOTIFY_BAD) | 155 | (void *)(long)cpu) == NOTIFY_BAD) |
164 | BUG(); | 156 | BUG(); |
165 | 157 | ||
@@ -182,8 +174,8 @@ int cpu_down(unsigned int cpu) | |||
182 | put_cpu(); | 174 | put_cpu(); |
183 | 175 | ||
184 | /* CPU is completely dead: tell everyone. Too late to complain. */ | 176 | /* CPU is completely dead: tell everyone. Too late to complain. */ |
185 | if (notifier_call_chain(&cpu_chain, CPU_DEAD, (void *)(long)cpu) | 177 | if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD, |
186 | == NOTIFY_BAD) | 178 | (void *)(long)cpu) == NOTIFY_BAD) |
187 | BUG(); | 179 | BUG(); |
188 | 180 | ||
189 | check_for_tasks(cpu); | 181 | check_for_tasks(cpu); |
@@ -211,7 +203,7 @@ int __devinit cpu_up(unsigned int cpu) | |||
211 | goto out; | 203 | goto out; |
212 | } | 204 | } |
213 | 205 | ||
214 | ret = notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); | 206 | ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu); |
215 | if (ret == NOTIFY_BAD) { | 207 | if (ret == NOTIFY_BAD) { |
216 | printk("%s: attempt to bring up CPU %u failed\n", | 208 | printk("%s: attempt to bring up CPU %u failed\n", |
217 | __FUNCTION__, cpu); | 209 | __FUNCTION__, cpu); |
@@ -226,11 +218,12 @@ int __devinit cpu_up(unsigned int cpu) | |||
226 | BUG_ON(!cpu_online(cpu)); | 218 | BUG_ON(!cpu_online(cpu)); |
227 | 219 | ||
228 | /* Now call notifier in preparation. */ | 220 | /* Now call notifier in preparation. */ |
229 | notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); | 221 | blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu); |
230 | 222 | ||
231 | out_notify: | 223 | out_notify: |
232 | if (ret != 0) | 224 | if (ret != 0) |
233 | notifier_call_chain(&cpu_chain, CPU_UP_CANCELED, hcpu); | 225 | blocking_notifier_call_chain(&cpu_chain, |
226 | CPU_UP_CANCELED, hcpu); | ||
234 | out: | 227 | out: |
235 | unlock_cpu_hotplug(); | 228 | unlock_cpu_hotplug(); |
236 | return ret; | 229 | return ret; |
diff --git a/kernel/module.c b/kernel/module.c index ddfe45ac2fd1..4fafd58038a0 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -64,26 +64,17 @@ static DEFINE_SPINLOCK(modlist_lock); | |||
64 | static DEFINE_MUTEX(module_mutex); | 64 | static DEFINE_MUTEX(module_mutex); |
65 | static LIST_HEAD(modules); | 65 | static LIST_HEAD(modules); |
66 | 66 | ||
67 | static DEFINE_MUTEX(notify_mutex); | 67 | static BLOCKING_NOTIFIER_HEAD(module_notify_list); |
68 | static struct notifier_block * module_notify_list; | ||
69 | 68 | ||
70 | int register_module_notifier(struct notifier_block * nb) | 69 | int register_module_notifier(struct notifier_block * nb) |
71 | { | 70 | { |
72 | int err; | 71 | return blocking_notifier_chain_register(&module_notify_list, nb); |
73 | mutex_lock(¬ify_mutex); | ||
74 | err = notifier_chain_register(&module_notify_list, nb); | ||
75 | mutex_unlock(¬ify_mutex); | ||
76 | return err; | ||
77 | } | 72 | } |
78 | EXPORT_SYMBOL(register_module_notifier); | 73 | EXPORT_SYMBOL(register_module_notifier); |
79 | 74 | ||
80 | int unregister_module_notifier(struct notifier_block * nb) | 75 | int unregister_module_notifier(struct notifier_block * nb) |
81 | { | 76 | { |
82 | int err; | 77 | return blocking_notifier_chain_unregister(&module_notify_list, nb); |
83 | mutex_lock(¬ify_mutex); | ||
84 | err = notifier_chain_unregister(&module_notify_list, nb); | ||
85 | mutex_unlock(¬ify_mutex); | ||
86 | return err; | ||
87 | } | 78 | } |
88 | EXPORT_SYMBOL(unregister_module_notifier); | 79 | EXPORT_SYMBOL(unregister_module_notifier); |
89 | 80 | ||
@@ -1816,9 +1807,8 @@ sys_init_module(void __user *umod, | |||
1816 | /* Drop lock so they can recurse */ | 1807 | /* Drop lock so they can recurse */ |
1817 | mutex_unlock(&module_mutex); | 1808 | mutex_unlock(&module_mutex); |
1818 | 1809 | ||
1819 | mutex_lock(¬ify_mutex); | 1810 | blocking_notifier_call_chain(&module_notify_list, |
1820 | notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod); | 1811 | MODULE_STATE_COMING, mod); |
1821 | mutex_unlock(¬ify_mutex); | ||
1822 | 1812 | ||
1823 | /* Start the module */ | 1813 | /* Start the module */ |
1824 | if (mod->init != NULL) | 1814 | if (mod->init != NULL) |
diff --git a/kernel/panic.c b/kernel/panic.c index acd95adddb93..f895c7c01d5b 100644 --- a/kernel/panic.c +++ b/kernel/panic.c | |||
@@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(pause_on_oops_lock); | |||
29 | int panic_timeout; | 29 | int panic_timeout; |
30 | EXPORT_SYMBOL(panic_timeout); | 30 | EXPORT_SYMBOL(panic_timeout); |
31 | 31 | ||
32 | struct notifier_block *panic_notifier_list; | 32 | ATOMIC_NOTIFIER_HEAD(panic_notifier_list); |
33 | 33 | ||
34 | EXPORT_SYMBOL(panic_notifier_list); | 34 | EXPORT_SYMBOL(panic_notifier_list); |
35 | 35 | ||
@@ -97,7 +97,7 @@ NORET_TYPE void panic(const char * fmt, ...) | |||
97 | smp_send_stop(); | 97 | smp_send_stop(); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | notifier_call_chain(&panic_notifier_list, 0, buf); | 100 | atomic_notifier_call_chain(&panic_notifier_list, 0, buf); |
101 | 101 | ||
102 | if (!panic_blink) | 102 | if (!panic_blink) |
103 | panic_blink = no_blink; | 103 | panic_blink = no_blink; |
diff --git a/kernel/profile.c b/kernel/profile.c index ad81f799a9b4..5a730fdb1a2c 100644 --- a/kernel/profile.c +++ b/kernel/profile.c | |||
@@ -87,72 +87,52 @@ void __init profile_init(void) | |||
87 | 87 | ||
88 | #ifdef CONFIG_PROFILING | 88 | #ifdef CONFIG_PROFILING |
89 | 89 | ||
90 | static DECLARE_RWSEM(profile_rwsem); | 90 | static BLOCKING_NOTIFIER_HEAD(task_exit_notifier); |
91 | static DEFINE_RWLOCK(handoff_lock); | 91 | static ATOMIC_NOTIFIER_HEAD(task_free_notifier); |
92 | static struct notifier_block * task_exit_notifier; | 92 | static BLOCKING_NOTIFIER_HEAD(munmap_notifier); |
93 | static struct notifier_block * task_free_notifier; | ||
94 | static struct notifier_block * munmap_notifier; | ||
95 | 93 | ||
96 | void profile_task_exit(struct task_struct * task) | 94 | void profile_task_exit(struct task_struct * task) |
97 | { | 95 | { |
98 | down_read(&profile_rwsem); | 96 | blocking_notifier_call_chain(&task_exit_notifier, 0, task); |
99 | notifier_call_chain(&task_exit_notifier, 0, task); | ||
100 | up_read(&profile_rwsem); | ||
101 | } | 97 | } |
102 | 98 | ||
103 | int profile_handoff_task(struct task_struct * task) | 99 | int profile_handoff_task(struct task_struct * task) |
104 | { | 100 | { |
105 | int ret; | 101 | int ret; |
106 | read_lock(&handoff_lock); | 102 | ret = atomic_notifier_call_chain(&task_free_notifier, 0, task); |
107 | ret = notifier_call_chain(&task_free_notifier, 0, task); | ||
108 | read_unlock(&handoff_lock); | ||
109 | return (ret == NOTIFY_OK) ? 1 : 0; | 103 | return (ret == NOTIFY_OK) ? 1 : 0; |
110 | } | 104 | } |
111 | 105 | ||
112 | void profile_munmap(unsigned long addr) | 106 | void profile_munmap(unsigned long addr) |
113 | { | 107 | { |
114 | down_read(&profile_rwsem); | 108 | blocking_notifier_call_chain(&munmap_notifier, 0, (void *)addr); |
115 | notifier_call_chain(&munmap_notifier, 0, (void *)addr); | ||
116 | up_read(&profile_rwsem); | ||
117 | } | 109 | } |
118 | 110 | ||
119 | int task_handoff_register(struct notifier_block * n) | 111 | int task_handoff_register(struct notifier_block * n) |
120 | { | 112 | { |
121 | int err = -EINVAL; | 113 | return atomic_notifier_chain_register(&task_free_notifier, n); |
122 | |||
123 | write_lock(&handoff_lock); | ||
124 | err = notifier_chain_register(&task_free_notifier, n); | ||
125 | write_unlock(&handoff_lock); | ||
126 | return err; | ||
127 | } | 114 | } |
128 | 115 | ||
129 | int task_handoff_unregister(struct notifier_block * n) | 116 | int task_handoff_unregister(struct notifier_block * n) |
130 | { | 117 | { |
131 | int err = -EINVAL; | 118 | return atomic_notifier_chain_unregister(&task_free_notifier, n); |
132 | |||
133 | write_lock(&handoff_lock); | ||
134 | err = notifier_chain_unregister(&task_free_notifier, n); | ||
135 | write_unlock(&handoff_lock); | ||
136 | return err; | ||
137 | } | 119 | } |
138 | 120 | ||
139 | int profile_event_register(enum profile_type type, struct notifier_block * n) | 121 | int profile_event_register(enum profile_type type, struct notifier_block * n) |
140 | { | 122 | { |
141 | int err = -EINVAL; | 123 | int err = -EINVAL; |
142 | 124 | ||
143 | down_write(&profile_rwsem); | ||
144 | |||
145 | switch (type) { | 125 | switch (type) { |
146 | case PROFILE_TASK_EXIT: | 126 | case PROFILE_TASK_EXIT: |
147 | err = notifier_chain_register(&task_exit_notifier, n); | 127 | err = blocking_notifier_chain_register( |
128 | &task_exit_notifier, n); | ||
148 | break; | 129 | break; |
149 | case PROFILE_MUNMAP: | 130 | case PROFILE_MUNMAP: |
150 | err = notifier_chain_register(&munmap_notifier, n); | 131 | err = blocking_notifier_chain_register( |
132 | &munmap_notifier, n); | ||
151 | break; | 133 | break; |
152 | } | 134 | } |
153 | 135 | ||
154 | up_write(&profile_rwsem); | ||
155 | |||
156 | return err; | 136 | return err; |
157 | } | 137 | } |
158 | 138 | ||
@@ -161,18 +141,17 @@ int profile_event_unregister(enum profile_type type, struct notifier_block * n) | |||
161 | { | 141 | { |
162 | int err = -EINVAL; | 142 | int err = -EINVAL; |
163 | 143 | ||
164 | down_write(&profile_rwsem); | ||
165 | |||
166 | switch (type) { | 144 | switch (type) { |
167 | case PROFILE_TASK_EXIT: | 145 | case PROFILE_TASK_EXIT: |
168 | err = notifier_chain_unregister(&task_exit_notifier, n); | 146 | err = blocking_notifier_chain_unregister( |
147 | &task_exit_notifier, n); | ||
169 | break; | 148 | break; |
170 | case PROFILE_MUNMAP: | 149 | case PROFILE_MUNMAP: |
171 | err = notifier_chain_unregister(&munmap_notifier, n); | 150 | err = blocking_notifier_chain_unregister( |
151 | &munmap_notifier, n); | ||
172 | break; | 152 | break; |
173 | } | 153 | } |
174 | 154 | ||
175 | up_write(&profile_rwsem); | ||
176 | return err; | 155 | return err; |
177 | } | 156 | } |
178 | 157 | ||
diff --git a/kernel/softlockup.c b/kernel/softlockup.c index d9b3d5847ed8..ced91e1ff564 100644 --- a/kernel/softlockup.c +++ b/kernel/softlockup.c | |||
@@ -152,5 +152,5 @@ __init void spawn_softlockup_task(void) | |||
152 | cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); | 152 | cpu_callback(&cpu_nfb, CPU_ONLINE, cpu); |
153 | register_cpu_notifier(&cpu_nfb); | 153 | register_cpu_notifier(&cpu_nfb); |
154 | 154 | ||
155 | notifier_chain_register(&panic_notifier_list, &panic_block); | 155 | atomic_notifier_chain_register(&panic_notifier_list, &panic_block); |
156 | } | 156 | } |
diff --git a/kernel/sys.c b/kernel/sys.c index 38bc73ede2ba..c93d37f71aef 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -95,99 +95,304 @@ int cad_pid = 1; | |||
95 | * and the like. | 95 | * and the like. |
96 | */ | 96 | */ |
97 | 97 | ||
98 | static struct notifier_block *reboot_notifier_list; | 98 | static BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); |
99 | static DEFINE_RWLOCK(notifier_lock); | 99 | |
100 | /* | ||
101 | * Notifier chain core routines. The exported routines below | ||
102 | * are layered on top of these, with appropriate locking added. | ||
103 | */ | ||
104 | |||
105 | static int notifier_chain_register(struct notifier_block **nl, | ||
106 | struct notifier_block *n) | ||
107 | { | ||
108 | while ((*nl) != NULL) { | ||
109 | if (n->priority > (*nl)->priority) | ||
110 | break; | ||
111 | nl = &((*nl)->next); | ||
112 | } | ||
113 | n->next = *nl; | ||
114 | rcu_assign_pointer(*nl, n); | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int notifier_chain_unregister(struct notifier_block **nl, | ||
119 | struct notifier_block *n) | ||
120 | { | ||
121 | while ((*nl) != NULL) { | ||
122 | if ((*nl) == n) { | ||
123 | rcu_assign_pointer(*nl, n->next); | ||
124 | return 0; | ||
125 | } | ||
126 | nl = &((*nl)->next); | ||
127 | } | ||
128 | return -ENOENT; | ||
129 | } | ||
130 | |||
131 | static int __kprobes notifier_call_chain(struct notifier_block **nl, | ||
132 | unsigned long val, void *v) | ||
133 | { | ||
134 | int ret = NOTIFY_DONE; | ||
135 | struct notifier_block *nb; | ||
136 | |||
137 | nb = rcu_dereference(*nl); | ||
138 | while (nb) { | ||
139 | ret = nb->notifier_call(nb, val, v); | ||
140 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) | ||
141 | break; | ||
142 | nb = rcu_dereference(nb->next); | ||
143 | } | ||
144 | return ret; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Atomic notifier chain routines. Registration and unregistration | ||
149 | * use a mutex, and call_chain is synchronized by RCU (no locks). | ||
150 | */ | ||
100 | 151 | ||
101 | /** | 152 | /** |
102 | * notifier_chain_register - Add notifier to a notifier chain | 153 | * atomic_notifier_chain_register - Add notifier to an atomic notifier chain |
103 | * @list: Pointer to root list pointer | 154 | * @nh: Pointer to head of the atomic notifier chain |
104 | * @n: New entry in notifier chain | 155 | * @n: New entry in notifier chain |
105 | * | 156 | * |
106 | * Adds a notifier to a notifier chain. | 157 | * Adds a notifier to an atomic notifier chain. |
107 | * | 158 | * |
108 | * Currently always returns zero. | 159 | * Currently always returns zero. |
109 | */ | 160 | */ |
161 | |||
162 | int atomic_notifier_chain_register(struct atomic_notifier_head *nh, | ||
163 | struct notifier_block *n) | ||
164 | { | ||
165 | unsigned long flags; | ||
166 | int ret; | ||
167 | |||
168 | spin_lock_irqsave(&nh->lock, flags); | ||
169 | ret = notifier_chain_register(&nh->head, n); | ||
170 | spin_unlock_irqrestore(&nh->lock, flags); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); | ||
175 | |||
176 | /** | ||
177 | * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain | ||
178 | * @nh: Pointer to head of the atomic notifier chain | ||
179 | * @n: Entry to remove from notifier chain | ||
180 | * | ||
181 | * Removes a notifier from an atomic notifier chain. | ||
182 | * | ||
183 | * Returns zero on success or %-ENOENT on failure. | ||
184 | */ | ||
185 | int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, | ||
186 | struct notifier_block *n) | ||
187 | { | ||
188 | unsigned long flags; | ||
189 | int ret; | ||
190 | |||
191 | spin_lock_irqsave(&nh->lock, flags); | ||
192 | ret = notifier_chain_unregister(&nh->head, n); | ||
193 | spin_unlock_irqrestore(&nh->lock, flags); | ||
194 | synchronize_rcu(); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); | ||
199 | |||
200 | /** | ||
201 | * atomic_notifier_call_chain - Call functions in an atomic notifier chain | ||
202 | * @nh: Pointer to head of the atomic notifier chain | ||
203 | * @val: Value passed unmodified to notifier function | ||
204 | * @v: Pointer passed unmodified to notifier function | ||
205 | * | ||
206 | * Calls each function in a notifier chain in turn. The functions | ||
207 | * run in an atomic context, so they must not block. | ||
208 | * This routine uses RCU to synchronize with changes to the chain. | ||
209 | * | ||
210 | * If the return value of the notifier can be and'ed | ||
211 | * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain | ||
212 | * will return immediately, with the return value of | ||
213 | * the notifier function which halted execution. | ||
214 | * Otherwise the return value is the return value | ||
215 | * of the last notifier function called. | ||
216 | */ | ||
110 | 217 | ||
111 | int notifier_chain_register(struct notifier_block **list, struct notifier_block *n) | 218 | int atomic_notifier_call_chain(struct atomic_notifier_head *nh, |
219 | unsigned long val, void *v) | ||
112 | { | 220 | { |
113 | write_lock(¬ifier_lock); | 221 | int ret; |
114 | while(*list) | 222 | |
115 | { | 223 | rcu_read_lock(); |
116 | if(n->priority > (*list)->priority) | 224 | ret = notifier_call_chain(&nh->head, val, v); |
117 | break; | 225 | rcu_read_unlock(); |
118 | list= &((*list)->next); | 226 | return ret; |
119 | } | ||
120 | n->next = *list; | ||
121 | *list=n; | ||
122 | write_unlock(¬ifier_lock); | ||
123 | return 0; | ||
124 | } | 227 | } |
125 | 228 | ||
126 | EXPORT_SYMBOL(notifier_chain_register); | 229 | EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); |
230 | |||
231 | /* | ||
232 | * Blocking notifier chain routines. All access to the chain is | ||
233 | * synchronized by an rwsem. | ||
234 | */ | ||
127 | 235 | ||
128 | /** | 236 | /** |
129 | * notifier_chain_unregister - Remove notifier from a notifier chain | 237 | * blocking_notifier_chain_register - Add notifier to a blocking notifier chain |
130 | * @nl: Pointer to root list pointer | 238 | * @nh: Pointer to head of the blocking notifier chain |
131 | * @n: New entry in notifier chain | 239 | * @n: New entry in notifier chain |
132 | * | 240 | * |
133 | * Removes a notifier from a notifier chain. | 241 | * Adds a notifier to a blocking notifier chain. |
242 | * Must be called in process context. | ||
134 | * | 243 | * |
135 | * Returns zero on success, or %-ENOENT on failure. | 244 | * Currently always returns zero. |
136 | */ | 245 | */ |
137 | 246 | ||
138 | int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n) | 247 | int blocking_notifier_chain_register(struct blocking_notifier_head *nh, |
248 | struct notifier_block *n) | ||
139 | { | 249 | { |
140 | write_lock(¬ifier_lock); | 250 | int ret; |
141 | while((*nl)!=NULL) | 251 | |
142 | { | 252 | /* |
143 | if((*nl)==n) | 253 | * This code gets used during boot-up, when task switching is |
144 | { | 254 | * not yet working and interrupts must remain disabled. At |
145 | *nl=n->next; | 255 | * such times we must not call down_write(). |
146 | write_unlock(¬ifier_lock); | 256 | */ |
147 | return 0; | 257 | if (unlikely(system_state == SYSTEM_BOOTING)) |
148 | } | 258 | return notifier_chain_register(&nh->head, n); |
149 | nl=&((*nl)->next); | 259 | |
150 | } | 260 | down_write(&nh->rwsem); |
151 | write_unlock(¬ifier_lock); | 261 | ret = notifier_chain_register(&nh->head, n); |
152 | return -ENOENT; | 262 | up_write(&nh->rwsem); |
263 | return ret; | ||
153 | } | 264 | } |
154 | 265 | ||
155 | EXPORT_SYMBOL(notifier_chain_unregister); | 266 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); |
156 | 267 | ||
157 | /** | 268 | /** |
158 | * notifier_call_chain - Call functions in a notifier chain | 269 | * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain |
159 | * @n: Pointer to root pointer of notifier chain | 270 | * @nh: Pointer to head of the blocking notifier chain |
271 | * @n: Entry to remove from notifier chain | ||
272 | * | ||
273 | * Removes a notifier from a blocking notifier chain. | ||
274 | * Must be called from process context. | ||
275 | * | ||
276 | * Returns zero on success or %-ENOENT on failure. | ||
277 | */ | ||
278 | int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, | ||
279 | struct notifier_block *n) | ||
280 | { | ||
281 | int ret; | ||
282 | |||
283 | /* | ||
284 | * This code gets used during boot-up, when task switching is | ||
285 | * not yet working and interrupts must remain disabled. At | ||
286 | * such times we must not call down_write(). | ||
287 | */ | ||
288 | if (unlikely(system_state == SYSTEM_BOOTING)) | ||
289 | return notifier_chain_unregister(&nh->head, n); | ||
290 | |||
291 | down_write(&nh->rwsem); | ||
292 | ret = notifier_chain_unregister(&nh->head, n); | ||
293 | up_write(&nh->rwsem); | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); | ||
298 | |||
299 | /** | ||
300 | * blocking_notifier_call_chain - Call functions in a blocking notifier chain | ||
301 | * @nh: Pointer to head of the blocking notifier chain | ||
160 | * @val: Value passed unmodified to notifier function | 302 | * @val: Value passed unmodified to notifier function |
161 | * @v: Pointer passed unmodified to notifier function | 303 | * @v: Pointer passed unmodified to notifier function |
162 | * | 304 | * |
163 | * Calls each function in a notifier chain in turn. | 305 | * Calls each function in a notifier chain in turn. The functions |
306 | * run in a process context, so they are allowed to block. | ||
164 | * | 307 | * |
165 | * If the return value of the notifier can be and'd | 308 | * If the return value of the notifier can be and'ed |
166 | * with %NOTIFY_STOP_MASK, then notifier_call_chain | 309 | * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain |
167 | * will return immediately, with the return value of | 310 | * will return immediately, with the return value of |
168 | * the notifier function which halted execution. | 311 | * the notifier function which halted execution. |
169 | * Otherwise, the return value is the return value | 312 | * Otherwise the return value is the return value |
170 | * of the last notifier function called. | 313 | * of the last notifier function called. |
171 | */ | 314 | */ |
172 | 315 | ||
173 | int __kprobes notifier_call_chain(struct notifier_block **n, unsigned long val, void *v) | 316 | int blocking_notifier_call_chain(struct blocking_notifier_head *nh, |
317 | unsigned long val, void *v) | ||
174 | { | 318 | { |
175 | int ret=NOTIFY_DONE; | 319 | int ret; |
176 | struct notifier_block *nb = *n; | ||
177 | 320 | ||
178 | while(nb) | 321 | down_read(&nh->rwsem); |
179 | { | 322 | ret = notifier_call_chain(&nh->head, val, v); |
180 | ret=nb->notifier_call(nb,val,v); | 323 | up_read(&nh->rwsem); |
181 | if(ret&NOTIFY_STOP_MASK) | ||
182 | { | ||
183 | return ret; | ||
184 | } | ||
185 | nb=nb->next; | ||
186 | } | ||
187 | return ret; | 324 | return ret; |
188 | } | 325 | } |
189 | 326 | ||
190 | EXPORT_SYMBOL(notifier_call_chain); | 327 | EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); |
328 | |||
329 | /* | ||
330 | * Raw notifier chain routines. There is no protection; | ||
331 | * the caller must provide it. Use at your own risk! | ||
332 | */ | ||
333 | |||
334 | /** | ||
335 | * raw_notifier_chain_register - Add notifier to a raw notifier chain | ||
336 | * @nh: Pointer to head of the raw notifier chain | ||
337 | * @n: New entry in notifier chain | ||
338 | * | ||
339 | * Adds a notifier to a raw notifier chain. | ||
340 | * All locking must be provided by the caller. | ||
341 | * | ||
342 | * Currently always returns zero. | ||
343 | */ | ||
344 | |||
345 | int raw_notifier_chain_register(struct raw_notifier_head *nh, | ||
346 | struct notifier_block *n) | ||
347 | { | ||
348 | return notifier_chain_register(&nh->head, n); | ||
349 | } | ||
350 | |||
351 | EXPORT_SYMBOL_GPL(raw_notifier_chain_register); | ||
352 | |||
353 | /** | ||
354 | * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain | ||
355 | * @nh: Pointer to head of the raw notifier chain | ||
356 | * @n: Entry to remove from notifier chain | ||
357 | * | ||
358 | * Removes a notifier from a raw notifier chain. | ||
359 | * All locking must be provided by the caller. | ||
360 | * | ||
361 | * Returns zero on success or %-ENOENT on failure. | ||
362 | */ | ||
363 | int raw_notifier_chain_unregister(struct raw_notifier_head *nh, | ||
364 | struct notifier_block *n) | ||
365 | { | ||
366 | return notifier_chain_unregister(&nh->head, n); | ||
367 | } | ||
368 | |||
369 | EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); | ||
370 | |||
371 | /** | ||
372 | * raw_notifier_call_chain - Call functions in a raw notifier chain | ||
373 | * @nh: Pointer to head of the raw notifier chain | ||
374 | * @val: Value passed unmodified to notifier function | ||
375 | * @v: Pointer passed unmodified to notifier function | ||
376 | * | ||
377 | * Calls each function in a notifier chain in turn. The functions | ||
378 | * run in an undefined context. | ||
379 | * All locking must be provided by the caller. | ||
380 | * | ||
381 | * If the return value of the notifier can be and'ed | ||
382 | * with %NOTIFY_STOP_MASK then raw_notifier_call_chain | ||
383 | * will return immediately, with the return value of | ||
384 | * the notifier function which halted execution. | ||
385 | * Otherwise the return value is the return value | ||
386 | * of the last notifier function called. | ||
387 | */ | ||
388 | |||
389 | int raw_notifier_call_chain(struct raw_notifier_head *nh, | ||
390 | unsigned long val, void *v) | ||
391 | { | ||
392 | return notifier_call_chain(&nh->head, val, v); | ||
393 | } | ||
394 | |||
395 | EXPORT_SYMBOL_GPL(raw_notifier_call_chain); | ||
191 | 396 | ||
192 | /** | 397 | /** |
193 | * register_reboot_notifier - Register function to be called at reboot time | 398 | * register_reboot_notifier - Register function to be called at reboot time |
@@ -196,13 +401,13 @@ EXPORT_SYMBOL(notifier_call_chain); | |||
196 | * Registers a function with the list of functions | 401 | * Registers a function with the list of functions |
197 | * to be called at reboot time. | 402 | * to be called at reboot time. |
198 | * | 403 | * |
199 | * Currently always returns zero, as notifier_chain_register | 404 | * Currently always returns zero, as blocking_notifier_chain_register |
200 | * always returns zero. | 405 | * always returns zero. |
201 | */ | 406 | */ |
202 | 407 | ||
203 | int register_reboot_notifier(struct notifier_block * nb) | 408 | int register_reboot_notifier(struct notifier_block * nb) |
204 | { | 409 | { |
205 | return notifier_chain_register(&reboot_notifier_list, nb); | 410 | return blocking_notifier_chain_register(&reboot_notifier_list, nb); |
206 | } | 411 | } |
207 | 412 | ||
208 | EXPORT_SYMBOL(register_reboot_notifier); | 413 | EXPORT_SYMBOL(register_reboot_notifier); |
@@ -219,7 +424,7 @@ EXPORT_SYMBOL(register_reboot_notifier); | |||
219 | 424 | ||
220 | int unregister_reboot_notifier(struct notifier_block * nb) | 425 | int unregister_reboot_notifier(struct notifier_block * nb) |
221 | { | 426 | { |
222 | return notifier_chain_unregister(&reboot_notifier_list, nb); | 427 | return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); |
223 | } | 428 | } |
224 | 429 | ||
225 | EXPORT_SYMBOL(unregister_reboot_notifier); | 430 | EXPORT_SYMBOL(unregister_reboot_notifier); |
@@ -380,7 +585,7 @@ EXPORT_SYMBOL_GPL(emergency_restart); | |||
380 | 585 | ||
381 | void kernel_restart_prepare(char *cmd) | 586 | void kernel_restart_prepare(char *cmd) |
382 | { | 587 | { |
383 | notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); | 588 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); |
384 | system_state = SYSTEM_RESTART; | 589 | system_state = SYSTEM_RESTART; |
385 | device_shutdown(); | 590 | device_shutdown(); |
386 | } | 591 | } |
@@ -430,7 +635,7 @@ EXPORT_SYMBOL_GPL(kernel_kexec); | |||
430 | 635 | ||
431 | void kernel_shutdown_prepare(enum system_states state) | 636 | void kernel_shutdown_prepare(enum system_states state) |
432 | { | 637 | { |
433 | notifier_call_chain(&reboot_notifier_list, | 638 | blocking_notifier_call_chain(&reboot_notifier_list, |
434 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); | 639 | (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); |
435 | system_state = state; | 640 | system_state = state; |
436 | device_shutdown(); | 641 | device_shutdown(); |