Blame view

kernel/params.c 18.3 KB
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
  #include <linux/moduleparam.h>
  #include <linux/kernel.h>
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/module.h>
  #include <linux/device.h>
  #include <linux/err.h>
4e57b6817   Tim Schmielau   [PATCH] fix missi...
25
  #include <linux/slab.h>
26d052bfc   Peter Oberparleiter   param: allow whit...
26
  #include <linux/ctype.h>
e7d2860b6   André Goddard Rosa   tree-wide: conver...
27
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
  
  #if 0
  #define DEBUGP printk
  #else
  #define DEBUGP(fmt, a...)
  #endif
b9e20a920   Eric Sesterhenn   [PATCH] Change da...
34
  static inline char dash2underscore(char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  {
  	if (c == '-')
  		return '_';
  	return c;
  }
  
  static inline int parameq(const char *input, const char *paramname)
  {
  	unsigned int i;
  	for (i = 0; dash2underscore(input[i]) == paramname[i]; i++)
  		if (input[i] == '\0')
  			return 1;
  	return 0;
  }
  
  static int parse_one(char *param,
  		     char *val,
  		     struct kernel_param *params, 
  		     unsigned num_params,
  		     int (*handle_unknown)(char *param, char *val))
  {
  	unsigned int i;
  
  	/* Find parameter */
  	for (i = 0; i < num_params; i++) {
  		if (parameq(param, params[i].name)) {
  			DEBUGP("They are equal!  Calling %p
  ",
  			       params[i].set);
  			return params[i].set(val, &params[i]);
  		}
  	}
  
  	if (handle_unknown) {
  		DEBUGP("Unknown argument: calling %p
  ", handle_unknown);
  		return handle_unknown(param, val);
  	}
  
  	DEBUGP("Unknown argument `%s'
  ", param);
  	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   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
  	if (*args == '"') {
  		args++;
  		in_quote = 1;
  		quoted = 1;
  	}
  
  	for (i = 0; args[i]; i++) {
26d052bfc   Peter Oberparleiter   param: allow whit...
93
  		if (isspace(args[i]) && !in_quote)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  			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';
  		}
  		if (quoted && args[i-1] == '"')
  			args[i-1] = '\0';
  	}
  
  	if (args[i]) {
  		args[i] = '\0';
  		next = args + i + 1;
  	} else
  		next = args + i;
f36462f07   Rusty Russell   [PATCH] Ignore tr...
125
126
  
  	/* Chew up trailing spaces. */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
127
  	return skip_spaces(next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
135
136
137
138
139
140
  }
  
  /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
  int parse_args(const char *name,
  	       char *args,
  	       struct kernel_param *params,
  	       unsigned num,
  	       int (*unknown)(char *param, char *val))
  {
  	char *param, *val;
  
  	DEBUGP("Parsing ARGS: %s
  ", args);
f36462f07   Rusty Russell   [PATCH] Ignore tr...
141
  	/* Chew leading spaces */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
142
  	args = skip_spaces(args);
f36462f07   Rusty Russell   [PATCH] Ignore tr...
143

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  	while (*args) {
  		int ret;
a416aba63   Ard van Breemen   [PATCH] kernelpar...
146
  		int irq_was_disabled;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
  
  		args = next_arg(args, &param, &val);
a416aba63   Ard van Breemen   [PATCH] kernelpar...
149
  		irq_was_disabled = irqs_disabled();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  		ret = parse_one(param, val, params, num, unknown);
a416aba63   Ard van Breemen   [PATCH] kernelpar...
151
152
153
154
155
  		if (irq_was_disabled && !irqs_disabled()) {
  			printk(KERN_WARNING "parse_args(): option '%s' enabled "
  					"irq's!
  ", param);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  		switch (ret) {
  		case -ENOENT:
  			printk(KERN_ERR "%s: Unknown parameter `%s'
  ",
  			       name, param);
  			return ret;
  		case -ENOSPC:
  			printk(KERN_ERR
  			       "%s: `%s' too large for parameter `%s'
  ",
  			       name, val ?: "", param);
  			return ret;
  		case 0:
  			break;
  		default:
  			printk(KERN_ERR
  			       "%s: `%s' invalid for parameter `%s'
  ",
  			       name, val ?: "", param);
  			return ret;
  		}
  	}
  
  	/* All parsed OK. */
  	return 0;
  }
  
  /* Lazy bastard, eh? */
  #define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)      	\
  	int param_set_##name(const char *val, struct kernel_param *kp)	\
  	{								\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  		tmptype l;						\
06b2a76d2   Yi Yang   Add new string fu...
188
  		int ret;						\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
  									\
  		if (!val) return -EINVAL;				\
06b2a76d2   Yi Yang   Add new string fu...
191
192
  		ret = strtolfn(val, 0, &l);				\
  		if (ret == -EINVAL || ((type)l != l))			\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
195
196
197
198
199
200
  			return -EINVAL;					\
  		*((type *)kp->arg) = l;					\
  		return 0;						\
  	}								\
  	int param_get_##name(char *buffer, struct kernel_param *kp)	\
  	{								\
  		return sprintf(buffer, format, *((type *)kp->arg));	\
  	}
06b2a76d2   Yi Yang   Add new string fu...
201
202
203
204
205
206
207
  STANDARD_PARAM_DEF(byte, unsigned char, "%c", unsigned long, strict_strtoul);
  STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
  STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul);
  STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol);
  STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
  STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
  STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  
  int param_set_charp(const char *val, struct kernel_param *kp)
  {
  	if (!val) {
  		printk(KERN_ERR "%s: string parameter expected
  ",
  		       kp->name);
  		return -EINVAL;
  	}
  
  	if (strlen(val) > 1024) {
  		printk(KERN_ERR "%s: string parameter too long
  ",
  		       kp->name);
  		return -ENOSPC;
  	}
e180a6b77   Rusty Russell   param: fix charp ...
224
225
226
  	/* This is a hack.  We can't need to strdup in early boot, and we
  	 * don't need to; this mangled commandline is preserved. */
  	if (slab_is_available()) {
e180a6b77   Rusty Russell   param: fix charp ...
227
  		*(char **)kp->arg = kstrdup(val, GFP_KERNEL);
d553ad864   Rusty Russell   param: fix NULL c...
228
  		if (!*(char **)kp->arg)
e180a6b77   Rusty Russell   param: fix charp ...
229
230
231
  			return -ENOMEM;
  	} else
  		*(const char **)kp->arg = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
236
237
238
  	return 0;
  }
  
  int param_get_charp(char *buffer, struct kernel_param *kp)
  {
  	return sprintf(buffer, "%s", *((char **)kp->arg));
  }
fddd52012   Rusty Russell   module_param: all...
239
  /* Actually could be a bool or an int, for historical reasons. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  int param_set_bool(const char *val, struct kernel_param *kp)
  {
fddd52012   Rusty Russell   module_param: all...
242
  	bool v;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
  	/* No equals means "set"... */
  	if (!val) val = "1";
  
  	/* One of =[yYnN01] */
  	switch (val[0]) {
  	case 'y': case 'Y': case '1':
fddd52012   Rusty Russell   module_param: all...
249
250
  		v = true;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
251
  	case 'n': case 'N': case '0':
fddd52012   Rusty Russell   module_param: all...
252
253
254
255
  		v = false;
  		break;
  	default:
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
  	}
fddd52012   Rusty Russell   module_param: all...
257
258
259
260
261
262
  
  	if (kp->flags & KPARAM_ISBOOL)
  		*(bool *)kp->arg = v;
  	else
  		*(int *)kp->arg = v;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
264
265
266
  }
  
  int param_get_bool(char *buffer, struct kernel_param *kp)
  {
fddd52012   Rusty Russell   module_param: all...
267
268
269
270
271
  	bool val;
  	if (kp->flags & KPARAM_ISBOOL)
  		val = *(bool *)kp->arg;
  	else
  		val = *(int *)kp->arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  	/* Y and N chosen as being relatively non-coder friendly */
fddd52012   Rusty Russell   module_param: all...
273
  	return sprintf(buffer, "%c", val ? 'Y' : 'N');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  }
fddd52012   Rusty Russell   module_param: all...
275
  /* This one must be bool. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
  int param_set_invbool(const char *val, struct kernel_param *kp)
  {
fddd52012   Rusty Russell   module_param: all...
278
279
  	int ret;
  	bool boolval;
22e48eaf5   Jan Beulich   constify string/a...
280
  	struct kernel_param dummy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281

22e48eaf5   Jan Beulich   constify string/a...
282
  	dummy.arg = &boolval;
fddd52012   Rusty Russell   module_param: all...
283
  	dummy.flags = KPARAM_ISBOOL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
  	ret = param_set_bool(val, &dummy);
  	if (ret == 0)
9a71af2c3   Rusty Russell   module_param: inv...
286
  		*(bool *)kp->arg = !boolval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
  	return ret;
  }
  
  int param_get_invbool(char *buffer, struct kernel_param *kp)
  {
9a71af2c3   Rusty Russell   module_param: inv...
292
  	return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  }
9730b5b06   Bert Wesarg   kernel/params.c: ...
294
  /* We break the rule and mangle the string. */
9871728b7   Adrian Bunk   [PATCH] kernel/pa...
295
296
297
298
299
  static int param_array(const char *name,
  		       const char *val,
  		       unsigned int min, unsigned int max,
  		       void *elem, int elemsize,
  		       int (*set)(const char *, struct kernel_param *kp),
3c7d76e37   Rusty Russell   param: fix settin...
300
  		       u16 flags,
eb38a996e   Richard Knutsson   kernel/params.c: ...
301
  		       unsigned int *num)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
306
307
308
309
  {
  	int ret;
  	struct kernel_param kp;
  	char save;
  
  	/* Get the name right for errors. */
  	kp.name = name;
  	kp.arg = elem;
3c7d76e37   Rusty Russell   param: fix settin...
310
  	kp.flags = flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
  
  	/* No equals sign? */
  	if (!val) {
  		printk(KERN_ERR "%s: expects arguments
  ", name);
  		return -EINVAL;
  	}
  
  	*num = 0;
  	/* We expect a comma-separated list of values. */
  	do {
  		int len;
  
  		if (*num == max) {
  			printk(KERN_ERR "%s: can only take %i arguments
  ",
  			       name, max);
  			return -EINVAL;
  		}
  		len = strcspn(val, ",");
  
  		/* nul-terminate and parse */
  		save = val[len];
  		((char *)val)[len] = '\0';
  		ret = set(val, &kp);
  
  		if (ret != 0)
  			return ret;
  		kp.arg += elemsize;
  		val += len+1;
  		(*num)++;
  	} while (save == ',');
  
  	if (*num < min) {
  		printk(KERN_ERR "%s: needs at least %i arguments
  ",
  		       name, min);
  		return -EINVAL;
  	}
  	return 0;
  }
  
  int param_array_set(const char *val, struct kernel_param *kp)
  {
22e48eaf5   Jan Beulich   constify string/a...
355
  	const struct kparam_array *arr = kp->arr;
31143a120   Bert Wesarg   [PATCH] kernel/pa...
356
  	unsigned int temp_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  
  	return param_array(kp->name, val, 1, arr->max, arr->elem,
3c7d76e37   Rusty Russell   param: fix settin...
359
360
  			   arr->elemsize, arr->set, kp->flags,
  			   arr->num ?: &temp_num);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
365
  }
  
  int param_array_get(char *buffer, struct kernel_param *kp)
  {
  	int i, off, ret;
22e48eaf5   Jan Beulich   constify string/a...
366
  	const struct kparam_array *arr = kp->arr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
  	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;
  		ret = arr->get(buffer + off, &p);
  		if (ret < 0)
  			return ret;
  		off += ret;
  	}
  	buffer[off] = '\0';
  	return off;
  }
  
  int param_set_copystring(const char *val, struct kernel_param *kp)
  {
22e48eaf5   Jan Beulich   constify string/a...
385
  	const struct kparam_string *kps = kp->str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386

fe20e581a   Randy Dunlap   [PATCH] fix kerne...
387
388
389
390
391
  	if (!val) {
  		printk(KERN_ERR "%s: missing param set value
  ", kp->name);
  		return -EINVAL;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
398
399
400
401
402
403
  	if (strlen(val)+1 > kps->maxlen) {
  		printk(KERN_ERR "%s: string doesn't fit in %u chars.
  ",
  		       kp->name, kps->maxlen-1);
  		return -ENOSPC;
  	}
  	strcpy(kps->string, val);
  	return 0;
  }
  
  int param_get_string(char *buffer, struct kernel_param *kp)
  {
22e48eaf5   Jan Beulich   constify string/a...
404
  	const struct kparam_string *kps = kp->str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
407
408
  	return strlcpy(buffer, kps->string, kps->maxlen);
  }
  
  /* sysfs output in /sys/modules/XYZ/parameters/ */
9b473de87   Rusty Russell   param: Fix duplic...
409
410
  #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   Linus Torvalds   Linux-2.6.12-rc2
411
412
  
  extern struct kernel_param __start___param[], __stop___param[];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
413
414
415
416
417
418
419
420
  struct param_attribute
  {
  	struct module_attribute mattr;
  	struct kernel_param *param;
  };
  
  struct module_param_attrs
  {
9b473de87   Rusty Russell   param: Fix duplic...
421
  	unsigned int num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
  	struct attribute_group grp;
  	struct param_attribute attrs[0];
  };
ef665c1a0   Randy Dunlap   sysfs: fix build ...
425
  #ifdef CONFIG_SYSFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
  #define to_param_attr(n) container_of(n, struct param_attribute, mattr);
  
  static ssize_t param_attr_show(struct module_attribute *mattr,
  			       struct module *mod, char *buf)
  {
  	int count;
  	struct param_attribute *attribute = to_param_attr(mattr);
  
  	if (!attribute->param->get)
  		return -EPERM;
  
  	count = attribute->param->get(buf, attribute->param);
  	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,
  				struct module *owner,
  				const char *buf, size_t len)
  {
   	int err;
  	struct param_attribute *attribute = to_param_attr(mattr);
  
  	if (!attribute->param->set)
  		return -EPERM;
  
  	err = attribute->param->set(buf, attribute->param);
  	if (!err)
  		return len;
  	return err;
  }
ef665c1a0   Randy Dunlap   sysfs: fix build ...
462
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
467
468
  
  #ifdef CONFIG_MODULES
  #define __modinit
  #else
  #define __modinit __init
  #endif
ef665c1a0   Randy Dunlap   sysfs: fix build ...
469
  #ifdef CONFIG_SYSFS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
  /*
9b473de87   Rusty Russell   param: Fix duplic...
471
472
473
474
   * 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   Linus Torvalds   Linux-2.6.12-rc2
475
   *
9b473de87   Rusty Russell   param: Fix duplic...
476
477
478
   * 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   Linus Torvalds   Linux-2.6.12-rc2
479
   */
9b473de87   Rusty Russell   param: Fix duplic...
480
481
482
  static __modinit int add_sysfs_param(struct module_kobject *mk,
  				     struct kernel_param *kp,
  				     const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  {
9b473de87   Rusty Russell   param: Fix duplic...
484
485
486
487
488
489
490
491
492
493
494
495
496
  	struct module_param_attrs *new;
  	struct attribute **attrs;
  	int err, num;
  
  	/* We don't bother calling this with invisible parameters. */
  	BUG_ON(!kp->perm);
  
  	if (!mk->mp) {
  		num = 0;
  		attrs = NULL;
  	} else {
  		num = mk->mp->num;
  		attrs = mk->mp->grp.attrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  	}
9b473de87   Rusty Russell   param: Fix duplic...
498
499
500
501
502
503
504
505
506
507
508
509
510
511
  	/* Enlarge. */
  	new = krealloc(mk->mp,
  		       sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1),
  		       GFP_KERNEL);
  	if (!new) {
  		kfree(mk->mp);
  		err = -ENOMEM;
  		goto fail;
  	}
  	attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL);
  	if (!attrs) {
  		err = -ENOMEM;
  		goto fail_free_new;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512

9b473de87   Rusty Russell   param: Fix duplic...
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
  	/* Sysfs wants everything zeroed. */
  	memset(new, 0, sizeof(*new));
  	memset(&new->attrs[num], 0, sizeof(new->attrs[num]));
  	memset(&attrs[num], 0, sizeof(attrs[num]));
  	new->grp.name = "parameters";
  	new->grp.attrs = attrs;
  
  	/* Tack new one on the end. */
  	new->attrs[num].param = kp;
  	new->attrs[num].mattr.show = param_attr_show;
  	new->attrs[num].mattr.store = param_attr_store;
  	new->attrs[num].mattr.attr.name = (char *)name;
  	new->attrs[num].mattr.attr.mode = kp->perm;
  	new->num = num+1;
  
  	/* Fix up all the pointers, since krealloc can move us */
  	for (num = 0; num < new->num; num++)
  		new->grp.attrs[num] = &new->attrs[num].mattr.attr;
  	new->grp.attrs[num] = NULL;
  
  	mk->mp = new;
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535

9b473de87   Rusty Russell   param: Fix duplic...
536
537
538
539
540
541
  fail_free_new:
  	kfree(new);
  fail:
  	mk->mp = NULL;
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542

d2441183d   Linus Torvalds   Fix compile warni...
543
  #ifdef CONFIG_MODULES
9b473de87   Rusty Russell   param: Fix duplic...
544
545
546
547
548
  static void free_module_param_attrs(struct module_kobject *mk)
  {
  	kfree(mk->mp->grp.attrs);
  	kfree(mk->mp);
  	mk->mp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
  /*
   * module_param_sysfs_setup - setup sysfs support for one module
   * @mod: module
   * @kparam: module parameters (array)
   * @num_params: number of module parameters
   *
9b473de87   Rusty Russell   param: Fix duplic...
556
557
   * Adds sysfs entries for module parameters under
   * /sys/module/[mod->name]/parameters/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
561
562
   */
  int module_param_sysfs_setup(struct module *mod,
  			     struct kernel_param *kparam,
  			     unsigned int num_params)
  {
9b473de87   Rusty Russell   param: Fix duplic...
563
564
565
566
567
568
569
570
571
572
573
  	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);
  		if (err)
  			return err;
  		params = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574

9b473de87   Rusty Russell   param: Fix duplic...
575
576
  	if (!params)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577

9b473de87   Rusty Russell   param: Fix duplic...
578
579
580
581
582
  	/* 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   Linus Torvalds   Linux-2.6.12-rc2
583
584
585
586
587
588
589
590
591
592
593
  }
  
  /*
   * 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   Rusty Russell   param: Fix duplic...
594
595
  	if (mod->mkobj.mp) {
  		sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
  		/* We are positive that no one is using any param
  		 * attrs at this point.  Deallocate immediately. */
9b473de87   Rusty Russell   param: Fix duplic...
598
  		free_module_param_attrs(&mod->mkobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
  	}
  }
  #endif
e180a6b77   Rusty Russell   param: fix charp ...
602
603
  void destroy_params(const struct kernel_param *params, unsigned num)
  {
65afac7d8   Rusty Russell   param: fix lots o...
604
  	/* FIXME: This should free kmalloced charp parameters.  It doesn't. */
e180a6b77   Rusty Russell   param: fix charp ...
605
  }
9b473de87   Rusty Russell   param: Fix duplic...
606
607
608
  static void __init kernel_add_sysfs_param(const char *name,
  					  struct kernel_param *kparam,
  					  unsigned int name_skip)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  {
  	struct module_kobject *mk;
9b473de87   Rusty Russell   param: Fix duplic...
611
612
  	struct kobject *kobj;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613

9b473de87   Rusty Russell   param: Fix duplic...
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
  	kobj = kset_find_obj(module_kset, name);
  	if (kobj) {
  		/* We already have one.  Remove params so we can add more. */
  		mk = to_module_kobject(kobj);
  		/* We need to remove it before adding parameters. */
  		sysfs_remove_group(&mk->kobj, &mk->mp->grp);
  	} 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);
  		if (err) {
  			kobject_put(&mk->kobj);
  			printk(KERN_ERR "Module '%s' failed add to sysfs, "
  			       "error number %d
  ", name, err);
  			printk(KERN_ERR	"The system will be unstable now.
  ");
  			return;
  		}
  		/* So that exit path is even. */
  		kobject_get(&mk->kobj);
74c5b597e   Greg Kroah-Hartman   modules: better e...
639
  	}
9b473de87   Rusty Russell   param: Fix duplic...
640
641
642
643
644
645
  
  	/* 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   Kay Sievers   MODULES: add the ...
646
  	kobject_uevent(&mk->kobj, KOBJ_ADD);
9b473de87   Rusty Russell   param: Fix duplic...
647
  	kobject_put(&mk->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
655
656
657
  }
  
  /*
   * param_sysfs_builtin - add contents in /sys/parameters for built-in modules
   *
   * 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   Rusty Russell   param: Fix duplic...
658
   * and for all who have the same, call kernel_add_sysfs_param.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
   */
  static void __init param_sysfs_builtin(void)
  {
9b473de87   Rusty Russell   param: Fix duplic...
662
663
664
  	struct kernel_param *kp;
  	unsigned int name_len;
  	char modname[MODULE_NAME_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
665

9b473de87   Rusty Russell   param: Fix duplic...
666
  	for (kp = __start___param; kp < __stop___param; kp++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
  		char *dot;
9b473de87   Rusty Russell   param: Fix duplic...
668
669
  		if (kp->perm == 0)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670

730b69d22   Rusty Russell   module: check ker...
671
  		dot = strchr(kp->name, '.');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
  		if (!dot) {
67e67ceaa   Rusty Russell   core_param() for ...
673
674
675
676
677
678
  			/* 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   Linus Torvalds   Linux-2.6.12-rc2
679
  		}
67e67ceaa   Rusty Russell   core_param() for ...
680
  		kernel_add_sysfs_param(modname, kp, name_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
683
684
685
  }
  
  
  /* module-related sysfs stuff */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
686

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
690
691
692
693
694
695
696
697
698
  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   Dmitry Torokhov   [PATCH] sysfs: (r...
699
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
  	ret = attribute->show(attribute, mk->mod, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
  	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   Dmitry Torokhov   [PATCH] sysfs: (r...
717
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
  	ret = attribute->store(attribute, mk->mod, buf, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
721
722
723
724
725
726
  	return ret;
  }
  
  static struct sysfs_ops module_sysfs_ops = {
  	.show = module_attr_show,
  	.store = module_attr_store,
  };
270a6c4ca   Kay Sievers   /sys/modules/*/ho...
727
728
729
730
731
732
733
734
735
736
737
738
  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;
  }
  
  static struct kset_uevent_ops module_uevent_ops = {
  	.filter = uevent_filter,
  };
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
739
  struct kset *module_kset;
823bccfc4   Greg Kroah-Hartman   remove "struct su...
740
  int module_sysfs_initialized;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
741

7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
742
  struct kobj_type module_ktype = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
744
  	.sysfs_ops =	&module_sysfs_ops,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
748
749
  /*
   * param_sysfs_init - wrapper for built-in params support
   */
  static int __init param_sysfs_init(void)
  {
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
750
751
752
753
754
755
  	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   Randy Dunlap   [PATCH] kernel/pa...
756
  	}
823bccfc4   Greg Kroah-Hartman   remove "struct su...
757
  	module_sysfs_initialized = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
762
  
  	param_sysfs_builtin();
  
  	return 0;
  }
d10be6d1b   Mark Huang   [PATCH] module_su...
763
  subsys_initcall(param_sysfs_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764

7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
765
  #endif /* CONFIG_SYSFS */
ef665c1a0   Randy Dunlap   sysfs: fix build ...
766

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
  EXPORT_SYMBOL(param_set_byte);
  EXPORT_SYMBOL(param_get_byte);
  EXPORT_SYMBOL(param_set_short);
  EXPORT_SYMBOL(param_get_short);
  EXPORT_SYMBOL(param_set_ushort);
  EXPORT_SYMBOL(param_get_ushort);
  EXPORT_SYMBOL(param_set_int);
  EXPORT_SYMBOL(param_get_int);
  EXPORT_SYMBOL(param_set_uint);
  EXPORT_SYMBOL(param_get_uint);
  EXPORT_SYMBOL(param_set_long);
  EXPORT_SYMBOL(param_get_long);
  EXPORT_SYMBOL(param_set_ulong);
  EXPORT_SYMBOL(param_get_ulong);
  EXPORT_SYMBOL(param_set_charp);
  EXPORT_SYMBOL(param_get_charp);
  EXPORT_SYMBOL(param_set_bool);
  EXPORT_SYMBOL(param_get_bool);
  EXPORT_SYMBOL(param_set_invbool);
  EXPORT_SYMBOL(param_get_invbool);
  EXPORT_SYMBOL(param_array_set);
  EXPORT_SYMBOL(param_array_get);
  EXPORT_SYMBOL(param_set_copystring);
  EXPORT_SYMBOL(param_get_string);