diff options
| author | Rusty Russell <rusty@rustcorp.com.au> | 2014-11-09 18:02:29 -0500 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2014-11-11 01:37:47 -0500 |
| commit | 18eb74fa94161380c1acc9cf562cb835c4e54a25 (patch) | |
| tree | 33434c7ac01b5dc7b9a8fc7cd4a02981fe2de93a /kernel | |
| parent | 6da0b565150b32318757062bc75834113f0508d6 (diff) | |
params: cleanup sysfs allocation
commit 63662139e519ce06090b2759cf4a1d291b9cc0e2 attempted to patch a
leak (which would only happen on OOM, ie. never), but it didn't quite
work.
This rewrites the code to be as simple as possible. add_sysfs_param()
adds a parameter. If it fails, it's the caller's responsibility to
clean up the parameters which already exist.
The kzalloc-then-always-krealloc pattern is perhaps overly simplistic,
but this code has clearly confused people. It worked on me...
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/params.c | 95 |
1 files changed, 44 insertions, 51 deletions
diff --git a/kernel/params.c b/kernel/params.c index db97b791390f..795321aba29f 100644 --- a/kernel/params.c +++ b/kernel/params.c | |||
| @@ -603,74 +603,65 @@ static __modinit int add_sysfs_param(struct module_kobject *mk, | |||
| 603 | const struct kernel_param *kp, | 603 | const struct kernel_param *kp, |
| 604 | const char *name) | 604 | const char *name) |
| 605 | { | 605 | { |
| 606 | struct module_param_attrs *new; | 606 | struct module_param_attrs *new_mp; |
| 607 | struct attribute **attrs; | 607 | struct attribute **new_attrs; |
| 608 | int err, num; | 608 | unsigned int i; |
| 609 | 609 | ||
| 610 | /* We don't bother calling this with invisible parameters. */ | 610 | /* We don't bother calling this with invisible parameters. */ |
| 611 | BUG_ON(!kp->perm); | 611 | BUG_ON(!kp->perm); |
| 612 | 612 | ||
| 613 | if (!mk->mp) { | 613 | if (!mk->mp) { |
| 614 | num = 0; | 614 | /* First allocation. */ |
| 615 | attrs = NULL; | 615 | mk->mp = kzalloc(sizeof(*mk->mp), GFP_KERNEL); |
| 616 | } else { | 616 | if (!mk->mp) |
| 617 | num = mk->mp->num; | 617 | return -ENOMEM; |
| 618 | attrs = mk->mp->grp.attrs; | 618 | mk->mp->grp.name = "parameters"; |
| 619 | /* NULL-terminated attribute array. */ | ||
| 620 | mk->mp->grp.attrs = kzalloc(sizeof(mk->mp->grp.attrs[0]), | ||
| 621 | GFP_KERNEL); | ||
| 622 | /* Caller will cleanup via free_module_param_attrs */ | ||
| 623 | if (!mk->mp->grp.attrs) | ||
| 624 | return -ENOMEM; | ||
| 619 | } | 625 | } |
| 620 | 626 | ||
| 621 | /* Enlarge. */ | 627 | /* Enlarge allocations. */ |
| 622 | new = krealloc(mk->mp, | 628 | new_mp = krealloc(mk->mp, |
| 623 | sizeof(*mk->mp) + sizeof(mk->mp->attrs[0]) * (num+1), | 629 | sizeof(*mk->mp) + |
| 624 | GFP_KERNEL); | 630 | sizeof(mk->mp->attrs[0]) * (mk->mp->num + 1), |
| 625 | if (!new) { | 631 | GFP_KERNEL); |
| 626 | kfree(attrs); | 632 | if (!new_mp) |
| 627 | err = -ENOMEM; | 633 | return -ENOMEM; |
| 628 | goto fail; | 634 | mk->mp = new_mp; |
| 629 | } | ||
| 630 | /* Despite looking like the typical realloc() bug, this is safe. | ||
| 631 | * We *want* the old 'attrs' to be freed either way, and we'll store | ||
| 632 | * the new one in the success case. */ | ||
| 633 | attrs = krealloc(attrs, sizeof(new->grp.attrs[0])*(num+2), GFP_KERNEL); | ||
| 634 | if (!attrs) { | ||
| 635 | err = -ENOMEM; | ||
| 636 | goto fail_free_new; | ||
| 637 | } | ||
| 638 | 635 | ||
| 639 | /* Sysfs wants everything zeroed. */ | 636 | /* Extra pointer for NULL terminator */ |
| 640 | memset(new, 0, sizeof(*new)); | 637 | new_attrs = krealloc(mk->mp->grp.attrs, |
| 641 | memset(&new->attrs[num], 0, sizeof(new->attrs[num])); | 638 | sizeof(mk->mp->grp.attrs[0]) * (mk->mp->num + 2), |
| 642 | memset(&attrs[num], 0, sizeof(attrs[num])); | 639 | GFP_KERNEL); |
| 643 | new->grp.name = "parameters"; | 640 | if (!new_attrs) |
| 644 | new->grp.attrs = attrs; | 641 | return -ENOMEM; |
| 642 | mk->mp->grp.attrs = new_attrs; | ||
| 645 | 643 | ||
| 646 | /* Tack new one on the end. */ | 644 | /* Tack new one on the end. */ |
| 647 | sysfs_attr_init(&new->attrs[num].mattr.attr); | 645 | sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr); |
| 648 | new->attrs[num].param = kp; | 646 | mk->mp->attrs[mk->mp->num].param = kp; |
| 649 | new->attrs[num].mattr.show = param_attr_show; | 647 | mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show; |
| 650 | new->attrs[num].mattr.store = param_attr_store; | 648 | mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store; |
| 651 | new->attrs[num].mattr.attr.name = (char *)name; | 649 | mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name; |
| 652 | new->attrs[num].mattr.attr.mode = kp->perm; | 650 | mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm; |
| 653 | new->num = num+1; | 651 | mk->mp->num++; |
| 654 | 652 | ||
| 655 | /* Fix up all the pointers, since krealloc can move us */ | 653 | /* Fix up all the pointers, since krealloc can move us */ |
| 656 | for (num = 0; num < new->num; num++) | 654 | for (i = 0; i < mk->mp->num; i++) |
| 657 | new->grp.attrs[num] = &new->attrs[num].mattr.attr; | 655 | mk->mp->grp.attrs[i] = &mk->mp->attrs[i].mattr.attr; |
| 658 | new->grp.attrs[num] = NULL; | 656 | mk->mp->grp.attrs[mk->mp->num] = NULL; |
| 659 | |||
| 660 | mk->mp = new; | ||
| 661 | return 0; | 657 | return 0; |
| 662 | |||
| 663 | fail_free_new: | ||
| 664 | kfree(new); | ||
| 665 | fail: | ||
| 666 | mk->mp = NULL; | ||
| 667 | return err; | ||
| 668 | } | 658 | } |
| 669 | 659 | ||
| 670 | #ifdef CONFIG_MODULES | 660 | #ifdef CONFIG_MODULES |
| 671 | static void free_module_param_attrs(struct module_kobject *mk) | 661 | static void free_module_param_attrs(struct module_kobject *mk) |
| 672 | { | 662 | { |
| 673 | kfree(mk->mp->grp.attrs); | 663 | if (mk->mp) |
| 664 | kfree(mk->mp->grp.attrs); | ||
| 674 | kfree(mk->mp); | 665 | kfree(mk->mp); |
| 675 | mk->mp = NULL; | 666 | mk->mp = NULL; |
| 676 | } | 667 | } |
| @@ -695,8 +686,10 @@ int module_param_sysfs_setup(struct module *mod, | |||
| 695 | if (kparam[i].perm == 0) | 686 | if (kparam[i].perm == 0) |
| 696 | continue; | 687 | continue; |
| 697 | err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); | 688 | err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); |
| 698 | if (err) | 689 | if (err) { |
| 690 | free_module_param_attrs(&mod->mkobj); | ||
| 699 | return err; | 691 | return err; |
| 692 | } | ||
| 700 | params = true; | 693 | params = true; |
| 701 | } | 694 | } |
| 702 | 695 | ||
