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/params.c | |
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/params.c')
-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 | ||