aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2010-08-12 01:04:19 -0400
committerRusty Russell <rusty@rustcorp.com.au>2010-08-11 09:34:20 -0400
commit907b29eb41aa604477a655bff7345731da94514d (patch)
tree12a7142ffa81a65da204384dfa26365d30803735
parent914dcaa84c53f2c3efa6016efcae13fd92a8a17c (diff)
param: locking for kernel parameters
There may be cases (most obviously, sysfs-writable charp parameters) where a module needs to prevent sysfs access to parameters. Rather than express this in terms of a big lock, the functions are expressed in terms of what they protect against. This is clearer, esp. if the implementation changes to a module-level or even param-level lock. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au> Reviewed-by: Takashi Iwai <tiwai@suse.de> Tested-by: Phil Carmody <ext-phil.2.carmody@nokia.com>
-rw-r--r--include/linux/moduleparam.h56
-rw-r--r--kernel/params.c33
2 files changed, 82 insertions, 7 deletions
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h
index 6d48831fe7d2..ca74a3402d63 100644
--- a/include/linux/moduleparam.h
+++ b/include/linux/moduleparam.h
@@ -130,6 +130,62 @@ __check_old_set_param(int (*oldset)(const char *, struct kernel_param *))
130#define module_param(name, type, perm) \ 130#define module_param(name, type, perm) \
131 module_param_named(name, name, type, perm) 131 module_param_named(name, name, type, perm)
132 132
133/**
134 * kparam_block_sysfs_write - make sure a parameter isn't written via sysfs.
135 * @name: the name of the parameter
136 *
137 * There's no point blocking write on a paramter that isn't writable via sysfs!
138 */
139#define kparam_block_sysfs_write(name) \
140 do { \
141 BUG_ON(!(__param_##name.perm & 0222)); \
142 __kernel_param_lock(); \
143 } while (0)
144
145/**
146 * kparam_unblock_sysfs_write - allows sysfs to write to a parameter again.
147 * @name: the name of the parameter
148 */
149#define kparam_unblock_sysfs_write(name) \
150 do { \
151 BUG_ON(!(__param_##name.perm & 0222)); \
152 __kernel_param_unlock(); \
153 } while (0)
154
155/**
156 * kparam_block_sysfs_read - make sure a parameter isn't read via sysfs.
157 * @name: the name of the parameter
158 *
159 * This also blocks sysfs writes.
160 */
161#define kparam_block_sysfs_read(name) \
162 do { \
163 BUG_ON(!(__param_##name.perm & 0444)); \
164 __kernel_param_lock(); \
165 } while (0)
166
167/**
168 * kparam_unblock_sysfs_read - allows sysfs to read a parameter again.
169 * @name: the name of the parameter
170 */
171#define kparam_unblock_sysfs_read(name) \
172 do { \
173 BUG_ON(!(__param_##name.perm & 0444)); \
174 __kernel_param_unlock(); \
175 } while (0)
176
177#ifdef CONFIG_SYSFS
178extern void __kernel_param_lock(void);
179extern void __kernel_param_unlock(void);
180#else
181static inline void __kernel_param_lock(void)
182{
183}
184static inline void __kernel_param_unlock(void)
185{
186}
187#endif
188
133#ifndef MODULE 189#ifndef MODULE
134/** 190/**
135 * core_param - define a historical core kernel parameter. 191 * core_param - define a historical core kernel parameter.
diff --git a/kernel/params.c b/kernel/params.c
index a3eeeefc9472..08107d181758 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -31,12 +31,14 @@
31#define DEBUGP(fmt, a...) 31#define DEBUGP(fmt, a...)
32#endif 32#endif
33 33
34/* Protects all parameters, and incidentally kmalloced_param list. */
35static DEFINE_MUTEX(param_lock);
36
34/* This just allows us to keep track of which parameters are kmalloced. */ 37/* This just allows us to keep track of which parameters are kmalloced. */
35struct kmalloced_param { 38struct kmalloced_param {
36 struct list_head list; 39 struct list_head list;
37 char val[]; 40 char val[];
38}; 41};
39static DEFINE_MUTEX(param_lock);
40static LIST_HEAD(kmalloced_params); 42static LIST_HEAD(kmalloced_params);
41 43
42static void *kmalloc_parameter(unsigned int size) 44static void *kmalloc_parameter(unsigned int size)
@@ -47,10 +49,7 @@ static void *kmalloc_parameter(unsigned int size)
47 if (!p) 49 if (!p)
48 return NULL; 50 return NULL;
49 51
50 mutex_lock(&param_lock);
51 list_add(&p->list, &kmalloced_params); 52 list_add(&p->list, &kmalloced_params);
52 mutex_unlock(&param_lock);
53
54 return p->val; 53 return p->val;
55} 54}
56 55
@@ -59,7 +58,6 @@ static void maybe_kfree_parameter(void *param)
59{ 58{
60 struct kmalloced_param *p; 59 struct kmalloced_param *p;
61 60
62 mutex_lock(&param_lock);
63 list_for_each_entry(p, &kmalloced_params, list) { 61 list_for_each_entry(p, &kmalloced_params, list) {
64 if (p->val == param) { 62 if (p->val == param) {
65 list_del(&p->list); 63 list_del(&p->list);
@@ -67,7 +65,6 @@ static void maybe_kfree_parameter(void *param)
67 break; 65 break;
68 } 66 }
69 } 67 }
70 mutex_unlock(&param_lock);
71} 68}
72 69
73static inline char dash2underscore(char c) 70static inline char dash2underscore(char c)
@@ -93,6 +90,7 @@ static int parse_one(char *param,
93 int (*handle_unknown)(char *param, char *val)) 90 int (*handle_unknown)(char *param, char *val))
94{ 91{
95 unsigned int i; 92 unsigned int i;
93 int err;
96 94
97 /* Find parameter */ 95 /* Find parameter */
98 for (i = 0; i < num_params; i++) { 96 for (i = 0; i < num_params; i++) {
@@ -102,7 +100,10 @@ static int parse_one(char *param,
102 return -EINVAL; 100 return -EINVAL;
103 DEBUGP("They are equal! Calling %p\n", 101 DEBUGP("They are equal! Calling %p\n",
104 params[i].ops->set); 102 params[i].ops->set);
105 return params[i].ops->set(val, &params[i]); 103 mutex_lock(&param_lock);
104 err = params[i].ops->set(val, &params[i]);
105 mutex_unlock(&param_lock);
106 return err;
106 } 107 }
107 } 108 }
108 109
@@ -400,6 +401,7 @@ static int param_array(const char *name,
400 /* nul-terminate and parse */ 401 /* nul-terminate and parse */
401 save = val[len]; 402 save = val[len];
402 ((char *)val)[len] = '\0'; 403 ((char *)val)[len] = '\0';
404 BUG_ON(!mutex_is_locked(&param_lock));
403 ret = set(val, &kp); 405 ret = set(val, &kp);
404 406
405 if (ret != 0) 407 if (ret != 0)
@@ -438,6 +440,7 @@ static int param_array_get(char *buffer, const struct kernel_param *kp)
438 if (i) 440 if (i)
439 buffer[off++] = ','; 441 buffer[off++] = ',';
440 p.arg = arr->elem + arr->elemsize * i; 442 p.arg = arr->elem + arr->elemsize * i;
443 BUG_ON(!mutex_is_locked(&param_lock));
441 ret = arr->ops->get(buffer + off, &p); 444 ret = arr->ops->get(buffer + off, &p);
442 if (ret < 0) 445 if (ret < 0)
443 return ret; 446 return ret;
@@ -522,7 +525,9 @@ static ssize_t param_attr_show(struct module_attribute *mattr,
522 if (!attribute->param->ops->get) 525 if (!attribute->param->ops->get)
523 return -EPERM; 526 return -EPERM;
524 527
528 mutex_lock(&param_lock);
525 count = attribute->param->ops->get(buf, attribute->param); 529 count = attribute->param->ops->get(buf, attribute->param);
530 mutex_unlock(&param_lock);
526 if (count > 0) { 531 if (count > 0) {
527 strcat(buf, "\n"); 532 strcat(buf, "\n");
528 ++count; 533 ++count;
@@ -541,7 +546,9 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
541 if (!attribute->param->ops->set) 546 if (!attribute->param->ops->set)
542 return -EPERM; 547 return -EPERM;
543 548
549 mutex_lock(&param_lock);
544 err = attribute->param->ops->set(buf, attribute->param); 550 err = attribute->param->ops->set(buf, attribute->param);
551 mutex_unlock(&param_lock);
545 if (!err) 552 if (!err)
546 return len; 553 return len;
547 return err; 554 return err;
@@ -555,6 +562,18 @@ static ssize_t param_attr_store(struct module_attribute *mattr,
555#endif 562#endif
556 563
557#ifdef CONFIG_SYSFS 564#ifdef CONFIG_SYSFS
565void __kernel_param_lock(void)
566{
567 mutex_lock(&param_lock);
568}
569EXPORT_SYMBOL(__kernel_param_lock);
570
571void __kernel_param_unlock(void)
572{
573 mutex_unlock(&param_lock);
574}
575EXPORT_SYMBOL(__kernel_param_unlock);
576
558/* 577/*
559 * add_sysfs_param - add a parameter to sysfs 578 * add_sysfs_param - add a parameter to sysfs
560 * @mk: struct module_kobject 579 * @mk: struct module_kobject