diff mbox

SLOW_WORK: Fix the CONFIG_MODULES=n case

Message ID 25668.1259675528@redhat.com
State New
Headers show

Commit Message

David Howells Dec. 1, 2009, 1:52 p.m. UTC
From: David Howells <dhowells@redhat.com>

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>
---

 kernel/slow-work.c |   46 +++++++++++++++++++++++++++++-----------------
 1 files changed, 29 insertions(+), 17 deletions(-)

Comments

Ingo Molnar Dec. 1, 2009, 2:26 p.m. UTC | #1
* David Howells <dhowells@redhat.com> wrote:

> @@ -943,6 +953,7 @@ EXPORT_SYMBOL(slow_work_register_user);
>   */
>  static void slow_work_wait_for_items(struct module *module)
>  {
> +#ifdef CONFIG_MODULES
>  	DECLARE_WAITQUEUE(myself, current);
>  	struct slow_work *work;
>  	int loop;
> @@ -989,6 +1000,7 @@ static void slow_work_wait_for_items(struct module *module)
>  
>  	remove_wait_queue(&slow_work_unreg_wq, &myself);
>  	mutex_unlock(&slow_work_unreg_sync_lock);
> +#endif /* CONFIG_MODULES */
>  }

this slow_work_wait_for_items() function should move into the #ifdef 
block too.

With that fixed it looks good to me for .33 (but i havent tested it):

  Acked-by: Ingo Molnar <mingo@elte.hu>

In terms of .32 i guess it's OK too and the fix is needed - but i'd 
really not have done even the preceding changes - why again did we need 
/proc/slow_work_rq via 8fba10a and why did it have to happen right 
before the final kernel?

If then it should have been done in debugfs - we dont need yet another 
/proc ABI.

Also, a very small aesthetic detail: i think the title should use the 
'slow-work: ' prefix, not 'SLOW_WORK: '.

Thanks,

	Ingo
David Howells Dec. 1, 2009, 3:13 p.m. UTC | #2
Ingo Molnar <mingo@elte.hu> wrote:

> this slow_work_wait_for_items() function should move into the #ifdef 
> block too.

I disagree: I want to keep the variable declaration blocks small; I'd rather
not even put the inline functions in there that I did.  I only did that because
you wanted the #ifdef count reduced.

> In terms of .32 i guess it's OK too and the fix is needed - but i'd really
> not have done even the preceding changes - why again did we need
> /proc/slow_work_rq via 8fba10a

The slow_work_rq debugging interface is not strictly necessary, but it proved a
useful debugging tool.  I emailed Linus before I went on holiday and asked if
he was willing to take these not-strictly-necessary patches on which other
patches were built, or whether he'd prefer me to drop those patches and adjust
the rest.

> and why did it have to happen right before the final kernel?

Because it did.  That's when I finished my set of patches and published them
before going on holiday for a week - and that in turn was related to when I
came up with a better test case.  Sometimes coincidences do happen.

> If then it should have been done in debugfs - we dont need yet another 
> /proc ABI.

Possibly.  That just means we have a debugfs ABI instead of a proc ABI - it
needs maintaining either way.  On the other hand, it can be moved there easily
and the docs changed, and doing so makes a reasonable amount of sense - except
that debugfs isn't normally mounted by at least Fedora for some reason.

David
diff mbox

Patch

diff --git a/kernel/slow-work.c b/kernel/slow-work.c
index da94f3c..b5c17f1 100644
--- a/kernel/slow-work.c
+++ b/kernel/slow-work.c
@@ -109,6 +109,30 @@  static struct module *slow_work_unreg_module;
 static struct slow_work *slow_work_unreg_work_item;
 static DECLARE_WAIT_QUEUE_HEAD(slow_work_unreg_wq);
 static DEFINE_MUTEX(slow_work_unreg_sync_lock);
+
+static void slow_work_set_thread_processing(int id, struct slow_work *work)
+{
+	if (work)
+		slow_work_thread_processing[id] = work->owner;
+}
+static void slow_work_done_thread_processing(int id, struct slow_work *work)
+{
+	struct module *module = slow_work_thread_processing[id];
+
+	slow_work_thread_processing[id] = NULL;
+	smp_mb();
+	if (slow_work_unreg_work_item == work ||
+	    slow_work_unreg_module == module)
+		wake_up_all(&slow_work_unreg_wq);
+}
+static void slow_work_clear_thread_processing(int id)
+{
+	slow_work_thread_processing[id] = NULL;
+}
+#else
+static void slow_work_set_thread_processing(int id, struct slow_work *work) {}
+static void slow_work_done_thread_processing(int id, struct slow_work *work) {}
+static void slow_work_clear_thread_processing(int id) {}
 #endif
 
 /*
@@ -197,9 +221,6 @@  static unsigned slow_work_calc_vsmax(void)
  */
 static noinline bool slow_work_execute(int id)
 {
-#ifdef CONFIG_MODULES
-	struct module *module;
-#endif
 	struct slow_work *work = NULL;
 	unsigned vsmax;
 	bool very_slow;
@@ -236,10 +257,7 @@  static noinline bool slow_work_execute(int id)
 		very_slow = false; /* avoid the compiler warning */
 	}
 
-#ifdef CONFIG_MODULES
-	if (work)
-		slow_work_thread_processing[id] = work->owner;
-#endif
+	slow_work_set_thread_processing(id, work);
 	if (work) {
 		slow_work_mark_time(work);
 		slow_work_begin_exec(id, work);
@@ -287,15 +305,7 @@  static noinline bool slow_work_execute(int id)
 
 	/* sort out the race between module unloading and put_ref() */
 	slow_work_put_ref(work);
-
-#ifdef CONFIG_MODULES
-	module = slow_work_thread_processing[id];
-	slow_work_thread_processing[id] = NULL;
-	smp_mb();
-	if (slow_work_unreg_work_item == work ||
-	    slow_work_unreg_module == module)
-		wake_up_all(&slow_work_unreg_wq);
-#endif
+	slow_work_done_thread_processing(id, work);
 
 	return true;
 
@@ -310,7 +320,7 @@  auto_requeue:
 	else
 		list_add_tail(&work->link, &slow_work_queue);
 	spin_unlock_irq(&slow_work_queue_lock);
-	slow_work_thread_processing[id] = NULL;
+	slow_work_clear_thread_processing(id);
 	return true;
 }
 
@@ -943,6 +953,7 @@  EXPORT_SYMBOL(slow_work_register_user);
  */
 static void slow_work_wait_for_items(struct module *module)
 {
+#ifdef CONFIG_MODULES
 	DECLARE_WAITQUEUE(myself, current);
 	struct slow_work *work;
 	int loop;
@@ -989,6 +1000,7 @@  static void slow_work_wait_for_items(struct module *module)
 
 	remove_wait_queue(&slow_work_unreg_wq, &myself);
 	mutex_unlock(&slow_work_unreg_sync_lock);
+#endif /* CONFIG_MODULES */
 }
 
 /**