]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/module.c
[PATCH] swsusp: documentation updates
[linux-2.6-omap-h63xx.git] / kernel / module.c
index 5aad477ddc79c94567c02e9ee704f1eb71fa1b66..77764f22f021e252fe0455cfa8ba9d3316b0e6f1 100644 (file)
@@ -126,8 +126,11 @@ extern const struct kernel_symbol __start___ksymtab[];
 extern const struct kernel_symbol __stop___ksymtab[];
 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 unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
+extern const unsigned long __start___kcrctab_gpl_future[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
@@ -135,6 +138,18 @@ extern const unsigned long __start___kcrctab_gpl[];
 #define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
 #endif
 
+/* lookup symbol in given range of kernel_symbols */
+static const struct kernel_symbol *lookup_symbol(const char *name,
+       const struct kernel_symbol *start,
+       const struct kernel_symbol *stop)
+{
+       const struct kernel_symbol *ks = start;
+       for (; ks < stop; ks++)
+               if (strcmp(ks->name, name) == 0)
+                       return ks;
+       return NULL;
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
@@ -142,40 +157,75 @@ static unsigned long __find_symbol(const char *name,
                                   int gplok)
 {
        struct module *mod;
-       unsigned int i;
+       const struct kernel_symbol *ks;
 
        /* Core kernel first. */ 
        *owner = NULL;
-       for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {
-               if (strcmp(__start___ksymtab[i].name, name) == 0) {
-                       *crc = symversion(__start___kcrctab, i);
-                       return __start___ksymtab[i].value;
-               }
+       ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+       if (ks) {
+               *crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
+               return ks->value;
        }
        if (gplok) {
-               for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)
-                       if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {
-                               *crc = symversion(__start___kcrctab_gpl, i);
-                               return __start___ksymtab_gpl[i].value;
-                       }
+               ks = lookup_symbol(name, __start___ksymtab_gpl,
+                                        __stop___ksymtab_gpl);
+               if (ks) {
+                       *crc = symversion(__start___kcrctab_gpl,
+                                         (ks - __start___ksymtab_gpl));
+                       return ks->value;
+               }
+       }
+       ks = lookup_symbol(name, __start___ksymtab_gpl_future,
+                                __stop___ksymtab_gpl_future);
+       if (ks) {
+               if (!gplok) {
+                       printk(KERN_WARNING "Symbol %s is being used "
+                              "by a non-GPL module, which will not "
+                              "be allowed in the future\n", name);
+                       printk(KERN_WARNING "Please see the file "
+                              "Documentation/feature-removal-schedule.txt "
+                              "in the kernel source tree for more "
+                              "details.\n");
+               }
+               *crc = symversion(__start___kcrctab_gpl_future,
+                                 (ks - __start___ksymtab_gpl_future));
+               return ks->value;
        }
 
        /* Now try modules. */ 
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
-               for (i = 0; i < mod->num_syms; i++)
-                       if (strcmp(mod->syms[i].name, name) == 0) {
-                               *crc = symversion(mod->crcs, i);
-                               return mod->syms[i].value;
-                       }
+               ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
+               if (ks) {
+                       *crc = symversion(mod->crcs, (ks - mod->syms));
+                       return ks->value;
+               }
 
                if (gplok) {
-                       for (i = 0; i < mod->num_gpl_syms; i++) {
-                               if (strcmp(mod->gpl_syms[i].name, name) == 0) {
-                                       *crc = symversion(mod->gpl_crcs, i);
-                                       return mod->gpl_syms[i].value;
-                               }
+                       ks = lookup_symbol(name, mod->gpl_syms,
+                                          mod->gpl_syms + mod->num_gpl_syms);
+                       if (ks) {
+                               *crc = symversion(mod->gpl_crcs,
+                                                 (ks - mod->gpl_syms));
+                               return ks->value;
+                       }
+               }
+               ks = lookup_symbol(name, mod->gpl_future_syms,
+                                  (mod->gpl_future_syms +
+                                   mod->num_gpl_future_syms));
+               if (ks) {
+                       if (!gplok) {
+                               printk(KERN_WARNING "Symbol %s is being used "
+                                      "by a non-GPL module, which will not "
+                                      "be allowed in the future\n", name);
+                               printk(KERN_WARNING "Please see the file "
+                                      "Documentation/feature-removal-schedule.txt "
+                                      "in the kernel source tree for more "
+                                      "details.\n");
                        }
+                       *crc = symversion(mod->gpl_future_crcs,
+                                         (ks - mod->gpl_future_syms));
+                       return ks->value;
                }
        }
        DEBUGP("Failed to find symbol %s\n", name);
@@ -379,7 +429,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
 }
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MODULE_UNLOAD
 #define MODINFO_ATTR(field)    \
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
@@ -411,12 +460,7 @@ static struct module_attribute modinfo_##field = {                    \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
-static struct module_attribute *modinfo_attrs[] = {
-       &modinfo_version,
-       &modinfo_srcversion,
-       NULL,
-};
-
+#ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
@@ -731,6 +775,15 @@ static inline void module_unload_init(struct module *mod)
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
+static struct module_attribute *modinfo_attrs[] = {
+       &modinfo_version,
+       &modinfo_srcversion,
+#ifdef CONFIG_MODULE_UNLOAD
+       &refcnt,
+#endif
+       NULL,
+};
+
 #ifdef CONFIG_OBSOLETE_MODPARM
 /* Bounds checking done below */
 static int obsparm_copy_string(const char *val, struct kernel_param *kp)
@@ -1056,37 +1109,28 @@ static inline void remove_sect_attrs(struct module *mod)
 }
 #endif /* CONFIG_KALLSYMS */
 
-
-#ifdef CONFIG_MODULE_UNLOAD
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-       return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-       return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
-}
-#else
-static inline int module_add_refcnt_attr(struct module *mod)
-{
-       return 0;
-}
-static void module_remove_refcnt_attr(struct module *mod)
-{
-}
-#endif
-
-#ifdef CONFIG_MODULE_UNLOAD
 static int module_add_modinfo_attrs(struct module *mod)
 {
        struct module_attribute *attr;
+       struct module_attribute *temp_attr;
        int error = 0;
        int i;
 
+       mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
+                                       (ARRAY_SIZE(modinfo_attrs) + 1)),
+                                       GFP_KERNEL);
+       if (!mod->modinfo_attrs)
+               return -ENOMEM;
+
+       temp_attr = mod->modinfo_attrs;
        for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
                if (!attr->test ||
-                   (attr->test && attr->test(mod)))
-                       error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+                   (attr->test && attr->test(mod))) {
+                       memcpy(temp_attr, attr, sizeof(*temp_attr));
+                       temp_attr->attr.owner = mod;
+                       error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
+                       ++temp_attr;
+               }
        }
        return error;
 }
@@ -1096,12 +1140,16 @@ static void module_remove_modinfo_attrs(struct module *mod)
        struct module_attribute *attr;
        int i;
 
-       for (i = 0; (attr = modinfo_attrs[i]); i++) {
+       for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+               /* pick a field to test for end of list */
+               if (!attr->attr.name)
+                       break;
                sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
-               attr->free(mod);
+               if (attr->free)
+                       attr->free(mod);
        }
+       kfree(mod->modinfo_attrs);
 }
-#endif
 
 static int mod_sysfs_setup(struct module *mod,
                           struct kernel_param *kparam,
@@ -1119,19 +1167,13 @@ static int mod_sysfs_setup(struct module *mod,
        if (err)
                goto out;
 
-       err = module_add_refcnt_attr(mod);
-       if (err)
-               goto out_unreg;
-
        err = module_param_sysfs_setup(mod, kparam, num_params);
        if (err)
                goto out_unreg;
 
-#ifdef CONFIG_MODULE_UNLOAD
        err = module_add_modinfo_attrs(mod);
        if (err)
                goto out_unreg;
-#endif
 
        return 0;
 
@@ -1143,10 +1185,7 @@ out:
 
 static void mod_kobject_remove(struct module *mod)
 {
-#ifdef CONFIG_MODULE_UNLOAD
        module_remove_modinfo_attrs(mod);
-#endif
-       module_remove_refcnt_attr(mod);
        module_param_sysfs_remove(mod);
 
        kobject_unregister(&mod->mkobj.kobj);
@@ -1424,7 +1463,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
        return NULL;
 }
 
-#ifdef CONFIG_MODULE_UNLOAD
 static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                          unsigned int infoindex)
 {
@@ -1439,23 +1477,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                                                attr->attr.name));
        }
 }
-#endif
 
 #ifdef CONFIG_KALLSYMS
 int is_exported(const char *name, const struct module *mod)
 {
-       unsigned int i;
-
-       if (!mod) {
-               for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++)
-                       if (strcmp(__start___ksymtab[i].name, name) == 0)
-                               return 1;
-               return 0;
-       }
-       for (i = 0; i < mod->num_syms; i++)
-               if (strcmp(mod->syms[i].name, name) == 0)
+       if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
+               return 1;
+       else
+               if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
                        return 1;
-       return 0;
+               else
+                       return 0;
 }
 
 /* As per nm */
@@ -1537,7 +1569,8 @@ static struct module *load_module(void __user *umod,
        char *secstrings, *args, *modmagic, *strtab = NULL;
        unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
                exportindex, modindex, obsparmindex, infoindex, gplindex,
-               crcindex, gplcrcindex, versindex, pcpuindex;
+               crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
+               gplfuturecrcindex;
        long arglen;
        struct module *mod;
        long err = 0;
@@ -1618,8 +1651,10 @@ static struct module *load_module(void __user *umod,
        /* Optional sections */
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+       gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+       gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
@@ -1755,10 +1790,8 @@ static struct module *load_module(void __user *umod,
        if (strcmp(mod->name, "driverloader") == 0)
                add_taint(TAINT_PROPRIETARY_MODULE);
 
-#ifdef CONFIG_MODULE_UNLOAD
        /* Set up MODINFO_ATTR fields */
        setup_modinfo(mod, sechdrs, infoindex);
-#endif
 
        /* Fix up syms, so that st_value is a pointer to location. */
        err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
@@ -1775,10 +1808,16 @@ static struct module *load_module(void __user *umod,
        mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
        if (gplcrcindex)
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
+       mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
+                                       sizeof(*mod->gpl_future_syms);
+       mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
+       if (gplfuturecrcindex)
+               mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
        if ((mod->num_syms && !crcindex) || 
-           (mod->num_gpl_syms && !gplcrcindex)) {
+           (mod->num_gpl_syms && !gplcrcindex) ||
+           (mod->num_gpl_future_syms && !gplfuturecrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
                add_taint(TAINT_FORCED_MODULE);