]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/module.c
Merge branches 'sched/clock', 'sched/cleanups' and 'linus' into sched/urgent
[linux-2.6-omap-h63xx.git] / kernel / module.c
index dd2a54155b54ab45df7ac5a9e7e13344e4611b1e..f47cce910f25aab3d346f680e6af35d599dd1da7 100644 (file)
@@ -757,8 +757,16 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
                return -EFAULT;
        name[MODULE_NAME_LEN-1] = '\0';
 
-       if (mutex_lock_interruptible(&module_mutex) != 0)
-               return -EINTR;
+       /* Create stop_machine threads since free_module relies on
+        * a non-failing stop_machine call. */
+       ret = stop_machine_create();
+       if (ret)
+               return ret;
+
+       if (mutex_lock_interruptible(&module_mutex) != 0) {
+               ret = -EINTR;
+               goto out_stop;
+       }
 
        mod = find_module(name);
        if (!mod) {
@@ -817,10 +825,12 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
 
  out:
        mutex_unlock(&module_mutex);
+out_stop:
+       stop_machine_destroy();
        return ret;
 }
 
-static void print_unload_info(struct seq_file *m, struct module *mod)
+static inline void print_unload_info(struct seq_file *m, struct module *mod)
 {
        struct module_use *use;
        int printed_something = 0;
@@ -893,7 +903,7 @@ void module_put(struct module *module)
 EXPORT_SYMBOL(module_put);
 
 #else /* !CONFIG_MODULE_UNLOAD */
-static void print_unload_info(struct seq_file *m, struct module *mod)
+static inline void print_unload_info(struct seq_file *m, struct module *mod)
 {
        /* We don't know the usage count, or what modules are using. */
        seq_printf(m, " - -");
@@ -1578,11 +1588,21 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
        return ret;
 }
 
+/* Additional bytes needed by arch in front of individual sections */
+unsigned int __weak arch_mod_section_prepend(struct module *mod,
+                                            unsigned int section)
+{
+       /* default implementation just returns zero */
+       return 0;
+}
+
 /* Update size with this section: return offset. */
-static long get_offset(unsigned int *size, Elf_Shdr *sechdr)
+static long get_offset(struct module *mod, unsigned int *size,
+                      Elf_Shdr *sechdr, unsigned int section)
 {
        long ret;
 
+       *size += arch_mod_section_prepend(mod, section);
        ret = ALIGN(*size, sechdr->sh_addralign ?: 1);
        *size = ret + sechdr->sh_size;
        return ret;
@@ -1622,7 +1642,7 @@ static void layout_sections(struct module *mod,
                            || strncmp(secstrings + s->sh_name,
                                       ".init", 5) == 0)
                                continue;
-                       s->sh_entsize = get_offset(&mod->core_size, s);
+                       s->sh_entsize = get_offset(mod, &mod->core_size, s, i);
                        DEBUGP("\t%s\n", secstrings + s->sh_name);
                }
                if (m == 0)
@@ -1640,7 +1660,7 @@ static void layout_sections(struct module *mod,
                            || strncmp(secstrings + s->sh_name,
                                       ".init", 5) != 0)
                                continue;
-                       s->sh_entsize = (get_offset(&mod->init_size, s)
+                       s->sh_entsize = (get_offset(mod, &mod->init_size, s, i)
                                         | INIT_OFFSET_MASK);
                        DEBUGP("\t%s\n", secstrings + s->sh_name);
                }
@@ -1725,15 +1745,15 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        return NULL;
 }
 
-static int is_exported(const char *name, const struct module *mod)
+static int is_exported(const char *name, unsigned long value,
+                      const struct module *mod)
 {
-       if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
-               return 1;
+       const struct kernel_symbol *ks;
+       if (!mod)
+               ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
        else
-               if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
-                       return 1;
-               else
-                       return 0;
+               ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+       return ks != NULL && ks->value == value;
 }
 
 /* As per nm */
@@ -1865,6 +1885,13 @@ static noinline struct module *load_module(void __user *umod,
        /* vmalloc barfs on "unusual" numbers.  Check here */
        if (len > 64 * 1024 * 1024 || (hdr = vmalloc(len)) == NULL)
                return ERR_PTR(-ENOMEM);
+
+       /* Create stop_machine threads since the error path relies on
+        * a non-failing stop_machine call. */
+       err = stop_machine_create();
+       if (err)
+               goto free_hdr;
+
        if (copy_from_user(hdr, umod, len) != 0) {
                err = -EFAULT;
                goto free_hdr;
@@ -2248,6 +2275,7 @@ static noinline struct module *load_module(void __user *umod,
        /* Get rid of temporary copy */
        vfree(hdr);
 
+       stop_machine_destroy();
        /* Done! */
        return mod;
 
@@ -2270,6 +2298,7 @@ static noinline struct module *load_module(void __user *umod,
        kfree(args);
  free_hdr:
        vfree(hdr);
+       stop_machine_destroy();
        return ERR_PTR(err);
 
  truncated:
@@ -2504,7 +2533,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                        strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
                                KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
-                       *exported = is_exported(name, mod);
+                       *exported = is_exported(name, *value, mod);
                        preempt_enable();
                        return 0;
                }