--- /dev/null
+From: Jeff Mahoney <jeffm@suse.com>
+Subject: Export supported status via sysfs
+
+ This patch adds a /sys/kernel/supported file indicating the supportability
+ status of the entire kernel.
+
+ It also adds a /sys/module/<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 <jeffm@suse.com>
+
+---
+
+ include/linux/module.h | 1
+ kernel/ksysfs.c | 18 ++++++++++++
+ kernel/module.c | 70 ++++++++++++++++++++++++++++++++-----------------
+ 3 files changed, 66 insertions(+), 23 deletions(-)
+
+--- a/include/linux/module.h
++++ b/include/linux/module.h
+@@ -363,6 +363,7 @@ static inline int module_is_live(struct
+ struct module *module_text_address(unsigned long addr);
+ struct module *__module_text_address(unsigned long addr);
+ int is_module_address(unsigned long addr);
++const char *supported_printable(int taint);
+
+ /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
+ symnum out of range. */
+--- a/kernel/ksysfs.c
++++ b/kernel/ksysfs.c
+@@ -104,6 +104,23 @@ static struct bin_attribute notes_attr =
+ struct kobject *kernel_kobj;
+ EXPORT_SYMBOL_GPL(kernel_kobj);
+
++const char *supported_printable(int taint)
++{
++ if (taint & TAINT_NO_SUPPORT)
++ return "No";
++ 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(tainted));
++}
++KERNEL_ATTR_RO(supported);
++
+ static struct attribute * kernel_attrs[] = {
+ #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET)
+ &uevent_seqnum_attr.attr,
+@@ -114,6 +131,7 @@ static struct attribute * kernel_attrs[]
+ &kexec_crash_loaded_attr.attr,
+ &vmcoreinfo_attr.attr,
+ #endif
++ &supported_attr.attr,
+ NULL
+ };
+
+--- a/kernel/module.c
++++ b/kernel/module.c
+@@ -922,10 +922,36 @@ static struct module_attribute initstate
+ .show = show_initstate,
+ };
+
++static void setup_modinfo_supported(struct module *mod, const char *s)
++{
++ if (!s) {
++ mod->taints |= TAINT_NO_SUPPORT;
++ return;
++ }
++
++ if (strcmp(s, "external") == 0)
++ mod->taints |= TAINT_EXTERNAL_SUPPORT;
++ else if (strcmp(s, "yes"))
++ mod->taints |= 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
+@@ -1820,7 +1846,6 @@ static noinline struct module *load_modu
+ Elf_Ehdr *hdr;
+ Elf_Shdr *sechdrs;
+ char *secstrings, *args, *modmagic, *strtab = NULL;
+- char *supported;
+ unsigned int i;
+ unsigned int symindex = 0;
+ unsigned int strindex = 0;
+@@ -1975,28 +2000,6 @@ static noinline struct module *load_modu
+ goto free_hdr;
+ }
+
+- 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)) {
+@@ -2256,6 +2259,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 & TAINT_EXTERNAL_SUPPORT)
++ tainted |= TAINT_EXTERNAL_SUPPORT;
++ else if (mod->taints == 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;
++ }
++ tainted |= 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);
++ }
++ }
++
+ /* 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,
+@@ -2735,6 +2758,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(tainted));
+ }
+
+ #ifdef CONFIG_MODVERSIONS