Blame view

kernel/params.c 22.7 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  /* Helpers for initial module or kernel cmdline parsing
     Copyright (C) 2001 Rusty Russell.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
  #include <linux/kernel.h>
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/module.h>
63a12d9d0   Geert Uytterhoeven   kernel/param: con...
9
  #include <linux/moduleparam.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
  #include <linux/device.h>
  #include <linux/err.h>
4e57b6817   Tim Schmielau   [PATCH] fix missi...
12
  #include <linux/slab.h>
26d052bfc   Peter Oberparleiter   param: allow whit...
13
  #include <linux/ctype.h>
20657f66e   David Howells   lockdown: Lock do...
14
  #include <linux/security.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15

cf2fde7b3   Rusty Russell   param: fix module...
16
  #ifdef CONFIG_SYSFS
b51d23e4e   Dan Streetman   module: add per-m...
17
  /* Protects all built-in parameters, modules use their own param_lock */
907b29eb4   Rusty Russell   param: locking fo...
18
  static DEFINE_MUTEX(param_lock);
b51d23e4e   Dan Streetman   module: add per-m...
19
  /* Use the module's mutex, or if built-in use the built-in mutex */
20bdc2cfd   Stephen Rothwell   modules: only use...
20
  #ifdef CONFIG_MODULES
b51d23e4e   Dan Streetman   module: add per-m...
21
  #define KPARAM_MUTEX(mod)	((mod) ? &(mod)->param_lock : &param_lock)
20bdc2cfd   Stephen Rothwell   modules: only use...
22
23
24
  #else
  #define KPARAM_MUTEX(mod)	(&param_lock)
  #endif
cf2fde7b3   Rusty Russell   param: fix module...
25
26
27
28
29
30
31
32
33
34
  
  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...
35

a1054322a   Rusty Russell   param: use free h...
36
37
38
39
40
  /* 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...
41
  static LIST_HEAD(kmalloced_params);
b51d23e4e   Dan Streetman   module: add per-m...
42
  static DEFINE_SPINLOCK(kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
43
44
45
46
47
48
49
50
  
  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...
51
  	spin_lock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
52
  	list_add(&p->list, &kmalloced_params);
b51d23e4e   Dan Streetman   module: add per-m...
53
  	spin_unlock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
54
55
56
57
58
59
60
  	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...
61
  	spin_lock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
62
63
64
65
66
67
68
  	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...
69
  	spin_unlock(&kmalloced_params_lock);
a1054322a   Rusty Russell   param: use free h...
70
  }
b1e4d20cb   Michal Schmidt   params: make dash...
71
  static char dash2underscore(char c)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
74
75
76
  {
  	if (c == '-')
  		return '_';
  	return c;
  }
b1e4d20cb   Michal Schmidt   params: make dash...
77
  bool parameqn(const char *a, const char *b, size_t n)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  {
b1e4d20cb   Michal Schmidt   params: make dash...
79
80
81
82
83
84
85
86
87
88
89
90
  	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
91
  }
20657f66e   David Howells   lockdown: Lock do...
92
  static bool param_check_unsafe(const struct kernel_param *kp)
7a486d378   Rusty Russell   param: check for ...
93
  {
20657f66e   David Howells   lockdown: Lock do...
94
95
96
  	if (kp->flags & KERNEL_PARAM_FL_HWPARAM &&
  	    security_locked_down(LOCKDOWN_MODULE_PARAMETERS))
  		return false;
7a486d378   Rusty Russell   param: check for ...
97
  	if (kp->flags & KERNEL_PARAM_FL_UNSAFE) {
edc41b3c5   Chris Wilson   kernel/params.c: ...
98
99
100
  		pr_notice("Setting dangerous option %s - tainting kernel
  ",
  			  kp->name);
7a486d378   Rusty Russell   param: check for ...
101
102
  		add_taint(TAINT_USER, LOCKDEP_STILL_OK);
  	}
20657f66e   David Howells   lockdown: Lock do...
103
104
  
  	return true;
7a486d378   Rusty Russell   param: check for ...
105
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
  static int parse_one(char *param,
  		     char *val,
9fb48c744   Jim Cromie   params: add 3rd a...
108
  		     const char *doing,
914dcaa84   Rusty Russell   param: make param...
109
  		     const struct kernel_param *params,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  		     unsigned num_params,
026cee008   Pawel Moll   params: <level>_i...
111
112
  		     s16 min_level,
  		     s16 max_level,
ecc861705   Luis R. Rodriguez   module: add extra...
113
  		     void *arg,
9fb48c744   Jim Cromie   params: add 3rd a...
114
  		     int (*handle_unknown)(char *param, char *val,
ecc861705   Luis R. Rodriguez   module: add extra...
115
  				     const char *doing, void *arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  {
  	unsigned int i;
907b29eb4   Rusty Russell   param: locking fo...
118
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
  
  	/* Find parameter */
  	for (i = 0; i < num_params; i++) {
  		if (parameq(param, params[i].name)) {
026cee008   Pawel Moll   params: <level>_i...
123
124
125
  			if (params[i].level < min_level
  			    || params[i].level > max_level)
  				return 0;
25985edce   Lucas De Marchi   Fix common misspe...
126
  			/* No one handled NULL, so do it here. */
ab013c5f6   Steven Rostedt   module: Add flag ...
127
  			if (!val &&
6a4c26431   Jani Nikula   module: rename KE...
128
  			    !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG))
2e9fb9953   Rusty Russell   params: don't han...
129
  				return -EINVAL;
9fb48c744   Jim Cromie   params: add 3rd a...
130
131
132
  			pr_debug("handling %s with %p
  ", param,
  				params[i].ops->set);
b51d23e4e   Dan Streetman   module: add per-m...
133
  			kernel_param_lock(params[i].mod);
20657f66e   David Howells   lockdown: Lock do...
134
135
136
137
  			if (param_check_unsafe(&params[i]))
  				err = params[i].ops->set(val, &params[i]);
  			else
  				err = -EPERM;
b51d23e4e   Dan Streetman   module: add per-m...
138
  			kernel_param_unlock(params[i].mod);
907b29eb4   Rusty Russell   param: locking fo...
139
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
141
142
143
  		}
  	}
  
  	if (handle_unknown) {
9fb48c744   Jim Cromie   params: add 3rd a...
144
145
  		pr_debug("doing %s: %s='%s'
  ", doing, param, val);
ecc861705   Luis R. Rodriguez   module: add extra...
146
  		return handle_unknown(param, val, doing, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	}
9fb48c744   Jim Cromie   params: add 3rd a...
148
149
  	pr_debug("Unknown argument '%s'
  ", param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
  	return -ENOENT;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  /* Args looks like "foo=bar,bar2 baz=fuz wiz". */
51e158c12   Rusty Russell   param: hand argum...
153
154
155
156
157
158
  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...
159
160
161
  		 void *arg,
  		 int (*unknown)(char *param, char *val,
  				const char *doing, void *arg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  {
74b22c465   Oleg Nesterov   params: don't ign...
163
  	char *param, *val, *err = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164

f36462f07   Rusty Russell   [PATCH] Ignore tr...
165
  	/* Chew leading spaces */
e7d2860b6   André Goddard Rosa   tree-wide: conver...
166
  	args = skip_spaces(args);
f36462f07   Rusty Russell   [PATCH] Ignore tr...
167

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

e0596c80f   Jean Delvare   kernel/params.c: ...
230
231
232
233
234
235
236
237
  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
238

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

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

3d9c637f4   Dan Streetman   module: export pa...
268
  void param_free_charp(void *arg)
a1054322a   Rusty Russell   param: use free h...
269
270
271
  {
  	maybe_kfree_parameter(*((char **)arg));
  }
3d9c637f4   Dan Streetman   module: export pa...
272
  EXPORT_SYMBOL(param_free_charp);
a1054322a   Rusty Russell   param: use free h...
273

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

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

9c27847dd   Luis R. Rodriguez   kernel/params: co...
299
  const struct kernel_param_ops param_ops_bool = {
6a4c26431   Jani Nikula   module: rename KE...
300
  	.flags = KERNEL_PARAM_OPS_FL_NOARG,
9bbb9e5a3   Rusty Russell   param: use ops in...
301
302
303
304
  	.set = param_set_bool,
  	.get = param_get_bool,
  };
  EXPORT_SYMBOL(param_ops_bool);
d19f05d8a   Luis R. Rodriguez   kernel/params.c: ...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
  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: ...
334
  EXPORT_SYMBOL_GPL(param_ops_bool_enable_only);
d19f05d8a   Luis R. Rodriguez   kernel/params.c: ...
335

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

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

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

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

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

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

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

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

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

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

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

b51d23e4e   Dan Streetman   module: add per-m...
577
578
  EXPORT_SYMBOL(kernel_param_lock);
  EXPORT_SYMBOL(kernel_param_unlock);
907b29eb4   Rusty Russell   param: locking fo...
579

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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