params.c 22.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/* Helpers for initial module or kernel cmdline parsing
   Copyright (C) 2001 Rusty Russell.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
T
Tim Schmielau 已提交
24
#include <linux/slab.h>
25
#include <linux/ctype.h>
L
Linus Torvalds 已提交
26

27 28 29
/* Protects all parameters, and incidentally kmalloced_param list. */
static DEFINE_MUTEX(param_lock);

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
/* This just allows us to keep track of which parameters are kmalloced. */
struct kmalloced_param {
	struct list_head list;
	char val[];
};
static LIST_HEAD(kmalloced_params);

static void *kmalloc_parameter(unsigned int size)
{
	struct kmalloced_param *p;

	p = kmalloc(sizeof(*p) + size, GFP_KERNEL);
	if (!p)
		return NULL;

	list_add(&p->list, &kmalloced_params);
	return p->val;
}

/* Does nothing if parameter wasn't kmalloced above. */
static void maybe_kfree_parameter(void *param)
{
	struct kmalloced_param *p;

	list_for_each_entry(p, &kmalloced_params, list) {
		if (p->val == param) {
			list_del(&p->list);
			kfree(p);
			break;
		}
	}
}

63
static char dash2underscore(char c)
L
Linus Torvalds 已提交
64 65 66 67 68 69
{
	if (c == '-')
		return '_';
	return c;
}

70
bool parameqn(const char *a, const char *b, size_t n)
L
Linus Torvalds 已提交
71
{
72 73 74 75 76 77 78 79 80 81 82 83
	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);
L
Linus Torvalds 已提交
84 85 86 87
}

static int parse_one(char *param,
		     char *val,
88
		     const char *doing,
89
		     const struct kernel_param *params,
L
Linus Torvalds 已提交
90
		     unsigned num_params,
91 92
		     s16 min_level,
		     s16 max_level,
93 94
		     int (*handle_unknown)(char *param, char *val,
				     const char *doing))
L
Linus Torvalds 已提交
95 96
{
	unsigned int i;
97
	int err;
L
Linus Torvalds 已提交
98 99 100 101

	/* Find parameter */
	for (i = 0; i < num_params; i++) {
		if (parameq(param, params[i].name)) {
102 103 104
			if (params[i].level < min_level
			    || params[i].level > max_level)
				return 0;
L
Lucas De Marchi 已提交
105
			/* No one handled NULL, so do it here. */
106 107
			if (!val &&
			    !(params[i].ops->flags & KERNEL_PARAM_FL_NOARG))
108
				return -EINVAL;
109 110
			pr_debug("handling %s with %p\n", param,
				params[i].ops->set);
111 112 113 114
			mutex_lock(&param_lock);
			err = params[i].ops->set(val, &params[i]);
			mutex_unlock(&param_lock);
			return err;
L
Linus Torvalds 已提交
115 116 117 118
		}
	}

	if (handle_unknown) {
119 120
		pr_debug("doing %s: %s='%s'\n", doing, param, val);
		return handle_unknown(param, val, doing);
L
Linus Torvalds 已提交
121 122
	}

123
	pr_debug("Unknown argument '%s'\n", param);
L
Linus Torvalds 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
	return -ENOENT;
}

/* You can use " around spaces, but can't escape ". */
/* Hyphens and underscores equivalent in parameter names. */
static char *next_arg(char *args, char **param, char **val)
{
	unsigned int i, equals = 0;
	int in_quote = 0, quoted = 0;
	char *next;

	if (*args == '"') {
		args++;
		in_quote = 1;
		quoted = 1;
	}

	for (i = 0; args[i]; i++) {
142
		if (isspace(args[i]) && !in_quote)
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
			break;
		if (equals == 0) {
			if (args[i] == '=')
				equals = i;
		}
		if (args[i] == '"')
			in_quote = !in_quote;
	}

	*param = args;
	if (!equals)
		*val = NULL;
	else {
		args[equals] = '\0';
		*val = args + equals + 1;

		/* Don't include quotes in value. */
		if (**val == '"') {
			(*val)++;
			if (args[i-1] == '"')
				args[i-1] = '\0';
		}
		if (quoted && args[i-1] == '"')
			args[i-1] = '\0';
	}

	if (args[i]) {
		args[i] = '\0';
		next = args + i + 1;
	} else
		next = args + i;
174 175

	/* Chew up trailing spaces. */
176
	return skip_spaces(next);
L
Linus Torvalds 已提交
177 178 179
}

/* Args looks like "foo=bar,bar2 baz=fuz wiz". */
180
int parse_args(const char *doing,
L
Linus Torvalds 已提交
181
	       char *args,
182
	       const struct kernel_param *params,
L
Linus Torvalds 已提交
183
	       unsigned num,
184 185
	       s16 min_level,
	       s16 max_level,
186
	       int (*unknown)(char *param, char *val, const char *doing))
L
Linus Torvalds 已提交
187 188 189
{
	char *param, *val;

190
	/* Chew leading spaces */
191
	args = skip_spaces(args);
192

193
	if (*args)
194 195
		pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);

L
Linus Torvalds 已提交
196 197
	while (*args) {
		int ret;
198
		int irq_was_disabled;
L
Linus Torvalds 已提交
199 200

		args = next_arg(args, &param, &val);
201
		irq_was_disabled = irqs_disabled();
202
		ret = parse_one(param, val, doing, params, num,
203
				min_level, max_level, unknown);
204 205 206 207
		if (irq_was_disabled && !irqs_disabled())
			pr_warn("%s: option '%s' enabled irq's!\n",
				doing, param);

L
Linus Torvalds 已提交
208 209
		switch (ret) {
		case -ENOENT:
210
			pr_err("%s: Unknown parameter `%s'\n", doing, param);
L
Linus Torvalds 已提交
211 212
			return ret;
		case -ENOSPC:
213
			pr_err("%s: `%s' too large for parameter `%s'\n",
214
			       doing, val ?: "", param);
L
Linus Torvalds 已提交
215 216 217 218
			return ret;
		case 0:
			break;
		default:
219
			pr_err("%s: `%s' invalid for parameter `%s'\n",
220
			       doing, val ?: "", param);
L
Linus Torvalds 已提交
221 222 223 224 225 226 227 228 229 230
			return ret;
		}
	}

	/* All parsed OK. */
	return 0;
}

/* Lazy bastard, eh? */
#define STANDARD_PARAM_DEF(name, type, format, tmptype, strtolfn)      	\
231
	int param_set_##name(const char *val, const struct kernel_param *kp) \
L
Linus Torvalds 已提交
232 233
	{								\
		tmptype l;						\
234
		int ret;						\
L
Linus Torvalds 已提交
235
									\
236
		ret = strtolfn(val, 0, &l);				\
237 238
		if (ret < 0 || ((type)l != l))				\
			return ret < 0 ? ret : -EINVAL;			\
L
Linus Torvalds 已提交
239 240 241
		*((type *)kp->arg) = l;					\
		return 0;						\
	}								\
242
	int param_get_##name(char *buffer, const struct kernel_param *kp) \
L
Linus Torvalds 已提交
243
	{								\
244 245
		return scnprintf(buffer, PAGE_SIZE, format,		\
				*((type *)kp->arg));			\
246
	}								\
247 248 249 250
	struct kernel_param_ops param_ops_##name = {			\
		.set = param_set_##name,				\
		.get = param_get_##name,				\
	};								\
251
	EXPORT_SYMBOL(param_set_##name);				\
252 253 254
	EXPORT_SYMBOL(param_get_##name);				\
	EXPORT_SYMBOL(param_ops_##name)

L
Linus Torvalds 已提交
255

256
STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", unsigned long, strict_strtoul);
257 258 259 260 261 262
STANDARD_PARAM_DEF(short, short, "%hi", long, strict_strtol);
STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", unsigned long, strict_strtoul);
STANDARD_PARAM_DEF(int, int, "%i", long, strict_strtol);
STANDARD_PARAM_DEF(uint, unsigned int, "%u", unsigned long, strict_strtoul);
STANDARD_PARAM_DEF(long, long, "%li", long, strict_strtol);
STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", unsigned long, strict_strtoul);
L
Linus Torvalds 已提交
263

264
int param_set_charp(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
265 266
{
	if (strlen(val) > 1024) {
267
		pr_err("%s: string parameter too long\n", kp->name);
L
Linus Torvalds 已提交
268 269 270
		return -ENOSPC;
	}

271 272 273
	maybe_kfree_parameter(*(char **)kp->arg);

	/* This is a hack.  We can't kmalloc in early boot, and we
274 275
	 * don't need to; this mangled commandline is preserved. */
	if (slab_is_available()) {
276
		*(char **)kp->arg = kmalloc_parameter(strlen(val)+1);
R
Rusty Russell 已提交
277
		if (!*(char **)kp->arg)
278
			return -ENOMEM;
279
		strcpy(*(char **)kp->arg, val);
280 281 282
	} else
		*(const char **)kp->arg = val;

L
Linus Torvalds 已提交
283 284
	return 0;
}
285
EXPORT_SYMBOL(param_set_charp);
L
Linus Torvalds 已提交
286

287
int param_get_charp(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
288
{
289
	return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg));
L
Linus Torvalds 已提交
290
}
291
EXPORT_SYMBOL(param_get_charp);
L
Linus Torvalds 已提交
292

293 294 295 296 297
static void param_free_charp(void *arg)
{
	maybe_kfree_parameter(*((char **)arg));
}

298 299 300
struct kernel_param_ops param_ops_charp = {
	.set = param_set_charp,
	.get = param_get_charp,
301
	.free = param_free_charp,
302 303 304
};
EXPORT_SYMBOL(param_ops_charp);

305
/* Actually could be a bool or an int, for historical reasons. */
306
int param_set_bool(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
307 308 309 310 311
{
	/* No equals means "set"... */
	if (!val) val = "1";

	/* One of =[yYnN01] */
312
	return strtobool(val, kp->arg);
L
Linus Torvalds 已提交
313
}
314
EXPORT_SYMBOL(param_set_bool);
L
Linus Torvalds 已提交
315

316
int param_get_bool(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
317 318
{
	/* Y and N chosen as being relatively non-coder friendly */
319
	return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N');
L
Linus Torvalds 已提交
320
}
321
EXPORT_SYMBOL(param_get_bool);
L
Linus Torvalds 已提交
322

323
struct kernel_param_ops param_ops_bool = {
324
	.flags = KERNEL_PARAM_FL_NOARG,
325 326 327 328 329
	.set = param_set_bool,
	.get = param_get_bool,
};
EXPORT_SYMBOL(param_ops_bool);

330
/* This one must be bool. */
331
int param_set_invbool(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
332
{
333 334
	int ret;
	bool boolval;
335
	struct kernel_param dummy;
L
Linus Torvalds 已提交
336

337
	dummy.arg = &boolval;
L
Linus Torvalds 已提交
338 339
	ret = param_set_bool(val, &dummy);
	if (ret == 0)
340
		*(bool *)kp->arg = !boolval;
L
Linus Torvalds 已提交
341 342
	return ret;
}
343
EXPORT_SYMBOL(param_set_invbool);
L
Linus Torvalds 已提交
344

345
int param_get_invbool(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
346
{
347
	return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
L
Linus Torvalds 已提交
348
}
349
EXPORT_SYMBOL(param_get_invbool);
L
Linus Torvalds 已提交
350

351 352 353 354 355 356
struct kernel_param_ops param_ops_invbool = {
	.set = param_set_invbool,
	.get = param_get_invbool,
};
EXPORT_SYMBOL(param_ops_invbool);

357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
int param_set_bint(const char *val, const struct kernel_param *kp)
{
	struct kernel_param boolkp;
	bool v;
	int ret;

	/* Match bool exactly, by re-using it. */
	boolkp = *kp;
	boolkp.arg = &v;

	ret = param_set_bool(val, &boolkp);
	if (ret == 0)
		*(int *)kp->arg = v;
	return ret;
}
EXPORT_SYMBOL(param_set_bint);

struct kernel_param_ops param_ops_bint = {
375
	.flags = KERNEL_PARAM_FL_NOARG,
376 377 378 379 380
	.set = param_set_bint,
	.get = param_get_int,
};
EXPORT_SYMBOL(param_ops_bint);

381
/* We break the rule and mangle the string. */
382 383 384 385
static int param_array(const char *name,
		       const char *val,
		       unsigned int min, unsigned int max,
		       void *elem, int elemsize,
386
		       int (*set)(const char *, const struct kernel_param *kp),
387
		       s16 level,
388
		       unsigned int *num)
L
Linus Torvalds 已提交
389 390 391 392 393 394 395 396
{
	int ret;
	struct kernel_param kp;
	char save;

	/* Get the name right for errors. */
	kp.name = name;
	kp.arg = elem;
397
	kp.level = level;
L
Linus Torvalds 已提交
398 399 400 401 402 403 404

	*num = 0;
	/* We expect a comma-separated list of values. */
	do {
		int len;

		if (*num == max) {
405
			pr_err("%s: can only take %i arguments\n", name, max);
L
Linus Torvalds 已提交
406 407 408 409 410 411 412
			return -EINVAL;
		}
		len = strcspn(val, ",");

		/* nul-terminate and parse */
		save = val[len];
		((char *)val)[len] = '\0';
413
		BUG_ON(!mutex_is_locked(&param_lock));
L
Linus Torvalds 已提交
414 415 416 417 418 419 420 421 422 423
		ret = set(val, &kp);

		if (ret != 0)
			return ret;
		kp.arg += elemsize;
		val += len+1;
		(*num)++;
	} while (save == ',');

	if (*num < min) {
424
		pr_err("%s: needs at least %i arguments\n", name, min);
L
Linus Torvalds 已提交
425 426 427 428 429
		return -EINVAL;
	}
	return 0;
}

430
static int param_array_set(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
431
{
432
	const struct kparam_array *arr = kp->arr;
433
	unsigned int temp_num;
L
Linus Torvalds 已提交
434 435

	return param_array(kp->name, val, 1, arr->max, arr->elem,
436
			   arr->elemsize, arr->ops->set, kp->level,
R
Rusty Russell 已提交
437
			   arr->num ?: &temp_num);
L
Linus Torvalds 已提交
438 439
}

440
static int param_array_get(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
441 442
{
	int i, off, ret;
443
	const struct kparam_array *arr = kp->arr;
L
Linus Torvalds 已提交
444 445 446 447 448 449 450
	struct kernel_param p;

	p = *kp;
	for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) {
		if (i)
			buffer[off++] = ',';
		p.arg = arr->elem + arr->elemsize * i;
451
		BUG_ON(!mutex_is_locked(&param_lock));
452
		ret = arr->ops->get(buffer + off, &p);
L
Linus Torvalds 已提交
453 454 455 456 457 458 459 460
		if (ret < 0)
			return ret;
		off += ret;
	}
	buffer[off] = '\0';
	return off;
}

461 462 463 464 465 466 467 468 469 470
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);
}

471 472 473
struct kernel_param_ops param_array_ops = {
	.set = param_array_set,
	.get = param_array_get,
474
	.free = param_array_free,
475 476 477 478
};
EXPORT_SYMBOL(param_array_ops);

int param_set_copystring(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
479
{
480
	const struct kparam_string *kps = kp->str;
L
Linus Torvalds 已提交
481 482

	if (strlen(val)+1 > kps->maxlen) {
483
		pr_err("%s: string doesn't fit in %u chars.\n",
L
Linus Torvalds 已提交
484 485 486 487 488 489
		       kp->name, kps->maxlen-1);
		return -ENOSPC;
	}
	strcpy(kps->string, val);
	return 0;
}
490
EXPORT_SYMBOL(param_set_copystring);
L
Linus Torvalds 已提交
491

492
int param_get_string(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
493
{
494
	const struct kparam_string *kps = kp->str;
L
Linus Torvalds 已提交
495 496
	return strlcpy(buffer, kps->string, kps->maxlen);
}
497
EXPORT_SYMBOL(param_get_string);
L
Linus Torvalds 已提交
498

499 500 501 502 503 504
struct kernel_param_ops param_ops_string = {
	.set = param_set_copystring,
	.get = param_get_string,
};
EXPORT_SYMBOL(param_ops_string);

L
Linus Torvalds 已提交
505
/* sysfs output in /sys/modules/XYZ/parameters/ */
506 507
#define to_module_attr(n) container_of(n, struct module_attribute, attr)
#define to_module_kobject(n) container_of(n, struct module_kobject, kobj)
L
Linus Torvalds 已提交
508 509 510 511 512 513

extern struct kernel_param __start___param[], __stop___param[];

struct param_attribute
{
	struct module_attribute mattr;
514
	const struct kernel_param *param;
L
Linus Torvalds 已提交
515 516 517 518
};

struct module_param_attrs
{
519
	unsigned int num;
L
Linus Torvalds 已提交
520 521 522 523
	struct attribute_group grp;
	struct param_attribute attrs[0];
};

524
#ifdef CONFIG_SYSFS
525
#define to_param_attr(n) container_of(n, struct param_attribute, mattr)
L
Linus Torvalds 已提交
526 527

static ssize_t param_attr_show(struct module_attribute *mattr,
528
			       struct module_kobject *mk, char *buf)
L
Linus Torvalds 已提交
529 530 531 532
{
	int count;
	struct param_attribute *attribute = to_param_attr(mattr);

533
	if (!attribute->param->ops->get)
L
Linus Torvalds 已提交
534 535
		return -EPERM;

536
	mutex_lock(&param_lock);
537
	count = attribute->param->ops->get(buf, attribute->param);
538
	mutex_unlock(&param_lock);
L
Linus Torvalds 已提交
539 540 541 542 543 544 545 546 547
	if (count > 0) {
		strcat(buf, "\n");
		++count;
	}
	return count;
}

/* sysfs always hands a nul-terminated string in buf.  We rely on that. */
static ssize_t param_attr_store(struct module_attribute *mattr,
548
				struct module_kobject *km,
L
Linus Torvalds 已提交
549 550 551 552 553
				const char *buf, size_t len)
{
 	int err;
	struct param_attribute *attribute = to_param_attr(mattr);

554
	if (!attribute->param->ops->set)
L
Linus Torvalds 已提交
555 556
		return -EPERM;

557
	mutex_lock(&param_lock);
558
	err = attribute->param->ops->set(buf, attribute->param);
559
	mutex_unlock(&param_lock);
L
Linus Torvalds 已提交
560 561 562 563
	if (!err)
		return len;
	return err;
}
564
#endif
L
Linus Torvalds 已提交
565 566 567 568 569 570 571

#ifdef CONFIG_MODULES
#define __modinit
#else
#define __modinit __init
#endif

572
#ifdef CONFIG_SYSFS
573 574 575 576 577 578 579 580 581 582 583 584
void __kernel_param_lock(void)
{
	mutex_lock(&param_lock);
}
EXPORT_SYMBOL(__kernel_param_lock);

void __kernel_param_unlock(void)
{
	mutex_unlock(&param_lock);
}
EXPORT_SYMBOL(__kernel_param_unlock);

L
Linus Torvalds 已提交
585
/*
586 587 588 589
 * add_sysfs_param - add a parameter to sysfs
 * @mk: struct module_kobject
 * @kparam: the actual parameter definition to add to sysfs
 * @name: name of parameter
L
Linus Torvalds 已提交
590
 *
591 592 593
 * 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.
L
Linus Torvalds 已提交
594
 */
595
static __modinit int add_sysfs_param(struct module_kobject *mk,
596
				     const struct kernel_param *kp,
597
				     const char *name)
L
Linus Torvalds 已提交
598
{
599 600 601 602 603 604 605 606 607 608 609 610 611
	struct module_param_attrs *new;
	struct attribute **attrs;
	int err, num;

	/* We don't bother calling this with invisible parameters. */
	BUG_ON(!kp->perm);

	if (!mk->mp) {
		num = 0;
		attrs = NULL;
	} else {
		num = mk->mp->num;
		attrs = mk->mp->grp.attrs;
L
Linus Torvalds 已提交
612 613
	}

614 615 616 617 618
	/* Enlarge. */
	new = krealloc(mk->mp,
		       sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1),
		       GFP_KERNEL);
	if (!new) {
619
		kfree(attrs);
620 621 622
		err = -ENOMEM;
		goto fail;
	}
623 624 625
	/* Despite looking like the typical realloc() bug, this is safe.
	 * We *want* the old 'attrs' to be freed either way, and we'll store
	 * the new one in the success case. */
626 627 628 629 630
	attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL);
	if (!attrs) {
		err = -ENOMEM;
		goto fail_free_new;
	}
L
Linus Torvalds 已提交
631

632 633 634 635 636 637 638 639
	/* Sysfs wants everything zeroed. */
	memset(new, 0, sizeof(*new));
	memset(&new->attrs[num], 0, sizeof(new->attrs[num]));
	memset(&attrs[num], 0, sizeof(attrs[num]));
	new->grp.name = "parameters";
	new->grp.attrs = attrs;

	/* Tack new one on the end. */
640
	sysfs_attr_init(&new->attrs[num].mattr.attr);
641 642 643 644 645 646 647 648 649 650 651 652 653 654
	new->attrs[num].param = kp;
	new->attrs[num].mattr.show = param_attr_show;
	new->attrs[num].mattr.store = param_attr_store;
	new->attrs[num].mattr.attr.name = (char *)name;
	new->attrs[num].mattr.attr.mode = kp->perm;
	new->num = num+1;

	/* Fix up all the pointers, since krealloc can move us */
	for (num = 0; num < new->num; num++)
		new->grp.attrs[num] = &new->attrs[num].mattr.attr;
	new->grp.attrs[num] = NULL;

	mk->mp = new;
	return 0;
L
Linus Torvalds 已提交
655

656 657 658 659 660 661
fail_free_new:
	kfree(new);
fail:
	mk->mp = NULL;
	return err;
}
L
Linus Torvalds 已提交
662

663
#ifdef CONFIG_MODULES
664 665 666 667 668
static void free_module_param_attrs(struct module_kobject *mk)
{
	kfree(mk->mp->grp.attrs);
	kfree(mk->mp);
	mk->mp = NULL;
L
Linus Torvalds 已提交
669 670 671 672 673 674 675 676
}

/*
 * module_param_sysfs_setup - setup sysfs support for one module
 * @mod: module
 * @kparam: module parameters (array)
 * @num_params: number of module parameters
 *
677 678
 * Adds sysfs entries for module parameters under
 * /sys/module/[mod->name]/parameters/
L
Linus Torvalds 已提交
679 680
 */
int module_param_sysfs_setup(struct module *mod,
681
			     const struct kernel_param *kparam,
L
Linus Torvalds 已提交
682 683
			     unsigned int num_params)
{
684 685 686 687 688 689 690 691 692 693 694
	int i, err;
	bool params = false;

	for (i = 0; i < num_params; i++) {
		if (kparam[i].perm == 0)
			continue;
		err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name);
		if (err)
			return err;
		params = true;
	}
L
Linus Torvalds 已提交
695

696 697
	if (!params)
		return 0;
L
Linus Torvalds 已提交
698

699 700 701 702 703
	/* 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;
L
Linus Torvalds 已提交
704 705 706 707 708 709 710 711 712 713 714
}

/*
 * 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)
{
715 716
	if (mod->mkobj.mp) {
		sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
L
Linus Torvalds 已提交
717 718
		/* We are positive that no one is using any param
		 * attrs at this point.  Deallocate immediately. */
719
		free_module_param_attrs(&mod->mkobj);
L
Linus Torvalds 已提交
720 721 722 723
	}
}
#endif

724 725
void destroy_params(const struct kernel_param *params, unsigned num)
{
726 727 728 729 730
	unsigned int i;

	for (i = 0; i < num; i++)
		if (params[i].ops->free)
			params[i].ops->free(params[i].arg);
731 732
}

733
static struct module_kobject * __init locate_module_kobject(const char *name)
L
Linus Torvalds 已提交
734 735
{
	struct module_kobject *mk;
736 737
	struct kobject *kobj;
	int err;
L
Linus Torvalds 已提交
738

739 740 741 742 743 744 745 746 747 748 749
	kobj = kset_find_obj(module_kset, name);
	if (kobj) {
		mk = to_module_kobject(kobj);
	} 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);
750 751 752 753
#ifdef CONFIG_MODULES
		if (!err)
			err = sysfs_create_file(&mk->kobj, &module_uevent.attr);
#endif
754 755
		if (err) {
			kobject_put(&mk->kobj);
756
			pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n",
757 758
				name, err);
			return NULL;
759
		}
760 761

		/* So that we hold reference in both cases. */
762
		kobject_get(&mk->kobj);
763
	}
764

765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782
	return mk;
}

static void __init kernel_add_sysfs_param(const char *name,
					  struct kernel_param *kparam,
					  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);

783 784 785 786 787
	/* 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);
788
	kobject_uevent(&mk->kobj, KOBJ_ADD);
789
	kobject_put(&mk->kobj);
L
Linus Torvalds 已提交
790 791 792
}

/*
J
Jean Delvare 已提交
793
 * param_sysfs_builtin - add sysfs parameters for built-in modules
L
Linus Torvalds 已提交
794 795 796 797 798 799
 *
 * 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,
800
 * and for all who have the same, call kernel_add_sysfs_param.
L
Linus Torvalds 已提交
801 802 803
 */
static void __init param_sysfs_builtin(void)
{
804 805 806
	struct kernel_param *kp;
	unsigned int name_len;
	char modname[MODULE_NAME_LEN];
L
Linus Torvalds 已提交
807

808
	for (kp = __start___param; kp < __stop___param; kp++) {
L
Linus Torvalds 已提交
809 810
		char *dot;

811 812
		if (kp->perm == 0)
			continue;
L
Linus Torvalds 已提交
813

814
		dot = strchr(kp->name, '.');
L
Linus Torvalds 已提交
815
		if (!dot) {
816 817 818 819 820 821
			/* This happens for core_param() */
			strcpy(modname, "kernel");
			name_len = 0;
		} else {
			name_len = dot - kp->name + 1;
			strlcpy(modname, kp->name, name_len);
L
Linus Torvalds 已提交
822
		}
823
		kernel_add_sysfs_param(modname, kp, name_len);
L
Linus Torvalds 已提交
824 825 826
	}
}

827
ssize_t __modver_version_show(struct module_attribute *mattr,
828
			      struct module_kobject *mk, char *buf)
829 830 831 832
{
	struct module_version_attribute *vattr =
		container_of(mattr, struct module_version_attribute, mattr);

833
	return scnprintf(buf, PAGE_SIZE, "%s\n", vattr->version);
834 835
}

836 837
extern const struct module_version_attribute *__start___modver[];
extern const struct module_version_attribute *__stop___modver[];
838 839 840

static void __init version_sysfs_builtin(void)
{
841
	const struct module_version_attribute **p;
842 843 844
	struct module_kobject *mk;
	int err;

845 846 847
	for (p = __start___modver; p < __stop___modver; p++) {
		const struct module_version_attribute *vattr = *p;

848 849 850 851 852 853 854 855
		mk = locate_module_kobject(vattr->module_name);
		if (mk) {
			err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
			kobject_uevent(&mk->kobj, KOBJ_ADD);
			kobject_put(&mk->kobj);
		}
	}
}
L
Linus Torvalds 已提交
856 857 858 859 860 861 862 863 864 865 866 867 868 869 870

/* module-related sysfs stuff */

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)
871
		return -EIO;
L
Linus Torvalds 已提交
872

873
	ret = attribute->show(attribute, mk, buf);
L
Linus Torvalds 已提交
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889

	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)
890
		return -EIO;
L
Linus Torvalds 已提交
891

892
	ret = attribute->store(attribute, mk, buf, len);
L
Linus Torvalds 已提交
893 894 895 896

	return ret;
}

897
static const struct sysfs_ops module_sysfs_ops = {
L
Linus Torvalds 已提交
898 899 900 901
	.show = module_attr_show,
	.store = module_attr_store,
};

K
Kay Sievers 已提交
902 903 904 905 906 907 908 909 910
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;
}

911
static const struct kset_uevent_ops module_uevent_ops = {
K
Kay Sievers 已提交
912 913 914
	.filter = uevent_filter,
};

915
struct kset *module_kset;
916
int module_sysfs_initialized;
L
Linus Torvalds 已提交
917

918
struct kobj_type module_ktype = {
L
Linus Torvalds 已提交
919 920 921 922 923 924 925 926
	.sysfs_ops =	&module_sysfs_ops,
};

/*
 * param_sysfs_init - wrapper for built-in params support
 */
static int __init param_sysfs_init(void)
{
927 928 929 930 931
	module_kset = kset_create_and_add("module", &module_uevent_ops, NULL);
	if (!module_kset) {
		printk(KERN_WARNING "%s (%d): error creating kset\n",
			__FILE__, __LINE__);
		return -ENOMEM;
932
	}
933
	module_sysfs_initialized = 1;
L
Linus Torvalds 已提交
934

935
	version_sysfs_builtin();
L
Linus Torvalds 已提交
936 937 938 939
	param_sysfs_builtin();

	return 0;
}
940
subsys_initcall(param_sysfs_init);
L
Linus Torvalds 已提交
941

942
#endif /* CONFIG_SYSFS */