Blame view

kernel/params.c 23.2 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
  	return -ENOENT;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
51e158c12   Rusty Russell   param: hand argum...
158
159
160
161
162
163
  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...
164
165
166
  		 void *arg,
  		 int (*unknown)(char *param, char *val,
  				const char *doing, void *arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
  {
74b22c465   Oleg Nesterov   params: don't ign...
168
  	char *param, *val, *err = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169

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

1ef9eaf2b   Jim Cromie   params.c: fix Sma...
173
  	if (*args)
9fb48c744   Jim Cromie   params: add 3rd a...
174
175
  		pr_debug("doing %s, parsing ARGS: '%s'
  ", doing, args);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
  	while (*args) {
  		int ret;
a416aba63   Ard van Breemen   [PATCH] kernelpar...
178
  		int irq_was_disabled;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
179
180
  
  		args = next_arg(args, &param, &val);
51e158c12   Rusty Russell   param: hand argum...
181
182
  		/* Stop at -- */
  		if (!val && strcmp(param, "--") == 0)
74b22c465   Oleg Nesterov   params: don't ign...
183
  			return err ?: args;
a416aba63   Ard van Breemen   [PATCH] kernelpar...
184
  		irq_was_disabled = irqs_disabled();
9fb48c744   Jim Cromie   params: add 3rd a...
185
  		ret = parse_one(param, val, doing, params, num,
ecc861705   Luis R. Rodriguez   module: add extra...
186
  				min_level, max_level, arg, unknown);
b5f3abf95   Jim Cromie   params: replace p...
187
188
189
190
  		if (irq_was_disabled && !irqs_disabled())
  			pr_warn("%s: option '%s' enabled irq's!
  ",
  				doing, param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  		switch (ret) {
74b22c465   Oleg Nesterov   params: don't ign...
192
193
  		case 0:
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  		case -ENOENT:
b5f3abf95   Jim Cromie   params: replace p...
195
196
  			pr_err("%s: Unknown parameter `%s'
  ", doing, param);
74b22c465   Oleg Nesterov   params: don't ign...
197
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  		case -ENOSPC:
b5f3abf95   Jim Cromie   params: replace p...
199
200
  			pr_err("%s: `%s' too large for parameter `%s'
  ",
9fb48c744   Jim Cromie   params: add 3rd a...
201
  			       doing, val ?: "", param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
  			break;
  		default:
b5f3abf95   Jim Cromie   params: replace p...
204
205
  			pr_err("%s: `%s' invalid for parameter `%s'
  ",
9fb48c744   Jim Cromie   params: add 3rd a...
206
  			       doing, val ?: "", param);
74b22c465   Oleg Nesterov   params: don't ign...
207
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  		}
74b22c465   Oleg Nesterov   params: don't ign...
209
210
  
  		err = ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  	}
74b22c465   Oleg Nesterov   params: don't ign...
212
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
  }
  
  /* Lazy bastard, eh? */
88a88b320   Felipe Contreras   params: improve s...
216
  #define STANDARD_PARAM_DEF(name, type, format, strtolfn)      		\
9bbb9e5a3   Rusty Russell   param: use ops in...
217
  	int param_set_##name(const char *val, const struct kernel_param *kp) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	{								\
88a88b320   Felipe Contreras   params: improve s...
219
  		return strtolfn(val, 0, (type *)kp->arg);		\
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
  	}								\
9bbb9e5a3   Rusty Russell   param: use ops in...
221
  	int param_get_##name(char *buffer, const struct kernel_param *kp) \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
  	{								\
96802e6b1   Jean Delvare   kernel/params.c: ...
223
224
  		return scnprintf(buffer, PAGE_SIZE, format "
  ",	\
f4940ab7c   Chen Gang   kernel/params.c: ...
225
  				*((type *)kp->arg));			\
a14fe249a   Rusty Russell   param: move the E...
226
  	}								\
9c27847dd   Luis R. Rodriguez   kernel/params: co...
227
  	const struct kernel_param_ops param_ops_##name = {			\
9bbb9e5a3   Rusty Russell   param: use ops in...
228
229
230
  		.set = param_set_##name,				\
  		.get = param_get_##name,				\
  	};								\
a14fe249a   Rusty Russell   param: move the E...
231
  	EXPORT_SYMBOL(param_set_##name);				\
9bbb9e5a3   Rusty Russell   param: use ops in...
232
233
  	EXPORT_SYMBOL(param_get_##name);				\
  	EXPORT_SYMBOL(param_ops_##name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234

e0596c80f   Jean Delvare   kernel/params.c: ...
235
236
237
238
239
240
241
242
  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);
  STANDARD_PARAM_DEF(ullong,	unsigned long long,	"%llu", kstrtoull);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243

9bbb9e5a3   Rusty Russell   param: use ops in...
244
  int param_set_charp(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  	if (strlen(val) > 1024) {
b5f3abf95   Jim Cromie   params: replace p...
247
248
  		pr_err("%s: string parameter too long
  ", kp->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
  		return -ENOSPC;
  	}
a1054322a   Rusty Russell   param: use free h...
251
252
253
  	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 ...
254
255
  	 * don't need to; this mangled commandline is preserved. */
  	if (slab_is_available()) {
a1054322a   Rusty Russell   param: use free h...
256
  		*(char **)kp->arg = kmalloc_parameter(strlen(val)+1);
d553ad864   Rusty Russell   param: fix NULL c...
257
  		if (!*(char **)kp->arg)
e180a6b77   Rusty Russell   param: fix charp ...
258
  			return -ENOMEM;
a1054322a   Rusty Russell   param: use free h...
259
  		strcpy(*(char **)kp->arg, val);
e180a6b77   Rusty Russell   param: fix charp ...
260
261
  	} else
  		*(const char **)kp->arg = val;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
  	return 0;
  }
a14fe249a   Rusty Russell   param: move the E...
264
  EXPORT_SYMBOL(param_set_charp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

9bbb9e5a3   Rusty Russell   param: use ops in...
266
  int param_get_charp(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
  {
96802e6b1   Jean Delvare   kernel/params.c: ...
268
269
  	return scnprintf(buffer, PAGE_SIZE, "%s
  ", *((char **)kp->arg));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  }
a14fe249a   Rusty Russell   param: move the E...
271
  EXPORT_SYMBOL(param_get_charp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272

3d9c637f4   Dan Streetman   module: export pa...
273
  void param_free_charp(void *arg)
a1054322a   Rusty Russell   param: use free h...
274
275
276
  {
  	maybe_kfree_parameter(*((char **)arg));
  }
3d9c637f4   Dan Streetman   module: export pa...
277
  EXPORT_SYMBOL(param_free_charp);
a1054322a   Rusty Russell   param: use free h...
278

9c27847dd   Luis R. Rodriguez   kernel/params: co...
279
  const struct kernel_param_ops param_ops_charp = {
9bbb9e5a3   Rusty Russell   param: use ops in...
280
281
  	.set = param_set_charp,
  	.get = param_get_charp,
a1054322a   Rusty Russell   param: use free h...
282
  	.free = param_free_charp,
9bbb9e5a3   Rusty Russell   param: use ops in...
283
284
  };
  EXPORT_SYMBOL(param_ops_charp);
fddd52012   Rusty Russell   module_param: all...
285
  /* Actually could be a bool or an int, for historical reasons. */
9bbb9e5a3   Rusty Russell   param: use ops in...
286
  int param_set_bool(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
  {
  	/* No equals means "set"... */
  	if (!val) val = "1";
  
  	/* One of =[yYnN01] */
8b8252813   Rusty Russell   module_param: rem...
292
  	return strtobool(val, kp->arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  }
a14fe249a   Rusty Russell   param: move the E...
294
  EXPORT_SYMBOL(param_set_bool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295

9bbb9e5a3   Rusty Russell   param: use ops in...
296
  int param_get_bool(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  {
  	/* Y and N chosen as being relatively non-coder friendly */
96802e6b1   Jean Delvare   kernel/params.c: ...
299
300
  	return sprintf(buffer, "%c
  ", *(bool *)kp->arg ? 'Y' : 'N');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  }
a14fe249a   Rusty Russell   param: move the E...
302
  EXPORT_SYMBOL(param_get_bool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303

9c27847dd   Luis R. Rodriguez   kernel/params: co...
304
  const struct kernel_param_ops param_ops_bool = {
6a4c26431   Jani Nikula   module: rename KE...
305
  	.flags = KERNEL_PARAM_OPS_FL_NOARG,
9bbb9e5a3   Rusty Russell   param: use ops in...
306
307
308
309
  	.set = param_set_bool,
  	.get = param_get_bool,
  };
  EXPORT_SYMBOL(param_ops_bool);
d19f05d8a   Luis R. Rodriguez   kernel/params.c: ...
310
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
  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: ...
339
  EXPORT_SYMBOL_GPL(param_ops_bool_enable_only);
d19f05d8a   Luis R. Rodriguez   kernel/params.c: ...
340

fddd52012   Rusty Russell   module_param: all...
341
  /* This one must be bool. */
9bbb9e5a3   Rusty Russell   param: use ops in...
342
  int param_set_invbool(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
343
  {
fddd52012   Rusty Russell   module_param: all...
344
345
  	int ret;
  	bool boolval;
22e48eaf5   Jan Beulich   constify string/a...
346
  	struct kernel_param dummy;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347

22e48eaf5   Jan Beulich   constify string/a...
348
  	dummy.arg = &boolval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
350
  	ret = param_set_bool(val, &dummy);
  	if (ret == 0)
9a71af2c3   Rusty Russell   module_param: inv...
351
  		*(bool *)kp->arg = !boolval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
353
  	return ret;
  }
a14fe249a   Rusty Russell   param: move the E...
354
  EXPORT_SYMBOL(param_set_invbool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355

9bbb9e5a3   Rusty Russell   param: use ops in...
356
  int param_get_invbool(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
  {
96802e6b1   Jean Delvare   kernel/params.c: ...
358
359
  	return sprintf(buffer, "%c
  ", (*(bool *)kp->arg) ? 'N' : 'Y');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  }
a14fe249a   Rusty Russell   param: move the E...
361
  EXPORT_SYMBOL(param_get_invbool);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362

9c27847dd   Luis R. Rodriguez   kernel/params: co...
363
  const struct kernel_param_ops param_ops_invbool = {
9bbb9e5a3   Rusty Russell   param: use ops in...
364
365
366
367
  	.set = param_set_invbool,
  	.get = param_get_invbool,
  };
  EXPORT_SYMBOL(param_ops_invbool);
69116f279   Rusty Russell   module_param: avo...
368
369
  int param_set_bint(const char *val, const struct kernel_param *kp)
  {
5104b7d76   Dan Streetman   module: make perm...
370
371
  	/* Match bool exactly, by re-using it. */
  	struct kernel_param boolkp = *kp;
69116f279   Rusty Russell   module_param: avo...
372
373
  	bool v;
  	int ret;
69116f279   Rusty Russell   module_param: avo...
374
  	boolkp.arg = &v;
69116f279   Rusty Russell   module_param: avo...
375
376
377
378
379
380
381
  
  	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...
382
  const struct kernel_param_ops param_ops_bint = {
6a4c26431   Jani Nikula   module: rename KE...
383
  	.flags = KERNEL_PARAM_OPS_FL_NOARG,
69116f279   Rusty Russell   module_param: avo...
384
385
386
387
  	.set = param_set_bint,
  	.get = param_get_int,
  };
  EXPORT_SYMBOL(param_ops_bint);
9730b5b06   Bert Wesarg   kernel/params.c: ...
388
  /* We break the rule and mangle the string. */
b51d23e4e   Dan Streetman   module: add per-m...
389
390
  static int param_array(struct module *mod,
  		       const char *name,
9871728b7   Adrian Bunk   [PATCH] kernel/pa...
391
392
393
  		       const char *val,
  		       unsigned int min, unsigned int max,
  		       void *elem, int elemsize,
9bbb9e5a3   Rusty Russell   param: use ops in...
394
  		       int (*set)(const char *, const struct kernel_param *kp),
026cee008   Pawel Moll   params: <level>_i...
395
  		       s16 level,
eb38a996e   Richard Knutsson   kernel/params.c: ...
396
  		       unsigned int *num)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
  {
  	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...
405
  	kp.level = level;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
407
408
409
410
411
412
  	*num = 0;
  	/* We expect a comma-separated list of values. */
  	do {
  		int len;
  
  		if (*num == max) {
b5f3abf95   Jim Cromie   params: replace p...
413
414
  			pr_err("%s: can only take %i arguments
  ", name, max);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
420
421
  			return -EINVAL;
  		}
  		len = strcspn(val, ",");
  
  		/* nul-terminate and parse */
  		save = val[len];
  		((char *)val)[len] = '\0';
cf2fde7b3   Rusty Russell   param: fix module...
422
  		check_kparam_locked(mod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
424
425
426
427
428
429
430
431
432
  		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...
433
434
  		pr_err("%s: needs at least %i arguments
  ", name, min);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
  		return -EINVAL;
  	}
  	return 0;
  }
9bbb9e5a3   Rusty Russell   param: use ops in...
439
  static int param_array_set(const char *val, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  {
22e48eaf5   Jan Beulich   constify string/a...
441
  	const struct kparam_array *arr = kp->arr;
31143a120   Bert Wesarg   [PATCH] kernel/pa...
442
  	unsigned int temp_num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  	for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
96802e6b1   Jean Delvare   kernel/params.c: ...
455
456
  		/* Replace 
   with comma */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  		if (i)
96802e6b1   Jean Delvare   kernel/params.c: ...
458
  			buffer[off - 1] = ',';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  		p.arg = arr->elem + arr->elemsize * i;
cf2fde7b3   Rusty Russell   param: fix module...
460
  		check_kparam_locked(p.mod);
9bbb9e5a3   Rusty Russell   param: use ops in...
461
  		ret = arr->ops->get(buffer + off, &p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
467
468
  		if (ret < 0)
  			return ret;
  		off += ret;
  	}
  	buffer[off] = '\0';
  	return off;
  }
e6df34a44   Rusty Russell   param: add a free...
469
470
471
472
473
474
475
476
477
  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...
478
  const struct kernel_param_ops param_array_ops = {
9bbb9e5a3   Rusty Russell   param: use ops in...
479
480
  	.set = param_array_set,
  	.get = param_array_get,
e6df34a44   Rusty Russell   param: add a free...
481
  	.free = param_array_free,
9bbb9e5a3   Rusty Russell   param: use ops in...
482
483
484
485
  };
  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
486
  {
22e48eaf5   Jan Beulich   constify string/a...
487
  	const struct kparam_string *kps = kp->str;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
  
  	if (strlen(val)+1 > kps->maxlen) {
b5f3abf95   Jim Cromie   params: replace p...
490
491
  		pr_err("%s: string doesn't fit in %u chars.
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
495
496
497
  		       kp->name, kps->maxlen-1);
  		return -ENOSPC;
  	}
  	strcpy(kps->string, val);
  	return 0;
  }
a14fe249a   Rusty Russell   param: move the E...
498
  EXPORT_SYMBOL(param_set_copystring);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
499

9bbb9e5a3   Rusty Russell   param: use ops in...
500
  int param_get_string(char *buffer, const struct kernel_param *kp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  {
22e48eaf5   Jan Beulich   constify string/a...
502
  	const struct kparam_string *kps = kp->str;
96802e6b1   Jean Delvare   kernel/params.c: ...
503
504
  	return scnprintf(buffer, PAGE_SIZE, "%s
  ", kps->string);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  }
a14fe249a   Rusty Russell   param: move the E...
506
  EXPORT_SYMBOL(param_get_string);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507

9c27847dd   Luis R. Rodriguez   kernel/params: co...
508
  const struct kernel_param_ops param_ops_string = {
9bbb9e5a3   Rusty Russell   param: use ops in...
509
510
511
512
  	.set = param_set_copystring,
  	.get = param_get_string,
  };
  EXPORT_SYMBOL(param_ops_string);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  /* sysfs output in /sys/modules/XYZ/parameters/ */
350f82586   Edward Z. Yang   Remove redundant ...
514
515
  #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
516

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
  struct param_attribute
  {
  	struct module_attribute mattr;
9bbb9e5a3   Rusty Russell   param: use ops in...
520
  	const struct kernel_param *param;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
  };
  
  struct module_param_attrs
  {
9b473de87   Rusty Russell   param: Fix duplic...
525
  	unsigned int num;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
  	struct attribute_group grp;
  	struct param_attribute attrs[0];
  };
ef665c1a0   Randy Dunlap   sysfs: fix build ...
529
  #ifdef CONFIG_SYSFS
350f82586   Edward Z. Yang   Remove redundant ...
530
  #define to_param_attr(n) container_of(n, struct param_attribute, mattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
  
  static ssize_t param_attr_show(struct module_attribute *mattr,
4befb026c   Kay Sievers   module: change at...
533
  			       struct module_kobject *mk, char *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
  {
  	int count;
  	struct param_attribute *attribute = to_param_attr(mattr);
9bbb9e5a3   Rusty Russell   param: use ops in...
537
  	if (!attribute->param->ops->get)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
  		return -EPERM;
b51d23e4e   Dan Streetman   module: add per-m...
539
  	kernel_param_lock(mk->mod);
9bbb9e5a3   Rusty Russell   param: use ops in...
540
  	count = attribute->param->ops->get(buf, attribute->param);
b51d23e4e   Dan Streetman   module: add per-m...
541
  	kernel_param_unlock(mk->mod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
  	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...
547
  				struct module_kobject *mk,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
549
550
551
  				const char *buf, size_t len)
  {
   	int err;
  	struct param_attribute *attribute = to_param_attr(mattr);
9bbb9e5a3   Rusty Russell   param: use ops in...
552
  	if (!attribute->param->ops->set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  		return -EPERM;
b51d23e4e   Dan Streetman   module: add per-m...
554
  	kernel_param_lock(mk->mod);
7a486d378   Rusty Russell   param: check for ...
555
  	param_check_unsafe(attribute->param);
9bbb9e5a3   Rusty Russell   param: use ops in...
556
  	err = attribute->param->ops->set(buf, attribute->param);
b51d23e4e   Dan Streetman   module: add per-m...
557
  	kernel_param_unlock(mk->mod);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
561
  	if (!err)
  		return len;
  	return err;
  }
ef665c1a0   Randy Dunlap   sysfs: fix build ...
562
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
  
  #ifdef CONFIG_MODULES
  #define __modinit
  #else
  #define __modinit __init
  #endif
ef665c1a0   Randy Dunlap   sysfs: fix build ...
569
  #ifdef CONFIG_SYSFS
b51d23e4e   Dan Streetman   module: add per-m...
570
  void kernel_param_lock(struct module *mod)
907b29eb4   Rusty Russell   param: locking fo...
571
  {
b51d23e4e   Dan Streetman   module: add per-m...
572
  	mutex_lock(KPARAM_MUTEX(mod));
907b29eb4   Rusty Russell   param: locking fo...
573
  }
907b29eb4   Rusty Russell   param: locking fo...
574

b51d23e4e   Dan Streetman   module: add per-m...
575
  void kernel_param_unlock(struct module *mod)
907b29eb4   Rusty Russell   param: locking fo...
576
  {
b51d23e4e   Dan Streetman   module: add per-m...
577
  	mutex_unlock(KPARAM_MUTEX(mod));
907b29eb4   Rusty Russell   param: locking fo...
578
  }
b51d23e4e   Dan Streetman   module: add per-m...
579

b51d23e4e   Dan Streetman   module: add per-m...
580
581
  EXPORT_SYMBOL(kernel_param_lock);
  EXPORT_SYMBOL(kernel_param_unlock);
907b29eb4   Rusty Russell   param: locking fo...
582

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  /*
9b473de87   Rusty Russell   param: Fix duplic...
584
585
   * add_sysfs_param - add a parameter to sysfs
   * @mk: struct module_kobject
630cc2b30   Jean Delvare   kernel/params.c: ...
586
   * @kp: the actual parameter definition to add to sysfs
9b473de87   Rusty Russell   param: Fix duplic...
587
   * @name: name of parameter
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
   *
9b473de87   Rusty Russell   param: Fix duplic...
589
590
591
   * 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
592
   */
9b473de87   Rusty Russell   param: Fix duplic...
593
  static __modinit int add_sysfs_param(struct module_kobject *mk,
9bbb9e5a3   Rusty Russell   param: use ops in...
594
  				     const struct kernel_param *kp,
9b473de87   Rusty Russell   param: Fix duplic...
595
  				     const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  {
18eb74fa9   Rusty Russell   params: cleanup s...
597
598
599
  	struct module_param_attrs *new_mp;
  	struct attribute **new_attrs;
  	unsigned int i;
9b473de87   Rusty Russell   param: Fix duplic...
600
601
602
603
604
  
  	/* We don't bother calling this with invisible parameters. */
  	BUG_ON(!kp->perm);
  
  	if (!mk->mp) {
18eb74fa9   Rusty Russell   params: cleanup s...
605
606
607
608
609
610
611
612
613
614
615
  		/* 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...
616
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617

18eb74fa9   Rusty Russell   params: cleanup s...
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  	/* 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...
634
635
  
  	/* Tack new one on the end. */
c772be523   Rusty Russell   param: fix uninit...
636
  	memset(&mk->mp->attrs[mk->mp->num], 0, sizeof(mk->mp->attrs[0]));
18eb74fa9   Rusty Russell   params: cleanup s...
637
638
639
  	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...
640
641
642
  	/* 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...
643
644
  	else
  		mk->mp->attrs[mk->mp->num].mattr.store = NULL;
18eb74fa9   Rusty Russell   params: cleanup s...
645
646
647
  	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...
648
649
  
  	/* Fix up all the pointers, since krealloc can move us */
18eb74fa9   Rusty Russell   params: cleanup s...
650
651
652
  	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...
653
  	return 0;
9b473de87   Rusty Russell   param: Fix duplic...
654
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655

d2441183d   Linus Torvalds   Fix compile warni...
656
  #ifdef CONFIG_MODULES
9b473de87   Rusty Russell   param: Fix duplic...
657
658
  static void free_module_param_attrs(struct module_kobject *mk)
  {
18eb74fa9   Rusty Russell   params: cleanup s...
659
660
  	if (mk->mp)
  		kfree(mk->mp->grp.attrs);
9b473de87   Rusty Russell   param: Fix duplic...
661
662
  	kfree(mk->mp);
  	mk->mp = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
664
665
666
667
668
669
  /*
   * 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...
670
671
   * Adds sysfs entries for module parameters under
   * /sys/module/[mod->name]/parameters/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
   */
  int module_param_sysfs_setup(struct module *mod,
9bbb9e5a3   Rusty Russell   param: use ops in...
674
  			     const struct kernel_param *kparam,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
676
  			     unsigned int num_params)
  {
9b473de87   Rusty Russell   param: Fix duplic...
677
678
679
680
681
682
683
  	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...
684
685
  		if (err) {
  			free_module_param_attrs(&mod->mkobj);
9b473de87   Rusty Russell   param: Fix duplic...
686
  			return err;
18eb74fa9   Rusty Russell   params: cleanup s...
687
  		}
9b473de87   Rusty Russell   param: Fix duplic...
688
689
  		params = true;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690

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

9b473de87   Rusty Russell   param: Fix duplic...
694
695
696
697
698
  	/* 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
699
700
701
702
703
704
705
706
707
708
709
  }
  
  /*
   * 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...
710
711
  	if (mod->mkobj.mp) {
  		sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
  		/* We are positive that no one is using any param
  		 * attrs at this point.  Deallocate immediately. */
9b473de87   Rusty Russell   param: Fix duplic...
714
  		free_module_param_attrs(&mod->mkobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  	}
  }
  #endif
e180a6b77   Rusty Russell   param: fix charp ...
718
719
  void destroy_params(const struct kernel_param *params, unsigned num)
  {
e6df34a44   Rusty Russell   param: add a free...
720
721
722
723
724
  	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 ...
725
  }
e94965ed5   Dmitry Torokhov   module: show vers...
726
  static struct module_kobject * __init locate_module_kobject(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
  {
  	struct module_kobject *mk;
9b473de87   Rusty Russell   param: Fix duplic...
729
730
  	struct kobject *kobj;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731

9b473de87   Rusty Russell   param: Fix duplic...
732
733
  	kobj = kset_find_obj(module_kset, name);
  	if (kobj) {
9b473de87   Rusty Russell   param: Fix duplic...
734
  		mk = to_module_kobject(kobj);
9b473de87   Rusty Russell   param: Fix duplic...
735
736
737
738
739
740
741
742
  	} 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/...
743
744
745
746
  #ifdef CONFIG_MODULES
  		if (!err)
  			err = sysfs_create_file(&mk->kobj, &module_uevent.attr);
  #endif
9b473de87   Rusty Russell   param: Fix duplic...
747
748
  		if (err) {
  			kobject_put(&mk->kobj);
b5f3abf95   Jim Cromie   params: replace p...
749
750
  			pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.
  ",
e94965ed5   Dmitry Torokhov   module: show vers...
751
  				name, err);
e94965ed5   Dmitry Torokhov   module: show vers...
752
  			return NULL;
9b473de87   Rusty Russell   param: Fix duplic...
753
  		}
e94965ed5   Dmitry Torokhov   module: show vers...
754
755
  
  		/* So that we hold reference in both cases. */
9b473de87   Rusty Russell   param: Fix duplic...
756
  		kobject_get(&mk->kobj);
74c5b597e   Greg Kroah-Hartman   modules: better e...
757
  	}
9b473de87   Rusty Russell   param: Fix duplic...
758

e94965ed5   Dmitry Torokhov   module: show vers...
759
760
761
762
  	return mk;
  }
  
  static void __init kernel_add_sysfs_param(const char *name,
63a12d9d0   Geert Uytterhoeven   kernel/param: con...
763
  					  const struct kernel_param *kparam,
e94965ed5   Dmitry Torokhov   module: show vers...
764
765
766
767
768
769
770
771
772
773
774
775
  					  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...
776
777
778
779
780
  	/* 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 ...
781
  	kobject_uevent(&mk->kobj, KOBJ_ADD);
9b473de87   Rusty Russell   param: Fix duplic...
782
  	kobject_put(&mk->kobj);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
784
785
  }
  
  /*
b634d130e   Jean Delvare   There is no /sys/...
786
   * param_sysfs_builtin - add sysfs parameters for built-in modules
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
791
792
   *
   * 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...
793
   * and for all who have the same, call kernel_add_sysfs_param.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
794
795
796
   */
  static void __init param_sysfs_builtin(void)
  {
63a12d9d0   Geert Uytterhoeven   kernel/param: con...
797
  	const struct kernel_param *kp;
9b473de87   Rusty Russell   param: Fix duplic...
798
799
  	unsigned int name_len;
  	char modname[MODULE_NAME_LEN];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800

9b473de87   Rusty Russell   param: Fix duplic...
801
  	for (kp = __start___param; kp < __stop___param; kp++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  		char *dot;
9b473de87   Rusty Russell   param: Fix duplic...
803
804
  		if (kp->perm == 0)
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805

730b69d22   Rusty Russell   module: check ker...
806
  		dot = strchr(kp->name, '.');
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  		if (!dot) {
67e67ceaa   Rusty Russell   core_param() for ...
808
809
810
811
812
813
  			/* 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
814
  		}
67e67ceaa   Rusty Russell   core_param() for ...
815
  		kernel_add_sysfs_param(modname, kp, name_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
  }
e94965ed5   Dmitry Torokhov   module: show vers...
818
  ssize_t __modver_version_show(struct module_attribute *mattr,
4befb026c   Kay Sievers   module: change at...
819
  			      struct module_kobject *mk, char *buf)
e94965ed5   Dmitry Torokhov   module: show vers...
820
821
822
  {
  	struct module_version_attribute *vattr =
  		container_of(mattr, struct module_version_attribute, mattr);
f4940ab7c   Chen Gang   kernel/params.c: ...
823
824
  	return scnprintf(buf, PAGE_SIZE, "%s
  ", vattr->version);
e94965ed5   Dmitry Torokhov   module: show vers...
825
  }
b4bc84280   Dmitry Torokhov   module: deal with...
826
827
  extern const struct module_version_attribute *__start___modver[];
  extern const struct module_version_attribute *__stop___modver[];
e94965ed5   Dmitry Torokhov   module: show vers...
828
829
830
  
  static void __init version_sysfs_builtin(void)
  {
b4bc84280   Dmitry Torokhov   module: deal with...
831
  	const struct module_version_attribute **p;
e94965ed5   Dmitry Torokhov   module: show vers...
832
833
  	struct module_kobject *mk;
  	int err;
b4bc84280   Dmitry Torokhov   module: deal with...
834
835
  	for (p = __start___modver; p < __stop___modver; p++) {
  		const struct module_version_attribute *vattr = *p;
e94965ed5   Dmitry Torokhov   module: show vers...
836
837
838
  		mk = locate_module_kobject(vattr->module_name);
  		if (mk) {
  			err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
74c3dea35   Rusty Russell   params: suppress ...
839
  			WARN_ON_ONCE(err);
e94965ed5   Dmitry Torokhov   module: show vers...
840
841
842
843
844
  			kobject_uevent(&mk->kobj, KOBJ_ADD);
  			kobject_put(&mk->kobj);
  		}
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
  
  /* module-related sysfs stuff */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
850
851
852
853
854
855
856
857
858
859
  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...
860
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
  	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...
879
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
  	return ret;
  }
52cf25d0a   Emese Revfy   Driver core: Cons...
885
  static const struct sysfs_ops module_sysfs_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
887
888
  	.show = module_attr_show,
  	.store = module_attr_store,
  };
270a6c4ca   Kay Sievers   /sys/modules/*/ho...
889
890
891
892
893
894
895
896
  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...
897
  static const struct kset_uevent_ops module_uevent_ops = {
270a6c4ca   Kay Sievers   /sys/modules/*/ho...
898
899
  	.filter = uevent_filter,
  };
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
900
  struct kset *module_kset;
823bccfc4   Greg Kroah-Hartman   remove "struct su...
901
  int module_sysfs_initialized;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902

942e44312   Li Zhong   module: Fix mod->...
903
904
905
906
907
  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...
908
  struct kobj_type module_ktype = {
942e44312   Li Zhong   module: Fix mod->...
909
  	.release   =	module_kobj_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
  	.sysfs_ops =	&module_sysfs_ops,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
914
915
916
  /*
   * param_sysfs_init - wrapper for built-in params support
   */
  static int __init param_sysfs_init(void)
  {
7405c1e15   Greg Kroah-Hartman   kset: convert /sy...
917
918
919
920
921
922
  	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...
923
  	}
823bccfc4   Greg Kroah-Hartman   remove "struct su...
924
  	module_sysfs_initialized = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925

e94965ed5   Dmitry Torokhov   module: show vers...
926
  	version_sysfs_builtin();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
  	param_sysfs_builtin();
  
  	return 0;
  }
d10be6d1b   Mark Huang   [PATCH] module_su...
931
  subsys_initcall(param_sysfs_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932

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