aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/params.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2014-11-09 18:02:29 -0500
committerRusty Russell <rusty@rustcorp.com.au>2014-11-11 01:37:47 -0500
commit18eb74fa94161380c1acc9cf562cb835c4e54a25 (patch)
tree33434c7ac01b5dc7b9a8fc7cd4a02981fe2de93a /kernel/params.c
parent6da0b565150b32318757062bc75834113f0508d6 (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.c95
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
663fail_free_new:
664 kfree(new);
665fail:
666 mk->mp = NULL;
667 return err;
668} 658}
669 659
670#ifdef CONFIG_MODULES 660#ifdef CONFIG_MODULES
671static void free_module_param_attrs(struct module_kobject *mk) 661static 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