- Update to 3.3-rc2.
[linux-flexiantxendom0-3.2.10.git] / kernel / module.c
index 2c93276..2a3feba 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/device.h>
 #include <linux/string.h>
 #include <linux/mutex.h>
+#include <linux/unwind.h>
 #include <linux/rculist.h>
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
 
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+/* Allow unsupported modules switch. */
+#ifdef UNSUPPORTED_MODULES
+int unsupported = UNSUPPORTED_MODULES;
+#else
+int unsupported = 2;  /* don't warn when loading unsupported modules. */
+#endif
+
+static int __init unsupported_setup(char *str)
+{
+       get_option(&str, &unsupported);
+       return 1;
+}
+__setup("unsupported=", unsupported_setup);
+#endif
+
 /*
  * Mutex protects:
  * 1) List of modules (also safely readable with preempt_disable),
@@ -136,7 +153,7 @@ struct load_info {
        struct _ddebug *debug;
        unsigned int num_debug;
        struct {
-               unsigned int sym, str, mod, vers, info, pcpu;
+               unsigned int sym, str, mod, vers, info, pcpu, unwind;
        } index;
 };
 
@@ -532,6 +549,27 @@ bool is_module_percpu_address(unsigned long addr)
 
 #endif /* CONFIG_SMP */
 
+static unsigned int find_unwind(struct load_info *info)
+{
+       int section = 0;
+#ifdef ARCH_UNWIND_SECTION_NAME
+       section = find_sec(info, ARCH_UNWIND_SECTION_NAME);
+       if (section)
+               info->sechdrs[section].sh_flags |= SHF_ALLOC;
+#endif
+       return section;
+}
+
+static void add_unwind_table(struct module *mod, struct load_info *info)
+{
+       int index = info->index.unwind;
+
+       /* Size of section 0 is 0, so this is ok if there is no unwind info. */
+       mod->unwind_info = unwind_add_table(mod,
+                                         (void *)info->sechdrs[index].sh_addr,
+                                         info->sechdrs[index].sh_size);
+}
+
 #define MODINFO_ATTR(field)    \
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
@@ -954,6 +992,12 @@ static size_t module_flags_taint(struct module *mod, char *buf)
                buf[l++] = 'F';
        if (mod->taints & (1 << TAINT_CRAP))
                buf[l++] = 'C';
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+       if (mod->taints & (1 << TAINT_NO_SUPPORT))
+               buf[l++] = 'N';
+       if (mod->taints & (1 << TAINT_EXTERNAL_SUPPORT))
+               buf[l++] = 'X';
+#endif
        /*
         * TAINT_FORCED_RMMOD: could be added.
         * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
@@ -1029,6 +1073,33 @@ static ssize_t show_taint(struct module_attribute *mattr,
 static struct module_attribute modinfo_taint =
        __ATTR(taint, 0444, show_taint, NULL);
 
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+static void setup_modinfo_supported(struct module *mod, const char *s)
+{
+       if (!s) {
+               mod->taints |= (1 << TAINT_NO_SUPPORT);
+               return;
+       }
+
+       if (strcmp(s, "external") == 0)
+               mod->taints |= (1 << TAINT_EXTERNAL_SUPPORT);
+       else if (strcmp(s, "yes"))
+               mod->taints |= (1 << TAINT_NO_SUPPORT);
+}
+
+static ssize_t show_modinfo_supported(struct module_attribute *mattr,
+                                     struct module_kobject *mk, char *buffer)
+{
+       return sprintf(buffer, "%s\n", supported_printable(mk->mod->taints));
+}
+
+static struct module_attribute modinfo_supported = {
+       .attr = { .name = "supported", .mode = 0444 },
+       .show = show_modinfo_supported,
+       .setup = setup_modinfo_supported,
+};
+#endif
+
 static struct module_attribute *modinfo_attrs[] = {
        &module_uevent,
        &modinfo_version,
@@ -1037,6 +1108,9 @@ static struct module_attribute *modinfo_attrs[] = {
        &modinfo_coresize,
        &modinfo_initsize,
        &modinfo_taint,
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+       &modinfo_supported,
+#endif
 #ifdef CONFIG_MODULE_UNLOAD
        &modinfo_refcnt,
 #endif
@@ -1578,9 +1652,36 @@ static int mod_sysfs_setup(struct module *mod,
        add_sect_attrs(mod, info);
        add_notes_attrs(mod, info);
 
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+       /* We don't use add_taint() here because it also disables lockdep. */
+       if (mod->taints & (1 << TAINT_EXTERNAL_SUPPORT))
+               add_nonfatal_taint(TAINT_EXTERNAL_SUPPORT);
+       else if (mod->taints == (1 << TAINT_NO_SUPPORT)) {
+               if (unsupported == 0) {
+                       printk(KERN_WARNING "%s: module not supported by "
+                              "Novell, refusing to load. To override, echo "
+                              "1 > /proc/sys/kernel/unsupported\n", mod->name);
+                       err = -ENOEXEC;
+                       goto out_remove_attrs;
+               }
+               add_nonfatal_taint(TAINT_NO_SUPPORT);
+               if (unsupported == 1) {
+                       printk(KERN_WARNING "%s: module is not supported by "
+                              "Novell. Novell Technical Services may decline "
+                              "your support request if it involves a kernel "
+                              "fault.\n", mod->name);
+               }
+       }
+#endif
+
        kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
        return 0;
 
+out_remove_attrs:
+       remove_notes_attrs(mod);
+       remove_sect_attrs(mod);
+       del_usage_links(mod);
+       module_remove_modinfo_attrs(mod);
 out_unreg_param:
        module_param_sysfs_remove(mod);
 out_unreg_holders:
@@ -1778,6 +1879,8 @@ static void free_module(struct module *mod)
        /* Remove dynamic debug info */
        ddebug_remove_module(mod->name);
 
+       unwind_remove_table(mod->unwind_info, 0);
+
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
@@ -2503,6 +2606,8 @@ static struct module *setup_load_info(struct load_info *info)
 
        info->index.pcpu = find_pcpusec(info);
 
+       info->index.unwind = find_unwind(info);
+
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
                return ERR_PTR(-ENOEXEC);
@@ -2931,6 +3036,9 @@ static struct module *load_module(void __user *umod,
        if (err < 0)
                goto unlink;
 
+       /* Initialize unwind table */
+       add_unwind_table(mod, &info);
+
        /* Get rid of temporary copy. */
        free_copy(&info);
 
@@ -3043,6 +3151,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        /* Drop initial reference. */
        module_put(mod);
        trim_init_extable(mod);
+       unwind_remove_table(mod->unwind_info, 1);
 #ifdef CONFIG_KALLSYMS
        mod->num_symtab = mod->core_num_syms;
        mod->symtab = mod->core_symtab;
@@ -3491,6 +3600,9 @@ void print_modules(void)
        if (last_unloaded_module[0])
                printk(" [last unloaded: %s]", last_unloaded_module);
        printk("\n");
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+       printk("Supported: %s\n", supported_printable(get_taint()));
+#endif
 }
 
 #ifdef CONFIG_MODVERSIONS