qubes-linux-kernel/patches.suse/supported-flag-sysfs
2010-07-07 13:12:45 +02:00

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)
{
/*