Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa1dae49 authored by David Howells's avatar David Howells Committed by Linus Torvalds
Browse files

SLOW_WORK: Fix the CONFIG_MODULES=n case



Commits 3d7a641e ("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
3bde31a4 ("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: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 6f054164
Loading
Loading
Loading
Loading
+29 −17
Original line number Diff line number Diff line
@@ -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 @@ static noinline bool slow_work_execute(int id)
	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 */
}

/**