public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: ebiederm@xmission.com, cornelia.huck@de.ibm.com, greg@kroah.com,
	stern@rowland.harvard.edu, kay.sievers@vrfy.org,
	linux-kernel@vger.kernel.org, rusty@rustcorp.com.au,
	htejun@gmail.com
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 1/4] module: implement module_inhibit_unload()
Date: Thu, 20 Sep 2007 16:26:15 +0900	[thread overview]
Message-ID: <11902731752708-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <11902731752407-git-send-email-htejun@gmail.com>

As its name suggests, module_inhibit_unload() inhibits all module
unloading till the matching module_allow_unload() is called.  This
unload inhibition doesn't affect whether a module can be unloaded or
not.  It just stalls the final module free till the inhibition is
lifted.

This sledgehammer mechanism is to be used briefly in obscure cases
where identifying or getting the module to prevent from unloading is
difficult or not worth the effort.  Note that module unloading is
siberia-cold path.  If the inhibion is relatively brief in human
scale, that is, upto a few secs at maximum, it should be fine.  So, if
this sledgehammer simplifies API and fixes premature unload bugs which
unfortunately aren't too rare, there isn't much reason not to use it.

Even if something goes wrong with unload inhibition (e.g. someone
forgets to lift the inhibition), it doesn't prevent modules from being
loaded.

Signed-off-by: Tejun Heo <htejun@gmail.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
---
 include/linux/module.h |   17 +++++++++++++
 kernel/module.c        |   59 ++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 72 insertions(+), 4 deletions(-)

diff --git a/include/linux/module.h b/include/linux/module.h
index b6a646c..a835659 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -418,6 +418,9 @@ static inline int try_module_get(struct module *module)
 
 extern void module_put(struct module *module);
 
+void module_inhibit_unload(void);
+void module_allow_unload(void);
+
 #else /*!CONFIG_MODULE_UNLOAD*/
 static inline int try_module_get(struct module *module)
 {
@@ -431,6 +434,12 @@ static inline void __module_get(struct module *module)
 }
 #define symbol_put(x) do { } while(0)
 #define symbol_put_addr(p) do { } while(0)
+static inline void module_inhibit_unload(void)
+{
+}
+static inline void module_allow_unload(void)
+{
+}
 
 #endif /* CONFIG_MODULE_UNLOAD */
 
@@ -516,6 +525,14 @@ static inline void module_put(struct module *module)
 {
 }
 
+static inline void module_inhibit_unload(void)
+{
+}
+
+static inline void module_allow_unload(void)
+{
+}
+
 #define module_name(mod) "kernel"
 
 #define __unsafe(mod)
diff --git a/kernel/module.c b/kernel/module.c
index db0ead0..8daff45 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -44,6 +44,7 @@
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
+#include <asm/atomic.h>
 #include <linux/license.h>
 
 extern int module_sysfs_initialized;
@@ -65,6 +66,8 @@ extern int module_sysfs_initialized;
  * (add/delete uses stop_machine). */
 static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
+static atomic_t module_unload_inhibit_cnt = ATOMIC_INIT(0);
+static DECLARE_WAIT_QUEUE_HEAD(module_unload_wait);
 
 static BLOCKING_NOTIFIER_HEAD(module_notify_list);
 
@@ -656,6 +659,7 @@ static void wait_for_zero_refcount(struct module *mod)
 asmlinkage long
 sys_delete_module(const char __user *name_user, unsigned int flags)
 {
+	DECLARE_WAITQUEUE(wait, current);
 	struct module *mod;
 	char name[MODULE_NAME_LEN];
 	int ret, forced = 0;
@@ -714,12 +718,22 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
 	if (!forced && module_refcount(mod) != 0)
 		wait_for_zero_refcount(mod);
 
+	mutex_unlock(&module_mutex);
+
 	/* Final destruction now noone is using it. */
-	if (mod->exit != NULL) {
-		mutex_unlock(&module_mutex);
+	if (mod->exit != NULL)
 		mod->exit();
-		mutex_lock(&module_mutex);
-	}
+
+	/* Don't proceed till inhibition is lifted. */
+	add_wait_queue(&module_unload_wait, &wait);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	if (atomic_read(&module_unload_inhibit_cnt))
+		schedule();
+	__set_current_state(TASK_RUNNING);
+	remove_wait_queue(&module_unload_wait, &wait);
+
+	mutex_lock(&module_mutex);
+
 	free_module(mod);
 
  out:
@@ -805,6 +819,43 @@ void module_put(struct module *module)
 }
 EXPORT_SYMBOL(module_put);
 
+/**
+ *	module_inhibit_unload - inhibit module unload
+ *
+ *	Inhibit module unload until allowed again.  All module unload
+ *	operations which reach zero reference count after this call
+ *	has returned are guaranteed to be stalled till inhibition is
+ *	lifted.
+ *
+ *	This is a simple mechanism to prevent premature unload while
+ *	code on a to-be-unloaded module is still executing.  Unload
+ *	inhibitions must be finite and relatively short.
+ *
+ *	LOCKING:
+ *	None.
+ */
+void module_inhibit_unload(void)
+{
+	atomic_inc(&module_unload_inhibit_cnt);
+}
+
+/**
+ *	module_allow_unload - allow module unload
+ *
+ *	Allow module unload.  Must be balanced with calls to
+ *	module_inhibit_unload().
+ *
+ *	LOCKING:
+ *	None.
+ */
+void module_allow_unload(void)
+{
+	if (atomic_dec_and_test(&module_unload_inhibit_cnt))
+		wake_up_all(&module_unload_wait);
+
+	BUG_ON(atomic_read(&module_unload_inhibit_cnt) < 0);
+}
+
 #else /* !CONFIG_MODULE_UNLOAD */
 static void print_unload_info(struct seq_file *m, struct module *mod)
 {
-- 
1.5.0.3



  parent reply	other threads:[~2007-09-20  7:28 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-09-20  7:26 [PATCHSET 2/4] sysfs: allow suicide Tejun Heo
2007-09-20  7:26 ` [PATCH 4/4] sysfs: make suicidal nodes just do it directly Tejun Heo
2007-09-20  9:24   ` Cornelia Huck
2007-09-20  9:43     ` Tejun Heo
2007-09-28 13:54   ` Cornelia Huck
2007-09-28 14:27     ` Tejun Heo
2007-09-20  7:26 ` [PATCH 2/4] sysfs: make the sysfs_addrm_cxt->removed list FIFO Tejun Heo
2007-09-20  7:26 ` [PATCH 3/4] sysfs: care-free suicide for sysfs files Tejun Heo
2007-09-20  7:26 ` Tejun Heo [this message]
2007-09-24 22:00   ` [PATCH 1/4] module: implement module_inhibit_unload() Jonathan Corbet
2007-09-24 23:18     ` Tejun Heo
2007-09-24 23:42       ` Rusty Russell
2007-09-25  1:40         ` Tejun Heo
2007-09-25  2:12           ` Rusty Russell
2007-09-25  2:39             ` Tejun Heo
2007-09-25  3:21               ` Rusty Russell
2007-09-25  3:36                 ` Tejun Heo
2007-09-25  4:38                   ` Rusty Russell
2007-09-25  8:01                     ` Cornelia Huck
2007-09-25  8:25                     ` Tejun Heo
2007-09-25  8:36                       ` Tejun Heo
2007-09-25  8:50                         ` Rusty Russell
2007-09-25 14:05                           ` Tejun Heo
2007-09-25 14:24       ` Alan Stern
2007-09-25 14:30         ` Tejun Heo
2007-09-25 15:09           ` Alan Stern
2007-09-25 23:15             ` Tejun Heo
2007-09-25 23:41               ` Rusty Russell
2007-09-26  1:42                 ` Tejun Heo
2007-09-26 14:39               ` Alan Stern
2007-09-25 22:02 ` [PATCHSET 2/4] sysfs: allow suicide Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11902731752708-git-send-email-htejun@gmail.com \
    --to=htejun@gmail.com \
    --cc=cornelia.huck@de.ibm.com \
    --cc=ebiederm@xmission.com \
    --cc=greg@kroah.com \
    --cc=kay.sievers@vrfy.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=rusty@rustcorp.com.au \
    --cc=stern@rowland.harvard.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox