params.c 21.8 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
			return ret;
		}
	}

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

/* Lazy bastard, eh? */
230
#define STANDARD_PARAM_DEF(name, type, format, strtolfn)      		\
231
	int param_set_##name(const char *val, const struct kernel_param *kp) \
L
Linus Torvalds 已提交
232
	{								\
233
		return strtolfn(val, 0, (type *)kp->arg);		\
L
Linus Torvalds 已提交
234
	}								\
235
	int param_get_##name(char *buffer, const struct kernel_param *kp) \
L
Linus Torvalds 已提交
236
	{								\
237 238
		return scnprintf(buffer, PAGE_SIZE, format,		\
				*((type *)kp->arg));			\
239
	}								\
240 241 242 243
	struct kernel_param_ops param_ops_##name = {			\
		.set = param_set_##name,				\
		.get = param_get_##name,				\
	};								\
244
	EXPORT_SYMBOL(param_set_##name);				\
245 246 247
	EXPORT_SYMBOL(param_get_##name);				\
	EXPORT_SYMBOL(param_ops_##name)

L
Linus Torvalds 已提交
248

249 250 251 252 253 254 255
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);
L
Linus Torvalds 已提交
256

257
int param_set_charp(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
258 259
{
	if (strlen(val) > 1024) {
260
		pr_err("%s: string parameter too long\n", kp->name);
L
Linus Torvalds 已提交
261 262 263
		return -ENOSPC;
	}

264 265 266
	maybe_kfree_parameter(*(char **)kp->arg);

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

L
Linus Torvalds 已提交
276 277
	return 0;
}
278
EXPORT_SYMBOL(param_set_charp);
L
Linus Torvalds 已提交
279

280
int param_get_charp(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
281
{
282
	return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg));
L
Linus Torvalds 已提交
283
}
284
EXPORT_SYMBOL(param_get_charp);
L
Linus Torvalds 已提交
285

286 287 288 289 290
static void param_free_charp(void *arg)
{
	maybe_kfree_parameter(*((char **)arg));
}

291 292 293
struct kernel_param_ops param_ops_charp = {
	.set = param_set_charp,
	.get = param_get_charp,
294
	.free = param_free_charp,
295 296 297
};
EXPORT_SYMBOL(param_ops_charp);

298
/* Actually could be a bool or an int, for historical reasons. */
299
int param_set_bool(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
300 301 302 303 304
{
	/* No equals means "set"... */
	if (!val) val = "1";

	/* One of =[yYnN01] */
305
	return strtobool(val, kp->arg);
L
Linus Torvalds 已提交
306
}
307
EXPORT_SYMBOL(param_set_bool);
L
Linus Torvalds 已提交
308

309
int param_get_bool(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
310 311
{
	/* Y and N chosen as being relatively non-coder friendly */
312
	return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N');
L
Linus Torvalds 已提交
313
}
314
EXPORT_SYMBOL(param_get_bool);
L
Linus Torvalds 已提交
315

316
struct kernel_param_ops param_ops_bool = {
317
	.flags = KERNEL_PARAM_FL_NOARG,
318 319 320 321 322
	.set = param_set_bool,
	.get = param_get_bool,
};
EXPORT_SYMBOL(param_ops_bool);

323
/* This one must be bool. */
324
int param_set_invbool(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
325
{
326 327
	int ret;
	bool boolval;
328
	struct kernel_param dummy;
L
Linus Torvalds 已提交
329

330
	dummy.arg = &boolval;
L
Linus Torvalds 已提交
331 332
	ret = param_set_bool(val, &dummy);
	if (ret == 0)
333
		*(bool *)kp->arg = !boolval;
L
Linus Torvalds 已提交
334 335
	return ret;
}
336
EXPORT_SYMBOL(param_set_invbool);
L
Linus Torvalds 已提交
337

338
int param_get_invbool(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
339
{
340
	return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y');
L
Linus Torvalds 已提交
341
}
342
EXPORT_SYMBOL(param_get_invbool);
L
Linus Torvalds 已提交
343

344 345 346 347 348 349
struct kernel_param_ops param_ops_invbool = {
	.set = param_set_invbool,
	.get = param_get_invbool,
};
EXPORT_SYMBOL(param_ops_invbool);

350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
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 = {
368
	.flags = KERNEL_PARAM_FL_NOARG,
369 370 371 372 373
	.set = param_set_bint,
	.get = param_get_int,
};
EXPORT_SYMBOL(param_ops_bint);

374
/* We break the rule and mangle the string. */
375 376 377 378
static int param_array(const char *name,
		       const char *val,
		       unsigned int min, unsigned int max,
		       void *elem, int elemsize,
379
		       int (*set)(const char *, const struct kernel_param *kp),
380
		       s16 level,
381
		       unsigned int *num)
L
Linus Torvalds 已提交
382 383 384 385 386 387 388 389
{
	int ret;
	struct kernel_param kp;
	char save;

	/* Get the name right for errors. */
	kp.name = name;
	kp.arg = elem;
390
	kp.level = level;
L
Linus Torvalds 已提交
391 392 393 394 395 396 397

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

		if (*num == max) {
398
			pr_err("%s: can only take %i arguments\n", name, max);
L
Linus Torvalds 已提交
399 400 401 402 403 404 405
			return -EINVAL;
		}
		len = strcspn(val, ",");

		/* nul-terminate and parse */
		save = val[len];
		((char *)val)[len] = '\0';
406
		BUG_ON(!mutex_is_locked(&param_lock));
L
Linus Torvalds 已提交
407 408 409 410 411 412 413 414 415 416
		ret = set(val, &kp);

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

	if (*num < min) {
417
		pr_err("%s: needs at least %i arguments\n", name, min);
L
Linus Torvalds 已提交
418 419 420 421 422
		return -EINVAL;
	}
	return 0;
}

423
static int param_array_set(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
424
{
425
	const struct kparam_array *arr = kp->arr;
426
	unsigned int temp_num;
L
Linus Torvalds 已提交
427 428

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

433
static int param_array_get(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
434 435
{
	int i, off, ret;
436
	const struct kparam_array *arr = kp->arr;
L
Linus Torvalds 已提交
437 438 439 440 441 442 443
	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;
444
		BUG_ON(!mutex_is_locked(&param_lock));
445
		ret = arr->ops->get(buffer + off, &p);
L
Linus Torvalds 已提交
446 447 448 449 450 451 452 453
		if (ret < 0)
			return ret;
		off += ret;
	}
	buffer[off] = '\0';
	return off;
}

454 455 456 457 458 459 460 461 462 463
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);
}

464 465 466
struct kernel_param_ops param_array_ops = {
	.set = param_array_set,
	.get = param_array_get,
467
	.free = param_array_free,
468 469 470 471
};
EXPORT_SYMBOL(param_array_ops);

int param_set_copystring(const char *val, const struct kernel_param *kp)
L
Linus Torvalds 已提交
472
{
473
	const struct kparam_string *kps = kp->str;
L
Linus Torvalds 已提交
474 475

	if (strlen(val)+1 > kps->maxlen) {
476
		pr_err("%s: string doesn't fit in %u chars.\n",
L
Linus Torvalds 已提交
477 478 479 480 481 482
		       kp->name, kps->maxlen-1);
		return -ENOSPC;
	}
	strcpy(kps->string, val);
	return 0;
}
483
EXPORT_SYMBOL(param_set_copystring);
L
Linus Torvalds 已提交
484

485
int param_get_string(char *buffer, const struct kernel_param *kp)
L
Linus Torvalds 已提交
486
{
487
	const struct kparam_string *kps = kp->str;
L
Linus Torvalds 已提交
488 489
	return strlcpy(buffer, kps->string, kps->maxlen);
}
490
EXPORT_SYMBOL(param_get_string);
L
Linus Torvalds 已提交
491

492 493 494 495 496 497
struct kernel_param_ops param_ops_string = {
	.set = param_set_copystring,
	.get = param_get_string,
};
EXPORT_SYMBOL(param_ops_string);

L
Linus Torvalds 已提交
498
/* sysfs output in /sys/modules/XYZ/parameters/ */
499 500
#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 已提交
501 502 503 504 505 506

extern struct kernel_param __start___param[], __stop___param[];

struct param_attribute
{
	struct module_attribute mattr;
507
	const struct kernel_param *param;
L
Linus Torvalds 已提交
508 509 510 511
};

struct module_param_attrs
{
512
	unsigned int num;
L
Linus Torvalds 已提交
513 514 515 516
	struct attribute_group grp;
	struct param_attribute attrs[0];
};

517
#ifdef CONFIG_SYSFS
518
#define to_param_attr(n) container_of(n, struct param_attribute, mattr)
L
Linus Torvalds 已提交
519 520

static ssize_t param_attr_show(struct module_attribute *mattr,
521
			       struct module_kobject *mk, char *buf)
L
Linus Torvalds 已提交
522 523 524 525
{
	int count;
	struct param_attribute *attribute = to_param_attr(mattr);

526
	if (!attribute->param->ops->get)
L
Linus Torvalds 已提交
527 528
		return -EPERM;

529
	mutex_lock(&param_lock);
530
	count = attribute->param->ops->get(buf, attribute->param);
531
	mutex_unlock(&param_lock);
L
Linus Torvalds 已提交
532 533 534 535 536 537 538 539 540
	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,
541
				struct module_kobject *km,
L
Linus Torvalds 已提交
542 543 544 545 546
				const char *buf, size_t len)
{
 	int err;
	struct param_attribute *attribute = to_param_attr(mattr);

547
	if (!attribute->param->ops->set)
L
Linus Torvalds 已提交
548 549
		return -EPERM;

550
	mutex_lock(&param_lock);
551
	err = attribute->param->ops->set(buf, attribute->param);
552
	mutex_unlock(&param_lock);
L
Linus Torvalds 已提交
553 554 555 556
	if (!err)
		return len;
	return err;
}
557
#endif
L
Linus Torvalds 已提交
558 559 560 561 562 563 564

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

565
#ifdef CONFIG_SYSFS
566 567 568 569 570 571 572 573 574 575 576 577
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 已提交
578
/*
579 580 581 582
 * 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 已提交
583
 *
584 585 586
 * 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 已提交
587
 */
588
static __modinit int add_sysfs_param(struct module_kobject *mk,
589
				     const struct kernel_param *kp,
590
				     const char *name)
L
Linus Torvalds 已提交
591
{
592 593 594 595 596 597 598 599 600 601 602 603 604
	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 已提交
605 606
	}

607 608 609 610 611
	/* Enlarge. */
	new = krealloc(mk->mp,
		       sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1),
		       GFP_KERNEL);
	if (!new) {
612
		kfree(attrs);
613 614 615
		err = -ENOMEM;
		goto fail;
	}
616 617 618
	/* 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. */
619 620 621 622 623
	attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL);
	if (!attrs) {
		err = -ENOMEM;
		goto fail_free_new;
	}
L
Linus Torvalds 已提交
624

625 626 627 628 629 630 631 632
	/* 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. */
633
	sysfs_attr_init(&new->attrs[num].mattr.attr);
634 635 636 637 638 639 640 641 642 643 644 645 646 647
	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 已提交
648

649 650 651 652 653 654
fail_free_new:
	kfree(new);
fail:
	mk->mp = NULL;
	return err;
}
L
Linus Torvalds 已提交
655

656
#ifdef CONFIG_MODULES
657 658 659 660 661
static void free_module_param_attrs(struct module_kobject *mk)
{
	kfree(mk->mp->grp.attrs);
	kfree(mk->mp);
	mk->mp = NULL;
L
Linus Torvalds 已提交
662 663 664 665 666 667 668 669
}

/*
 * module_param_sysfs_setup - setup sysfs support for one module
 * @mod: module
 * @kparam: module parameters (array)
 * @num_params: number of module parameters
 *
670 671
 * Adds sysfs entries for module parameters under
 * /sys/module/[mod->name]/parameters/
L
Linus Torvalds 已提交
672 673
 */
int module_param_sysfs_setup(struct module *mod,
674
			     const struct kernel_param *kparam,
L
Linus Torvalds 已提交
675 676
			     unsigned int num_params)
{
677 678 679 680 681 682 683 684 685 686 687
	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 已提交
688

689 690
	if (!params)
		return 0;
L
Linus Torvalds 已提交
691

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;
L
Linus Torvalds 已提交
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)
{
708 709
	if (mod->mkobj.mp) {
		sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp);
L
Linus Torvalds 已提交
710 711
		/* We are positive that no one is using any param
		 * attrs at this point.  Deallocate immediately. */
712
		free_module_param_attrs(&mod->mkobj);
L
Linus Torvalds 已提交
713 714 715 716
	}
}
#endif

717 718
void destroy_params(const struct kernel_param *params, unsigned num)
{
719 720 721 722 723
	unsigned int i;

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

726
static struct module_kobject * __init locate_module_kobject(const char *name)
L
Linus Torvalds 已提交
727 728
{
	struct module_kobject *mk;
729 730
	struct kobject *kobj;
	int err;
L
Linus Torvalds 已提交
731

732 733 734 735 736 737 738 739 740 741 742
	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);
743 744 745 746
#ifdef CONFIG_MODULES
		if (!err)
			err = sysfs_create_file(&mk->kobj, &module_uevent.attr);
#endif
747 748
		if (err) {
			kobject_put(&mk->kobj);
749
			pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n",
750 751
				name, err);
			return NULL;
752
		}
753 754

		/* So that we hold reference in both cases. */
755
		kobject_get(&mk->kobj);
756
	}
757

758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
	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);

776 777 778 779 780
	/* These should not fail at boot. */
	err = add_sysfs_param(mk, kparam, kparam->name + name_skip);
	BUG_ON(err);
	err = sysfs_create_group(&mk->kobj, &mk->mp->grp);
	BUG_ON(err);
781
	kobject_uevent(&mk->kobj, KOBJ_ADD);
782
	kobject_put(&mk->kobj);
L
Linus Torvalds 已提交
783 784 785
}

/*
J
Jean Delvare 已提交
786
 * param_sysfs_builtin - add sysfs parameters for built-in modules
L
Linus Torvalds 已提交
787 788 789 790 791 792
 *
 * Add module_parameters to sysfs for "modules" built into the kernel.
 *
 * The "module" name (KBUILD_MODNAME) is stored before a dot, the
 * "parameter" name is stored behind a dot in kernel_param->name. So,
 * extract the "module" name for all built-in kernel_param-eters,
793
 * and for all who have the same, call kernel_add_sysfs_param.
L
Linus Torvalds 已提交
794 795 796
 */
static void __init param_sysfs_builtin(void)
{
797 798 799
	struct kernel_param *kp;
	unsigned int name_len;
	char modname[MODULE_NAME_LEN];
L
Linus Torvalds 已提交
800

801
	for (kp = __start___param; kp < __stop___param; kp++) {
L
Linus Torvalds 已提交
802 803
		char *dot;

804 805
		if (kp->perm == 0)
			continue;
L
Linus Torvalds 已提交
806

807
		dot = strchr(kp->name, '.');
L
Linus Torvalds 已提交
808
		if (!dot) {
809 810 811 812 813 814
			/* 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 已提交
815
		}
816
		kernel_add_sysfs_param(modname, kp, name_len);
L
Linus Torvalds 已提交
817 818 819
	}
}

820
ssize_t __modver_version_show(struct module_attribute *mattr,
821
			      struct module_kobject *mk, char *buf)
822 823 824 825
{
	struct module_version_attribute *vattr =
		container_of(mattr, struct module_version_attribute, mattr);

826
	return scnprintf(buf, PAGE_SIZE, "%s\n", vattr->version);
827 828
}

829 830
extern const struct module_version_attribute *__start___modver[];
extern const struct module_version_attribute *__stop___modver[];
831 832 833

static void __init version_sysfs_builtin(void)
{
834
	const struct module_version_attribute **p;
835 836 837
	struct module_kobject *mk;
	int err;

838 839 840
	for (p = __start___modver; p < __stop___modver; p++) {
		const struct module_version_attribute *vattr = *p;

841 842 843 844 845 846 847 848
		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 已提交
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863

/* 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)
864
		return -EIO;
L
Linus Torvalds 已提交
865

866
	ret = attribute->show(attribute, mk, buf);
L
Linus Torvalds 已提交
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882

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

885
	ret = attribute->store(attribute, mk, buf, len);
L
Linus Torvalds 已提交
886 887 888 889

	return ret;
}

890
static const struct sysfs_ops module_sysfs_ops = {
L
Linus Torvalds 已提交
891 892 893 894
	.show = module_attr_show,
	.store = module_attr_store,
};

K
Kay Sievers 已提交
895 896 897 898 899 900 901 902 903
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;
}

904
static const struct kset_uevent_ops module_uevent_ops = {
K
Kay Sievers 已提交
905 906 907
	.filter = uevent_filter,
};

908
struct kset *module_kset;
909
int module_sysfs_initialized;
L
Linus Torvalds 已提交
910

911 912 913 914 915 916
static void module_kobj_release(struct kobject *kobj)
{
	struct module_kobject *mk = to_module_kobject(kobj);
	complete(mk->kobj_completion);
}

917
struct kobj_type module_ktype = {
918
	.release   =	module_kobj_release,
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 */