diff options
Diffstat (limited to 'kernel/params.c')
| -rw-r--r-- | kernel/params.c | 276 |
1 files changed, 147 insertions, 129 deletions
diff --git a/kernel/params.c b/kernel/params.c index afc46a23eb6d..a1e3025b19a9 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
| @@ -373,6 +373,8 @@ int param_get_string(char *buffer, struct kernel_param *kp) | |||
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | /* sysfs output in /sys/modules/XYZ/parameters/ */ | 375 | /* sysfs output in /sys/modules/XYZ/parameters/ */ |
| 376 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); | ||
| 377 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); | ||
| 376 | 378 | ||
| 377 | extern struct kernel_param __start___param[], __stop___param[]; | 379 | extern struct kernel_param __start___param[], __stop___param[]; |
| 378 | 380 | ||
| @@ -384,6 +386,7 @@ struct param_attribute | |||
| 384 | 386 | ||
| 385 | struct module_param_attrs | 387 | struct module_param_attrs |
| 386 | { | 388 | { |
| 389 | unsigned int num; | ||
| 387 | struct attribute_group grp; | 390 | struct attribute_group grp; |
| 388 | struct param_attribute attrs[0]; | 391 | struct param_attribute attrs[0]; |
| 389 | }; | 392 | }; |
| @@ -434,93 +437,120 @@ static ssize_t param_attr_store(struct module_attribute *mattr, | |||
| 434 | 437 | ||
| 435 | #ifdef CONFIG_SYSFS | 438 | #ifdef CONFIG_SYSFS |
| 436 | /* | 439 | /* |
| 437 | * param_sysfs_setup - setup sysfs support for one module or KBUILD_MODNAME | 440 | * add_sysfs_param - add a parameter to sysfs |
| 438 | * @mk: struct module_kobject (contains parent kobject) | 441 | * @mk: struct module_kobject |
| 439 | * @kparam: array of struct kernel_param, the actual parameter definitions | 442 | * @kparam: the actual parameter definition to add to sysfs |
| 440 | * @num_params: number of entries in array | 443 | * @name: name of parameter |
| 441 | * @name_skip: offset where the parameter name start in kparam[].name. Needed for built-in "modules" | ||
| 442 | * | 444 | * |
| 443 | * Create a kobject for a (per-module) group of parameters, and create files | 445 | * Create a kobject if for a (per-module) parameter if mp NULL, and |
| 444 | * in sysfs. A pointer to the param_kobject is returned on success, | 446 | * create file in sysfs. Returns an error on out of memory. Always cleans up |
| 445 | * NULL if there's no parameter to export, or other ERR_PTR(err). | 447 | * if there's an error. |
| 446 | */ | 448 | */ |
| 447 | static __modinit struct module_param_attrs * | 449 | static __modinit int add_sysfs_param(struct module_kobject *mk, |
| 448 | param_sysfs_setup(struct module_kobject *mk, | 450 | struct kernel_param *kp, |
| 449 | struct kernel_param *kparam, | 451 | const char *name) |
| 450 | unsigned int num_params, | ||
| 451 | unsigned int name_skip) | ||
| 452 | { | 452 | { |
| 453 | struct module_param_attrs *mp; | 453 | struct module_param_attrs *new; |
| 454 | unsigned int valid_attrs = 0; | 454 | struct attribute **attrs; |
| 455 | unsigned int i, size[2]; | 455 | int err, num; |
| 456 | struct param_attribute *pattr; | 456 | |
| 457 | struct attribute **gattr; | 457 | /* We don't bother calling this with invisible parameters. */ |
| 458 | int err; | 458 | BUG_ON(!kp->perm); |
| 459 | 459 | ||
| 460 | for (i=0; i<num_params; i++) { | 460 | if (!mk->mp) { |
| 461 | if (kparam[i].perm) | 461 | num = 0; |
| 462 | valid_attrs++; | 462 | attrs = NULL; |
| 463 | } else { | ||
| 464 | num = mk->mp->num; | ||
| 465 | attrs = mk->mp->grp.attrs; | ||
| 463 | } | 466 | } |
| 464 | 467 | ||
| 465 | if (!valid_attrs) | 468 | /* Enlarge. */ |
| 466 | return NULL; | 469 | new = krealloc(mk->mp, |
| 467 | 470 | sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1), | |
| 468 | size[0] = ALIGN(sizeof(*mp) + | 471 | GFP_KERNEL); |
| 469 | valid_attrs * sizeof(mp->attrs[0]), | 472 | if (!new) { |
| 470 | sizeof(mp->grp.attrs[0])); | 473 | kfree(mk->mp); |
| 471 | size[1] = (valid_attrs + 1) * sizeof(mp->grp.attrs[0]); | 474 | err = -ENOMEM; |
| 472 | 475 | goto fail; | |
| 473 | mp = kzalloc(size[0] + size[1], GFP_KERNEL); | ||
| 474 | if (!mp) | ||
| 475 | return ERR_PTR(-ENOMEM); | ||
| 476 | |||
| 477 | mp->grp.name = "parameters"; | ||
| 478 | mp->grp.attrs = (void *)mp + size[0]; | ||
| 479 | |||
| 480 | pattr = &mp->attrs[0]; | ||
| 481 | gattr = &mp->grp.attrs[0]; | ||
| 482 | for (i = 0; i < num_params; i++) { | ||
| 483 | struct kernel_param *kp = &kparam[i]; | ||
| 484 | if (kp->perm) { | ||
| 485 | pattr->param = kp; | ||
| 486 | pattr->mattr.show = param_attr_show; | ||
| 487 | pattr->mattr.store = param_attr_store; | ||
| 488 | pattr->mattr.attr.name = (char *)&kp->name[name_skip]; | ||
| 489 | pattr->mattr.attr.mode = kp->perm; | ||
| 490 | *(gattr++) = &(pattr++)->mattr.attr; | ||
| 491 | } | ||
| 492 | } | 476 | } |
| 493 | *gattr = NULL; | 477 | attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL); |
| 494 | 478 | if (!attrs) { | |
| 495 | if ((err = sysfs_create_group(&mk->kobj, &mp->grp))) { | 479 | err = -ENOMEM; |
| 496 | kfree(mp); | 480 | goto fail_free_new; |
| 497 | return ERR_PTR(err); | ||
| 498 | } | 481 | } |
| 499 | return mp; | 482 | |
| 483 | /* Sysfs wants everything zeroed. */ | ||
| 484 | memset(new, 0, sizeof(*new)); | ||
| 485 | memset(&new->attrs[num], 0, sizeof(new->attrs[num])); | ||
| 486 | memset(&attrs[num], 0, sizeof(attrs[num])); | ||
| 487 | new->grp.name = "parameters"; | ||
| 488 | new->grp.attrs = attrs; | ||
| 489 | |||
| 490 | /* Tack new one on the end. */ | ||
| 491 | new->attrs[num].param = kp; | ||
| 492 | new->attrs[num].mattr.show = param_attr_show; | ||
| 493 | new->attrs[num].mattr.store = param_attr_store; | ||
| 494 | new->attrs[num].mattr.attr.name = (char *)name; | ||
| 495 | new->attrs[num].mattr.attr.mode = kp->perm; | ||
| 496 | new->num = num+1; | ||
| 497 | |||
| 498 | /* Fix up all the pointers, since krealloc can move us */ | ||
| 499 | for (num = 0; num < new->num; num++) | ||
| 500 | new->grp.attrs[num] = &new->attrs[num].mattr.attr; | ||
| 501 | new->grp.attrs[num] = NULL; | ||
| 502 | |||
| 503 | mk->mp = new; | ||
| 504 | return 0; | ||
| 505 | |||
| 506 | fail_free_new: | ||
| 507 | kfree(new); | ||
| 508 | fail: | ||
| 509 | mk->mp = NULL; | ||
| 510 | return err; | ||
| 500 | } | 511 | } |
| 501 | 512 | ||
| 502 | #ifdef CONFIG_MODULES | 513 | #ifdef CONFIG_MODULES |
| 514 | static void free_module_param_attrs(struct module_kobject *mk) | ||
| 515 | { | ||
| 516 | kfree(mk->mp->grp.attrs); | ||
| 517 | kfree(mk->mp); | ||
| 518 | mk->mp = NULL; | ||
| 519 | } | ||
| 520 | |||
| 503 | /* | 521 | /* |
| 504 | * module_param_sysfs_setup - setup sysfs support for one module | 522 | * module_param_sysfs_setup - setup sysfs support for one module |
| 505 | * @mod: module | 523 | * @mod: module |
| 506 | * @kparam: module parameters (array) | 524 | * @kparam: module parameters (array) |
| 507 | * @num_params: number of module parameters | 525 | * @num_params: number of module parameters |
| 508 | * | 526 | * |
| 509 | * Adds sysfs entries for module parameters, and creates a link from | 527 | * Adds sysfs entries for module parameters under |
| 510 | * /sys/module/[mod->name]/parameters to /sys/parameters/[mod->name]/ | 528 | * /sys/module/[mod->name]/parameters/ |
| 511 | */ | 529 | */ |
| 512 | int module_param_sysfs_setup(struct module *mod, | 530 | int module_param_sysfs_setup(struct module *mod, |
| 513 | struct kernel_param *kparam, | 531 | struct kernel_param *kparam, |
| 514 | unsigned int num_params) | 532 | unsigned int num_params) |
| 515 | { | 533 | { |
| 516 | struct module_param_attrs *mp; | 534 | int i, err; |
| 535 | bool params = false; | ||
| 536 | |||
| 537 | for (i = 0; i < num_params; i++) { | ||
| 538 | if (kparam[i].perm == 0) | ||
| 539 | continue; | ||
| 540 | err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); | ||
| 541 | if (err) | ||
| 542 | return err; | ||
| 543 | params = true; | ||
| 544 | } | ||
| 517 | 545 | ||
| 518 | mp = param_sysfs_setup(&mod->mkobj, kparam, num_params, 0); | 546 | if (!params) |
| 519 | if (IS_ERR(mp)) | 547 | return 0; |
| 520 | return PTR_ERR(mp); | ||
| 521 | 548 | ||
| 522 | mod->param_attrs = mp; | 549 | /* Create the param group. */ |
| 523 | return 0; | 550 | err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); |
| 551 | if (err) | ||
| 552 | free_module_param_attrs(&mod->mkobj); | ||
| 553 | return err; | ||
| 524 | } | 554 | } |
| 525 | 555 | ||
| 526 | /* | 556 | /* |
| @@ -532,43 +562,55 @@ int module_param_sysfs_setup(struct module *mod, | |||
| 532 | */ | 562 | */ |
| 533 | void module_param_sysfs_remove(struct module *mod) | 563 | void module_param_sysfs_remove(struct module *mod) |
| 534 | { | 564 | { |
| 535 | if (mod->param_attrs) { | 565 | if (mod->mkobj.mp) { |
| 536 | sysfs_remove_group(&mod->mkobj.kobj, | 566 | sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); |
| 537 | &mod->param_attrs->grp); | ||
| 538 | /* We are positive that no one is using any param | 567 | /* We are positive that no one is using any param |
| 539 | * attrs at this point. Deallocate immediately. */ | 568 | * attrs at this point. Deallocate immediately. */ |
| 540 | kfree(mod->param_attrs); | 569 | free_module_param_attrs(&mod->mkobj); |
| 541 | mod->param_attrs = NULL; | ||
| 542 | } | 570 | } |
| 543 | } | 571 | } |
| 544 | #endif | 572 | #endif |
| 545 | 573 | ||
| 546 | /* | 574 | static void __init kernel_add_sysfs_param(const char *name, |
| 547 | * kernel_param_sysfs_setup - wrapper for built-in params support | 575 | struct kernel_param *kparam, |
| 548 | */ | 576 | unsigned int name_skip) |
| 549 | static void __init kernel_param_sysfs_setup(const char *name, | ||
| 550 | struct kernel_param *kparam, | ||
| 551 | unsigned int num_params, | ||
| 552 | unsigned int name_skip) | ||
| 553 | { | 577 | { |
| 554 | struct module_kobject *mk; | 578 | struct module_kobject *mk; |
| 555 | int ret; | 579 | struct kobject *kobj; |
| 580 | int err; | ||
| 556 | 581 | ||
| 557 | mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); | 582 | kobj = kset_find_obj(module_kset, name); |
| 558 | BUG_ON(!mk); | 583 | if (kobj) { |
| 559 | 584 | /* We already have one. Remove params so we can add more. */ | |
| 560 | mk->mod = THIS_MODULE; | 585 | mk = to_module_kobject(kobj); |
| 561 | mk->kobj.kset = module_kset; | 586 | /* We need to remove it before adding parameters. */ |
| 562 | ret = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, "%s", name); | 587 | sysfs_remove_group(&mk->kobj, &mk->mp->grp); |
| 563 | if (ret) { | 588 | } else { |
| 564 | kobject_put(&mk->kobj); | 589 | mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); |
| 565 | printk(KERN_ERR "Module '%s' failed to be added to sysfs, " | 590 | BUG_ON(!mk); |
| 566 | "error number %d\n", name, ret); | 591 | |
| 567 | printk(KERN_ERR "The system will be unstable now.\n"); | 592 | mk->mod = THIS_MODULE; |
| 568 | return; | 593 | mk->kobj.kset = module_kset; |
| 594 | err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, | ||
| 595 | "%s", name); | ||
| 596 | if (err) { | ||
| 597 | kobject_put(&mk->kobj); | ||
| 598 | printk(KERN_ERR "Module '%s' failed add to sysfs, " | ||
| 599 | "error number %d\n", name, err); | ||
| 600 | printk(KERN_ERR "The system will be unstable now.\n"); | ||
| 601 | return; | ||
| 602 | } | ||
| 603 | /* So that exit path is even. */ | ||
| 604 | kobject_get(&mk->kobj); | ||
| 569 | } | 605 | } |
| 570 | param_sysfs_setup(mk, kparam, num_params, name_skip); | 606 | |
| 607 | /* These should not fail at boot. */ | ||
| 608 | err = add_sysfs_param(mk, kparam, kparam->name + name_skip); | ||
| 609 | BUG_ON(err); | ||
| 610 | err = sysfs_create_group(&mk->kobj, &mk->mp->grp); | ||
| 611 | BUG_ON(err); | ||
| 571 | kobject_uevent(&mk->kobj, KOBJ_ADD); | 612 | kobject_uevent(&mk->kobj, KOBJ_ADD); |
| 613 | kobject_put(&mk->kobj); | ||
| 572 | } | 614 | } |
| 573 | 615 | ||
| 574 | /* | 616 | /* |
| @@ -579,60 +621,36 @@ static void __init kernel_param_sysfs_setup(const char *name, | |||
| 579 | * The "module" name (KBUILD_MODNAME) is stored before a dot, the | 621 | * The "module" name (KBUILD_MODNAME) is stored before a dot, the |
| 580 | * "parameter" name is stored behind a dot in kernel_param->name. So, | 622 | * "parameter" name is stored behind a dot in kernel_param->name. So, |
| 581 | * extract the "module" name for all built-in kernel_param-eters, | 623 | * extract the "module" name for all built-in kernel_param-eters, |
| 582 | * and for all who have the same, call kernel_param_sysfs_setup. | 624 | * and for all who have the same, call kernel_add_sysfs_param. |
| 583 | */ | 625 | */ |
| 584 | static void __init param_sysfs_builtin(void) | 626 | static void __init param_sysfs_builtin(void) |
| 585 | { | 627 | { |
| 586 | struct kernel_param *kp, *kp_begin = NULL; | 628 | struct kernel_param *kp; |
| 587 | unsigned int i, name_len, count = 0; | 629 | unsigned int name_len; |
| 588 | char modname[MODULE_NAME_LEN + 1] = ""; | 630 | char modname[MODULE_NAME_LEN]; |
| 589 | 631 | ||
| 590 | for (i=0; i < __stop___param - __start___param; i++) { | 632 | for (kp = __start___param; kp < __stop___param; kp++) { |
| 591 | char *dot; | 633 | char *dot; |
| 592 | size_t max_name_len; | ||
| 593 | 634 | ||
| 594 | kp = &__start___param[i]; | 635 | if (kp->perm == 0) |
| 595 | max_name_len = | 636 | continue; |
| 596 | min_t(size_t, MODULE_NAME_LEN, strlen(kp->name)); | ||
| 597 | 637 | ||
| 598 | dot = memchr(kp->name, '.', max_name_len); | 638 | dot = strchr(kp->name, '.'); |
| 599 | if (!dot) { | 639 | if (!dot) { |
| 600 | DEBUGP("couldn't find period in first %d characters " | 640 | /* This happens for core_param() */ |
| 601 | "of %s\n", MODULE_NAME_LEN, kp->name); | 641 | strcpy(modname, "kernel"); |
| 602 | continue; | 642 | name_len = 0; |
| 603 | } | 643 | } else { |
| 604 | name_len = dot - kp->name; | 644 | name_len = dot - kp->name + 1; |
| 605 | 645 | strlcpy(modname, kp->name, name_len); | |
| 606 | /* new kbuild_modname? */ | ||
| 607 | if (strlen(modname) != name_len | ||
| 608 | || strncmp(modname, kp->name, name_len) != 0) { | ||
| 609 | /* add a new kobject for previous kernel_params. */ | ||
| 610 | if (count) | ||
| 611 | kernel_param_sysfs_setup(modname, | ||
| 612 | kp_begin, | ||
| 613 | count, | ||
| 614 | strlen(modname)+1); | ||
| 615 | |||
| 616 | strncpy(modname, kp->name, name_len); | ||
| 617 | modname[name_len] = '\0'; | ||
| 618 | count = 0; | ||
| 619 | kp_begin = kp; | ||
| 620 | } | 646 | } |
| 621 | count++; | 647 | kernel_add_sysfs_param(modname, kp, name_len); |
| 622 | } | 648 | } |
| 623 | |||
| 624 | /* last kernel_params need to be registered as well */ | ||
| 625 | if (count) | ||
| 626 | kernel_param_sysfs_setup(modname, kp_begin, count, | ||
| 627 | strlen(modname)+1); | ||
| 628 | } | 649 | } |
| 629 | 650 | ||
| 630 | 651 | ||
| 631 | /* module-related sysfs stuff */ | 652 | /* module-related sysfs stuff */ |
| 632 | 653 | ||
| 633 | #define to_module_attr(n) container_of(n, struct module_attribute, attr); | ||
| 634 | #define to_module_kobject(n) container_of(n, struct module_kobject, kobj); | ||
| 635 | |||
| 636 | static ssize_t module_attr_show(struct kobject *kobj, | 654 | static ssize_t module_attr_show(struct kobject *kobj, |
| 637 | struct attribute *attr, | 655 | struct attribute *attr, |
| 638 | char *buf) | 656 | char *buf) |
