Blame view

kernel/params.c 24.1 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
  #include <linux/kernel.h>
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/module.h>
63a12d9d0   Geert Uytterhoeven   kernel/param: con...
22
  #include <linux/moduleparam.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  #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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27

cf2fde7b3   Rusty Russell   param: fix module...
28
  #ifdef CONFIG_SYSFS
b51d23e4e   Dan Streetman   module: add per-m...
29
  /* Protects all built-in parameters, modules use their own param_lock */
907b29eb4   Rusty Russell   param: locking fo...
30
  static DEFINE_MUTEX(param_lock);
b51d23e4e   Dan Streetman   module: add per-m...
31
  /* Use the module's mutex, or if built-in use the built-in mutex */
20bdc2cfd   Stephen Rothwell   modules: only use...
32
  #ifdef CONFIG_MODULES
b51d23e4e   Dan Streetman   module: add per-m...
33
  #define KPARAM_MUTEX(mod)	((mod) ? &(mod)->param_lock : &param_lock)
20bdc2cfd   Stephen Rothwell   modules: only use...
34
35
36
  #else
  #define KPARAM_MUTEX(mod)	(&param_lock)
  #endif
cf2fde7b3   Rusty Russell   param: fix module...
37
38
39
40
41
42
43
44
45
46
  
  static inline void check_kparam_locked(struct module *mod)
  {
  	BUG_ON(!mutex_is_locked(KPARAM_MUTEX(mod)));
  }
  #else
  static inline void check_kparam_locked(struct module *mod)
  {
  }
  #endif /* !CONFIG_SYSFS */
b51d23e4e   Dan Streetman   module: add per-m...
47

a1054322a   Rusty Russell   param: use free h...
48
49
50
51
52
  /* This just allows us to keep track of which parameters are kmalloced. */
  struct kmalloced_param {
  	struct list_head list;
  	char val[];
  };
a1054322a   Rusty Russell   param: use free h...
53
  static LIST_HEAD(kmalloced_params);
b51d23e4e   Dan Streetman   module: add per-m...
54
  static DEFINE_SPINLOCK(kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
55
56
57
58
59
60
61
62
  
  static void *kmalloc_parameter(unsigned int size)
  {
  	struct kmalloced_param *p;
  
  	p = kmalloc(sizeof(*p) + size, GFP_KERNEL);
  	if (!p)
  		return NULL;
b51d23e4e   Dan Streetman   module: add per-m...
63
  	spin_lock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
64
  	list_add(&p->list, &kmalloced_params);
b51d23e4e   Dan Streetman   module: add per-m...
65
  	spin_unlock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
66
67
68
69
70
71
72
  	return p->val;
  }
  
  /* Does nothing if parameter wasn't kmalloced above. */
  static void maybe_kfree_parameter(void *param)
  {
  	struct kmalloced_param *p;
b51d23e4e   Dan Streetman   module: add per-m...
73
  	spin_lock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
74
75
76
77
78
79
80
  	list_for_each_entry(p, &kmalloced_params, list) {
  		if (p->val == param) {
  			list_del(&p->list);
  			kfree(p);
  			break;
  		}
  	}
b51d23e4e   Dan Streetman   module: add per-m...
81
  	spin_unlock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
82
  }
b1e4d20cb   Michal Schmidt   params: make dash...
83
  static char dash2underscore(char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
  {
  	if (c == '-')
  		return '_';
  	return c;
  }
b1e4d20cb   Michal Schmidt   params: make dash...
89
  bool parameqn(const char *a, const char *b, size_t n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  {
b1e4d20cb   Michal Schmidt   params: make dash...
91
92
93
94
95
96
97
98
99
100
101
102
  	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   Linus Torvalds   Linux-2.6.12-rc2
103
  }
7a486d378   Rusty Russell   param: check for ...
104
105
106
107
108
109
110
111
112
  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   Linus Torvalds   Linux-2.6.12-rc2
113
114
  static int parse_one(char *param,
  		     char *val,
9fb48c744   Jim Cromie   params: add 3rd a...
115
  		     const char *doing,
914dcaa84   Rusty Russell   param: make param...
116
  		     const struct kernel_param *params,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  		     unsigned num_params,
026cee008   Pawel Moll   params: <level>_i...
118
119
  		     s16 min_level,
  		     s16 max_level,
ecc861705   Luis R. Rodriguez   module: add extra...
120
  		     void *arg,
9fb48c744   Jim Cromie   params: add 3rd a...
121
  		     int (*handle_unknown)(char *param, char *val,
ecc861705   Luis R. Rodriguez   module: add extra...
122
  				     const char *doing, void *arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  {
  	unsigned int i;
907b29eb4   Rusty Russell   param: locking fo...
125
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
  
  	/* Find parameter */
  	for (i = 0; i < num_params; i++) {
  		if (parameq(param, params[i].name)) {
026cee008   Pawel Moll   params: <level>_i...
130
131
132
  			if (params[i].level < min_level
  			    || params[i].level > max_level)
  				return 0;
25985edce   Lucas De Marchi   Fix common misspe...
133
  			/* No one handled NULL, so do it here. */
ab013c5f6   Steven Rostedt   module: Add flag ...
134
  			if (!val &&
6a4c26431   Jani Nikula   module: rename KE...
135
  			    !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG))
2e9fb9953   Rusty Russell   params: don't han...
136
  				return -EINVAL;
9fb48c744   Jim Cromie   params: add 3rd a...
137
138
139
  			pr_debug("handling %s with %p
  ", param,
  				params[i].ops->set);
b51d23e4e   Dan Streetman   module: add per-m...
140
  			kernel_param_lock(params[i].mod);
7a486d378   Rusty Russell   param: check for ...
141
  			param_check_unsafe(&params[i]);
907b29eb4   Rusty Russell   param: locking fo...
142
  			err = params[i].ops->set(val, &params[i]);
b51d23e4e   Dan Streetman   module: add per-m...
143
  			kernel_param_unlock(params[i].mod);
907b29eb4   Rusty Russell   param: locking fo...
144
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
  		}
  	}
  
  	if (handle_unknown) {
9fb48c744   Jim Cromie   params: add 3rd a...
149
150
  		pr_debug("doing %s: %s='%s'
  ", doing, param, val);
ecc861705   Luis R. Rodriguez   module: add extra...
151
  		return handle_unknown(param, val, doing, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  	}
9fb48c744   Jim Cromie   params: add 3rd a...
153
154
  	pr_debug("Unknown argument '%s'
  ", param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
160
161
162
163
164
  	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
165
166
167
168
169
170
171
  	if (*args == '"') {
  		args++;
  		in_quote = 1;
  		quoted = 1;
  	}
  
  	for (i = 0; args[i]; i++) {
26d052bfc   Peter Oberparleiter   param: allow whit...
172
  		if (isspace(args[i]) && !in_quote)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
  			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   Linus Torvalds   Linux-2.6.12-rc2
195
  	}
b9cc4489c   Rusty Russell   params: handle qu...
196
197
  	if (quoted && args[i-1] == '"')
  		args[i-1] = '\0';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
201
202
203
  
  	if (args[i]) {
  		args[i] = '\0';
  		next = args + i + 1;
  	} else
  		next = args + i;
f36462f07   Rusty Russell   [PATCH] Ignore tr...
204
205
  
  	/* Chew up trailing spaces. */
e7d2860b6   AndrĂ© Goddard Rosa   tree-wide: conver...
206
  	return skip_spaces(next);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
  }
  
  /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
51e158c12   Rusty Russell   param: hand argum...
210
211
212
213
214
215
  char *parse_args(const char *doing,
  		 char *args,
  		 const struct kernel_param *params,
  		 unsigned num,
  		 s16 min_level,
  		 s16 max_level,
ecc861705   Luis R. Rodriguez   module: add extra...
216
217
218
  		 void *arg,
  		 int (*unknown)(char *param, char *val,
  				const char *doing, void *arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
219
  {
74b22c465   Oleg Nesterov   params: don't ign...
220
  	char *param, *val, *err = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221

f36462f07   Rusty Russell   [PATCH] Ignore tr...
222
  	/* Chew leading spaces */
e7d2860b6   AndrĂ© Goddard Rosa   tree-wide: conver...
223
  	args = skip_spaces(args);
f36462f07   Rusty Russell   [PATCH] Ignore tr...
224

1ef9eaf2b   Jim Cromie   params.c: fix Sma...
225
  	if (*args)
9fb48c744   Jim Cromie   params: add 3rd a...
226
227
  		pr_debug("doing %s, parsing ARGS: '%s'
  ", doing, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
  	while (*args) {
  		int ret;
a416aba63   Ard van Breemen   [PATCH] kernelpar...
230
  		int irq_was_disabled;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
  
  		args = next_arg(args, &param, &val);
51e158c12   Rusty Russell   param: hand argum...
233
234
  		/* Stop at -- */
  		if (!val && strcmp(param, "--") == 0)
74b22c465   Oleg Nesterov   params: don't ign...
235
  			return err ?: args;
a416aba63   Ard van Breemen   [PATCH] kernelpar...
236
  		irq_was_disabled = irqs_disabled();
9fb48c744   Jim Cromie   params: add 3rd a...
237
  		ret = parse_one(param, val, doing, params, num,
ecc861705   Luis R. Rodriguez   module: add extra...
238
  				min_level, max_level, arg, unknown);
b5f3abf95   Jim Cromie   params: replace p...
239
240
241
242
  		if (irq_was_disabled && !irqs_disabled())
  			pr_warn("%s: option '%s' enabled irq's!
  ",
  				doing, param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  		switch (ret) {
74b22c465   Oleg Nesterov   params: don't ign...
244
245
  		case 0:
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  		case -ENOENT:
b5f3abf95   Jim Cromie   params: replace p...
247
248
  			pr_err("%s: Unknown parameter `%s'
  ", doing, param);
74b22c465   Oleg Nesterov   params: don't ign...
249
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
  		case -ENOSPC:
b5f3abf95   Jim Cromie   params: replace p...
251
252
  			pr_err("%s: `%s' too large for parameter `%s'
  ",
9fb48c744   Jim Cromie   params: add 3rd a...
253
  			       doing, val ?: "", param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
  			break;
  		default:
b5f3abf95   Jim Cromie   params: replace p...
256
257
  			pr_err("%s: `%s' invalid for parameter `%s'
  ",
9fb48c744   Jim Cromie   params: add 3rd a...
258
  			       doing, val ?: "", param);
74b22c465   Oleg Nesterov   params: don't ign...
259
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
  		}
74b22c465   Oleg Nesterov   params: don't ign...
261
262
  
  		err = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  	}
74b22c465   Oleg Nesterov   params: don't ign...
264
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
  }
  
  /* Lazy bastard, eh? */
88a88b320   Felipe Contreras   params: improve s...
268
  #define STANDARD_PARAM_DEF(name, type, format, strtolfn)      		\
9bbb9e5a3   Rusty Russell   param: use ops in...
269
  	int param_set_##name(const char *val, const struct kernel_param *kp) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  	{								\
88a88b320   Felipe Contreras   params: improve s...
271
  		return strtolfn(val, 0, (type *)kp->arg);		\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  	}								\
9bbb9e5a3   Rusty Russell   param: use ops in...
273
  	int param_get_##name(char *buffer, const struct kernel_param *kp) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  	{								\
f4940ab7c   Chen Gang   kernel/params.c: ...
275
276
  		return scnprintf(buffer, PAGE_SIZE, format,		\
  				*((type *)kp->arg));			\
a14fe249a   Rusty Russell   param: move the E...
277
  	}								\
9c27847dd   Luis R. Rodriguez   kernel/params: co...
278
  	const struct kernel_param_ops param_ops_##name = {			\
9bbb9e5a3   Rusty Russell   param: use ops in...
279
280
281
  		.set = param_set_##name,				\
  		.get = param_get_##name,				\
  	};								\
a14fe249a   Rusty Russell   param: move the E...
282
  	EXPORT_SYMBOL(param_set_##name);				\
9bbb9e5a3   Rusty Russell   param: use ops in...
283
284
  	EXPORT_SYMBOL(param_get_##name);				\
  	EXPORT_SYMBOL(param_ops_##name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285

88a88b320   Felipe Contreras   params: improve s...
286
287
288
289
290
291
292
  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   Hannes Reinecke   Add module param ...
293
  STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294

9bbb9e5a3   Rusty Russell   param: use ops in...
295
  int param_set_charp(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
  	if (strlen(val) > 1024) {
b5f3abf95   Jim Cromie   params: replace p...
298
299
  		pr_err("%s: string parameter too long
  ", kp->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  		return -ENOSPC;
  	}
a1054322a   Rusty Russell   param: use free h...
302
303
304
  	maybe_kfree_parameter(*(char **)kp->arg);
  
  	/* This is a hack.  We can't kmalloc in early boot, and we
e180a6b77   Rusty Russell   param: fix charp ...
305
306
  	 * don't need to; this mangled commandline is preserved. */
  	if (slab_is_available()) {
a1054322a   Rusty Russell   param: use free h...
307
  		*(char **)kp->arg = kmalloc_parameter(strlen(val)+1);
d553ad864   Rusty Russell   param: fix NULL c...
308
  		if (!*(char **)kp->arg)
e180a6b77   Rusty Russell   param: fix charp ...
309
  			return -ENOMEM;
a1054322a   Rusty Russell   param: use free h...
310
  		strcpy(*(char **)kp->arg, val);
e180a6b77   Rusty Russell   param: fix charp ...
311
312
  	} else
  		*(const char **)kp->arg = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
313
314
  	return 0;
  }
a14fe249a   Rusty Russell   param: move the E...
315
  EXPORT_SYMBOL(param_set_charp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316

9bbb9e5a3   Rusty Russell   param: use ops in...
317
  int param_get_charp(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  {
f4940ab7c   Chen Gang   kernel/params.c: ...
319
  	return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  }
a14fe249a   Rusty Russell   param: move the E...
321
  EXPORT_SYMBOL(param_get_charp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322

3d9c637f4   Dan Streetman   module: export pa...
323
  void param_free_charp(void *arg)
a1054322a   Rusty Russell   param: use free h...
324
325
326
  {
  	maybe_kfree_parameter(*((char **)arg));
  }
3d9c637f4   Dan Streetman   module: export pa...
327
  EXPORT_SYMBOL(param_free_charp);
a1054322a   Rusty Russell   param: use free h...
328

9c27847dd   Luis R. Rodriguez   kernel/params: co...
329
  const struct kernel_param_ops param_ops_charp = {
9bbb9e5a3   Rusty Russell   param: use ops in...
330
331
  	.set = param_set_charp,
  	.get = param_get_charp,
a1054322a   Rusty Russell   param: use free h...
332
  	.free = param_free_charp,
9bbb9e5a3   Rusty Russell   param: use ops in...
333
334
  };
  EXPORT_SYMBOL(param_ops_charp);
fddd52012   Rusty Russell   module_param: all...
335
  /* Actually could be a bool or an int, for historical reasons. */
9bbb9e5a3   Rusty Russell   param: use ops in...
336
  int param_set_bool(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
  {
  	/* No equals means "set"... */
  	if (!val) val = "1";
  
  	/* One of =[yYnN01] */
8b8252813   Rusty Russell   module_param: rem...
342
  	return strtobool(val, kp->arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  }
a14fe249a   Rusty Russell   param: move the E...
344
  EXPORT_SYMBOL(param_set_bool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345

9bbb9e5a3   Rusty Russell   param: use ops in...
346
  int param_get_bool(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
  {
  	/* Y and N chosen as being relatively non-coder friendly */
8b8252813   Rusty Russell   module_param: rem...
349
  	return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  }
a14fe249a   Rusty Russell   param: move the E...
351
  EXPORT_SYMBOL(param_get_bool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352

9c27847dd   Luis R. Rodriguez   kernel/params: co...
353
  const struct kernel_param_ops param_ops_bool = {
6a4c26431   Jani Nikula   module: rename KE...
354
  	.flags = KERNEL_PARAM_OPS_FL_NOARG,
9bbb9e5a3   Rusty Russell   param: use ops in...
355
356
357
358
  	.set = param_set_bool,
  	.get = param_get_bool,
  };
  EXPORT_SYMBOL(param_ops_bool);
d19f05d8a   Luis R. Rodriguez   kernel/params.c: ...
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  int param_set_bool_enable_only(const char *val, const struct kernel_param *kp)
  {
  	int err = 0;
  	bool new_value;
  	bool orig_value = *(bool *)kp->arg;
  	struct kernel_param dummy_kp = *kp;
  
  	dummy_kp.arg = &new_value;
  
  	err = param_set_bool(val, &dummy_kp);
  	if (err)
  		return err;
  
  	/* Don't let them unset it once it's set! */
  	if (!new_value && orig_value)
  		return -EROFS;
  
  	if (new_value)
  		err = param_set_bool(val, kp);
  
  	return err;
  }
  EXPORT_SYMBOL_GPL(param_set_bool_enable_only);
  
  const struct kernel_param_ops param_ops_bool_enable_only = {
  	.flags = KERNEL_PARAM_OPS_FL_NOARG,
  	.set = param_set_bool_enable_only,
  	.get = param_get_bool,
  };
154be21c5   Luis R. Rodriguez   kernel/params.c: ...
388
  EXPORT_SYMBOL_GPL(param_ops_bool_enable_only);
d19f05d8a   Luis R. Rodriguez   kernel/params.c: ...
389

fddd52012   Rusty Russell   module_param: all...
390
  /* This one must be bool. */
9bbb9e5a3   Rusty Russell   param: use ops in...
391
  int param_set_invbool(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  {
fddd52012   Rusty Russell   module_param: all...
393
394
  	int ret;
  	bool boolval;
22e48eaf5   Jan Beulich   constify string/a...
395
  	struct kernel_param dummy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396

22e48eaf5   Jan Beulich   constify string/a...
397
  	dummy.arg = &boolval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
399
  	ret = param_set_bool(val, &dummy);
  	if (ret == 0)
9a71af2c3   Rusty Russell   module_param: inv...
400
  		*(bool *)kp->arg = !boolval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
  	return ret;
  }
a14fe249a   Rusty Russell   param: move the E...
403
  EXPORT_SYMBOL(param_set_invbool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404

9bbb9e5a3   Rusty Russell   param: use ops in...
405
  int param_get_invbool(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
  {
9a71af2c3   Rusty Russell   module_param: inv...
407
  	return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  }
a14fe249a   Rusty Russell   param: move the E...
409
  EXPORT_SYMBOL(param_get_invbool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410

9c27847dd   Luis R. Rodriguez   kernel/params: co...
411
  const struct kernel_param_ops param_ops_invbool = {
9bbb9e5a3   Rusty Russell   param: use ops in...
412
413
414
415
  	.set = param_set_invbool,
  	.get = param_get_invbool,
  };
  EXPORT_SYMBOL(param_ops_invbool);
69116f279   Rusty Russell   module_param: avo...
416
417
  int param_set_bint(const char *val, const struct kernel_param *kp)
  {
5104b7d76   Dan Streetman   module: make perm...
418
419
  	/* Match bool exactly, by re-using it. */
  	struct kernel_param boolkp = *kp;
69116f279   Rusty Russell   module_param: avo...
420
421
  	bool v;
  	int ret;
69116f279   Rusty Russell   module_param: avo...
422
  	boolkp.arg = &v;
69116f279   Rusty Russell   module_param: avo...
423
424
425
426
427
428
429
  
  	ret = param_set_bool(val, &boolkp);
  	if (ret == 0)
  		*(int *)kp->arg = v;
  	return ret;
  }
  EXPORT_SYMBOL(param_set_bint);
9c27847dd   Luis R. Rodriguez   kernel/params: co...
430
  const struct kernel_param_ops param_ops_bint = {
6a4c26431   Jani Nikula   module: rename KE...
431
  	.flags = KERNEL_PARAM_OPS_FL_NOARG,
69116f279   Rusty Russell   module_param: avo...
432
433
434
435
  	.set = param_set_bint,
  	.get = param_get_int,
  };
  EXPORT_SYMBOL(param_ops_bint);
9730b5b06   Bert Wesarg   kernel/params.c: ...
436
  /* We break the rule and mangle the string. */
b51d23e4e   Dan Streetman   module: add per-m...
437
438
  static int param_array(struct module *mod,
  		       const char *name,
9871728b7   Adrian Bunk   [PATCH] kernel/pa...
439
440
441
  		       const char *val,
  		       unsigned int min, unsigned int max,
  		       void *elem, int elemsize,
9bbb9e5a3   Rusty Russell   param: use ops in...
442
  		       int (*set)(const char *, const struct kernel_param *kp),
026cee008   Pawel Moll   params: <level>_i...
443
  		       s16 level,
eb38a996e   Richard Knutsson   kernel/params.c: ...
444
  		       unsigned int *num)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
  {
  	int ret;
  	struct kernel_param kp;
  	char save;
  
  	/* Get the name right for errors. */
  	kp.name = name;
  	kp.arg = elem;
026cee008   Pawel Moll   params: <level>_i...
453
  	kp.level = level;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
458
459
460
  	*num = 0;
  	/* We expect a comma-separated list of values. */
  	do {
  		int len;
  
  		if (*num == max) {
b5f3abf95   Jim Cromie   params: replace p...
461
462
  			pr_err("%s: can only take %i arguments
  ", name, max);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
467
468
469
  			return -EINVAL;
  		}
  		len = strcspn(val, ",");
  
  		/* nul-terminate and parse */
  		save = val[len];
  		((char *)val)[len] = '\0';
cf2fde7b3   Rusty Russell   param: fix module...
470
  		check_kparam_locked(mod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
476
477
478
479
480
  		ret = set(val, &kp);
  
  		if (ret != 0)
  			return ret;
  		kp.arg += elemsize;
  		val += len+1;
  		(*num)++;
  	} while (save == ',');
  
  	if (*num < min) {
b5f3abf95   Jim Cromie   params: replace p...
481
482
  		pr_err("%s: needs at least %i arguments
  ", name, min);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
  		return -EINVAL;
  	}
  	return 0;
  }
9bbb9e5a3   Rusty Russell   param: use ops in...
487
  static int param_array_set(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  {
22e48eaf5   Jan Beulich   constify string/a...
489
  	const struct kparam_array *arr = kp->arr;
31143a120   Bert Wesarg   [PATCH] kernel/pa...
490
  	unsigned int temp_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491

b51d23e4e   Dan Streetman   module: add per-m...
492
  	return param_array(kp->mod, kp->name, val, 1, arr->max, arr->elem,
026cee008   Pawel Moll   params: <level>_i...
493
  			   arr->elemsize, arr->ops->set, kp->level,
3c7d76e37   Rusty Russell   param: fix settin...
494
  			   arr->num ?: &temp_num);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  }
9bbb9e5a3   Rusty Russell   param: use ops in...
496
  static int param_array_get(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  {
  	int i, off, ret;
22e48eaf5   Jan Beulich   constify string/a...
499
  	const struct kparam_array *arr = kp->arr;
5104b7d76   Dan Streetman   module: make perm...
500
  	struct kernel_param p = *kp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
504
505
  	for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
  		if (i)
  			buffer[off++] = ',';
  		p.arg = arr->elem + arr->elemsize * i;
cf2fde7b3   Rusty Russell   param: fix module...
506
  		check_kparam_locked(p.mod);
9bbb9e5a3   Rusty Russell   param: use ops in...
507
  		ret = arr->ops->get(buffer + off, &p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
  		if (ret < 0)
  			return ret;
  		off += ret;
  	}
  	buffer[off] = '\0';
  	return off;
  }
e6df34a44   Rusty Russell   param: add a free...
515
516
517
518
519
520
521
522
523
  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);
  }
9c27847dd   Luis R. Rodriguez   kernel/params: co...
524
  const struct kernel_param_ops param_array_ops = {
9bbb9e5a3   Rusty Russell   param: use ops in...
525
526
  	.set = param_array_set,
  	.get = param_array_get,
e6df34a44   Rusty Russell   param: add a free...
527
  	.free = param_array_free,
9bbb9e5a3   Rusty Russell   param: use ops in...
528
529
530
531
  };
  EXPORT_SYMBOL(param_array_ops);
  
  int param_set_copystring(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  {
22e48eaf5   Jan Beulich   constify string/a...
533
  	const struct kparam_string *kps = kp->str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
  
  	if (strlen(val)+1 > kps->maxlen) {
b5f3abf95   Jim Cromie   params: replace p...
536
537
  		pr_err("%s: string doesn't fit in %u chars.
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
542
543
  		       kp->name, kps->maxlen-1);
  		return -ENOSPC;
  	}
  	strcpy(kps->string, val);
  	return 0;
  }
a14fe249a   Rusty Russell   param: move the E...
544
  EXPORT_SYMBOL(param_set_copystring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545

9bbb9e5a3   Rusty Russell   param: use ops in...
546
  int param_get_string(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  {
22e48eaf5   Jan Beulich   constify string/a...
548
  	const struct kparam_string *kps = kp->str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
  	return strlcpy(buffer, kps->string, kps->maxlen);
  }
a14fe249a   Rusty Russell   param: move the E...
551
  EXPORT_SYMBOL(param_get_string);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552

9c27847dd   Luis R. Rodriguez   kernel/params: co...
553
  const struct kernel_param_ops param_ops_string = {
9bbb9e5a3   Rusty Russell   param: use ops in...
554
555
556
557
  	.set = param_set_copystring,
  	.get = param_get_string,
  };
  EXPORT_SYMBOL(param_ops_string);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  /* sysfs output in /sys/modules/XYZ/parameters/ */
350f82586   Edward Z. Yang   Remove redundant ...
559
560
  #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
561

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
  struct param_attribute
  {
  	struct module_attribute mattr;
9bbb9e5a3   Rusty Russell   param: use ops in...
565
  	const struct kernel_param *param;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
  };
  
  struct module_param_attrs
  {
9b473de87   Rusty Russell   param: Fix duplic...
570
  	unsigned int num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
  	struct attribute_group grp;
  	struct param_attribute attrs[0];
  };
ef665c1a0   Randy Dunlap   sysfs: fix build ...
574
  #ifdef CONFIG_SYSFS
350f82586   Edward Z. Yang   Remove redundant ...
575
  #define to_param_attr(n) container_of(n, struct param_attribute, mattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
577
  
  static ssize_t param_attr_show(struct module_attribute *mattr,
4befb026c   Kay Sievers   module: change at...
578
  			       struct module_kobject *mk, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
581
  {
  	int count;
  	struct param_attribute *attribute = to_param_attr(mattr);
9bbb9e5a3   Rusty Russell   param: use ops in...
582
  	if (!attribute->param->ops->get)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  		return -EPERM;
b51d23e4e   Dan Streetman   module: add per-m...
584
  	kernel_param_lock(mk->mod);
9bbb9e5a3   Rusty Russell   param: use ops in...
585
  	count = attribute->param->ops->get(buf, attribute->param);
b51d23e4e   Dan Streetman   module: add per-m...
586
  	kernel_param_unlock(mk->mod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
592
593
594
595
596
  	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,
b51d23e4e   Dan Streetman   module: add per-m...
597
  				struct module_kobject *mk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
  				const char *buf, size_t len)
  {
   	int err;
  	struct param_attribute *attribute = to_param_attr(mattr);
9bbb9e5a3   Rusty Russell   param: use ops in...
602
  	if (!attribute->param->ops->set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
  		return -EPERM;
b51d23e4e   Dan Streetman   module: add per-m...
604
  	kernel_param_lock(mk->mod);
7a486d378   Rusty Russell   param: check for ...
605
  	param_check_unsafe(attribute->param);
9bbb9e5a3   Rusty Russell   param: use ops in...
606
  	err = attribute->param->ops->set(buf, attribute->param);
b51d23e4e   Dan Streetman   module: add per-m...
607
  	kernel_param_unlock(mk->mod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
610
611
  	if (!err)
  		return len;
  	return err;
  }
ef665c1a0   Randy Dunlap   sysfs: fix build ...
612
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
618
  
  #ifdef CONFIG_MODULES
  #define __modinit
  #else
  #define __modinit __init
  #endif
ef665c1a0   Randy Dunlap   sysfs: fix build ...
619
  #ifdef CONFIG_SYSFS
b51d23e4e   Dan Streetman   module: add per-m...
620
  void kernel_param_lock(struct module *mod)
907b29eb4   Rusty Russell   param: locking fo...
621
  {
b51d23e4e   Dan Streetman   module: add per-m...
622
  	mutex_lock(KPARAM_MUTEX(mod));
907b29eb4   Rusty Russell   param: locking fo...
623
  }
907b29eb4   Rusty Russell   param: locking fo...
624

b51d23e4e   Dan Streetman   module: add per-m...
625
  void kernel_param_unlock(struct module *mod)
907b29eb4   Rusty Russell   param: locking fo...
626
  {
b51d23e4e   Dan Streetman   module: add per-m...
627
  	mutex_unlock(KPARAM_MUTEX(mod));
907b29eb4   Rusty Russell   param: locking fo...
628
  }
b51d23e4e   Dan Streetman   module: add per-m...
629

b51d23e4e   Dan Streetman   module: add per-m...
630
631
  EXPORT_SYMBOL(kernel_param_lock);
  EXPORT_SYMBOL(kernel_param_unlock);
907b29eb4   Rusty Russell   param: locking fo...
632

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
  /*
9b473de87   Rusty Russell   param: Fix duplic...
634
635
636
637
   * 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
638
   *
9b473de87   Rusty Russell   param: Fix duplic...
639
640
641
   * 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
642
   */
9b473de87   Rusty Russell   param: Fix duplic...
643
  static __modinit int add_sysfs_param(struct module_kobject *mk,
9bbb9e5a3   Rusty Russell   param: use ops in...
644
  				     const struct kernel_param *kp,
9b473de87   Rusty Russell   param: Fix duplic...
645
  				     const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
  {
18eb74fa9   Rusty Russell   params: cleanup s...
647
648
649
  	struct module_param_attrs *new_mp;
  	struct attribute **new_attrs;
  	unsigned int i;
9b473de87   Rusty Russell   param: Fix duplic...
650
651
652
653
654
  
  	/* We don't bother calling this with invisible parameters. */
  	BUG_ON(!kp->perm);
  
  	if (!mk->mp) {
18eb74fa9   Rusty Russell   params: cleanup s...
655
656
657
658
659
660
661
662
663
664
665
  		/* 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   Rusty Russell   param: Fix duplic...
666
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667

18eb74fa9   Rusty Russell   params: cleanup s...
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
  	/* 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   Rusty Russell   param: Fix duplic...
684
685
  
  	/* Tack new one on the end. */
c772be523   Rusty Russell   param: fix uninit...
686
  	memset(&mk->mp->attrs[mk->mp->num], 0, sizeof(mk->mp->attrs[0]));
18eb74fa9   Rusty Russell   params: cleanup s...
687
688
689
  	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   Kees Cook   param: do not set...
690
691
692
  	/* 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   Rusty Russell   param: initialize...
693
694
  	else
  		mk->mp->attrs[mk->mp->num].mattr.store = NULL;
18eb74fa9   Rusty Russell   params: cleanup s...
695
696
697
  	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   Rusty Russell   param: Fix duplic...
698
699
  
  	/* Fix up all the pointers, since krealloc can move us */
18eb74fa9   Rusty Russell   params: cleanup s...
700
701
702
  	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   Rusty Russell   param: Fix duplic...
703
  	return 0;
9b473de87   Rusty Russell   param: Fix duplic...
704
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705

d2441183d   Linus Torvalds   Fix compile warni...
706
  #ifdef CONFIG_MODULES
9b473de87   Rusty Russell   param: Fix duplic...
707
708
  static void free_module_param_attrs(struct module_kobject *mk)
  {
18eb74fa9   Rusty Russell   params: cleanup s...
709
710
  	if (mk->mp)
  		kfree(mk->mp->grp.attrs);
9b473de87   Rusty Russell   param: Fix duplic...
711
712
  	kfree(mk->mp);
  	mk->mp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
713
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
718
719
  /*
   * 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...
720
721
   * Adds sysfs entries for module parameters under
   * /sys/module/[mod->name]/parameters/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
   */
  int module_param_sysfs_setup(struct module *mod,
9bbb9e5a3   Rusty Russell   param: use ops in...
724
  			     const struct kernel_param *kparam,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
  			     unsigned int num_params)
  {
9b473de87   Rusty Russell   param: Fix duplic...
727
728
729
730
731
732
733
  	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   Rusty Russell   params: cleanup s...
734
735
  		if (err) {
  			free_module_param_attrs(&mod->mkobj);
9b473de87   Rusty Russell   param: Fix duplic...
736
  			return err;
18eb74fa9   Rusty Russell   params: cleanup s...
737
  		}
9b473de87   Rusty Russell   param: Fix duplic...
738
739
  		params = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740

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

9b473de87   Rusty Russell   param: Fix duplic...
744
745
746
747
748
  	/* 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
749
750
751
752
753
754
755
756
757
758
759
  }
  
  /*
   * 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...
760
761
  	if (mod->mkobj.mp) {
  		sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
  		/* We are positive that no one is using any param
  		 * attrs at this point.  Deallocate immediately. */
9b473de87   Rusty Russell   param: Fix duplic...
764
  		free_module_param_attrs(&mod->mkobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
766
767
  	}
  }
  #endif
e180a6b77   Rusty Russell   param: fix charp ...
768
769
  void destroy_params(const struct kernel_param *params, unsigned num)
  {
e6df34a44   Rusty Russell   param: add a free...
770
771
772
773
774
  	unsigned int i;
  
  	for (i = 0; i < num; i++)
  		if (params[i].ops->free)
  			params[i].ops->free(params[i].arg);
e180a6b77   Rusty Russell   param: fix charp ...
775
  }
e94965ed5   Dmitry Torokhov   module: show vers...
776
  static struct module_kobject * __init locate_module_kobject(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
  {
  	struct module_kobject *mk;
9b473de87   Rusty Russell   param: Fix duplic...
779
780
  	struct kobject *kobj;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781

9b473de87   Rusty Russell   param: Fix duplic...
782
783
  	kobj = kset_find_obj(module_kset, name);
  	if (kobj) {
9b473de87   Rusty Russell   param: Fix duplic...
784
  		mk = to_module_kobject(kobj);
9b473de87   Rusty Russell   param: Fix duplic...
785
786
787
788
789
790
791
792
  	} 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   Kay Sievers   module: add /sys/...
793
794
795
796
  #ifdef CONFIG_MODULES
  		if (!err)
  			err = sysfs_create_file(&mk->kobj, &module_uevent.attr);
  #endif
9b473de87   Rusty Russell   param: Fix duplic...
797
798
  		if (err) {
  			kobject_put(&mk->kobj);
b5f3abf95   Jim Cromie   params: replace p...
799
800
  			pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.
  ",
e94965ed5   Dmitry Torokhov   module: show vers...
801
  				name, err);
e94965ed5   Dmitry Torokhov   module: show vers...
802
  			return NULL;
9b473de87   Rusty Russell   param: Fix duplic...
803
  		}
e94965ed5   Dmitry Torokhov   module: show vers...
804
805
  
  		/* So that we hold reference in both cases. */
9b473de87   Rusty Russell   param: Fix duplic...
806
  		kobject_get(&mk->kobj);
74c5b597e   Greg Kroah-Hartman   modules: better e...
807
  	}
9b473de87   Rusty Russell   param: Fix duplic...
808

e94965ed5   Dmitry Torokhov   module: show vers...
809
810
811
812
  	return mk;
  }
  
  static void __init kernel_add_sysfs_param(const char *name,
63a12d9d0   Geert Uytterhoeven   kernel/param: con...
813
  					  const struct kernel_param *kparam,
e94965ed5   Dmitry Torokhov   module: show vers...
814
815
816
817
818
819
820
821
822
823
824
825
  					  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   Rusty Russell   param: Fix duplic...
826
827
828
829
830
  	/* 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 ...
831
  	kobject_uevent(&mk->kobj, KOBJ_ADD);
9b473de87   Rusty Russell   param: Fix duplic...
832
  	kobject_put(&mk->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
835
  }
  
  /*
b634d130e   Jean Delvare   There is no /sys/...
836
   * param_sysfs_builtin - add sysfs parameters for built-in modules
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
842
   *
   * 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...
843
   * and for all who have the same, call kernel_add_sysfs_param.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
845
846
   */
  static void __init param_sysfs_builtin(void)
  {
63a12d9d0   Geert Uytterhoeven   kernel/param: con...
847
  	const struct kernel_param *kp;
9b473de87   Rusty Russell   param: Fix duplic...
848
849
  	unsigned int name_len;
  	char modname[MODULE_NAME_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850

9b473de87   Rusty Russell   param: Fix duplic...
851
  	for (kp = __start___param; kp < __stop___param; kp++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
  		char *dot;
9b473de87   Rusty Russell   param: Fix duplic...
853
854
  		if (kp->perm == 0)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855

730b69d22   Rusty Russell   module: check ker...
856
  		dot = strchr(kp->name, '.');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  		if (!dot) {
67e67ceaa   Rusty Russell   core_param() for ...
858
859
860
861
862
863
  			/* 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
864
  		}
67e67ceaa   Rusty Russell   core_param() for ...
865
  		kernel_add_sysfs_param(modname, kp, name_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  }
e94965ed5   Dmitry Torokhov   module: show vers...
868
  ssize_t __modver_version_show(struct module_attribute *mattr,
4befb026c   Kay Sievers   module: change at...
869
  			      struct module_kobject *mk, char *buf)
e94965ed5   Dmitry Torokhov   module: show vers...
870
871
872
  {
  	struct module_version_attribute *vattr =
  		container_of(mattr, struct module_version_attribute, mattr);
f4940ab7c   Chen Gang   kernel/params.c: ...
873
874
  	return scnprintf(buf, PAGE_SIZE, "%s
  ", vattr->version);
e94965ed5   Dmitry Torokhov   module: show vers...
875
  }
b4bc84280   Dmitry Torokhov   module: deal with...
876
877
  extern const struct module_version_attribute *__start___modver[];
  extern const struct module_version_attribute *__stop___modver[];
e94965ed5   Dmitry Torokhov   module: show vers...
878
879
880
  
  static void __init version_sysfs_builtin(void)
  {
b4bc84280   Dmitry Torokhov   module: deal with...
881
  	const struct module_version_attribute **p;
e94965ed5   Dmitry Torokhov   module: show vers...
882
883
  	struct module_kobject *mk;
  	int err;
b4bc84280   Dmitry Torokhov   module: deal with...
884
885
  	for (p = __start___modver; p < __stop___modver; p++) {
  		const struct module_version_attribute *vattr = *p;
e94965ed5   Dmitry Torokhov   module: show vers...
886
887
888
  		mk = locate_module_kobject(vattr->module_name);
  		if (mk) {
  			err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
74c3dea35   Rusty Russell   params: suppress ...
889
  			WARN_ON_ONCE(err);
e94965ed5   Dmitry Torokhov   module: show vers...
890
891
892
893
894
  			kobject_uevent(&mk->kobj, KOBJ_ADD);
  			kobject_put(&mk->kobj);
  		}
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
  
  /* module-related sysfs stuff */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
898
899
900
901
902
903
904
905
906
907
908
909
  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...
910
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911

4befb026c   Kay Sievers   module: change at...
912
  	ret = attribute->show(attribute, mk, buf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
913

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
  	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...
929
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930

4befb026c   Kay Sievers   module: change at...
931
  	ret = attribute->store(attribute, mk, buf, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
934
  	return ret;
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
935
  static const struct sysfs_ops module_sysfs_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
936
937
938
  	.show = module_attr_show,
  	.store = module_attr_store,
  };
270a6c4ca   Kay Sievers   /sys/modules/*/ho...
939
940
941
942
943
944
945
946
  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   Emese Revfy   kobject: Constify...
947
  static const struct kset_uevent_ops module_uevent_ops = {
270a6c4ca   Kay Sievers   /sys/modules/*/ho...
948
949
  	.filter = uevent_filter,
  };
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
950
  struct kset *module_kset;
823bccfc4   Greg Kroah-Hartman   remove "struct su...
951
  int module_sysfs_initialized;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952

942e44312   Li Zhong   module: Fix mod->...
953
954
955
956
957
  static void module_kobj_release(struct kobject *kobj)
  {
  	struct module_kobject *mk = to_module_kobject(kobj);
  	complete(mk->kobj_completion);
  }
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
958
  struct kobj_type module_ktype = {
942e44312   Li Zhong   module: Fix mod->...
959
  	.release   =	module_kobj_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
  	.sysfs_ops =	&module_sysfs_ops,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
964
965
966
  /*
   * param_sysfs_init - wrapper for built-in params support
   */
  static int __init param_sysfs_init(void)
  {
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
967
968
969
970
971
972
  	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...
973
  	}
823bccfc4   Greg Kroah-Hartman   remove "struct su...
974
  	module_sysfs_initialized = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975

e94965ed5   Dmitry Torokhov   module: show vers...
976
  	version_sysfs_builtin();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
978
979
980
  	param_sysfs_builtin();
  
  	return 0;
  }
d10be6d1b   Mark Huang   [PATCH] module_su...
981
  subsys_initcall(param_sysfs_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
982

7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
983
  #endif /* CONFIG_SYSFS */