#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),
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;
};
#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) \
{ \
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
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,
&modinfo_coresize,
&modinfo_initsize,
&modinfo_taint,
+#ifdef CONFIG_ENTERPRISE_SUPPORT
+ &modinfo_supported,
+#endif
#ifdef CONFIG_MODULE_UNLOAD
&modinfo_refcnt,
#endif
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:
/* Remove dynamic debug info */
ddebug_remove_module(mod->name);
+ unwind_remove_table(mod->unwind_info, 0);
+
/* Arch-specific cleanup. */
module_arch_cleanup(mod);
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);
if (err < 0)
goto unlink;
+ /* Initialize unwind table */
+ add_unwind_table(mod, &info);
+
/* Get rid of temporary copy. */
free_copy(&info);
/* 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;
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