diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index dd89dd353c4ae84154dd8975d8cffdaa744e1aad..3ad97953537c3b49db6297f0ef72d08c02ab57c8 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -1167,8 +1167,9 @@ static char *setup_root_args(char *args) return buf; } -static struct dentry *mount_subvol(const char *subvol_name, int flags, - const char *device_name, char *data) +static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid, + int flags, const char *device_name, + char *data) { struct dentry *root; struct vfsmount *mnt = NULL; @@ -1214,12 +1215,27 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags, /* mount_subtree() drops our reference on the vfsmount. */ mnt = NULL; - if (!IS_ERR(root) && !is_subvolume_inode(d_inode(root))) { + if (!IS_ERR(root)) { struct super_block *s = root->d_sb; - dput(root); - root = ERR_PTR(-EINVAL); - deactivate_locked_super(s); - pr_err("BTRFS: '%s' is not a valid subvolume\n", subvol_name); + struct inode *root_inode = d_inode(root); + u64 root_objectid = BTRFS_I(root_inode)->root->root_key.objectid; + + ret = 0; + if (!is_subvolume_inode(root_inode)) { + pr_err("BTRFS: '%s' is not a valid subvolume\n", + subvol_name); + ret = -EINVAL; + } + if (subvol_objectid && root_objectid != subvol_objectid) { + pr_err("BTRFS: subvol '%s' does not match subvolid %llu\n", + subvol_name, subvol_objectid); + ret = -EINVAL; + } + if (ret) { + dput(root); + root = ERR_PTR(ret); + deactivate_locked_super(s); + } } out: @@ -1312,7 +1328,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, if (subvol_name) { /* mount_subvol() will free subvol_name. */ - return mount_subvol(subvol_name, flags, device_name, data); + return mount_subvol(subvol_name, subvol_objectid, flags, + device_name, data); } security_init_mnt_opts(&new_sec_opts);