211 lines
6.2 KiB
Plaintext
211 lines
6.2 KiB
Plaintext
|
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)
|
||
|
{
|
||
|
/*
|