Blame view

kernel/params.c 22.8 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

7d8365771   Paul Menzel   moduleparams: Add...
230
231
232
233
234
235
236
237
238
  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);
  STANDARD_PARAM_DEF(hexint,	unsigned int,		"%#08x", 	kstrtouint);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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