Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / kernel / module.c
index 893ec57..f9a5987 100644 (file)
@@ -1,4 +1,4 @@
-/* Rewritten by Rusty Russell, on the backs of many others...
+/*
    Copyright (C) 2002 Richard Henderson
    Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
 
@@ -16,7 +16,6 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/mutex.h>
+#include <linux/unwind.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
+#include <linux/license.h>
 #include "module-verify.h"
 
 #if 0
@@ -121,9 +122,17 @@ extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __start___ksymtab_gpl_future[];
 extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
+extern const struct kernel_symbol __start___ksymtab_unused[];
+extern const struct kernel_symbol __stop___ksymtab_unused[];
+extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab_gpl_future[];
+extern const unsigned long __start___kcrctab_unused[];
+extern const unsigned long __start___kcrctab_unused_gpl[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -143,6 +152,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        return NULL;
 }
 
+static void printk_unused_warning(const char *name)
+{
+       printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+               "however this module is using it.\n", name);
+       printk(KERN_WARNING "This symbol will go away in the future.\n");
+       printk(KERN_WARNING "Please evalute if this is the right api to use, "
+               "and if it really is, submit a report the linux kernel "
+               "mailinglist together with submitting your code for "
+               "inclusion.\n");
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
@@ -185,6 +205,25 @@ static unsigned long __find_symbol(const char *name,
                return ks->value;
        }
 
+       ks = lookup_symbol(name, __start___ksymtab_unused,
+                                __stop___ksymtab_unused);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused,
+                                 (ks - __start___ksymtab_unused));
+               return ks->value;
+       }
+
+       if (gplok)
+               ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
+                                __stop___ksymtab_unused_gpl);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused_gpl,
+                                 (ks - __start___ksymtab_unused_gpl));
+               return ks->value;
+       }
+
        /* Now try modules. */ 
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
@@ -203,6 +242,23 @@ static unsigned long __find_symbol(const char *name,
                                return ks->value;
                        }
                }
+               ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+               if (ks) {
+                       printk_unused_warning(name);
+                       *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
+                       return ks->value;
+               }
+
+               if (gplok) {
+                       ks = lookup_symbol(name, mod->unused_gpl_syms,
+                                          mod->unused_gpl_syms + mod->num_unused_gpl_syms);
+                       if (ks) {
+                               printk_unused_warning(name);
+                               *crc = symversion(mod->unused_gpl_crcs,
+                                                 (ks - mod->unused_gpl_syms));
+                               return ks->value;
+                       }
+               }
                ks = lookup_symbol(name, mod->gpl_future_syms,
                                   (mod->gpl_future_syms +
                                    mod->num_gpl_future_syms));
@@ -999,6 +1055,12 @@ static int mod_sysfs_setup(struct module *mod,
 {
        int err;
 
+       if (!module_subsys.kset.subsys) {
+               printk(KERN_ERR "%s: module_subsys not initialized\n",
+                      mod->name);
+               err = -EINVAL;
+               goto out;
+       }
        memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
        err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name);
        if (err)
@@ -1052,6 +1114,8 @@ static void free_module(struct module *mod)
        remove_sect_attrs(mod);
        mod_kobject_remove(mod);
 
+       unwind_remove_table(mod->unwind_info, 0);
+
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
@@ -1064,6 +1128,9 @@ static void free_module(struct module *mod)
        if (mod->percpu)
                percpu_modfree(mod->percpu);
 
+       /* Free lock-classes: */
+       lockdep_free_key_range(mod->module_core, mod->core_size);
+
        /* Finally, free the core (containing the module structure) */
        module_free(mod, mod->module_core);
 }
@@ -1249,16 +1316,6 @@ static void layout_sections(struct module *mod,
        }
 }
 
-static inline int license_is_gpl_compatible(const char *license)
-{
-       return (strcmp(license, "GPL") == 0
-               || strcmp(license, "GPL v2") == 0
-               || strcmp(license, "GPL and additional rights") == 0
-               || strcmp(license, "Dual BSD/GPL") == 0
-               || strcmp(license, "Dual MIT/GPL") == 0
-               || strcmp(license, "Dual MPL/GPL") == 0);
-}
-
 static void set_license(struct module *mod, const char *license)
 {
        if (!license)
@@ -1327,7 +1384,7 @@ int is_exported(const char *name, const struct module *mod)
        if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
                return 1;
        else
-               if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
+               if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
                        return 1;
                else
                        return 0;
@@ -1410,10 +1467,27 @@ static struct module *load_module(void __user *umod,
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        char *secstrings, *args, *modmagic, *strtab = NULL;
-       unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
-               exportindex, modindex, obsparmindex, infoindex, gplindex,
-               crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
-               gplfuturecrcindex;
+       unsigned int i;
+       unsigned int symindex = 0;
+       unsigned int strindex = 0;
+       unsigned int setupindex;
+       unsigned int exindex;
+       unsigned int exportindex;
+       unsigned int modindex;
+       unsigned int obsparmindex;
+       unsigned int infoindex;
+       unsigned int gplindex;
+       unsigned int crcindex;
+       unsigned int gplcrcindex;
+       unsigned int versindex;
+       unsigned int pcpuindex;
+       unsigned int gplfutureindex;
+       unsigned int gplfuturecrcindex;
+       unsigned int unwindex = 0;
+       unsigned int unusedindex;
+       unsigned int unusedcrcindex;
+       unsigned int unusedgplindex;
+       unsigned int unusedgplcrcindex;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1501,15 +1575,22 @@ static struct module *load_module(void __user *umod,
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
        gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
+       unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
+       unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
        gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
+       unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
+       unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
        versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
        infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
        pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
+#ifdef ARCH_UNWIND_SECTION_NAME
+       unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
+#endif
 
        /* Don't keep modinfo section */
        sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1518,6 +1599,8 @@ static struct module *load_module(void __user *umod,
        sechdrs[symindex].sh_flags |= SHF_ALLOC;
        sechdrs[strindex].sh_flags |= SHF_ALLOC;
 #endif
+       if (unwindex)
+               sechdrs[unwindex].sh_flags |= SHF_ALLOC;
 
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1647,14 +1730,27 @@ static struct module *load_module(void __user *umod,
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
        mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
                                        sizeof(*mod->gpl_future_syms);
+       mod->num_unused_syms = sechdrs[unusedindex].sh_size /
+                                       sizeof(*mod->unused_syms);
+       mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
+                                       sizeof(*mod->unused_gpl_syms);
        mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
        if (gplfuturecrcindex)
                mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
+       mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
+       if (unusedcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
+       mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
+       if (unusedgplcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !crcindex) || 
            (mod->num_gpl_syms && !gplcrcindex) ||
-           (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
+           (mod->num_gpl_future_syms && !gplfuturecrcindex) ||
+           (mod->num_unused_syms && !unusedcrcindex) ||
+           (mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
                add_taint(TAINT_FORCED_MODULE);
@@ -1746,6 +1842,11 @@ static struct module *load_module(void __user *umod,
                goto arch_cleanup;
        add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
+       /* Size of section 0 is 0, so this works well if no unwind info. */
+       mod->unwind_info = unwind_add_table(mod,
+                                           (void *)sechdrs[unwindex].sh_addr,
+                                           sechdrs[unwindex].sh_size);
+
        /* Get rid of temporary copy */
        vfree(hdr);
 
@@ -1844,6 +1945,7 @@ sys_init_module(void __user *umod,
        mod->state = MODULE_STATE_LIVE;
        /* Drop initial reference. */
        module_put(mod);
+       unwind_remove_table(mod->unwind_info, 1);
        module_free(mod, mod->module_init);
        mod->module_init = NULL;
        mod->init_size = 0;
@@ -1931,10 +2033,8 @@ const char *module_address_lookup(unsigned long addr,
        return NULL;
 }
 
-struct module *module_get_kallsym(unsigned int symnum,
-                                 unsigned long *value,
-                                 char *type,
-                                 char namebuf[128])
+struct module *module_get_kallsym(unsigned int symnum, unsigned long *value,
+                               char *type, char *name, size_t namelen)
 {
        struct module *mod;
 
@@ -1943,9 +2043,8 @@ struct module *module_get_kallsym(unsigned int symnum,
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
                        *type = mod->symtab[symnum].st_info;
-                       strncpy(namebuf,
-                               mod->strtab + mod->symtab[symnum].st_name,
-                               127);
+                       strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
+                               namelen);
                        mutex_unlock(&module_mutex);
                        return mod;
                }
@@ -2074,6 +2173,29 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
        return e;
 }
 
+/*
+ * Is this a valid module address?
+ */
+int is_module_address(unsigned long addr)
+{
+       unsigned long flags;
+       struct module *mod;
+
+       spin_lock_irqsave(&modlist_lock, flags);
+
+       list_for_each_entry(mod, &modules, list) {
+               if (within(addr, mod->module_core, mod->core_size)) {
+                       spin_unlock_irqrestore(&modlist_lock, flags);
+                       return 1;
+               }
+       }
+
+       spin_unlock_irqrestore(&modlist_lock, flags);
+
+       return 0;
+}
+
+
 /* Is this a valid kernel address?  We don't grab the lock: we are oopsing. */
 struct module *__module_text_address(unsigned long addr)
 {