diff options
author | Joel Becker <joel.becker@oracle.com> | 2006-03-27 21:46:09 -0500 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2006-05-17 17:38:50 -0400 |
commit | 84efad1a53dd05969094f9a2562b4e6666571c00 (patch) | |
tree | 15ddfe0250f5d59d56e989cd89c682096139c1f5 | |
parent | afae00ab45ea71d89086f924ebee6ca51c81e48e (diff) |
configfs: Fix a reference leak in configfs_mkdir().
configfs_mkdir() failed to release the working parent reference in most
exit paths. Also changed the exit path for readability.
Signed-off-by: Joel Becker <joel.becker@oracle.com>
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
-rw-r--r-- | fs/configfs/dir.c | 37 |
1 files changed, 26 insertions, 11 deletions
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 5638c8f9362f..810c1395d6b2 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -704,13 +704,18 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
704 | struct module *owner; | 704 | struct module *owner; |
705 | char *name; | 705 | char *name; |
706 | 706 | ||
707 | if (dentry->d_parent == configfs_sb->s_root) | 707 | if (dentry->d_parent == configfs_sb->s_root) { |
708 | return -EPERM; | 708 | ret = -EPERM; |
709 | goto out; | ||
710 | } | ||
709 | 711 | ||
710 | sd = dentry->d_parent->d_fsdata; | 712 | sd = dentry->d_parent->d_fsdata; |
711 | if (!(sd->s_type & CONFIGFS_USET_DIR)) | 713 | if (!(sd->s_type & CONFIGFS_USET_DIR)) { |
712 | return -EPERM; | 714 | ret = -EPERM; |
715 | goto out; | ||
716 | } | ||
713 | 717 | ||
718 | /* Get a working ref for the duration of this function */ | ||
714 | parent_item = configfs_get_config_item(dentry->d_parent); | 719 | parent_item = configfs_get_config_item(dentry->d_parent); |
715 | type = parent_item->ci_type; | 720 | type = parent_item->ci_type; |
716 | subsys = to_config_group(parent_item)->cg_subsys; | 721 | subsys = to_config_group(parent_item)->cg_subsys; |
@@ -719,15 +724,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
719 | if (!type || !type->ct_group_ops || | 724 | if (!type || !type->ct_group_ops || |
720 | (!type->ct_group_ops->make_group && | 725 | (!type->ct_group_ops->make_group && |
721 | !type->ct_group_ops->make_item)) { | 726 | !type->ct_group_ops->make_item)) { |
722 | config_item_put(parent_item); | 727 | ret = -EPERM; /* Lack-of-mkdir returns -EPERM */ |
723 | return -EPERM; /* What lack-of-mkdir returns */ | 728 | goto out_put; |
724 | } | 729 | } |
725 | 730 | ||
726 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); | 731 | name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL); |
727 | if (!name) { | 732 | if (!name) { |
728 | config_item_put(parent_item); | 733 | ret = -ENOMEM; |
729 | return -ENOMEM; | 734 | goto out_put; |
730 | } | 735 | } |
736 | |||
731 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); | 737 | snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name); |
732 | 738 | ||
733 | down(&subsys->su_sem); | 739 | down(&subsys->su_sem); |
@@ -748,8 +754,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
748 | 754 | ||
749 | kfree(name); | 755 | kfree(name); |
750 | if (!item) { | 756 | if (!item) { |
751 | config_item_put(parent_item); | 757 | ret = -ENOMEM; |
752 | return -ENOMEM; | 758 | goto out_put; |
753 | } | 759 | } |
754 | 760 | ||
755 | ret = -EINVAL; | 761 | ret = -EINVAL; |
@@ -776,12 +782,19 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
776 | client_drop_item(parent_item, item); | 782 | client_drop_item(parent_item, item); |
777 | up(&subsys->su_sem); | 783 | up(&subsys->su_sem); |
778 | 784 | ||
779 | config_item_put(parent_item); | ||
780 | module_put(owner); | 785 | module_put(owner); |
781 | } | 786 | } |
782 | } | 787 | } |
783 | } | 788 | } |
784 | 789 | ||
790 | out_put: | ||
791 | /* | ||
792 | * link_obj()/link_group() took a reference from child->parent. | ||
793 | * Drop our working ref | ||
794 | */ | ||
795 | config_item_put(parent_item); | ||
796 | |||
797 | out: | ||
785 | return ret; | 798 | return ret; |
786 | } | 799 | } |
787 | 800 | ||
@@ -801,6 +814,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
801 | if (sd->s_type & CONFIGFS_USET_DEFAULT) | 814 | if (sd->s_type & CONFIGFS_USET_DEFAULT) |
802 | return -EPERM; | 815 | return -EPERM; |
803 | 816 | ||
817 | /* Get a working ref until we have the child */ | ||
804 | parent_item = configfs_get_config_item(dentry->d_parent); | 818 | parent_item = configfs_get_config_item(dentry->d_parent); |
805 | subsys = to_config_group(parent_item)->cg_subsys; | 819 | subsys = to_config_group(parent_item)->cg_subsys; |
806 | BUG_ON(!subsys); | 820 | BUG_ON(!subsys); |
@@ -817,6 +831,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
817 | return ret; | 831 | return ret; |
818 | } | 832 | } |
819 | 833 | ||
834 | /* Get a working ref for the duration of this function */ | ||
820 | item = configfs_get_config_item(dentry); | 835 | item = configfs_get_config_item(dentry); |
821 | 836 | ||
822 | /* Drop reference from above, item already holds one. */ | 837 | /* Drop reference from above, item already holds one. */ |