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