diff options
author | David Howells <dhowells@redhat.com> | 2009-12-01 08:52:08 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-01 10:35:11 -0500 |
commit | fa1dae4906982b5d896c07613b1fe42456133b1c (patch) | |
tree | 027dec5baeedbe25a7b645311b530a06d78b36f3 | |
parent | 6f054164322bc6c1233402b9ed6b40d4af39a98f (diff) |
SLOW_WORK: Fix the CONFIG_MODULES=n case
Commits 3d7a641 ("SLOW_WORK: Wait for outstanding work items belonging to a
module to clear") introduced some code to make sure that all of a module's
slow-work items were complete before that module was removed, and commit
3bde31a ("SLOW_WORK: Allow a requeueable work item to sleep till the thread is
needed") further extended that, breaking it in the process if CONFIG_MODULES=n:
CC kernel/slow-work.o
kernel/slow-work.c: In function 'slow_work_execute':
kernel/slow-work.c:313: error: 'slow_work_thread_processing' undeclared (first use in this function)
kernel/slow-work.c:313: error: (Each undeclared identifier is reported only once
kernel/slow-work.c:313: error: for each function it appears in.)
kernel/slow-work.c: In function 'slow_work_wait_for_items':
kernel/slow-work.c:950: error: 'slow_work_unreg_sync_lock' undeclared (first use in this function)
kernel/slow-work.c:951: error: 'slow_work_unreg_wq' undeclared (first use in this function)
kernel/slow-work.c:961: error: 'slow_work_unreg_work_item' undeclared (first use in this function)
kernel/slow-work.c:974: error: 'slow_work_unreg_module' undeclared (first use in this function)
kernel/slow-work.c:977: error: 'slow_work_thread_processing' undeclared (first use in this function)
make[1]: *** [kernel/slow-work.o] Error 1
Fix this by:
(1) Extracting the bits of slow_work_execute() that are contingent on
CONFIG_MODULES, and the bits that should be, into inline functions and
placing them into the #ifdef'd section that defines the relevant variables
and adding stubs for moduleless kernels. This allows the removal of some
#ifdefs.
(2) #ifdef'ing out the contents of slow_work_wait_for_items() in moduleless
kernels.
The four functions related to handling module unloading synchronisation (and
their associated variables) could be offloaded into a separate .c file, but
each function is only used once and three of them are tiny, so doing so would
prevent them from being inlined.
Reported-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | kernel/slow-work.c | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/kernel/slow-work.c b/kernel/slow-work.c index da94f3c101af..b5c17f15f9de 100644 --- a/kernel/slow-work.c +++ b/kernel/slow-work.c | |||
@@ -109,6 +109,30 @@ static struct module *slow_work_unreg_module; | |||
109 | static struct slow_work *slow_work_unreg_work_item; | 109 | static struct slow_work *slow_work_unreg_work_item; |
110 | static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq); | 110 | static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq); |
111 | static DEFINE_MUTEX(slow_work_unreg_sync_lock); | 111 | static DEFINE_MUTEX(slow_work_unreg_sync_lock); |
112 | |||
113 | static void slow_work_set_thread_processing(int id, struct slow_work *work) | ||
114 | { | ||
115 | if (work) | ||
116 | slow_work_thread_processing[id] = work->owner; | ||
117 | } | ||
118 | static void slow_work_done_thread_processing(int id, struct slow_work *work) | ||
119 | { | ||
120 | struct module *module = slow_work_thread_processing[id]; | ||
121 | |||
122 | slow_work_thread_processing[id] = NULL; | ||
123 | smp_mb(); | ||
124 | if (slow_work_unreg_work_item == work || | ||
125 | slow_work_unreg_module == module) | ||
126 | wake_up_all(&slow_work_unreg_wq); | ||
127 | } | ||
128 | static void slow_work_clear_thread_processing(int id) | ||
129 | { | ||
130 | slow_work_thread_processing[id] = NULL; | ||
131 | } | ||
132 | #else | ||
133 | static void slow_work_set_thread_processing(int id, struct slow_work *work) {} | ||
134 | static void slow_work_done_thread_processing(int id, struct slow_work *work) {} | ||
135 | static void slow_work_clear_thread_processing(int id) {} | ||
112 | #endif | 136 | #endif |
113 | 137 | ||
114 | /* | 138 | /* |
@@ -197,9 +221,6 @@ static unsigned slow_work_calc_vsmax(void) | |||
197 | */ | 221 | */ |
198 | static noinline bool slow_work_execute(int id) | 222 | static noinline bool slow_work_execute(int id) |
199 | { | 223 | { |
200 | #ifdef CONFIG_MODULES | ||
201 | struct module *module; | ||
202 | #endif | ||
203 | struct slow_work *work = NULL; | 224 | struct slow_work *work = NULL; |
204 | unsigned vsmax; | 225 | unsigned vsmax; |
205 | bool very_slow; | 226 | bool very_slow; |
@@ -236,10 +257,7 @@ static noinline bool slow_work_execute(int id) | |||
236 | very_slow = false; /* avoid the compiler warning */ | 257 | very_slow = false; /* avoid the compiler warning */ |
237 | } | 258 | } |
238 | 259 | ||
239 | #ifdef CONFIG_MODULES | 260 | slow_work_set_thread_processing(id, work); |
240 | if (work) | ||
241 | slow_work_thread_processing[id] = work->owner; | ||
242 | #endif | ||
243 | if (work) { | 261 | if (work) { |
244 | slow_work_mark_time(work); | 262 | slow_work_mark_time(work); |
245 | slow_work_begin_exec(id, work); | 263 | slow_work_begin_exec(id, work); |
@@ -287,15 +305,7 @@ static noinline bool slow_work_execute(int id) | |||
287 | 305 | ||
288 | /* sort out the race between module unloading and put_ref() */ | 306 | /* sort out the race between module unloading and put_ref() */ |
289 | slow_work_put_ref(work); | 307 | slow_work_put_ref(work); |
290 | 308 | slow_work_done_thread_processing(id, work); | |
291 | #ifdef CONFIG_MODULES | ||
292 | module = slow_work_thread_processing[id]; | ||
293 | slow_work_thread_processing[id] = NULL; | ||
294 | smp_mb(); | ||
295 | if (slow_work_unreg_work_item == work || | ||
296 | slow_work_unreg_module == module) | ||
297 | wake_up_all(&slow_work_unreg_wq); | ||
298 | #endif | ||
299 | 309 | ||
300 | return true; | 310 | return true; |
301 | 311 | ||
@@ -310,7 +320,7 @@ auto_requeue: | |||
310 | else | 320 | else |
311 | list_add_tail(&work->link, &slow_work_queue); | 321 | list_add_tail(&work->link, &slow_work_queue); |
312 | spin_unlock_irq(&slow_work_queue_lock); | 322 | spin_unlock_irq(&slow_work_queue_lock); |
313 | slow_work_thread_processing[id] = NULL; | 323 | slow_work_clear_thread_processing(id); |
314 | return true; | 324 | return true; |
315 | } | 325 | } |
316 | 326 | ||
@@ -943,6 +953,7 @@ EXPORT_SYMBOL(slow_work_register_user); | |||
943 | */ | 953 | */ |
944 | static void slow_work_wait_for_items(struct module *module) | 954 | static void slow_work_wait_for_items(struct module *module) |
945 | { | 955 | { |
956 | #ifdef CONFIG_MODULES | ||
946 | DECLARE_WAITQUEUE(myself, current); | 957 | DECLARE_WAITQUEUE(myself, current); |
947 | struct slow_work *work; | 958 | struct slow_work *work; |
948 | int loop; | 959 | int loop; |
@@ -989,6 +1000,7 @@ static void slow_work_wait_for_items(struct module *module) | |||
989 | 1000 | ||
990 | remove_wait_queue(&slow_work_unreg_wq, &myself); | 1001 | remove_wait_queue(&slow_work_unreg_wq, &myself); |
991 | mutex_unlock(&slow_work_unreg_sync_lock); | 1002 | mutex_unlock(&slow_work_unreg_sync_lock); |
1003 | #endif /* CONFIG_MODULES */ | ||
992 | } | 1004 | } |
993 | 1005 | ||
994 | /** | 1006 | /** |