aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Streetman <ddstreet@ieee.org>2015-06-16 16:48:52 -0400
committerRusty Russell <rusty@rustcorp.com.au>2015-06-23 01:57:38 -0400
commitb51d23e4e9fea6f264d39535c2a62d1f51e7ccc3 (patch)
tree032ebaa1088f1c20985b0872ab31a9d403a35884
parent5104b7d7678b0029417f6ac08243773a77259ac6 (diff)
module: add per-module param_lock
Add a "param_lock" mutex to each module, and update params.c to use the correct built-in or module mutex while locking kernel params. Remove the kparam_block_sysfs_r/w() macros, replace them with direct calls to kernel_param_[un]lock(module). The kernel param code currently uses a single mutex to protect modification of any and all kernel params. While this generally works, there is one specific problem with it; a module callback function cannot safely load another module, i.e. with request_module() or even with indirect calls such as crypto_has_alg(). If the module to be loaded has any of its params configured (e.g. with a /etc/modprobe.d/* config file), then the attempt will result in a deadlock between the first module param callback waiting for modprobe, and modprobe trying to lock the single kernel param mutex to set the new module's param. This fixes that by using per-module mutexes, so that each individual module is protected against concurrent changes in its own kernel params, but is not blocked by changes to other module params. All built-in modules continue to use the built-in mutex, since they will always be loaded at runtime and references (e.g. request_module(), crypto_has_alg()) to them will never cause load-time param changing. This also simplifies the interface used by modules to block sysfs access to their params; while there are currently functions to block and unblock sysfs param access which are split up by read and write and expect a single kernel param to be passed, their actual operation is identical and applies to all params, not just the one passed to them; they simply lock and unlock the global param mutex. They are replaced with direct calls to kernel_param_[un]lock(THIS_MODULE), which locks THIS_MODULE's param_lock, or if the module is built-in, it locks the built-in mutex. Suggested-by: Rusty Russell <rusty@rustcorp.com.au> Signed-off-by: Dan Streetman <ddstreet@ieee.org> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--arch/um/drivers/hostaudio_kern.c20
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c6
-rw-r--r--drivers/net/wireless/libertas_tf/if_usb.c6
-rw-r--r--drivers/usb/atm/ueagle-atm.c4
-rw-r--r--drivers/video/fbdev/vt8623fb.c4
-rw-r--r--include/linux/module.h1
-rw-r--r--include/linux/moduleparam.h61
-rw-r--r--kernel/module.c2
-rw-r--r--kernel/params.c50
-rw-r--r--net/mac80211/rate.c4
10 files changed, 65 insertions, 93 deletions
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index 9b90fdc4b151..f6b911cc3923 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -185,9 +185,9 @@ static int hostaudio_open(struct inode *inode, struct file *file)
185 int ret; 185 int ret;
186 186
187#ifdef DEBUG 187#ifdef DEBUG
188 kparam_block_sysfs_write(dsp); 188 kernel_param_lock(THIS_MODULE);
189 printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp); 189 printk(KERN_DEBUG "hostaudio: open called (host: %s)\n", dsp);
190 kparam_unblock_sysfs_write(dsp); 190 kernel_param_unlock(THIS_MODULE);
191#endif 191#endif
192 192
193 state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL); 193 state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
@@ -199,11 +199,11 @@ static int hostaudio_open(struct inode *inode, struct file *file)
199 if (file->f_mode & FMODE_WRITE) 199 if (file->f_mode & FMODE_WRITE)
200 w = 1; 200 w = 1;
201 201
202 kparam_block_sysfs_write(dsp); 202 kernel_param_lock(THIS_MODULE);
203 mutex_lock(&hostaudio_mutex); 203 mutex_lock(&hostaudio_mutex);
204 ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); 204 ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
205 mutex_unlock(&hostaudio_mutex); 205 mutex_unlock(&hostaudio_mutex);
206 kparam_unblock_sysfs_write(dsp); 206 kernel_param_unlock(THIS_MODULE);
207 207
208 if (ret < 0) { 208 if (ret < 0) {
209 kfree(state); 209 kfree(state);
@@ -260,17 +260,17 @@ static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
260 if (file->f_mode & FMODE_WRITE) 260 if (file->f_mode & FMODE_WRITE)
261 w = 1; 261 w = 1;
262 262
263 kparam_block_sysfs_write(mixer); 263 kernel_param_lock(THIS_MODULE);
264 mutex_lock(&hostaudio_mutex); 264 mutex_lock(&hostaudio_mutex);
265 ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); 265 ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
266 mutex_unlock(&hostaudio_mutex); 266 mutex_unlock(&hostaudio_mutex);
267 kparam_unblock_sysfs_write(mixer); 267 kernel_param_unlock(THIS_MODULE);
268 268
269 if (ret < 0) { 269 if (ret < 0) {
270 kparam_block_sysfs_write(dsp); 270 kernel_param_lock(THIS_MODULE);
271 printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', " 271 printk(KERN_ERR "hostaudio_open_mixdev failed to open '%s', "
272 "err = %d\n", dsp, -ret); 272 "err = %d\n", dsp, -ret);
273 kparam_unblock_sysfs_write(dsp); 273 kernel_param_unlock(THIS_MODULE);
274 kfree(state); 274 kfree(state);
275 return ret; 275 return ret;
276 } 276 }
@@ -326,10 +326,10 @@ MODULE_LICENSE("GPL");
326 326
327static int __init hostaudio_init_module(void) 327static int __init hostaudio_init_module(void)
328{ 328{
329 __kernel_param_lock(); 329 kernel_param_lock(THIS_MODULE);
330 printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", 330 printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n",
331 dsp, mixer); 331 dsp, mixer);
332 __kernel_param_unlock(); 332 kernel_param_unlock(THIS_MODULE);
333 333
334 module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); 334 module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1);
335 if (module_data.dev_audio < 0) { 335 if (module_data.dev_audio < 0) {
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index 2bae50292dcd..83651ac8ddb9 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -279,7 +279,7 @@ MODULE_FIRMWARE("myri10ge_eth_z8e.dat");
279MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat"); 279MODULE_FIRMWARE("myri10ge_rss_ethp_z8e.dat");
280MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat"); 280MODULE_FIRMWARE("myri10ge_rss_eth_z8e.dat");
281 281
282/* Careful: must be accessed under kparam_block_sysfs_write */ 282/* Careful: must be accessed under kernel_param_lock() */
283static char *myri10ge_fw_name = NULL; 283static char *myri10ge_fw_name = NULL;
284module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR); 284module_param(myri10ge_fw_name, charp, S_IRUGO | S_IWUSR);
285MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name"); 285MODULE_PARM_DESC(myri10ge_fw_name, "Firmware image name");
@@ -3427,7 +3427,7 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
3427 } 3427 }
3428 } 3428 }
3429 3429
3430 kparam_block_sysfs_write(myri10ge_fw_name); 3430 kernel_param_lock(THIS_MODULE);
3431 if (myri10ge_fw_name != NULL) { 3431 if (myri10ge_fw_name != NULL) {
3432 char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL); 3432 char *fw_name = kstrdup(myri10ge_fw_name, GFP_KERNEL);
3433 if (fw_name) { 3433 if (fw_name) {
@@ -3435,7 +3435,7 @@ static void myri10ge_select_firmware(struct myri10ge_priv *mgp)
3435 set_fw_name(mgp, fw_name, true); 3435 set_fw_name(mgp, fw_name, true);
3436 } 3436 }
3437 } 3437 }
3438 kparam_unblock_sysfs_write(myri10ge_fw_name); 3438 kernel_param_unlock(THIS_MODULE);
3439 3439
3440 if (mgp->board_number < MYRI10GE_MAX_BOARDS && 3440 if (mgp->board_number < MYRI10GE_MAX_BOARDS &&
3441 myri10ge_fw_names[mgp->board_number] != NULL && 3441 myri10ge_fw_names[mgp->board_number] != NULL &&
diff --git a/drivers/net/wireless/libertas_tf/if_usb.c b/drivers/net/wireless/libertas_tf/if_usb.c
index 1a20cee5febe..799a2efe5793 100644
--- a/drivers/net/wireless/libertas_tf/if_usb.c
+++ b/drivers/net/wireless/libertas_tf/if_usb.c
@@ -821,15 +821,15 @@ static int if_usb_prog_firmware(struct if_usb_card *cardp)
821 821
822 lbtf_deb_enter(LBTF_DEB_USB); 822 lbtf_deb_enter(LBTF_DEB_USB);
823 823
824 kparam_block_sysfs_write(fw_name); 824 kernel_param_lock(THIS_MODULE);
825 ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev); 825 ret = request_firmware(&cardp->fw, lbtf_fw_name, &cardp->udev->dev);
826 if (ret < 0) { 826 if (ret < 0) {
827 pr_err("request_firmware() failed with %#x\n", ret); 827 pr_err("request_firmware() failed with %#x\n", ret);
828 pr_err("firmware %s not found\n", lbtf_fw_name); 828 pr_err("firmware %s not found\n", lbtf_fw_name);
829 kparam_unblock_sysfs_write(fw_name); 829 kernel_param_unlock(THIS_MODULE);
830 goto done; 830 goto done;
831 } 831 }
832 kparam_unblock_sysfs_write(fw_name); 832 kernel_param_unlock(THIS_MODULE);
833 833
834 if (check_fwfile_format(cardp->fw->data, cardp->fw->size)) 834 if (check_fwfile_format(cardp->fw->data, cardp->fw->size))
835 goto release_fw; 835 goto release_fw;
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 888998a7fe31..a2ae88dbda78 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -1599,7 +1599,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
1599 char file_arr[] = "CMVxy.bin"; 1599 char file_arr[] = "CMVxy.bin";
1600 char *file; 1600 char *file;
1601 1601
1602 kparam_block_sysfs_write(cmv_file); 1602 kernel_param_lock(THIS_MODULE);
1603 /* set proper name corresponding modem version and line type */ 1603 /* set proper name corresponding modem version and line type */
1604 if (cmv_file[sc->modem_index] == NULL) { 1604 if (cmv_file[sc->modem_index] == NULL) {
1605 if (UEA_CHIP_VERSION(sc) == ADI930) 1605 if (UEA_CHIP_VERSION(sc) == ADI930)
@@ -1618,7 +1618,7 @@ static void cmvs_file_name(struct uea_softc *sc, char *const cmv_name, int ver)
1618 strlcat(cmv_name, file, UEA_FW_NAME_MAX); 1618 strlcat(cmv_name, file, UEA_FW_NAME_MAX);
1619 if (ver == 2) 1619 if (ver == 2)
1620 strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX); 1620 strlcat(cmv_name, ".v2", UEA_FW_NAME_MAX);
1621 kparam_unblock_sysfs_write(cmv_file); 1621 kernel_param_unlock(THIS_MODULE);
1622} 1622}
1623 1623
1624static int request_cmvs_old(struct uea_softc *sc, 1624static int request_cmvs_old(struct uea_softc *sc,
diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
index ea7f056ed5fe..8bac309c24b9 100644
--- a/drivers/video/fbdev/vt8623fb.c
+++ b/drivers/video/fbdev/vt8623fb.c
@@ -754,9 +754,9 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
754 754
755 /* Prepare startup mode */ 755 /* Prepare startup mode */
756 756
757 kparam_block_sysfs_write(mode_option); 757 kernel_param_lock(THIS_MODULE);
758 rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8); 758 rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
759 kparam_unblock_sysfs_write(mode_option); 759 kernel_param_unlock(THIS_MODULE);
760 if (! ((rc == 1) || (rc == 2))) { 760 if (! ((rc == 1) || (rc == 2))) {
761 rc = -EINVAL; 761 rc = -EINVAL;
762 dev_err(info->device, "mode %s not found\n", mode_option); 762 dev_err(info->device, "mode %s not found\n", mode_option);
diff --git a/include/linux/module.h b/include/linux/module.h
index 4c1b02e1361d..6ba0e87fa804 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -240,6 +240,7 @@ struct module {
240 unsigned int num_syms; 240 unsigned int num_syms;
241 241
242 /* Kernel parameters. */ 242 /* Kernel parameters. */
243 struct mutex param_lock;
243 struct kernel_param *kp; 244 struct kernel_param *kp;
244 unsigned int num_kp; 245 unsigned int num_kp;
245 246
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index ab5031453807..f1fdc50520d8 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -67,6 +67,7 @@ enum {
67 67
68struct kernel_param { 68struct kernel_param {
69 const char *name; 69 const char *name;
70 struct module *mod;
70 const struct kernel_param_ops *ops; 71 const struct kernel_param_ops *ops;
71 const u16 perm; 72 const u16 perm;
72 s8 level; 73 s8 level;
@@ -108,7 +109,7 @@ struct kparam_array
108 * 109 *
109 * @perm is 0 if the the variable is not to appear in sysfs, or 0444 110 * @perm is 0 if the the variable is not to appear in sysfs, or 0444
110 * for world-readable, 0644 for root-writable, etc. Note that if it 111 * for world-readable, 0644 for root-writable, etc. Note that if it
111 * is writable, you may need to use kparam_block_sysfs_write() around 112 * is writable, you may need to use kernel_param_lock() around
112 * accesses (esp. charp, which can be kfreed when it changes). 113 * accesses (esp. charp, which can be kfreed when it changes).
113 * 114 *
114 * The @type is simply pasted to refer to a param_ops_##type and a 115 * The @type is simply pasted to refer to a param_ops_##type and a
@@ -216,12 +217,12 @@ struct kparam_array
216 parameters. */ 217 parameters. */
217#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \ 218#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \
218 /* Default value instead of permissions? */ \ 219 /* Default value instead of permissions? */ \
219 static const char __param_str_##name[] = prefix #name; \ 220 static const char __param_str_##name[] = prefix #name; \
220 static struct kernel_param __moduleparam_const __param_##name \ 221 static struct kernel_param __moduleparam_const __param_##name \
221 __used \ 222 __used \
222 __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ 223 __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
223 = { __param_str_##name, ops, VERIFY_OCTAL_PERMISSIONS(perm), \ 224 = { __param_str_##name, THIS_MODULE, ops, \
224 level, flags, { arg } } 225 VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }
225 226
226/* Obsolete - use module_param_cb() */ 227/* Obsolete - use module_param_cb() */
227#define module_param_call(name, set, get, arg, perm) \ 228#define module_param_call(name, set, get, arg, perm) \
@@ -238,58 +239,14 @@ __check_old_set_param(int (*oldset)(const char *, struct kernel_param *))
238 return 0; 239 return 0;
239} 240}
240 241
241/**
242 * kparam_block_sysfs_write - make sure a parameter isn't written via sysfs.
243 * @name: the name of the parameter
244 *
245 * There's no point blocking write on a paramter that isn't writable via sysfs!
246 */
247#define kparam_block_sysfs_write(name) \
248 do { \
249 BUG_ON(!(__param_##name.perm & 0222)); \
250 __kernel_param_lock(); \
251 } while (0)
252
253/**
254 * kparam_unblock_sysfs_write - allows sysfs to write to a parameter again.
255 * @name: the name of the parameter
256 */
257#define kparam_unblock_sysfs_write(name) \
258 do { \
259 BUG_ON(!(__param_##name.perm & 0222)); \
260 __kernel_param_unlock(); \
261 } while (0)
262
263/**
264 * kparam_block_sysfs_read - make sure a parameter isn't read via sysfs.
265 * @name: the name of the parameter
266 *
267 * This also blocks sysfs writes.
268 */
269#define kparam_block_sysfs_read(name) \
270 do { \
271 BUG_ON(!(__param_##name.perm & 0444)); \
272 __kernel_param_lock(); \
273 } while (0)
274
275/**
276 * kparam_unblock_sysfs_read - allows sysfs to read a parameter again.
277 * @name: the name of the parameter
278 */
279#define kparam_unblock_sysfs_read(name) \
280 do { \
281 BUG_ON(!(__param_##name.perm & 0444)); \
282 __kernel_param_unlock(); \
283 } while (0)
284
285#ifdef CONFIG_SYSFS 242#ifdef CONFIG_SYSFS
286extern void __kernel_param_lock(void); 243extern void kernel_param_lock(struct module *mod);
287extern void __kernel_param_unlock(void); 244extern void kernel_param_unlock(struct module *mod);
288#else 245#else
289static inline void __kernel_param_lock(void) 246static inline void kernel_param_lock(struct module *mod)
290{ 247{
291} 248}
292static inline void __kernel_param_unlock(void) 249static inline void kernel_param_unlock(struct module *mod)
293{ 250{
294} 251}
295#endif 252#endif
diff --git a/kernel/module.c b/kernel/module.c
index 427b99f1a4b3..8ec33ce202a6 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3442,6 +3442,8 @@ static int load_module(struct load_info *info, const char __user *uargs,
3442 if (err) 3442 if (err)
3443 goto unlink_mod; 3443 goto unlink_mod;
3444 3444
3445 mutex_init(&mod->param_lock);
3446
3445 /* Now we've got everything in the final locations, we can 3447 /* Now we've got everything in the final locations, we can
3446 * find optional sections. */ 3448 * find optional sections. */
3447 err = find_module_sections(mod, info); 3449 err = find_module_sections(mod, info);
diff --git a/kernel/params.c b/kernel/params.c
index a8b09f6c87dc..8890d0b8dffc 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -25,15 +25,20 @@
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/ctype.h> 26#include <linux/ctype.h>
27 27
28/* Protects all parameters, and incidentally kmalloced_param list. */ 28/* Protects all built-in parameters, modules use their own param_lock */
29static DEFINE_MUTEX(param_lock); 29static DEFINE_MUTEX(param_lock);
30 30
31/* Use the module's mutex, or if built-in use the built-in mutex */
32#define KPARAM_MUTEX(mod) ((mod) ? &(mod)->param_lock : &param_lock)
33#define KPARAM_IS_LOCKED(mod) mutex_is_locked(KPARAM_MUTEX(mod))
34
31/* This just allows us to keep track of which parameters are kmalloced. */ 35/* This just allows us to keep track of which parameters are kmalloced. */
32struct kmalloced_param { 36struct kmalloced_param {
33 struct list_head list; 37 struct list_head list;
34 char val[]; 38 char val[];
35}; 39};
36static LIST_HEAD(kmalloced_params); 40static LIST_HEAD(kmalloced_params);
41static DEFINE_SPINLOCK(kmalloced_params_lock);
37 42
38static void *kmalloc_parameter(unsigned int size) 43static void *kmalloc_parameter(unsigned int size)
39{ 44{
@@ -43,7 +48,10 @@ static void *kmalloc_parameter(unsigned int size)
43 if (!p) 48 if (!p)
44 return NULL; 49 return NULL;
45 50
51 spin_lock(&kmalloced_params_lock);
46 list_add(&p->list, &kmalloced_params); 52 list_add(&p->list, &kmalloced_params);
53 spin_unlock(&kmalloced_params_lock);
54
47 return p->val; 55 return p->val;
48} 56}
49 57
@@ -52,6 +60,7 @@ static void maybe_kfree_parameter(void *param)
52{ 60{
53 struct kmalloced_param *p; 61 struct kmalloced_param *p;
54 62
63 spin_lock(&kmalloced_params_lock);
55 list_for_each_entry(p, &kmalloced_params, list) { 64 list_for_each_entry(p, &kmalloced_params, list) {
56 if (p->val == param) { 65 if (p->val == param) {
57 list_del(&p->list); 66 list_del(&p->list);
@@ -59,6 +68,7 @@ static void maybe_kfree_parameter(void *param)
59 break; 68 break;
60 } 69 }
61 } 70 }
71 spin_unlock(&kmalloced_params_lock);
62} 72}
63 73
64static char dash2underscore(char c) 74static char dash2underscore(char c)
@@ -118,10 +128,10 @@ static int parse_one(char *param,
118 return -EINVAL; 128 return -EINVAL;
119 pr_debug("handling %s with %p\n", param, 129 pr_debug("handling %s with %p\n", param,
120 params[i].ops->set); 130 params[i].ops->set);
121 mutex_lock(&param_lock); 131 kernel_param_lock(params[i].mod);
122 param_check_unsafe(&params[i]); 132 param_check_unsafe(&params[i]);
123 err = params[i].ops->set(val, &params[i]); 133 err = params[i].ops->set(val, &params[i]);
124 mutex_unlock(&param_lock); 134 kernel_param_unlock(params[i].mod);
125 return err; 135 return err;
126 } 136 }
127 } 137 }
@@ -417,7 +427,8 @@ const struct kernel_param_ops param_ops_bint = {
417EXPORT_SYMBOL(param_ops_bint); 427EXPORT_SYMBOL(param_ops_bint);
418 428
419/* We break the rule and mangle the string. */ 429/* We break the rule and mangle the string. */
420static int param_array(const char *name, 430static int param_array(struct module *mod,
431 const char *name,
421 const char *val, 432 const char *val,
422 unsigned int min, unsigned int max, 433 unsigned int min, unsigned int max,
423 void *elem, int elemsize, 434 void *elem, int elemsize,
@@ -448,7 +459,7 @@ static int param_array(const char *name,
448 /* nul-terminate and parse */ 459 /* nul-terminate and parse */
449 save = val[len]; 460 save = val[len];
450 ((char *)val)[len] = '\0'; 461 ((char *)val)[len] = '\0';
451 BUG_ON(!mutex_is_locked(&param_lock)); 462 BUG_ON(!KPARAM_IS_LOCKED(mod));
452 ret = set(val, &kp); 463 ret = set(val, &kp);
453 464
454 if (ret != 0) 465 if (ret != 0)
@@ -470,7 +481,7 @@ static int param_array_set(const char *val, const struct kernel_param *kp)
470 const struct kparam_array *arr = kp->arr; 481 const struct kparam_array *arr = kp->arr;
471 unsigned int temp_num; 482 unsigned int temp_num;
472 483
473 return param_array(kp->name, val, 1, arr->max, arr->elem, 484 return param_array(kp->mod, kp->name, val, 1, arr->max, arr->elem,
474 arr->elemsize, arr->ops->set, kp->level, 485 arr->elemsize, arr->ops->set, kp->level,
475 arr->num ?: &temp_num); 486 arr->num ?: &temp_num);
476} 487}
@@ -485,7 +496,7 @@ static int param_array_get(char *buffer, const struct kernel_param *kp)
485 if (i) 496 if (i)
486 buffer[off++] = ','; 497 buffer[off++] = ',';
487 p.arg = arr->elem + arr->elemsize * i; 498 p.arg = arr->elem + arr->elemsize * i;
488 BUG_ON(!mutex_is_locked(&param_lock)); 499 BUG_ON(!KPARAM_IS_LOCKED(p.mod));
489 ret = arr->ops->get(buffer + off, &p); 500 ret = arr->ops->get(buffer + off, &p);
490 if (ret < 0) 501 if (ret < 0)
491 return ret; 502 return ret;
@@ -568,9 +579,9 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
568 if (!attribute->param->ops->get) 579 if (!attribute->param->ops->get)
569 return -EPERM; 580 return -EPERM;
570 581
571 mutex_lock(&param_lock); 582 kernel_param_lock(mk->mod);
572 count = attribute->param->ops->get(buf, attribute->param); 583 count = attribute->param->ops->get(buf, attribute->param);
573 mutex_unlock(&param_lock); 584 kernel_param_unlock(mk->mod);
574 if (count > 0) { 585 if (count > 0) {
575 strcat(buf, "\n"); 586 strcat(buf, "\n");
576 ++count; 587 ++count;
@@ -580,7 +591,7 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
580 591
581/* sysfs always hands a nul-terminated string in buf. We rely on that. */ 592/* sysfs always hands a nul-terminated string in buf. We rely on that. */
582static ssize_t param_attr_store(struct module_attribute *mattr, 593static ssize_t param_attr_store(struct module_attribute *mattr,
583 struct module_kobject *km, 594 struct module_kobject *mk,
584 const char *buf, size_t len) 595 const char *buf, size_t len)
585{ 596{
586 int err; 597 int err;
@@ -589,10 +600,10 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
589 if (!attribute->param->ops->set) 600 if (!attribute->param->ops->set)
590 return -EPERM; 601 return -EPERM;
591 602
592 mutex_lock(&param_lock); 603 kernel_param_lock(mk->mod);
593 param_check_unsafe(attribute->param); 604 param_check_unsafe(attribute->param);
594 err = attribute->param->ops->set(buf, attribute->param); 605 err = attribute->param->ops->set(buf, attribute->param);
595 mutex_unlock(&param_lock); 606 kernel_param_unlock(mk->mod);
596 if (!err) 607 if (!err)
597 return len; 608 return len;
598 return err; 609 return err;
@@ -605,18 +616,19 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
605#define __modinit __init 616#define __modinit __init
606#endif 617#endif
607 618
608#ifdef CONFIG_SYSFS 619void kernel_param_lock(struct module *mod)
609void __kernel_param_lock(void)
610{ 620{
611 mutex_lock(&param_lock); 621 mutex_lock(KPARAM_MUTEX(mod));
612} 622}
613EXPORT_SYMBOL(__kernel_param_lock);
614 623
615void __kernel_param_unlock(void) 624void kernel_param_unlock(struct module *mod)
616{ 625{
617 mutex_unlock(&param_lock); 626 mutex_unlock(KPARAM_MUTEX(mod));
618} 627}
619EXPORT_SYMBOL(__kernel_param_unlock); 628
629#ifdef CONFIG_SYSFS
630EXPORT_SYMBOL(kernel_param_lock);
631EXPORT_SYMBOL(kernel_param_unlock);
620 632
621/* 633/*
622 * add_sysfs_param - add a parameter to sysfs 634 * add_sysfs_param - add a parameter to sysfs
diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c
index d53355b011f5..8544e2eb570e 100644
--- a/net/mac80211/rate.c
+++ b/net/mac80211/rate.c
@@ -103,7 +103,7 @@ ieee80211_rate_control_ops_get(const char *name)
103 const struct rate_control_ops *ops; 103 const struct rate_control_ops *ops;
104 const char *alg_name; 104 const char *alg_name;
105 105
106 kparam_block_sysfs_write(ieee80211_default_rc_algo); 106 kernel_param_lock(THIS_MODULE);
107 if (!name) 107 if (!name)
108 alg_name = ieee80211_default_rc_algo; 108 alg_name = ieee80211_default_rc_algo;
109 else 109 else
@@ -117,7 +117,7 @@ ieee80211_rate_control_ops_get(const char *name)
117 /* try built-in one if specific alg requested but not found */ 117 /* try built-in one if specific alg requested but not found */
118 if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT)) 118 if (!ops && strlen(CONFIG_MAC80211_RC_DEFAULT))
119 ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT); 119 ops = ieee80211_try_rate_control_ops_get(CONFIG_MAC80211_RC_DEFAULT);
120 kparam_unblock_sysfs_write(ieee80211_default_rc_algo); 120 kernel_param_unlock(THIS_MODULE);
121 121
122 return ops; 122 return ops;
123} 123}