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