]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Jeff Mahoney <jeffm@suse.com> |
2 | Subject: Export supported status via sysfs | |
3 | ||
4 | This patch adds a /sys/kernel/supported file indicating the supportability | |
5 | status of the entire kernel. | |
6 | ||
7 | It also adds a /sys/module/<module>/supported file indicating the | |
8 | supportability status of individual modules. | |
9 | ||
10 | This is useful because it can be used to obtain the supported status | |
11 | of a running system without current modules (ie: immediately after | |
12 | a kernel update but before a reboot) and without generating an oops. | |
13 | ||
14 | Signed-off-by: Jeff Mahoney <jeffm@suse.com> | |
15 | ||
16 | --- | |
17 | ||
18 | include/linux/module.h | 1 | |
19 | kernel/ksysfs.c | 18 ++++++++++++ | |
20 | kernel/module.c | 70 ++++++++++++++++++++++++++++++++----------------- | |
21 | 3 files changed, 66 insertions(+), 23 deletions(-) | |
22 | ||
23 | --- a/include/linux/module.h | |
24 | +++ b/include/linux/module.h | |
25 | @@ -363,6 +363,7 @@ static inline int module_is_live(struct | |
26 | struct module *module_text_address(unsigned long addr); | |
27 | struct module *__module_text_address(unsigned long addr); | |
28 | int is_module_address(unsigned long addr); | |
29 | +const char *supported_printable(int taint); | |
30 | ||
31 | /* Returns 0 and fills in value, defined and namebuf, or -ERANGE if | |
32 | symnum out of range. */ | |
33 | --- a/kernel/ksysfs.c | |
34 | +++ b/kernel/ksysfs.c | |
35 | @@ -104,6 +104,23 @@ static struct bin_attribute notes_attr = | |
36 | struct kobject *kernel_kobj; | |
37 | EXPORT_SYMBOL_GPL(kernel_kobj); | |
38 | ||
39 | +const char *supported_printable(int taint) | |
40 | +{ | |
41 | + if (taint & TAINT_NO_SUPPORT) | |
42 | + return "No"; | |
43 | + else if (taint & TAINT_EXTERNAL_SUPPORT) | |
44 | + return "Yes, External"; | |
45 | + else | |
46 | + return "Yes"; | |
47 | +} | |
48 | + | |
49 | +static ssize_t supported_show(struct kobject *kobj, | |
50 | + struct kobj_attribute *attr, char *buf) | |
51 | +{ | |
52 | + return sprintf(buf, "%s\n", supported_printable(tainted)); | |
53 | +} | |
54 | +KERNEL_ATTR_RO(supported); | |
55 | + | |
56 | static struct attribute * kernel_attrs[] = { | |
57 | #if defined(CONFIG_HOTPLUG) && defined(CONFIG_NET) | |
58 | &uevent_seqnum_attr.attr, | |
59 | @@ -114,6 +131,7 @@ static struct attribute * kernel_attrs[] | |
60 | &kexec_crash_loaded_attr.attr, | |
61 | &vmcoreinfo_attr.attr, | |
62 | #endif | |
63 | + &supported_attr.attr, | |
64 | NULL | |
65 | }; | |
66 | ||
67 | --- a/kernel/module.c | |
68 | +++ b/kernel/module.c | |
69 | @@ -922,10 +922,36 @@ static struct module_attribute initstate | |
70 | .show = show_initstate, | |
71 | }; | |
72 | ||
73 | +static void setup_modinfo_supported(struct module *mod, const char *s) | |
74 | +{ | |
75 | + if (!s) { | |
76 | + mod->taints |= TAINT_NO_SUPPORT; | |
77 | + return; | |
78 | + } | |
79 | + | |
80 | + if (strcmp(s, "external") == 0) | |
81 | + mod->taints |= TAINT_EXTERNAL_SUPPORT; | |
82 | + else if (strcmp(s, "yes")) | |
83 | + mod->taints |= TAINT_NO_SUPPORT; | |
84 | +} | |
85 | + | |
86 | +static ssize_t show_modinfo_supported(struct module_attribute *mattr, | |
87 | + struct module *mod, char *buffer) | |
88 | +{ | |
89 | + return sprintf(buffer, "%s\n", supported_printable(mod->taints)); | |
90 | +} | |
91 | + | |
92 | +static struct module_attribute modinfo_supported = { | |
93 | + .attr = { .name = "supported", .mode = 0444 }, | |
94 | + .show = show_modinfo_supported, | |
95 | + .setup = setup_modinfo_supported, | |
96 | +}; | |
97 | + | |
98 | static struct module_attribute *modinfo_attrs[] = { | |
99 | &modinfo_version, | |
100 | &modinfo_srcversion, | |
101 | &initstate, | |
102 | + &modinfo_supported, | |
103 | #ifdef CONFIG_MODULE_UNLOAD | |
104 | &refcnt, | |
105 | #endif | |
106 | @@ -1820,7 +1846,6 @@ static noinline struct module *load_modu | |
107 | Elf_Ehdr *hdr; | |
108 | Elf_Shdr *sechdrs; | |
109 | char *secstrings, *args, *modmagic, *strtab = NULL; | |
110 | - char *supported; | |
111 | unsigned int i; | |
112 | unsigned int symindex = 0; | |
113 | unsigned int strindex = 0; | |
114 | @@ -1975,28 +2000,6 @@ static noinline struct module *load_modu | |
115 | goto free_hdr; | |
116 | } | |
117 | ||
118 | - supported = get_modinfo(sechdrs, infoindex, "supported"); | |
119 | - if (supported) { | |
120 | - if (!strcmp(supported, "external")) | |
121 | - add_taint_module(mod, TAINT_EXTERNAL_SUPPORT); | |
122 | - else if (strcmp(supported, "yes")) | |
123 | - supported = NULL; | |
124 | - } | |
125 | - if (!supported) { | |
126 | - if (unsupported == 0) { | |
127 | - printk(KERN_WARNING "%s: module not supported by " | |
128 | - "Novell, refusing to load. To override, echo " | |
129 | - "1 > /proc/sys/kernel/unsupported\n", mod->name); | |
130 | - err = -ENOEXEC; | |
131 | - goto free_hdr; | |
132 | - } | |
133 | - add_taint_module(mod, TAINT_NO_SUPPORT); | |
134 | - if (unsupported == 1) { | |
135 | - printk(KERN_WARNING "%s: module not supported by " | |
136 | - "Novell, setting U taint flag.\n", mod->name); | |
137 | - } | |
138 | - } | |
139 | - | |
140 | /* Now copy in args */ | |
141 | args = strndup_user(uargs, ~0UL >> 1); | |
142 | if (IS_ERR(args)) { | |
143 | @@ -2256,6 +2259,26 @@ static noinline struct module *load_modu | |
144 | add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | |
145 | add_notes_attrs(mod, hdr->e_shnum, secstrings, sechdrs); | |
146 | ||
147 | + /* We don't use add_taint() here because it also disables lockdep. */ | |
148 | + if (mod->taints & TAINT_EXTERNAL_SUPPORT) | |
149 | + tainted |= TAINT_EXTERNAL_SUPPORT; | |
150 | + else if (mod->taints == TAINT_NO_SUPPORT) { | |
151 | + if (unsupported == 0) { | |
152 | + printk(KERN_WARNING "%s: module not supported by " | |
153 | + "Novell, refusing to load. To override, echo " | |
154 | + "1 > /proc/sys/kernel/unsupported\n", mod->name); | |
155 | + err = -ENOEXEC; | |
156 | + goto free_hdr; | |
157 | + } | |
158 | + tainted |= TAINT_NO_SUPPORT; | |
159 | + if (unsupported == 1) { | |
160 | + printk(KERN_WARNING "%s: module is not supported by " | |
161 | + "Novell. Novell Technical Services may decline " | |
162 | + "your support request if it involves a kernel " | |
163 | + "fault.\n", mod->name); | |
164 | + } | |
165 | + } | |
166 | + | |
167 | /* Size of section 0 is 0, so this works well if no unwind info. */ | |
168 | mod->unwind_info = unwind_add_table(mod, | |
169 | (void *)sechdrs[unwindex].sh_addr, | |
170 | @@ -2735,6 +2758,7 @@ void print_modules(void) | |
171 | if (last_unloaded_module[0]) | |
172 | printk(" [last unloaded: %s]", last_unloaded_module); | |
173 | printk("\n"); | |
174 | + printk("Supported: %s\n", supported_printable(tainted)); | |
175 | } | |
176 | ||
177 | #ifdef CONFIG_MODVERSIONS |