[PATCH] Module rewrite 16/20: module_put_return for x86

Rusty Russell (rusty@rustcorp.com.au)
Wed, 25 Sep 2002 13:19:01 +1000


Name: module_put_return primitive for x86
Author: Rusty Russell
Status: Experimental
Depends: Module/forceunload.patch.gz

D: This patch implements module_put_return() for x86, which allows a
D: module to control its own reference counts in some cases. A module
D: must never use module_put() on itself, since this may result in the
D: module being removable immediately: this is the alternative, which
D: atomically decrements the count and returns.
D:
D: Each architecture will need to implement this for preempt.

diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13134-linux-2.5.38/arch/i386/kernel/module.c .13134-linux-2.5.38.updated/arch/i386/kernel/module.c
--- .13134-linux-2.5.38/arch/i386/kernel/module.c 2002-09-25 02:02:28.000000000 +1000
+++ .13134-linux-2.5.38.updated/arch/i386/kernel/module.c 2002-09-25 02:02:56.000000000 +1000
@@ -28,6 +28,9 @@
#define DEBUGP(fmt , ...)
#endif

+/* For the magic module return. */
+struct module_percpu module_percpu[NR_CPUS];
+
static void *alloc_and_zero(unsigned long size)
{
void *ret;
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13134-linux-2.5.38/arch/i386/lib/module.S .13134-linux-2.5.38.updated/arch/i386/lib/module.S
--- .13134-linux-2.5.38/arch/i386/lib/module.S 1970-01-01 10:00:00.000000000 +1000
+++ .13134-linux-2.5.38.updated/arch/i386/lib/module.S 2002-09-25 02:02:56.000000000 +1000
@@ -0,0 +1,33 @@
+/* Icky, icky, return trampoline for dying modules. Entered with
+ interrupts off. (C) 2002 Stephen Rothwell, IBM Corporation. */
+
+#include <asm/thread_info.h>
+
+.text
+.align 4
+.globl __magic_module_return
+
+#define MODULE_PERCPU_SIZE_ORDER 3
+
+__magic_module_return:
+ /* Save one working variable */
+ pushl %eax
+
+ /* Get CPU number from current. */
+ GET_THREAD_INFO(%eax)
+ movl TI_CPU(%eax), %eax
+
+ /* Push module_percpu[cpu].flags on the stack */
+ shll $MODULE_PERCPU_SIZE_ORDER, %eax
+ pushl module_percpu(%eax)
+
+ /* Put module_percpu[cpu].returnaddr into %eax */
+ movl module_percpu+4(%eax), %eax
+
+ /* Push returnaddr and restore eax */
+ xchgl %eax, 4(%esp)
+
+ /* Restore interrupts */
+ popf
+ /* Go home */
+ ret
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13134-linux-2.5.38/include/asm-i386/module.h .13134-linux-2.5.38.updated/include/asm-i386/module.h
--- .13134-linux-2.5.38/include/asm-i386/module.h 2002-09-25 02:02:28.000000000 +1000
+++ .13134-linux-2.5.38.updated/include/asm-i386/module.h 2002-09-25 02:02:56.000000000 +1000
@@ -8,4 +8,33 @@ struct mod_arch_specific
#define Elf_Shdr Elf32_Shdr
#define Elf_Sym Elf32_Sym
#define Elf_Ehdr Elf32_Ehdr
+
+/* Non-preemtible decrement the refcount and return. */
+#define module_put_return(firstarg , ...) \
+do { \
+ unsigned int cpu; \
+ unsigned long flags; \
+ \
+ local_irq_save(flags); \
+ if (unlikely(module_put(THIS_MODULE)) { \
+ module_percpu[cpu].flags = flags; \
+ module_percpu[cpu].returnaddr = ((void **)&(firstarg))[-1]; \
+ ((void **)&(firstarg))[-1] = __magic_module_return; \
+ } else \
+ local_irq_restore(flags); \
+ return __VA_ARGS__; \
+} while(0)
+
+/* FIXME: Use per-cpu vars --RR */
+struct module_percpu
+{
+ unsigned long flags;
+ void *returnaddr;
+};
+
+extern struct module_percpu module_percpu[NR_CPUS];
+
+/* Restore flags and return to caller. */
+extern void __magic_module_return(void);
+
#endif /* _ASM_I386_MODULE_H */
diff -urpN --exclude TAGS -X /home/rusty/devel/kernel/kernel-patches/current-dontdiff --minimal .13134-linux-2.5.38/kernel/module.c .13134-linux-2.5.38.updated/kernel/module.c
--- .13134-linux-2.5.38/kernel/module.c 2002-09-25 02:02:32.000000000 +1000
+++ .13134-linux-2.5.38.updated/kernel/module.c 2002-09-25 02:03:37.000000000 +1000
@@ -267,9 +267,11 @@ sys_delete_module(const char *name_user,
goto reanimate;

/* Since it's not live, count should monotonically decrease. */
- if (!forced)
+ if (!forced) {
bigref_wait_for_zero(&mod->use);
- else {
+ /* Wait in case they are using module_put_return */
+ synchronize_kernel();
+ } else {
printk(KERN_WARNING "Forced removal of %s.\n", mod->name);
tainted |= TAINT_FORCED_RMMOD;
}

--
  Anyone who quotes me in their sig is an idiot. -- Rusty Russell.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/