diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/params.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/kernel/params.c b/kernel/params.c index 458a09b886c4..ef60db14fae0 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
@@ -31,6 +31,45 @@ | |||
31 | #define DEBUGP(fmt, a...) | 31 | #define DEBUGP(fmt, a...) |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | /* This just allows us to keep track of which parameters are kmalloced. */ | ||
35 | struct kmalloced_param { | ||
36 | struct list_head list; | ||
37 | char val[]; | ||
38 | }; | ||
39 | static DEFINE_MUTEX(param_lock); | ||
40 | static LIST_HEAD(kmalloced_params); | ||
41 | |||
42 | static void *kmalloc_parameter(unsigned int size) | ||
43 | { | ||
44 | struct kmalloced_param *p; | ||
45 | |||
46 | p = kmalloc(sizeof(*p) + size, GFP_KERNEL); | ||
47 | if (!p) | ||
48 | return NULL; | ||
49 | |||
50 | mutex_lock(¶m_lock); | ||
51 | list_add(&p->list, &kmalloced_params); | ||
52 | mutex_unlock(¶m_lock); | ||
53 | |||
54 | return p->val; | ||
55 | } | ||
56 | |||
57 | /* Does nothing if parameter wasn't kmalloced above. */ | ||
58 | static void maybe_kfree_parameter(void *param) | ||
59 | { | ||
60 | struct kmalloced_param *p; | ||
61 | |||
62 | mutex_lock(¶m_lock); | ||
63 | list_for_each_entry(p, &kmalloced_params, list) { | ||
64 | if (p->val == param) { | ||
65 | list_del(&p->list); | ||
66 | kfree(p); | ||
67 | break; | ||
68 | } | ||
69 | } | ||
70 | mutex_unlock(¶m_lock); | ||
71 | } | ||
72 | |||
34 | static inline char dash2underscore(char c) | 73 | static inline char dash2underscore(char c) |
35 | { | 74 | { |
36 | if (c == '-') | 75 | if (c == '-') |
@@ -219,12 +258,15 @@ int param_set_charp(const char *val, const struct kernel_param *kp) | |||
219 | return -ENOSPC; | 258 | return -ENOSPC; |
220 | } | 259 | } |
221 | 260 | ||
222 | /* This is a hack. We can't need to strdup in early boot, and we | 261 | maybe_kfree_parameter(*(char **)kp->arg); |
262 | |||
263 | /* This is a hack. We can't kmalloc in early boot, and we | ||
223 | * don't need to; this mangled commandline is preserved. */ | 264 | * don't need to; this mangled commandline is preserved. */ |
224 | if (slab_is_available()) { | 265 | if (slab_is_available()) { |
225 | *(char **)kp->arg = kstrdup(val, GFP_KERNEL); | 266 | *(char **)kp->arg = kmalloc_parameter(strlen(val)+1); |
226 | if (!*(char **)kp->arg) | 267 | if (!*(char **)kp->arg) |
227 | return -ENOMEM; | 268 | return -ENOMEM; |
269 | strcpy(*(char **)kp->arg, val); | ||
228 | } else | 270 | } else |
229 | *(const char **)kp->arg = val; | 271 | *(const char **)kp->arg = val; |
230 | 272 | ||
@@ -238,9 +280,15 @@ int param_get_charp(char *buffer, const struct kernel_param *kp) | |||
238 | } | 280 | } |
239 | EXPORT_SYMBOL(param_get_charp); | 281 | EXPORT_SYMBOL(param_get_charp); |
240 | 282 | ||
283 | static void param_free_charp(void *arg) | ||
284 | { | ||
285 | maybe_kfree_parameter(*((char **)arg)); | ||
286 | } | ||
287 | |||
241 | struct kernel_param_ops param_ops_charp = { | 288 | struct kernel_param_ops param_ops_charp = { |
242 | .set = param_set_charp, | 289 | .set = param_set_charp, |
243 | .get = param_get_charp, | 290 | .get = param_get_charp, |
291 | .free = param_free_charp, | ||
244 | }; | 292 | }; |
245 | EXPORT_SYMBOL(param_ops_charp); | 293 | EXPORT_SYMBOL(param_ops_charp); |
246 | 294 | ||