summaryrefslogtreecommitdiffstats
path: root/fs/btrfs/super.c
diff options
context:
space:
mode:
authorOmar Sandoval2015-05-18 11:16:28 +0200
committerChris Mason2015-06-03 13:02:59 +0200
commitfa3306595071ae03e181c2336d0dcd8f5e3cf9b0 (patch)
treeaf48f275b97a747a9fc7b270c80bf0c257cf1e5b /fs/btrfs/super.c
parentBtrfs: remove all subvol options before mounting top-level (diff)
downloadkernel-qcow2-linux-fa3306595071ae03e181c2336d0dcd8f5e3cf9b0.tar.gz
kernel-qcow2-linux-fa3306595071ae03e181c2336d0dcd8f5e3cf9b0.tar.xz
kernel-qcow2-linux-fa3306595071ae03e181c2336d0dcd8f5e3cf9b0.zip
Btrfs: clean up error handling in mount_subvol()
In preparation for new functionality in mount_subvol(), give it ownership of subvol_name and tidy up the error paths. Reviewed-by: David Sterba <dsterba@suse.cz> Signed-off-by: Omar Sandoval <osandov@osandov.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r--fs/btrfs/super.c61
1 files changed, 33 insertions, 28 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 1c57c0d0dc41..dd89dd353c4a 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1171,55 +1171,61 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
const char *device_name, char *data)
{
struct dentry *root;
- struct vfsmount *mnt;
+ struct vfsmount *mnt = NULL;
char *newargs;
+ int ret;
newargs = setup_root_args(data);
- if (!newargs)
- return ERR_PTR(-ENOMEM);
- mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name,
- newargs);
+ if (!newargs) {
+ root = ERR_PTR(-ENOMEM);
+ goto out;
+ }
- if (PTR_RET(mnt) == -EBUSY) {
+ mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name, newargs);
+ if (PTR_ERR_OR_ZERO(mnt) == -EBUSY) {
if (flags & MS_RDONLY) {
- mnt = vfs_kern_mount(&btrfs_fs_type, flags & ~MS_RDONLY, device_name,
- newargs);
+ mnt = vfs_kern_mount(&btrfs_fs_type, flags & ~MS_RDONLY,
+ device_name, newargs);
} else {
- int r;
- mnt = vfs_kern_mount(&btrfs_fs_type, flags | MS_RDONLY, device_name,
- newargs);
+ mnt = vfs_kern_mount(&btrfs_fs_type, flags | MS_RDONLY,
+ device_name, newargs);
if (IS_ERR(mnt)) {
- kfree(newargs);
- return ERR_CAST(mnt);
+ root = ERR_CAST(mnt);
+ mnt = NULL;
+ goto out;
}
down_write(&mnt->mnt_sb->s_umount);
- r = btrfs_remount(mnt->mnt_sb, &flags, NULL);
+ ret = btrfs_remount(mnt->mnt_sb, &flags, NULL);
up_write(&mnt->mnt_sb->s_umount);
- if (r < 0) {
- /* FIXME: release vfsmount mnt ??*/
- kfree(newargs);
- return ERR_PTR(r);
+ if (ret < 0) {
+ root = ERR_PTR(ret);
+ goto out;
}
}
}
-
- kfree(newargs);
-
- if (IS_ERR(mnt))
- return ERR_CAST(mnt);
+ if (IS_ERR(mnt)) {
+ root = ERR_CAST(mnt);
+ mnt = NULL;
+ goto out;
+ }
root = mount_subtree(mnt, subvol_name);
+ /* mount_subtree() drops our reference on the vfsmount. */
+ mnt = NULL;
if (!IS_ERR(root) && !is_subvolume_inode(d_inode(root))) {
struct super_block *s = root->d_sb;
dput(root);
root = ERR_PTR(-EINVAL);
deactivate_locked_super(s);
- printk(KERN_ERR "BTRFS: '%s' is not a valid subvolume\n",
- subvol_name);
+ pr_err("BTRFS: '%s' is not a valid subvolume\n", subvol_name);
}
+out:
+ mntput(mnt);
+ kfree(newargs);
+ kfree(subvol_name);
return root;
}
@@ -1305,9 +1311,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
}
if (subvol_name) {
- root = mount_subvol(subvol_name, flags, device_name, data);
- kfree(subvol_name);
- return root;
+ /* mount_subvol() will free subvol_name. */
+ return mount_subvol(subvol_name, flags, device_name, data);
}
security_init_mnt_opts(&new_sec_opts);