Blame view
kernel/params.c
22.6 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/* Helpers for initial module or kernel cmdline parsing Copyright (C) 2001 Rusty Russell. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
1da177e4c Linux-2.6.12-rc2 |
18 19 20 21 |
#include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> #include <linux/module.h> |
63a12d9d0 kernel/param: con... |
22 |
#include <linux/moduleparam.h> |
1da177e4c Linux-2.6.12-rc2 |
23 24 |
#include <linux/device.h> #include <linux/err.h> |
4e57b6817 [PATCH] fix missi... |
25 |
#include <linux/slab.h> |
26d052bfc param: allow whit... |
26 |
#include <linux/ctype.h> |
1da177e4c Linux-2.6.12-rc2 |
27 |
|
907b29eb4 param: locking fo... |
28 29 |
/* Protects all parameters, and incidentally kmalloced_param list. */ static DEFINE_MUTEX(param_lock); |
a1054322a param: use free h... |
30 31 32 33 34 |
/* This just allows us to keep track of which parameters are kmalloced. */ struct kmalloced_param { struct list_head list; char val[]; }; |
a1054322a param: use free h... |
35 36 37 38 39 40 41 42 43 |
static LIST_HEAD(kmalloced_params); static void *kmalloc_parameter(unsigned int size) { struct kmalloced_param *p; p = kmalloc(sizeof(*p) + size, GFP_KERNEL); if (!p) return NULL; |
a1054322a param: use free h... |
44 |
list_add(&p->list, &kmalloced_params); |
a1054322a param: use free h... |
45 46 47 48 49 50 51 |
return p->val; } /* Does nothing if parameter wasn't kmalloced above. */ static void maybe_kfree_parameter(void *param) { struct kmalloced_param *p; |
a1054322a param: use free h... |
52 53 54 55 56 57 58 |
list_for_each_entry(p, &kmalloced_params, list) { if (p->val == param) { list_del(&p->list); kfree(p); break; } } |
a1054322a param: use free h... |
59 |
} |
b1e4d20cb params: make dash... |
60 |
static char dash2underscore(char c) |
1da177e4c Linux-2.6.12-rc2 |
61 62 63 64 65 |
{ if (c == '-') return '_'; return c; } |
b1e4d20cb params: make dash... |
66 |
bool parameqn(const char *a, const char *b, size_t n) |
1da177e4c Linux-2.6.12-rc2 |
67 |
{ |
b1e4d20cb params: make dash... |
68 69 70 71 72 73 74 75 76 77 78 79 |
size_t i; for (i = 0; i < n; i++) { if (dash2underscore(a[i]) != dash2underscore(b[i])) return false; } return true; } bool parameq(const char *a, const char *b) { return parameqn(a, b, strlen(a)+1); |
1da177e4c Linux-2.6.12-rc2 |
80 |
} |
7a486d378 param: check for ... |
81 82 83 84 85 86 87 88 89 |
static void param_check_unsafe(const struct kernel_param *kp) { if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { pr_warn("Setting dangerous option %s - tainting kernel ", kp->name); add_taint(TAINT_USER, LOCKDEP_STILL_OK); } } |
1da177e4c Linux-2.6.12-rc2 |
90 91 |
static int parse_one(char *param, char *val, |
9fb48c744 params: add 3rd a... |
92 |
const char *doing, |
914dcaa84 param: make param... |
93 |
const struct kernel_param *params, |
1da177e4c Linux-2.6.12-rc2 |
94 |
unsigned num_params, |
026cee008 params: <level>_i... |
95 96 |
s16 min_level, s16 max_level, |
9fb48c744 params: add 3rd a... |
97 98 |
int (*handle_unknown)(char *param, char *val, const char *doing)) |
1da177e4c Linux-2.6.12-rc2 |
99 100 |
{ unsigned int i; |
907b29eb4 param: locking fo... |
101 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
102 103 104 105 |
/* Find parameter */ for (i = 0; i < num_params; i++) { if (parameq(param, params[i].name)) { |
026cee008 params: <level>_i... |
106 107 108 |
if (params[i].level < min_level || params[i].level > max_level) return 0; |
25985edce Fix common misspe... |
109 |
/* No one handled NULL, so do it here. */ |
ab013c5f6 module: Add flag ... |
110 |
if (!val && |
6a4c26431 module: rename KE... |
111 |
!(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG)) |
2e9fb9953 params: don't han... |
112 |
return -EINVAL; |
9fb48c744 params: add 3rd a... |
113 114 115 |
pr_debug("handling %s with %p ", param, params[i].ops->set); |
907b29eb4 param: locking fo... |
116 |
mutex_lock(¶m_lock); |
7a486d378 param: check for ... |
117 |
param_check_unsafe(¶ms[i]); |
907b29eb4 param: locking fo... |
118 119 120 |
err = params[i].ops->set(val, ¶ms[i]); mutex_unlock(¶m_lock); return err; |
1da177e4c Linux-2.6.12-rc2 |
121 122 123 124 |
} } if (handle_unknown) { |
9fb48c744 params: add 3rd a... |
125 126 127 |
pr_debug("doing %s: %s='%s' ", doing, param, val); return handle_unknown(param, val, doing); |
1da177e4c Linux-2.6.12-rc2 |
128 |
} |
9fb48c744 params: add 3rd a... |
129 130 |
pr_debug("Unknown argument '%s' ", param); |
1da177e4c Linux-2.6.12-rc2 |
131 132 133 134 135 136 137 138 139 140 |
return -ENOENT; } /* You can use " around spaces, but can't escape ". */ /* Hyphens and underscores equivalent in parameter names. */ static char *next_arg(char *args, char **param, char **val) { unsigned int i, equals = 0; int in_quote = 0, quoted = 0; char *next; |
1da177e4c Linux-2.6.12-rc2 |
141 142 143 144 145 146 147 |
if (*args == '"') { args++; in_quote = 1; quoted = 1; } for (i = 0; args[i]; i++) { |
26d052bfc param: allow whit... |
148 |
if (isspace(args[i]) && !in_quote) |
1da177e4c Linux-2.6.12-rc2 |
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
break; if (equals == 0) { if (args[i] == '=') equals = i; } if (args[i] == '"') in_quote = !in_quote; } *param = args; if (!equals) *val = NULL; else { args[equals] = '\0'; *val = args + equals + 1; /* Don't include quotes in value. */ if (**val == '"') { (*val)++; if (args[i-1] == '"') args[i-1] = '\0'; } |
1da177e4c Linux-2.6.12-rc2 |
171 |
} |
b9cc4489c params: handle qu... |
172 173 |
if (quoted && args[i-1] == '"') args[i-1] = '\0'; |
1da177e4c Linux-2.6.12-rc2 |
174 175 176 177 178 179 |
if (args[i]) { args[i] = '\0'; next = args + i + 1; } else next = args + i; |
f36462f07 [PATCH] Ignore tr... |
180 181 |
/* Chew up trailing spaces. */ |
e7d2860b6 tree-wide: conver... |
182 |
return skip_spaces(next); |
1da177e4c Linux-2.6.12-rc2 |
183 184 185 |
} /* Args looks like "foo=bar,bar2 baz=fuz wiz". */ |
51e158c12 param: hand argum... |
186 187 188 189 190 191 192 |
char *parse_args(const char *doing, char *args, const struct kernel_param *params, unsigned num, s16 min_level, s16 max_level, int (*unknown)(char *param, char *val, const char *doing)) |
1da177e4c Linux-2.6.12-rc2 |
193 194 |
{ char *param, *val; |
f36462f07 [PATCH] Ignore tr... |
195 |
/* Chew leading spaces */ |
e7d2860b6 tree-wide: conver... |
196 |
args = skip_spaces(args); |
f36462f07 [PATCH] Ignore tr... |
197 |
|
1ef9eaf2b params.c: fix Sma... |
198 |
if (*args) |
9fb48c744 params: add 3rd a... |
199 200 |
pr_debug("doing %s, parsing ARGS: '%s' ", doing, args); |
1da177e4c Linux-2.6.12-rc2 |
201 202 |
while (*args) { int ret; |
a416aba63 [PATCH] kernelpar... |
203 |
int irq_was_disabled; |
1da177e4c Linux-2.6.12-rc2 |
204 205 |
args = next_arg(args, ¶m, &val); |
51e158c12 param: hand argum... |
206 207 208 |
/* Stop at -- */ if (!val && strcmp(param, "--") == 0) return args; |
a416aba63 [PATCH] kernelpar... |
209 |
irq_was_disabled = irqs_disabled(); |
9fb48c744 params: add 3rd a... |
210 |
ret = parse_one(param, val, doing, params, num, |
026cee008 params: <level>_i... |
211 |
min_level, max_level, unknown); |
b5f3abf95 params: replace p... |
212 213 214 215 |
if (irq_was_disabled && !irqs_disabled()) pr_warn("%s: option '%s' enabled irq's! ", doing, param); |
1da177e4c Linux-2.6.12-rc2 |
216 217 |
switch (ret) { case -ENOENT: |
b5f3abf95 params: replace p... |
218 219 |
pr_err("%s: Unknown parameter `%s' ", doing, param); |
51e158c12 param: hand argum... |
220 |
return ERR_PTR(ret); |
1da177e4c Linux-2.6.12-rc2 |
221 |
case -ENOSPC: |
b5f3abf95 params: replace p... |
222 223 |
pr_err("%s: `%s' too large for parameter `%s' ", |
9fb48c744 params: add 3rd a... |
224 |
doing, val ?: "", param); |
51e158c12 param: hand argum... |
225 |
return ERR_PTR(ret); |
1da177e4c Linux-2.6.12-rc2 |
226 227 228 |
case 0: break; default: |
b5f3abf95 params: replace p... |
229 230 |
pr_err("%s: `%s' invalid for parameter `%s' ", |
9fb48c744 params: add 3rd a... |
231 |
doing, val ?: "", param); |
51e158c12 param: hand argum... |
232 |
return ERR_PTR(ret); |
1da177e4c Linux-2.6.12-rc2 |
233 234 235 236 |
} } /* All parsed OK. */ |
51e158c12 param: hand argum... |
237 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
238 239 240 |
} /* Lazy bastard, eh? */ |
88a88b320 params: improve s... |
241 |
#define STANDARD_PARAM_DEF(name, type, format, strtolfn) \ |
9bbb9e5a3 param: use ops in... |
242 |
int param_set_##name(const char *val, const struct kernel_param *kp) \ |
1da177e4c Linux-2.6.12-rc2 |
243 |
{ \ |
88a88b320 params: improve s... |
244 |
return strtolfn(val, 0, (type *)kp->arg); \ |
1da177e4c Linux-2.6.12-rc2 |
245 |
} \ |
9bbb9e5a3 param: use ops in... |
246 |
int param_get_##name(char *buffer, const struct kernel_param *kp) \ |
1da177e4c Linux-2.6.12-rc2 |
247 |
{ \ |
f4940ab7c kernel/params.c: ... |
248 249 |
return scnprintf(buffer, PAGE_SIZE, format, \ *((type *)kp->arg)); \ |
a14fe249a param: move the E... |
250 |
} \ |
9bbb9e5a3 param: use ops in... |
251 252 253 254 |
struct kernel_param_ops param_ops_##name = { \ .set = param_set_##name, \ .get = param_get_##name, \ }; \ |
a14fe249a param: move the E... |
255 |
EXPORT_SYMBOL(param_set_##name); \ |
9bbb9e5a3 param: use ops in... |
256 257 |
EXPORT_SYMBOL(param_get_##name); \ EXPORT_SYMBOL(param_ops_##name) |
1da177e4c Linux-2.6.12-rc2 |
258 |
|
88a88b320 params: improve s... |
259 260 261 262 263 264 265 |
STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", kstrtou8); STANDARD_PARAM_DEF(short, short, "%hi", kstrtos16); STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", kstrtou16); STANDARD_PARAM_DEF(int, int, "%i", kstrtoint); STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint); STANDARD_PARAM_DEF(long, long, "%li", kstrtol); STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", kstrtoul); |
b4210b810 Add module param ... |
266 |
STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull); |
1da177e4c Linux-2.6.12-rc2 |
267 |
|
9bbb9e5a3 param: use ops in... |
268 |
int param_set_charp(const char *val, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
269 |
{ |
1da177e4c Linux-2.6.12-rc2 |
270 |
if (strlen(val) > 1024) { |
b5f3abf95 params: replace p... |
271 272 |
pr_err("%s: string parameter too long ", kp->name); |
1da177e4c Linux-2.6.12-rc2 |
273 274 |
return -ENOSPC; } |
a1054322a param: use free h... |
275 276 277 |
maybe_kfree_parameter(*(char **)kp->arg); /* This is a hack. We can't kmalloc in early boot, and we |
e180a6b77 param: fix charp ... |
278 279 |
* don't need to; this mangled commandline is preserved. */ if (slab_is_available()) { |
a1054322a param: use free h... |
280 |
*(char **)kp->arg = kmalloc_parameter(strlen(val)+1); |
d553ad864 param: fix NULL c... |
281 |
if (!*(char **)kp->arg) |
e180a6b77 param: fix charp ... |
282 |
return -ENOMEM; |
a1054322a param: use free h... |
283 |
strcpy(*(char **)kp->arg, val); |
e180a6b77 param: fix charp ... |
284 285 |
} else *(const char **)kp->arg = val; |
1da177e4c Linux-2.6.12-rc2 |
286 287 |
return 0; } |
a14fe249a param: move the E... |
288 |
EXPORT_SYMBOL(param_set_charp); |
1da177e4c Linux-2.6.12-rc2 |
289 |
|
9bbb9e5a3 param: use ops in... |
290 |
int param_get_charp(char *buffer, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
291 |
{ |
f4940ab7c kernel/params.c: ... |
292 |
return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg)); |
1da177e4c Linux-2.6.12-rc2 |
293 |
} |
a14fe249a param: move the E... |
294 |
EXPORT_SYMBOL(param_get_charp); |
1da177e4c Linux-2.6.12-rc2 |
295 |
|
a1054322a param: use free h... |
296 297 298 299 |
static void param_free_charp(void *arg) { maybe_kfree_parameter(*((char **)arg)); } |
9bbb9e5a3 param: use ops in... |
300 301 302 |
struct kernel_param_ops param_ops_charp = { .set = param_set_charp, .get = param_get_charp, |
a1054322a param: use free h... |
303 |
.free = param_free_charp, |
9bbb9e5a3 param: use ops in... |
304 305 |
}; EXPORT_SYMBOL(param_ops_charp); |
fddd52012 module_param: all... |
306 |
/* Actually could be a bool or an int, for historical reasons. */ |
9bbb9e5a3 param: use ops in... |
307 |
int param_set_bool(const char *val, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
308 309 310 311 312 |
{ /* No equals means "set"... */ if (!val) val = "1"; /* One of =[yYnN01] */ |
8b8252813 module_param: rem... |
313 |
return strtobool(val, kp->arg); |
1da177e4c Linux-2.6.12-rc2 |
314 |
} |
a14fe249a param: move the E... |
315 |
EXPORT_SYMBOL(param_set_bool); |
1da177e4c Linux-2.6.12-rc2 |
316 |
|
9bbb9e5a3 param: use ops in... |
317 |
int param_get_bool(char *buffer, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
318 319 |
{ /* Y and N chosen as being relatively non-coder friendly */ |
8b8252813 module_param: rem... |
320 |
return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N'); |
1da177e4c Linux-2.6.12-rc2 |
321 |
} |
a14fe249a param: move the E... |
322 |
EXPORT_SYMBOL(param_get_bool); |
1da177e4c Linux-2.6.12-rc2 |
323 |
|
9bbb9e5a3 param: use ops in... |
324 |
struct kernel_param_ops param_ops_bool = { |
6a4c26431 module: rename KE... |
325 |
.flags = KERNEL_PARAM_OPS_FL_NOARG, |
9bbb9e5a3 param: use ops in... |
326 327 328 329 |
.set = param_set_bool, .get = param_get_bool, }; EXPORT_SYMBOL(param_ops_bool); |
fddd52012 module_param: all... |
330 |
/* This one must be bool. */ |
9bbb9e5a3 param: use ops in... |
331 |
int param_set_invbool(const char *val, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
332 |
{ |
fddd52012 module_param: all... |
333 334 |
int ret; bool boolval; |
22e48eaf5 constify string/a... |
335 |
struct kernel_param dummy; |
1da177e4c Linux-2.6.12-rc2 |
336 |
|
22e48eaf5 constify string/a... |
337 |
dummy.arg = &boolval; |
1da177e4c Linux-2.6.12-rc2 |
338 339 |
ret = param_set_bool(val, &dummy); if (ret == 0) |
9a71af2c3 module_param: inv... |
340 |
*(bool *)kp->arg = !boolval; |
1da177e4c Linux-2.6.12-rc2 |
341 342 |
return ret; } |
a14fe249a param: move the E... |
343 |
EXPORT_SYMBOL(param_set_invbool); |
1da177e4c Linux-2.6.12-rc2 |
344 |
|
9bbb9e5a3 param: use ops in... |
345 |
int param_get_invbool(char *buffer, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
346 |
{ |
9a71af2c3 module_param: inv... |
347 |
return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y'); |
1da177e4c Linux-2.6.12-rc2 |
348 |
} |
a14fe249a param: move the E... |
349 |
EXPORT_SYMBOL(param_get_invbool); |
1da177e4c Linux-2.6.12-rc2 |
350 |
|
9bbb9e5a3 param: use ops in... |
351 352 353 354 355 |
struct kernel_param_ops param_ops_invbool = { .set = param_set_invbool, .get = param_get_invbool, }; EXPORT_SYMBOL(param_ops_invbool); |
69116f279 module_param: avo... |
356 357 358 359 360 361 362 363 364 |
int param_set_bint(const char *val, const struct kernel_param *kp) { struct kernel_param boolkp; bool v; int ret; /* Match bool exactly, by re-using it. */ boolkp = *kp; boolkp.arg = &v; |
69116f279 module_param: avo... |
365 366 367 368 369 370 371 372 373 |
ret = param_set_bool(val, &boolkp); if (ret == 0) *(int *)kp->arg = v; return ret; } EXPORT_SYMBOL(param_set_bint); struct kernel_param_ops param_ops_bint = { |
6a4c26431 module: rename KE... |
374 |
.flags = KERNEL_PARAM_OPS_FL_NOARG, |
69116f279 module_param: avo... |
375 376 377 378 |
.set = param_set_bint, .get = param_get_int, }; EXPORT_SYMBOL(param_ops_bint); |
9730b5b06 kernel/params.c: ... |
379 |
/* We break the rule and mangle the string. */ |
9871728b7 [PATCH] kernel/pa... |
380 381 382 383 |
static int param_array(const char *name, const char *val, unsigned int min, unsigned int max, void *elem, int elemsize, |
9bbb9e5a3 param: use ops in... |
384 |
int (*set)(const char *, const struct kernel_param *kp), |
026cee008 params: <level>_i... |
385 |
s16 level, |
eb38a996e kernel/params.c: ... |
386 |
unsigned int *num) |
1da177e4c Linux-2.6.12-rc2 |
387 388 389 390 391 392 393 394 |
{ int ret; struct kernel_param kp; char save; /* Get the name right for errors. */ kp.name = name; kp.arg = elem; |
026cee008 params: <level>_i... |
395 |
kp.level = level; |
1da177e4c Linux-2.6.12-rc2 |
396 |
|
1da177e4c Linux-2.6.12-rc2 |
397 398 399 400 401 402 |
*num = 0; /* We expect a comma-separated list of values. */ do { int len; if (*num == max) { |
b5f3abf95 params: replace p... |
403 404 |
pr_err("%s: can only take %i arguments ", name, max); |
1da177e4c Linux-2.6.12-rc2 |
405 406 407 408 409 410 411 |
return -EINVAL; } len = strcspn(val, ","); /* nul-terminate and parse */ save = val[len]; ((char *)val)[len] = '\0'; |
907b29eb4 param: locking fo... |
412 |
BUG_ON(!mutex_is_locked(¶m_lock)); |
1da177e4c Linux-2.6.12-rc2 |
413 414 415 416 417 418 419 420 421 422 |
ret = set(val, &kp); if (ret != 0) return ret; kp.arg += elemsize; val += len+1; (*num)++; } while (save == ','); if (*num < min) { |
b5f3abf95 params: replace p... |
423 424 |
pr_err("%s: needs at least %i arguments ", name, min); |
1da177e4c Linux-2.6.12-rc2 |
425 426 427 428 |
return -EINVAL; } return 0; } |
9bbb9e5a3 param: use ops in... |
429 |
static int param_array_set(const char *val, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
430 |
{ |
22e48eaf5 constify string/a... |
431 |
const struct kparam_array *arr = kp->arr; |
31143a120 [PATCH] kernel/pa... |
432 |
unsigned int temp_num; |
1da177e4c Linux-2.6.12-rc2 |
433 434 |
return param_array(kp->name, val, 1, arr->max, arr->elem, |
026cee008 params: <level>_i... |
435 |
arr->elemsize, arr->ops->set, kp->level, |
3c7d76e37 param: fix settin... |
436 |
arr->num ?: &temp_num); |
1da177e4c Linux-2.6.12-rc2 |
437 |
} |
9bbb9e5a3 param: use ops in... |
438 |
static int param_array_get(char *buffer, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
439 440 |
{ int i, off, ret; |
22e48eaf5 constify string/a... |
441 |
const struct kparam_array *arr = kp->arr; |
1da177e4c Linux-2.6.12-rc2 |
442 443 444 445 446 447 448 |
struct kernel_param p; p = *kp; for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) { if (i) buffer[off++] = ','; p.arg = arr->elem + arr->elemsize * i; |
907b29eb4 param: locking fo... |
449 |
BUG_ON(!mutex_is_locked(¶m_lock)); |
9bbb9e5a3 param: use ops in... |
450 |
ret = arr->ops->get(buffer + off, &p); |
1da177e4c Linux-2.6.12-rc2 |
451 452 453 454 455 456 457 |
if (ret < 0) return ret; off += ret; } buffer[off] = '\0'; return off; } |
e6df34a44 param: add a free... |
458 459 460 461 462 463 464 465 466 |
static void param_array_free(void *arg) { unsigned int i; const struct kparam_array *arr = arg; if (arr->ops->free) for (i = 0; i < (arr->num ? *arr->num : arr->max); i++) arr->ops->free(arr->elem + arr->elemsize * i); } |
9bbb9e5a3 param: use ops in... |
467 468 469 |
struct kernel_param_ops param_array_ops = { .set = param_array_set, .get = param_array_get, |
e6df34a44 param: add a free... |
470 |
.free = param_array_free, |
9bbb9e5a3 param: use ops in... |
471 472 473 474 |
}; EXPORT_SYMBOL(param_array_ops); int param_set_copystring(const char *val, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
475 |
{ |
22e48eaf5 constify string/a... |
476 |
const struct kparam_string *kps = kp->str; |
1da177e4c Linux-2.6.12-rc2 |
477 478 |
if (strlen(val)+1 > kps->maxlen) { |
b5f3abf95 params: replace p... |
479 480 |
pr_err("%s: string doesn't fit in %u chars. ", |
1da177e4c Linux-2.6.12-rc2 |
481 482 483 484 485 486 |
kp->name, kps->maxlen-1); return -ENOSPC; } strcpy(kps->string, val); return 0; } |
a14fe249a param: move the E... |
487 |
EXPORT_SYMBOL(param_set_copystring); |
1da177e4c Linux-2.6.12-rc2 |
488 |
|
9bbb9e5a3 param: use ops in... |
489 |
int param_get_string(char *buffer, const struct kernel_param *kp) |
1da177e4c Linux-2.6.12-rc2 |
490 |
{ |
22e48eaf5 constify string/a... |
491 |
const struct kparam_string *kps = kp->str; |
1da177e4c Linux-2.6.12-rc2 |
492 493 |
return strlcpy(buffer, kps->string, kps->maxlen); } |
a14fe249a param: move the E... |
494 |
EXPORT_SYMBOL(param_get_string); |
1da177e4c Linux-2.6.12-rc2 |
495 |
|
9bbb9e5a3 param: use ops in... |
496 497 498 499 500 |
struct kernel_param_ops param_ops_string = { .set = param_set_copystring, .get = param_get_string, }; EXPORT_SYMBOL(param_ops_string); |
1da177e4c Linux-2.6.12-rc2 |
501 |
/* sysfs output in /sys/modules/XYZ/parameters/ */ |
350f82586 Remove redundant ... |
502 503 |
#define to_module_attr(n) container_of(n, struct module_attribute, attr) #define to_module_kobject(n) container_of(n, struct module_kobject, kobj) |
1da177e4c Linux-2.6.12-rc2 |
504 |
|
1da177e4c Linux-2.6.12-rc2 |
505 506 507 |
struct param_attribute { struct module_attribute mattr; |
9bbb9e5a3 param: use ops in... |
508 |
const struct kernel_param *param; |
1da177e4c Linux-2.6.12-rc2 |
509 510 511 512 |
}; struct module_param_attrs { |
9b473de87 param: Fix duplic... |
513 |
unsigned int num; |
1da177e4c Linux-2.6.12-rc2 |
514 515 516 |
struct attribute_group grp; struct param_attribute attrs[0]; }; |
ef665c1a0 sysfs: fix build ... |
517 |
#ifdef CONFIG_SYSFS |
350f82586 Remove redundant ... |
518 |
#define to_param_attr(n) container_of(n, struct param_attribute, mattr) |
1da177e4c Linux-2.6.12-rc2 |
519 520 |
static ssize_t param_attr_show(struct module_attribute *mattr, |
4befb026c module: change at... |
521 |
struct module_kobject *mk, char *buf) |
1da177e4c Linux-2.6.12-rc2 |
522 523 524 |
{ int count; struct param_attribute *attribute = to_param_attr(mattr); |
9bbb9e5a3 param: use ops in... |
525 |
if (!attribute->param->ops->get) |
1da177e4c Linux-2.6.12-rc2 |
526 |
return -EPERM; |
907b29eb4 param: locking fo... |
527 |
mutex_lock(¶m_lock); |
9bbb9e5a3 param: use ops in... |
528 |
count = attribute->param->ops->get(buf, attribute->param); |
907b29eb4 param: locking fo... |
529 |
mutex_unlock(¶m_lock); |
1da177e4c Linux-2.6.12-rc2 |
530 531 532 533 534 535 536 537 538 539 |
if (count > 0) { strcat(buf, " "); ++count; } return count; } /* sysfs always hands a nul-terminated string in buf. We rely on that. */ static ssize_t param_attr_store(struct module_attribute *mattr, |
4befb026c module: change at... |
540 |
struct module_kobject *km, |
1da177e4c Linux-2.6.12-rc2 |
541 542 543 544 |
const char *buf, size_t len) { int err; struct param_attribute *attribute = to_param_attr(mattr); |
9bbb9e5a3 param: use ops in... |
545 |
if (!attribute->param->ops->set) |
1da177e4c Linux-2.6.12-rc2 |
546 |
return -EPERM; |
907b29eb4 param: locking fo... |
547 |
mutex_lock(¶m_lock); |
7a486d378 param: check for ... |
548 |
param_check_unsafe(attribute->param); |
9bbb9e5a3 param: use ops in... |
549 |
err = attribute->param->ops->set(buf, attribute->param); |
907b29eb4 param: locking fo... |
550 |
mutex_unlock(¶m_lock); |
1da177e4c Linux-2.6.12-rc2 |
551 552 553 554 |
if (!err) return len; return err; } |
ef665c1a0 sysfs: fix build ... |
555 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
556 557 558 559 560 561 |
#ifdef CONFIG_MODULES #define __modinit #else #define __modinit __init #endif |
ef665c1a0 sysfs: fix build ... |
562 |
#ifdef CONFIG_SYSFS |
907b29eb4 param: locking fo... |
563 564 565 566 567 568 569 570 571 572 573 |
void __kernel_param_lock(void) { mutex_lock(¶m_lock); } EXPORT_SYMBOL(__kernel_param_lock); void __kernel_param_unlock(void) { mutex_unlock(¶m_lock); } EXPORT_SYMBOL(__kernel_param_unlock); |
1da177e4c Linux-2.6.12-rc2 |
574 |
/* |
9b473de87 param: Fix duplic... |
575 576 577 578 |
* add_sysfs_param - add a parameter to sysfs * @mk: struct module_kobject * @kparam: the actual parameter definition to add to sysfs * @name: name of parameter |
1da177e4c Linux-2.6.12-rc2 |
579 |
* |
9b473de87 param: Fix duplic... |
580 581 582 |
* Create a kobject if for a (per-module) parameter if mp NULL, and * create file in sysfs. Returns an error on out of memory. Always cleans up * if there's an error. |
1da177e4c Linux-2.6.12-rc2 |
583 |
*/ |
9b473de87 param: Fix duplic... |
584 |
static __modinit int add_sysfs_param(struct module_kobject *mk, |
9bbb9e5a3 param: use ops in... |
585 |
const struct kernel_param *kp, |
9b473de87 param: Fix duplic... |
586 |
const char *name) |
1da177e4c Linux-2.6.12-rc2 |
587 |
{ |
18eb74fa9 params: cleanup s... |
588 589 590 |
struct module_param_attrs *new_mp; struct attribute **new_attrs; unsigned int i; |
9b473de87 param: Fix duplic... |
591 592 593 594 595 |
/* We don't bother calling this with invisible parameters. */ BUG_ON(!kp->perm); if (!mk->mp) { |
18eb74fa9 params: cleanup s... |
596 597 598 599 600 601 602 603 604 605 606 |
/* First allocation. */ mk->mp = kzalloc(sizeof(*mk->mp), GFP_KERNEL); if (!mk->mp) return -ENOMEM; mk->mp->grp.name = "parameters"; /* NULL-terminated attribute array. */ mk->mp->grp.attrs = kzalloc(sizeof(mk->mp->grp.attrs[0]), GFP_KERNEL); /* Caller will cleanup via free_module_param_attrs */ if (!mk->mp->grp.attrs) return -ENOMEM; |
9b473de87 param: Fix duplic... |
607 |
} |
1da177e4c Linux-2.6.12-rc2 |
608 |
|
18eb74fa9 params: cleanup s... |
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 |
/* Enlarge allocations. */ new_mp = krealloc(mk->mp, sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (mk->mp->num + 1), GFP_KERNEL); if (!new_mp) return -ENOMEM; mk->mp = new_mp; /* Extra pointer for NULL terminator */ new_attrs = krealloc(mk->mp->grp.attrs, sizeof(mk->mp->grp.attrs[0]) * (mk->mp->num + 2), GFP_KERNEL); if (!new_attrs) return -ENOMEM; mk->mp->grp.attrs = new_attrs; |
9b473de87 param: Fix duplic... |
625 626 |
/* Tack new one on the end. */ |
c772be523 param: fix uninit... |
627 |
memset(&mk->mp->attrs[mk->mp->num], 0, sizeof(mk->mp->attrs[0])); |
18eb74fa9 params: cleanup s... |
628 629 630 |
sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr); mk->mp->attrs[mk->mp->num].param = kp; mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show; |
b0a65b0cc param: do not set... |
631 632 633 |
/* Do not allow runtime DAC changes to make param writable. */ if ((kp->perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store; |
574732c73 param: initialize... |
634 635 |
else mk->mp->attrs[mk->mp->num].mattr.store = NULL; |
18eb74fa9 params: cleanup s... |
636 637 638 |
mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name; mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm; mk->mp->num++; |
9b473de87 param: Fix duplic... |
639 640 |
/* Fix up all the pointers, since krealloc can move us */ |
18eb74fa9 params: cleanup s... |
641 642 643 |
for (i = 0; i < mk->mp->num; i++) mk->mp->grp.attrs[i] = &mk->mp->attrs[i].mattr.attr; mk->mp->grp.attrs[mk->mp->num] = NULL; |
9b473de87 param: Fix duplic... |
644 |
return 0; |
9b473de87 param: Fix duplic... |
645 |
} |
1da177e4c Linux-2.6.12-rc2 |
646 |
|
d2441183d Fix compile warni... |
647 |
#ifdef CONFIG_MODULES |
9b473de87 param: Fix duplic... |
648 649 |
static void free_module_param_attrs(struct module_kobject *mk) { |
18eb74fa9 params: cleanup s... |
650 651 |
if (mk->mp) kfree(mk->mp->grp.attrs); |
9b473de87 param: Fix duplic... |
652 653 |
kfree(mk->mp); mk->mp = NULL; |
1da177e4c Linux-2.6.12-rc2 |
654 |
} |
1da177e4c Linux-2.6.12-rc2 |
655 656 657 658 659 660 |
/* * module_param_sysfs_setup - setup sysfs support for one module * @mod: module * @kparam: module parameters (array) * @num_params: number of module parameters * |
9b473de87 param: Fix duplic... |
661 662 |
* Adds sysfs entries for module parameters under * /sys/module/[mod->name]/parameters/ |
1da177e4c Linux-2.6.12-rc2 |
663 664 |
*/ int module_param_sysfs_setup(struct module *mod, |
9bbb9e5a3 param: use ops in... |
665 |
const struct kernel_param *kparam, |
1da177e4c Linux-2.6.12-rc2 |
666 667 |
unsigned int num_params) { |
9b473de87 param: Fix duplic... |
668 669 670 671 672 673 674 |
int i, err; bool params = false; for (i = 0; i < num_params; i++) { if (kparam[i].perm == 0) continue; err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); |
18eb74fa9 params: cleanup s... |
675 676 |
if (err) { free_module_param_attrs(&mod->mkobj); |
9b473de87 param: Fix duplic... |
677 |
return err; |
18eb74fa9 params: cleanup s... |
678 |
} |
9b473de87 param: Fix duplic... |
679 680 |
params = true; } |
1da177e4c Linux-2.6.12-rc2 |
681 |
|
9b473de87 param: Fix duplic... |
682 683 |
if (!params) return 0; |
1da177e4c Linux-2.6.12-rc2 |
684 |
|
9b473de87 param: Fix duplic... |
685 686 687 688 689 |
/* Create the param group. */ err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); if (err) free_module_param_attrs(&mod->mkobj); return err; |
1da177e4c Linux-2.6.12-rc2 |
690 691 692 693 694 695 696 697 698 699 700 |
} /* * module_param_sysfs_remove - remove sysfs support for one module * @mod: module * * Remove sysfs entries for module parameters and the corresponding * kobject. */ void module_param_sysfs_remove(struct module *mod) { |
9b473de87 param: Fix duplic... |
701 702 |
if (mod->mkobj.mp) { sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); |
1da177e4c Linux-2.6.12-rc2 |
703 704 |
/* We are positive that no one is using any param * attrs at this point. Deallocate immediately. */ |
9b473de87 param: Fix duplic... |
705 |
free_module_param_attrs(&mod->mkobj); |
1da177e4c Linux-2.6.12-rc2 |
706 707 708 |
} } #endif |
e180a6b77 param: fix charp ... |
709 710 |
void destroy_params(const struct kernel_param *params, unsigned num) { |
e6df34a44 param: add a free... |
711 712 713 714 715 |
unsigned int i; for (i = 0; i < num; i++) if (params[i].ops->free) params[i].ops->free(params[i].arg); |
e180a6b77 param: fix charp ... |
716 |
} |
e94965ed5 module: show vers... |
717 |
static struct module_kobject * __init locate_module_kobject(const char *name) |
1da177e4c Linux-2.6.12-rc2 |
718 719 |
{ struct module_kobject *mk; |
9b473de87 param: Fix duplic... |
720 721 |
struct kobject *kobj; int err; |
1da177e4c Linux-2.6.12-rc2 |
722 |
|
9b473de87 param: Fix duplic... |
723 724 |
kobj = kset_find_obj(module_kset, name); if (kobj) { |
9b473de87 param: Fix duplic... |
725 |
mk = to_module_kobject(kobj); |
9b473de87 param: Fix duplic... |
726 727 728 729 730 731 732 733 |
} else { mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); BUG_ON(!mk); mk->mod = THIS_MODULE; mk->kobj.kset = module_kset; err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name); |
88bfa3247 module: add /sys/... |
734 735 736 737 |
#ifdef CONFIG_MODULES if (!err) err = sysfs_create_file(&mk->kobj, &module_uevent.attr); #endif |
9b473de87 param: Fix duplic... |
738 739 |
if (err) { kobject_put(&mk->kobj); |
b5f3abf95 params: replace p... |
740 741 |
pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable. ", |
e94965ed5 module: show vers... |
742 |
name, err); |
e94965ed5 module: show vers... |
743 |
return NULL; |
9b473de87 param: Fix duplic... |
744 |
} |
e94965ed5 module: show vers... |
745 746 |
/* So that we hold reference in both cases. */ |
9b473de87 param: Fix duplic... |
747 |
kobject_get(&mk->kobj); |
74c5b597e modules: better e... |
748 |
} |
9b473de87 param: Fix duplic... |
749 |
|
e94965ed5 module: show vers... |
750 751 752 753 |
return mk; } static void __init kernel_add_sysfs_param(const char *name, |
63a12d9d0 kernel/param: con... |
754 |
const struct kernel_param *kparam, |
e94965ed5 module: show vers... |
755 756 757 758 759 760 761 762 763 764 765 766 |
unsigned int name_skip) { struct module_kobject *mk; int err; mk = locate_module_kobject(name); if (!mk) return; /* We need to remove old parameters before adding more. */ if (mk->mp) sysfs_remove_group(&mk->kobj, &mk->mp->grp); |
9b473de87 param: Fix duplic... |
767 768 769 770 771 |
/* These should not fail at boot. */ err = add_sysfs_param(mk, kparam, kparam->name + name_skip); BUG_ON(err); err = sysfs_create_group(&mk->kobj, &mk->mp->grp); BUG_ON(err); |
f30c53a87 MODULES: add the ... |
772 |
kobject_uevent(&mk->kobj, KOBJ_ADD); |
9b473de87 param: Fix duplic... |
773 |
kobject_put(&mk->kobj); |
1da177e4c Linux-2.6.12-rc2 |
774 775 776 |
} /* |
b634d130e There is no /sys/... |
777 |
* param_sysfs_builtin - add sysfs parameters for built-in modules |
1da177e4c Linux-2.6.12-rc2 |
778 779 780 781 782 783 |
* * Add module_parameters to sysfs for "modules" built into the kernel. * * The "module" name (KBUILD_MODNAME) is stored before a dot, the * "parameter" name is stored behind a dot in kernel_param->name. So, * extract the "module" name for all built-in kernel_param-eters, |
9b473de87 param: Fix duplic... |
784 |
* and for all who have the same, call kernel_add_sysfs_param. |
1da177e4c Linux-2.6.12-rc2 |
785 786 787 |
*/ static void __init param_sysfs_builtin(void) { |
63a12d9d0 kernel/param: con... |
788 |
const struct kernel_param *kp; |
9b473de87 param: Fix duplic... |
789 790 |
unsigned int name_len; char modname[MODULE_NAME_LEN]; |
1da177e4c Linux-2.6.12-rc2 |
791 |
|
9b473de87 param: Fix duplic... |
792 |
for (kp = __start___param; kp < __stop___param; kp++) { |
1da177e4c Linux-2.6.12-rc2 |
793 |
char *dot; |
9b473de87 param: Fix duplic... |
794 795 |
if (kp->perm == 0) continue; |
1da177e4c Linux-2.6.12-rc2 |
796 |
|
730b69d22 module: check ker... |
797 |
dot = strchr(kp->name, '.'); |
1da177e4c Linux-2.6.12-rc2 |
798 |
if (!dot) { |
67e67ceaa core_param() for ... |
799 800 801 802 803 804 |
/* This happens for core_param() */ strcpy(modname, "kernel"); name_len = 0; } else { name_len = dot - kp->name + 1; strlcpy(modname, kp->name, name_len); |
1da177e4c Linux-2.6.12-rc2 |
805 |
} |
67e67ceaa core_param() for ... |
806 |
kernel_add_sysfs_param(modname, kp, name_len); |
1da177e4c Linux-2.6.12-rc2 |
807 |
} |
1da177e4c Linux-2.6.12-rc2 |
808 |
} |
e94965ed5 module: show vers... |
809 |
ssize_t __modver_version_show(struct module_attribute *mattr, |
4befb026c module: change at... |
810 |
struct module_kobject *mk, char *buf) |
e94965ed5 module: show vers... |
811 812 813 |
{ struct module_version_attribute *vattr = container_of(mattr, struct module_version_attribute, mattr); |
f4940ab7c kernel/params.c: ... |
814 815 |
return scnprintf(buf, PAGE_SIZE, "%s ", vattr->version); |
e94965ed5 module: show vers... |
816 |
} |
b4bc84280 module: deal with... |
817 818 |
extern const struct module_version_attribute *__start___modver[]; extern const struct module_version_attribute *__stop___modver[]; |
e94965ed5 module: show vers... |
819 820 821 |
static void __init version_sysfs_builtin(void) { |
b4bc84280 module: deal with... |
822 |
const struct module_version_attribute **p; |
e94965ed5 module: show vers... |
823 824 |
struct module_kobject *mk; int err; |
b4bc84280 module: deal with... |
825 826 |
for (p = __start___modver; p < __stop___modver; p++) { const struct module_version_attribute *vattr = *p; |
e94965ed5 module: show vers... |
827 828 829 830 831 832 833 834 |
mk = locate_module_kobject(vattr->module_name); if (mk) { err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); kobject_uevent(&mk->kobj, KOBJ_ADD); kobject_put(&mk->kobj); } } } |
1da177e4c Linux-2.6.12-rc2 |
835 836 |
/* module-related sysfs stuff */ |
1da177e4c Linux-2.6.12-rc2 |
837 |
|
1da177e4c Linux-2.6.12-rc2 |
838 839 840 841 842 843 844 845 846 847 848 849 |
static ssize_t module_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) { struct module_attribute *attribute; struct module_kobject *mk; int ret; attribute = to_module_attr(attr); mk = to_module_kobject(kobj); if (!attribute->show) |
70f2817a4 [PATCH] sysfs: (r... |
850 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
851 |
|
4befb026c module: change at... |
852 |
ret = attribute->show(attribute, mk, buf); |
1da177e4c Linux-2.6.12-rc2 |
853 |
|
1da177e4c Linux-2.6.12-rc2 |
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 |
return ret; } static ssize_t module_attr_store(struct kobject *kobj, struct attribute *attr, const char *buf, size_t len) { struct module_attribute *attribute; struct module_kobject *mk; int ret; attribute = to_module_attr(attr); mk = to_module_kobject(kobj); if (!attribute->store) |
70f2817a4 [PATCH] sysfs: (r... |
869 |
return -EIO; |
1da177e4c Linux-2.6.12-rc2 |
870 |
|
4befb026c module: change at... |
871 |
ret = attribute->store(attribute, mk, buf, len); |
1da177e4c Linux-2.6.12-rc2 |
872 |
|
1da177e4c Linux-2.6.12-rc2 |
873 874 |
return ret; } |
52cf25d0a Driver core: Cons... |
875 |
static const struct sysfs_ops module_sysfs_ops = { |
1da177e4c Linux-2.6.12-rc2 |
876 877 878 |
.show = module_attr_show, .store = module_attr_store, }; |
270a6c4ca /sys/modules/*/ho... |
879 880 881 882 883 884 885 886 |
static int uevent_filter(struct kset *kset, struct kobject *kobj) { struct kobj_type *ktype = get_ktype(kobj); if (ktype == &module_ktype) return 1; return 0; } |
9cd43611c kobject: Constify... |
887 |
static const struct kset_uevent_ops module_uevent_ops = { |
270a6c4ca /sys/modules/*/ho... |
888 889 |
.filter = uevent_filter, }; |
7405c1e15 kset: convert /sy... |
890 |
struct kset *module_kset; |
823bccfc4 remove "struct su... |
891 |
int module_sysfs_initialized; |
1da177e4c Linux-2.6.12-rc2 |
892 |
|
942e44312 module: Fix mod->... |
893 894 895 896 897 |
static void module_kobj_release(struct kobject *kobj) { struct module_kobject *mk = to_module_kobject(kobj); complete(mk->kobj_completion); } |
7405c1e15 kset: convert /sy... |
898 |
struct kobj_type module_ktype = { |
942e44312 module: Fix mod->... |
899 |
.release = module_kobj_release, |
1da177e4c Linux-2.6.12-rc2 |
900 901 |
.sysfs_ops = &module_sysfs_ops, }; |
1da177e4c Linux-2.6.12-rc2 |
902 903 904 905 906 |
/* * param_sysfs_init - wrapper for built-in params support */ static int __init param_sysfs_init(void) { |
7405c1e15 kset: convert /sy... |
907 908 909 910 911 912 |
module_kset = kset_create_and_add("module", &module_uevent_ops, NULL); if (!module_kset) { printk(KERN_WARNING "%s (%d): error creating kset ", __FILE__, __LINE__); return -ENOMEM; |
d8c7649e9 [PATCH] kernel/pa... |
913 |
} |
823bccfc4 remove "struct su... |
914 |
module_sysfs_initialized = 1; |
1da177e4c Linux-2.6.12-rc2 |
915 |
|
e94965ed5 module: show vers... |
916 |
version_sysfs_builtin(); |
1da177e4c Linux-2.6.12-rc2 |
917 918 919 920 |
param_sysfs_builtin(); return 0; } |
d10be6d1b [PATCH] module_su... |
921 |
subsys_initcall(param_sysfs_init); |
1da177e4c Linux-2.6.12-rc2 |
922 |
|
7405c1e15 kset: convert /sy... |
923 |
#endif /* CONFIG_SYSFS */ |