summaryrefslogtreecommitdiff
path: root/fs/configfs/dir.c
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2006-03-28 06:46:09 +0400
committerMark Fasheh <mark.fasheh@oracle.com>2006-05-18 01:38:50 +0400
commit84efad1a53dd05969094f9a2562b4e6666571c00 (patch)
tree15ddfe0250f5d59d56e989cd89c682096139c1f5 /fs/configfs/dir.c
parentafae00ab45ea71d89086f924ebee6ca51c81e48e (diff)
downloadlinux-84efad1a53dd05969094f9a2562b4e6666571c00.tar.xz
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>
Diffstat (limited to 'fs/configfs/dir.c')
-rw-r--r--fs/configfs/dir.c37
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)
struct module *owner;
char *name;
- if (dentry->d_parent == configfs_sb->s_root)
- return -EPERM;
+ if (dentry->d_parent == configfs_sb->s_root) {
+ ret = -EPERM;
+ goto out;
+ }
sd = dentry->d_parent->d_fsdata;
- if (!(sd->s_type & CONFIGFS_USET_DIR))
- return -EPERM;
+ if (!(sd->s_type & CONFIGFS_USET_DIR)) {
+ ret = -EPERM;
+ goto out;
+ }
+ /* Get a working ref for the duration of this function */
parent_item = configfs_get_config_item(dentry->d_parent);
type = parent_item->ci_type;
subsys = to_config_group(parent_item)->cg_subsys;
@@ -719,15 +724,16 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (!type || !type->ct_group_ops ||
(!type->ct_group_ops->make_group &&
!type->ct_group_ops->make_item)) {
- config_item_put(parent_item);
- return -EPERM; /* What lack-of-mkdir returns */
+ ret = -EPERM; /* Lack-of-mkdir returns -EPERM */
+ goto out_put;
}
name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL);
if (!name) {
- config_item_put(parent_item);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_put;
}
+
snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);
down(&subsys->su_sem);
@@ -748,8 +754,8 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
kfree(name);
if (!item) {
- config_item_put(parent_item);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_put;
}
ret = -EINVAL;
@@ -776,12 +782,19 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
client_drop_item(parent_item, item);
up(&subsys->su_sem);
- config_item_put(parent_item);
module_put(owner);
}
}
}
+out_put:
+ /*
+ * link_obj()/link_group() took a reference from child->parent.
+ * Drop our working ref
+ */
+ config_item_put(parent_item);
+
+out:
return ret;
}
@@ -801,6 +814,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
if (sd->s_type & CONFIGFS_USET_DEFAULT)
return -EPERM;
+ /* Get a working ref until we have the child */
parent_item = configfs_get_config_item(dentry->d_parent);
subsys = to_config_group(parent_item)->cg_subsys;
BUG_ON(!subsys);
@@ -817,6 +831,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
return ret;
}
+ /* Get a working ref for the duration of this function */
item = configfs_get_config_item(dentry);
/* Drop reference from above, item already holds one. */