From: Jeff Mahoney Subject: Export supported status via sysfs Patch-mainline: Never, SLES feature This patch adds a /sys/kernel/supported file indicating the supportability status of the entire kernel. It also adds a /sys/module//supported file indicating the supportability status of individual modules. This is useful because it can be used to obtain the supported status of a running system without current modules (ie: immediately after a kernel update but before a reboot) and without generating an oops. Signed-off-by: Jeff Mahoney --- include/linux/kernel.h | 1 include/linux/module.h | 1 kernel/ksysfs.c | 23 +++++++++++++++ kernel/module.c | 71 +++++++++++++++++++++++++++++++++---------------- kernel/panic.c | 5 +++ 5 files changed, 78 insertions(+), 23 deletions(-) --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -320,6 +320,7 @@ extern int panic_on_io_nmi; extern int unsupported; extern const char *print_tainted(void); extern void add_taint(unsigned flag); +extern void add_nonfatal_taint(unsigned flag); extern int test_taint(unsigned flag); extern unsigned long get_taint(void); extern int root_mountflags; --- a/include/linux/module.h +++ b/include/linux/module.h @@ -398,6 +398,7 @@ struct module *__module_address(unsigned bool is_module_address(unsigned long addr); bool is_module_percpu_address(unsigned long addr); bool is_module_text_address(unsigned long addr); +const char *supported_printable(int taint); static inline int within_module_core(unsigned long addr, struct module *mod) { --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -156,6 +156,28 @@ static struct bin_attribute notes_attr = struct kobject *kernel_kobj; EXPORT_SYMBOL_GPL(kernel_kobj); +const char *supported_printable(int taint) +{ + int mask = TAINT_PROPRIETARY_MODULE|TAINT_NO_SUPPORT; + if ((taint & mask) == mask) + return "No, Proprietary and Unsupported modules are loaded"; + else if (taint & TAINT_PROPRIETARY_MODULE) + return "No, Proprietary modules are loaded"; + else if (taint & TAINT_NO_SUPPORT) + return "No, Unsupported modules are loaded"; + else if (taint & TAINT_EXTERNAL_SUPPORT) + return "Yes, External"; + else + return "Yes"; +} + +static ssize_t supported_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%s\n", supported_printable(get_taint())); +} +KERNEL_ATTR_RO(supported); + static struct attribute * kernel_attrs[] = { #if defined(CONFIG_HOTPLUG) &uevent_seqnum_attr.attr, @@ -170,6 +192,7 @@ static struct attribute * kernel_attrs[] &kexec_crash_size_attr.attr, &vmcoreinfo_attr.attr, #endif + &supported_attr.attr, NULL }; --- a/kernel/module.c +++ b/kernel/module.c @@ -937,10 +937,36 @@ static struct module_attribute initstate .show = show_initstate, }; +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 *mod, char *buffer) +{ + return sprintf(buffer, "%s\n", supported_printable(mod->taints)); +} + +static struct module_attribute modinfo_supported = { + .attr = { .name = "supported", .mode = 0444 }, + .show = show_modinfo_supported, + .setup = setup_modinfo_supported, +}; + static struct module_attribute *modinfo_attrs[] = { &modinfo_version, &modinfo_srcversion, &initstate, + &modinfo_supported, #ifdef CONFIG_MODULE_UNLOAD &refcnt, #endif @@ -2027,7 +2053,7 @@ static noinline struct module *load_modu Elf_Ehdr *hdr; Elf_Shdr *sechdrs; char *secstrings, *args, *modmagic, *strtab = NULL; - char *staging, *supported; + char *staging; unsigned int i; unsigned int symindex = 0; unsigned int strindex = 0; @@ -2146,28 +2172,6 @@ static noinline struct module *load_modu mod->name); } - supported = get_modinfo(sechdrs, infoindex, "supported"); - if (supported) { - if (!strcmp(supported, "external")) - add_taint_module(mod, TAINT_EXTERNAL_SUPPORT); - else if (strcmp(supported, "yes")) - supported = NULL; - } - if (!supported) { - 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 free_hdr; - } - add_taint_module(mod, TAINT_NO_SUPPORT); - if (unsupported == 1) { - printk(KERN_WARNING "%s: module not supported by " - "Novell, setting U taint flag.\n", mod->name); - } - } - /* Now copy in args */ args = strndup_user(uargs, ~0UL >> 1); if (IS_ERR(args)) { @@ -2479,6 +2483,26 @@ static noinline struct module *load_modu add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs); + /* 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 free_hdr; + } + 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); + } + } + /* Get rid of temporary copy */ vfree(hdr); @@ -3061,6 +3085,7 @@ void print_modules(void) if (last_unloaded_module[0]) printk(" [last unloaded: %s]", last_unloaded_module); printk("\n"); + printk("Supported: %s\n", supported_printable(get_taint())); } #ifdef CONFIG_MODVERSIONS --- a/kernel/panic.c +++ b/kernel/panic.c @@ -233,6 +233,11 @@ unsigned long get_taint(void) return tainted_mask; } +void add_nonfatal_taint(unsigned flag) +{ + set_bit(flag, &tainted_mask); +} + void add_taint(unsigned flag) { /*