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
			if (!val &&
107
			    !(params[i].ops->flags & KERNEL_PARAM_OPS_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 181 182 183 184 185 186
char *parse_args(const char *doing,
		 char *args,
		 const struct kernel_param *params,
		 unsigned num,
		 s16 min_level,
		 s16 max_level,
		 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 202 203
		/* Stop at -- */
		if (!val && strcmp(param, "--") == 0)
			return args;
204
		irq_was_disabled = irqs_disabled();
205
		ret = parse_one(param, val, doing, params, num,
206
				min_level, max_level, unknown);
207 208 209 210
		if (irq_was_disabled && !irqs_disabled())
			pr_warn("%s: option '%s' enabled irq's!\n",
				doing, param);

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

	/* All parsed OK. */
229
	return NULL;
L
Linus Torvalds 已提交
230 231 232
}

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

L
Linus Torvalds 已提交
251

252 253 254 255 256 257 258
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);
H
Hannes Reinecke 已提交
259
STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull);
L
Linus Torvalds 已提交
260

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

268 269 270
	maybe_kfree_parameter(*(char **)kp->arg);

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

L
Linus Torvalds 已提交
280 281
	return 0;
}
282
EXPORT_SYMBOL(param_set_charp);
L
Linus Torvalds 已提交
283

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

290 291 292 293 294
static void param_free_charp(void *arg)
{
	maybe_kfree_parameter(*((char **)arg));
}

295 296 297
struct kernel_param_ops param_ops_charp = {
	.set = param_set_charp,
	.get = param_get_charp,
298
	.free = param_free_charp,
299 300 301
};
EXPORT_SYMBOL(param_ops_charp);

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

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

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

320
struct kernel_param_ops param_ops_bool = {
321
	.flags = KERNEL_PARAM_OPS_FL_NOARG,
322 323 324 325 326
	.set = param_set_bool,
	.get = param_get_bool,
};
EXPORT_SYMBOL(param_ops_bool);

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

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

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

348 349 350 351 352 353
struct kernel_param_ops param_ops_invbool = {
	.set = param_set_invbool,
	.get = param_get_invbool,
};
EXPORT_SYMBOL(param_ops_invbool);

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

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

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

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

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

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

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

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

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

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

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

458 459 460 461 462 463 464 465 466 467
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);
}

468 469 470
struct kernel_param_ops param_array_ops = {
	.set = param_array_set,
	.get = param_array_get,
471
	.free = param_array_free,
472 473 474 475
};
EXPORT_SYMBOL(param_array_ops);

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

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

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

496 497 498 499 500 501
struct kernel_param_ops param_ops_string = {
	.set = param_set_copystring,
	.get = param_get_string,
};
EXPORT_SYMBOL(param_ops_string);

L
Linus Torvalds 已提交
502
/* sysfs output in /sys/modules/XYZ/parameters/ */
503 504
#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 已提交
505 506 507 508 509 510

extern struct kernel_param __start___param[], __stop___param[];

struct param_attribute
{
	struct module_attribute mattr;
511
	const struct kernel_param *param;
L
Linus Torvalds 已提交
512 513 514 515
};

struct module_param_attrs
{
516
	unsigned int num;
L
Linus Torvalds 已提交
517 518 519 520
	struct attribute_group grp;
	struct param_attribute attrs[0];
};

521
#ifdef CONFIG_SYSFS
522
#define to_param_attr(n) container_of(n, struct param_attribute, mattr)
L
Linus Torvalds 已提交
523 524

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

530
	if (!attribute->param->ops->get)
L
Linus Torvalds 已提交
531 532
		return -EPERM;

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

551
	if (!attribute->param->ops->set)
L
Linus Torvalds 已提交
552 553
		return -EPERM;

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

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

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

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

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

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

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

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

693 694
	if (!params)
		return 0;
L
Linus Torvalds 已提交
695

696 697 698 699 700
	/* 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 已提交
701 702 703 704 705 706 707 708 709 710 711
}

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

721 722
void destroy_params(const struct kernel_param *params, unsigned num)
{
723 724 725 726 727
	unsigned int i;

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

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

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

		/* So that we hold reference in both cases. */
759
		kobject_get(&mk->kobj);
760
	}
761

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
	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);

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

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

805
	for (kp = __start___param; kp < __stop___param; kp++) {
L
Linus Torvalds 已提交
806 807
		char *dot;

808 809
		if (kp->perm == 0)
			continue;
L
Linus Torvalds 已提交
810

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

824
ssize_t __modver_version_show(struct module_attribute *mattr,
825
			      struct module_kobject *mk, char *buf)
826 827 828 829
{
	struct module_version_attribute *vattr =
		container_of(mattr, struct module_version_attribute, mattr);

830
	return scnprintf(buf, PAGE_SIZE, "%s\n", vattr->version);
831 832
}

833 834
extern const struct module_version_attribute *__start___modver[];
extern const struct module_version_attribute *__stop___modver[];
835 836 837

static void __init version_sysfs_builtin(void)
{
838
	const struct module_version_attribute **p;
839 840 841
	struct module_kobject *mk;
	int err;

842 843 844
	for (p = __start___modver; p < __stop___modver; p++) {
		const struct module_version_attribute *vattr = *p;

845 846 847 848 849 850 851 852
		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 已提交
853 854 855 856 857 858 859 860 861 862 863 864 865 866 867

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

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

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

889
	ret = attribute->store(attribute, mk, buf, len);
L
Linus Torvalds 已提交
890 891 892 893

	return ret;
}

894
static const struct sysfs_ops module_sysfs_ops = {
L
Linus Torvalds 已提交
895 896 897 898
	.show = module_attr_show,
	.store = module_attr_store,
};

K
Kay Sievers 已提交
899 900 901 902 903 904 905 906 907
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;
}

908
static const struct kset_uevent_ops module_uevent_ops = {
K
Kay Sievers 已提交
909 910 911
	.filter = uevent_filter,
};

912
struct kset *module_kset;
913
int module_sysfs_initialized;
L
Linus Torvalds 已提交
914

915 916 917 918 919 920
static void module_kobj_release(struct kobject *kobj)
{
	struct module_kobject *mk = to_module_kobject(kobj);
	complete(mk->kobj_completion);
}

921
struct kobj_type module_ktype = {
922
	.release   =	module_kobj_release,
L
Linus Torvalds 已提交
923 924 925 926 927 928 929 930
	.sysfs_ops =	&module_sysfs_ops,
};

/*
 * param_sysfs_init - wrapper for built-in params support
 */
static int __init param_sysfs_init(void)
{
931 932 933 934 935
	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;
936
	}
937
	module_sysfs_initialized = 1;
L
Linus Torvalds 已提交
938

939
	version_sysfs_builtin();
L
Linus Torvalds 已提交
940 941 942 943
	param_sysfs_builtin();

	return 0;
}
944
subsys_initcall(param_sysfs_init);
L
Linus Torvalds 已提交
945

946
#endif /* CONFIG_SYSFS */