diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kmod.c | 120 | ||||
-rw-r--r-- | kernel/module.c | 32 | ||||
-rw-r--r-- | kernel/params.c | 1 | ||||
-rw-r--r-- | kernel/power/main.c | 5 |
4 files changed, 20 insertions, 138 deletions
diff --git a/kernel/kmod.c b/kernel/kmod.c index 9f923f8ce6a0..796276141e51 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -36,8 +36,6 @@ | |||
36 | #include <linux/resource.h> | 36 | #include <linux/resource.h> |
37 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
38 | 38 | ||
39 | extern int delete_module(const char *name, unsigned int flags); | ||
40 | |||
41 | extern int max_threads; | 39 | extern int max_threads; |
42 | 40 | ||
43 | static struct workqueue_struct *khelper_wq; | 41 | static struct workqueue_struct *khelper_wq; |
@@ -48,7 +46,6 @@ static struct workqueue_struct *khelper_wq; | |||
48 | modprobe_path is set via /proc/sys. | 46 | modprobe_path is set via /proc/sys. |
49 | */ | 47 | */ |
50 | char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; | 48 | char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; |
51 | struct module_kobject kmod_mk; | ||
52 | 49 | ||
53 | /** | 50 | /** |
54 | * request_module - try to load a kernel module | 51 | * request_module - try to load a kernel module |
@@ -78,11 +75,6 @@ int request_module(const char *fmt, ...) | |||
78 | static atomic_t kmod_concurrent = ATOMIC_INIT(0); | 75 | static atomic_t kmod_concurrent = ATOMIC_INIT(0); |
79 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ | 76 | #define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ |
80 | static int kmod_loop_msg; | 77 | static int kmod_loop_msg; |
81 | char modalias[16 + MODULE_NAME_LEN] = "MODALIAS="; | ||
82 | char *uevent_envp[2] = { | ||
83 | modalias, | ||
84 | NULL | ||
85 | }; | ||
86 | 78 | ||
87 | va_start(args, fmt); | 79 | va_start(args, fmt); |
88 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); | 80 | ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); |
@@ -90,12 +82,6 @@ int request_module(const char *fmt, ...) | |||
90 | if (ret >= MODULE_NAME_LEN) | 82 | if (ret >= MODULE_NAME_LEN) |
91 | return -ENAMETOOLONG; | 83 | return -ENAMETOOLONG; |
92 | 84 | ||
93 | strcpy(&modalias[strlen("MODALIAS=")], module_name); | ||
94 | kobject_uevent_env(&kmod_mk.kobj, KOBJ_CHANGE, uevent_envp); | ||
95 | |||
96 | if (modprobe_path[0] == '\0') | ||
97 | goto out; | ||
98 | |||
99 | /* If modprobe needs a service that is in a module, we get a recursive | 85 | /* If modprobe needs a service that is in a module, we get a recursive |
100 | * loop. Limit the number of running kmod threads to max_threads/2 or | 86 | * loop. Limit the number of running kmod threads to max_threads/2 or |
101 | * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method | 87 | * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method |
@@ -122,115 +108,9 @@ int request_module(const char *fmt, ...) | |||
122 | 108 | ||
123 | ret = call_usermodehelper(modprobe_path, argv, envp, 1); | 109 | ret = call_usermodehelper(modprobe_path, argv, envp, 1); |
124 | atomic_dec(&kmod_concurrent); | 110 | atomic_dec(&kmod_concurrent); |
125 | out: | ||
126 | return ret; | 111 | return ret; |
127 | } | 112 | } |
128 | EXPORT_SYMBOL(request_module); | 113 | EXPORT_SYMBOL(request_module); |
129 | |||
130 | static ssize_t store_mod_request(struct module_attribute *mattr, | ||
131 | struct module *mod, | ||
132 | const char *buffer, size_t count) | ||
133 | { | ||
134 | char name[MODULE_NAME_LEN]; | ||
135 | int ret; | ||
136 | |||
137 | if (count < 1 || count+1 > MODULE_NAME_LEN) | ||
138 | return -EINVAL; | ||
139 | memcpy(name, buffer, count); | ||
140 | name[count] = '\0'; | ||
141 | if (name[count-1] == '\n') | ||
142 | name[count-1] = '\0'; | ||
143 | |||
144 | ret = request_module(name); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | return count; | ||
148 | } | ||
149 | |||
150 | static struct module_attribute mod_request = { | ||
151 | .attr = { .name = "mod_request", .mode = S_IWUSR, .owner = THIS_MODULE }, | ||
152 | .store = store_mod_request, | ||
153 | }; | ||
154 | |||
155 | #ifdef CONFIG_MODULE_UNLOAD | ||
156 | static ssize_t store_mod_unload(struct module_attribute *mattr, | ||
157 | struct module *mod, | ||
158 | const char *buffer, size_t count) | ||
159 | { | ||
160 | char name[MODULE_NAME_LEN]; | ||
161 | int ret; | ||
162 | |||
163 | if (count < 1 || count+1 > MODULE_NAME_LEN) | ||
164 | return -EINVAL; | ||
165 | memcpy(name, buffer, count); | ||
166 | name[count] = '\0'; | ||
167 | if (name[count-1] == '\n') | ||
168 | name[count-1] = '\0'; | ||
169 | |||
170 | ret = delete_module(name, O_NONBLOCK); | ||
171 | if (ret < 0) | ||
172 | return ret; | ||
173 | return count; | ||
174 | } | ||
175 | |||
176 | static struct module_attribute mod_unload = { | ||
177 | .attr = { .name = "mod_unload", .mode = S_IWUSR, .owner = THIS_MODULE }, | ||
178 | .store = store_mod_unload, | ||
179 | }; | ||
180 | #endif | ||
181 | |||
182 | static ssize_t show_mod_request_helper(struct module_attribute *mattr, | ||
183 | struct module *mod, | ||
184 | char *buffer) | ||
185 | { | ||
186 | return sprintf(buffer, "%s\n", modprobe_path); | ||
187 | } | ||
188 | |||
189 | static ssize_t store_mod_request_helper(struct module_attribute *mattr, | ||
190 | struct module *mod, | ||
191 | const char *buffer, size_t count) | ||
192 | { | ||
193 | if (count < 1 || count+1 > KMOD_PATH_LEN) | ||
194 | return -EINVAL; | ||
195 | memcpy(modprobe_path, buffer, count); | ||
196 | modprobe_path[count] = '\0'; | ||
197 | if (modprobe_path[count-1] == '\n') | ||
198 | modprobe_path[count-1] = '\0'; | ||
199 | return count; | ||
200 | } | ||
201 | |||
202 | static struct module_attribute mod_request_helper = { | ||
203 | .attr = { | ||
204 | .name = "mod_request_helper", | ||
205 | .mode = S_IWUSR | S_IRUGO, | ||
206 | .owner = THIS_MODULE | ||
207 | }, | ||
208 | .show = show_mod_request_helper, | ||
209 | .store = store_mod_request_helper, | ||
210 | }; | ||
211 | |||
212 | void __init kmod_sysfs_init(void) | ||
213 | { | ||
214 | int ret; | ||
215 | |||
216 | kmod_mk.mod = THIS_MODULE; | ||
217 | kobj_set_kset_s(&kmod_mk, module_subsys); | ||
218 | kobject_set_name(&kmod_mk.kobj, "kmod"); | ||
219 | kobject_init(&kmod_mk.kobj); | ||
220 | ret = kobject_add(&kmod_mk.kobj); | ||
221 | if (ret < 0) | ||
222 | goto out; | ||
223 | |||
224 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_request_helper.attr); | ||
225 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_request.attr); | ||
226 | #ifdef CONFIG_MODULE_UNLOAD | ||
227 | ret = sysfs_create_file(&kmod_mk.kobj, &mod_unload.attr); | ||
228 | #endif | ||
229 | |||
230 | kobject_uevent(&kmod_mk.kobj, KOBJ_ADD); | ||
231 | out: | ||
232 | return; | ||
233 | } | ||
234 | #endif /* CONFIG_KMOD */ | 114 | #endif /* CONFIG_KMOD */ |
235 | 115 | ||
236 | struct subprocess_info { | 116 | struct subprocess_info { |
diff --git a/kernel/module.c b/kernel/module.c index 8c25b1a04fa6..f77e893e4620 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -653,11 +653,20 @@ static void wait_for_zero_refcount(struct module *mod) | |||
653 | mutex_lock(&module_mutex); | 653 | mutex_lock(&module_mutex); |
654 | } | 654 | } |
655 | 655 | ||
656 | int delete_module(const char *name, unsigned int flags) | 656 | asmlinkage long |
657 | sys_delete_module(const char __user *name_user, unsigned int flags) | ||
657 | { | 658 | { |
658 | struct module *mod; | 659 | struct module *mod; |
660 | char name[MODULE_NAME_LEN]; | ||
659 | int ret, forced = 0; | 661 | int ret, forced = 0; |
660 | 662 | ||
663 | if (!capable(CAP_SYS_MODULE)) | ||
664 | return -EPERM; | ||
665 | |||
666 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | ||
667 | return -EFAULT; | ||
668 | name[MODULE_NAME_LEN-1] = '\0'; | ||
669 | |||
661 | if (mutex_lock_interruptible(&module_mutex) != 0) | 670 | if (mutex_lock_interruptible(&module_mutex) != 0) |
662 | return -EINTR; | 671 | return -EINTR; |
663 | 672 | ||
@@ -718,21 +727,6 @@ int delete_module(const char *name, unsigned int flags) | |||
718 | return ret; | 727 | return ret; |
719 | } | 728 | } |
720 | 729 | ||
721 | asmlinkage long | ||
722 | sys_delete_module(const char __user *name_user, unsigned int flags) | ||
723 | { | ||
724 | char name[MODULE_NAME_LEN]; | ||
725 | |||
726 | if (!capable(CAP_SYS_MODULE)) | ||
727 | return -EPERM; | ||
728 | |||
729 | if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) | ||
730 | return -EFAULT; | ||
731 | name[MODULE_NAME_LEN-1] = '\0'; | ||
732 | |||
733 | return delete_module(name, flags); | ||
734 | } | ||
735 | |||
736 | static void print_unload_info(struct seq_file *m, struct module *mod) | 730 | static void print_unload_info(struct seq_file *m, struct module *mod) |
737 | { | 731 | { |
738 | struct module_use *use; | 732 | struct module_use *use; |
@@ -2425,6 +2419,12 @@ void module_remove_driver(struct device_driver *drv) | |||
2425 | kfree(driver_name); | 2419 | kfree(driver_name); |
2426 | } | 2420 | } |
2427 | } | 2421 | } |
2422 | /* | ||
2423 | * Undo the additional reference we added in module_add_driver() | ||
2424 | * via kset_find_obj() | ||
2425 | */ | ||
2426 | if (drv->mod_name) | ||
2427 | kobject_put(&drv->kobj); | ||
2428 | } | 2428 | } |
2429 | EXPORT_SYMBOL(module_remove_driver); | 2429 | EXPORT_SYMBOL(module_remove_driver); |
2430 | #endif | 2430 | #endif |
diff --git a/kernel/params.c b/kernel/params.c index 7a751570b56d..e265b13195b1 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -707,7 +707,6 @@ static int __init param_sysfs_init(void) | |||
707 | } | 707 | } |
708 | 708 | ||
709 | param_sysfs_builtin(); | 709 | param_sysfs_builtin(); |
710 | kmod_sysfs_init(); | ||
711 | 710 | ||
712 | return 0; | 711 | return 0; |
713 | } | 712 | } |
diff --git a/kernel/power/main.c b/kernel/power/main.c index e1c413120469..a064dfd8877a 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -167,7 +167,10 @@ static inline int valid_state(suspend_state_t state) | |||
167 | if (state == PM_SUSPEND_DISK) | 167 | if (state == PM_SUSPEND_DISK) |
168 | return 1; | 168 | return 1; |
169 | 169 | ||
170 | if (pm_ops && pm_ops->valid && !pm_ops->valid(state)) | 170 | /* all other states need lowlevel support and need to be |
171 | * valid to the lowlevel implementation, no valid callback | ||
172 | * implies that all are valid. */ | ||
173 | if (!pm_ops || (pm_ops->valid && !pm_ops->valid(state))) | ||
171 | return 0; | 174 | return 0; |
172 | return 1; | 175 | return 1; |
173 | } | 176 | } |