From: Jeff Mahoney <jeffm@suse.com>
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/<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/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)
 {
 	/*
