Skip to content

Commit bb289b7

Browse files
osandovmasoncl
authored andcommitted
Btrfs: fail on mismatched subvol and subvolid mount options
There's nothing to stop a user from passing both subvol= and subvolid= to mount, but if they don't refer to the same subvolume, someone is going to be surprised at some point. Error out on this case, but allow users to pass in both if they do match (which they could, for example, get out of /proc/mounts). Reviewed-by: David Sterba <[email protected]> Signed-off-by: Omar Sandoval <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent fa33065 commit bb289b7

File tree

1 file changed

+25
-8
lines changed

1 file changed

+25
-8
lines changed

fs/btrfs/super.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,8 +1167,9 @@ static char *setup_root_args(char *args)
11671167
return buf;
11681168
}
11691169

1170-
static struct dentry *mount_subvol(const char *subvol_name, int flags,
1171-
const char *device_name, char *data)
1170+
static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
1171+
int flags, const char *device_name,
1172+
char *data)
11721173
{
11731174
struct dentry *root;
11741175
struct vfsmount *mnt = NULL;
@@ -1214,12 +1215,27 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
12141215
/* mount_subtree() drops our reference on the vfsmount. */
12151216
mnt = NULL;
12161217

1217-
if (!IS_ERR(root) && !is_subvolume_inode(d_inode(root))) {
1218+
if (!IS_ERR(root)) {
12181219
struct super_block *s = root->d_sb;
1219-
dput(root);
1220-
root = ERR_PTR(-EINVAL);
1221-
deactivate_locked_super(s);
1222-
pr_err("BTRFS: '%s' is not a valid subvolume\n", subvol_name);
1220+
struct inode *root_inode = d_inode(root);
1221+
u64 root_objectid = BTRFS_I(root_inode)->root->root_key.objectid;
1222+
1223+
ret = 0;
1224+
if (!is_subvolume_inode(root_inode)) {
1225+
pr_err("BTRFS: '%s' is not a valid subvolume\n",
1226+
subvol_name);
1227+
ret = -EINVAL;
1228+
}
1229+
if (subvol_objectid && root_objectid != subvol_objectid) {
1230+
pr_err("BTRFS: subvol '%s' does not match subvolid %llu\n",
1231+
subvol_name, subvol_objectid);
1232+
ret = -EINVAL;
1233+
}
1234+
if (ret) {
1235+
dput(root);
1236+
root = ERR_PTR(ret);
1237+
deactivate_locked_super(s);
1238+
}
12231239
}
12241240

12251241
out:
@@ -1312,7 +1328,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
13121328

13131329
if (subvol_name) {
13141330
/* mount_subvol() will free subvol_name. */
1315-
return mount_subvol(subvol_name, flags, device_name, data);
1331+
return mount_subvol(subvol_name, subvol_objectid, flags,
1332+
device_name, data);
13161333
}
13171334

13181335
security_init_mnt_opts(&new_sec_opts);

0 commit comments

Comments
 (0)