Skip to content

Commit 312c89f

Browse files
t-msnkdave
authored andcommitted
btrfs: cleanup btrfs_mount() using btrfs_mount_root()
Cleanup btrfs_mount() by using btrfs_mount_root(). This avoids getting btrfs_mount() called twice in mount path. Old btrfs_mount() will do: 0. VFS layer calls vfs_kern_mount() with registered file_system_type (for btrfs, btrfs_fs_type). btrfs_mount() is called on the way. 1. btrfs_parse_early_options() parses "subvolid=" mount option and set the value to subvol_objectid. Otherwise, subvol_objectid has the initial value of 0 2. check subvol_objectid is 5 or not. Assume this time id is not 5, then btrfs_mount() returns by calling mount_subvol() 3. In mount_subvol(), original mount options are modified to contain "subvolid=0" in setup_root_args(). Then, vfs_kern_mount() is called with btrfs_fs_type and new options 4. btrfs_mount() is called again 5. btrfs_parse_early_options() parses "subvolid=0" and set 5 (instead of 0) to subvol_objectid 6. check subvol_objectid is 5 or not. This time id is 5 and mount_subvol() is not called. btrfs_mount() finishes mounting a root 7. (in mount_subvol()) with using a return vale of vfs_kern_mount(), it calls mount_subtree() 8. return subvolume's dentry Reusing the same file_system_type (and btrfs_mount()) for vfs_kern_mount() is the cause of complication. Instead, new btrfs_mount() will do: 1. parse subvol id related options for later use in mount_subvol() 2. mount device's root by calling vfs_kern_mount() with btrfs_root_fs_type, which is not registered to VFS by register_filesystem(). As a result, btrfs_mount_root() is called 3. return by calling mount_subvol() The code of 2. is moved from the first part of mount_subvol(). The semantics of device holder changes from btrfs_fs_type to btrfs_root_fs_type and has to be used in all contexts. Otherwise we'd get wrong results when mount and dev scan would not check the same thing. (this has been found indendently and the fix is folded into this patch) Signed-off-by: Tomohiro Misono <misono.tomohiro@jp.fujitsu.com> Reviewed-by: David Sterba <dsterba@suse.com> [ fold the btrfs_control_ioctl fixup, extend the comment ] Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 72fa39f commit 312c89f

File tree

1 file changed

+63
-130
lines changed

1 file changed

+63
-130
lines changed

fs/btrfs/super.c

Lines changed: 63 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ static const struct super_operations btrfs_super_ops;
7171
* requested by subvol=/path. That way the callchain is straightforward and we
7272
* don't have to play tricks with the mount options and recursive calls to
7373
* btrfs_mount.
74+
*
75+
* The new btrfs_root_fs_type also servers as a tag for the bdev_holder.
7476
*/
7577
static struct file_system_type btrfs_fs_type;
7678
static struct file_system_type btrfs_root_fs_type;
@@ -1405,48 +1407,11 @@ static char *setup_root_args(char *args)
14051407

14061408
static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
14071409
int flags, const char *device_name,
1408-
char *data)
1410+
char *data, struct vfsmount *mnt)
14091411
{
14101412
struct dentry *root;
1411-
struct vfsmount *mnt = NULL;
1412-
char *newargs;
14131413
int ret;
14141414

1415-
newargs = setup_root_args(data);
1416-
if (!newargs) {
1417-
root = ERR_PTR(-ENOMEM);
1418-
goto out;
1419-
}
1420-
1421-
mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name, newargs);
1422-
if (PTR_ERR_OR_ZERO(mnt) == -EBUSY) {
1423-
if (flags & SB_RDONLY) {
1424-
mnt = vfs_kern_mount(&btrfs_fs_type, flags & ~SB_RDONLY,
1425-
device_name, newargs);
1426-
} else {
1427-
mnt = vfs_kern_mount(&btrfs_fs_type, flags | SB_RDONLY,
1428-
device_name, newargs);
1429-
if (IS_ERR(mnt)) {
1430-
root = ERR_CAST(mnt);
1431-
mnt = NULL;
1432-
goto out;
1433-
}
1434-
1435-
down_write(&mnt->mnt_sb->s_umount);
1436-
ret = btrfs_remount(mnt->mnt_sb, &flags, NULL);
1437-
up_write(&mnt->mnt_sb->s_umount);
1438-
if (ret < 0) {
1439-
root = ERR_PTR(ret);
1440-
goto out;
1441-
}
1442-
}
1443-
}
1444-
if (IS_ERR(mnt)) {
1445-
root = ERR_CAST(mnt);
1446-
mnt = NULL;
1447-
goto out;
1448-
}
1449-
14501415
if (!subvol_name) {
14511416
if (!subvol_objectid) {
14521417
ret = get_default_subvol_objectid(btrfs_sb(mnt->mnt_sb),
@@ -1502,7 +1467,6 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
15021467

15031468
out:
15041469
mntput(mnt);
1505-
kfree(newargs);
15061470
kfree(subvol_name);
15071471
return root;
15081472
}
@@ -1557,6 +1521,12 @@ static int setup_security_options(struct btrfs_fs_info *fs_info,
15571521
return ret;
15581522
}
15591523

1524+
/*
1525+
* Find a superblock for the given device / mount point.
1526+
*
1527+
* Note: This is based on mount_bdev from fs/super.c with a few additions
1528+
* for multiple device setup. Make sure to keep it in sync.
1529+
*/
15601530
static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
15611531
int flags, const char *device_name, void *data)
15621532
{
@@ -1663,20 +1633,35 @@ static struct dentry *btrfs_mount_root(struct file_system_type *fs_type,
16631633
security_free_mnt_opts(&new_sec_opts);
16641634
return ERR_PTR(error);
16651635
}
1636+
16661637
/*
1667-
* Find a superblock for the given device / mount point.
1638+
* Mount function which is called by VFS layer.
16681639
*
1669-
* Note: This is based on get_sb_bdev from fs/super.c with a few additions
1670-
* for multiple device setup. Make sure to keep it in sync.
1640+
* In order to allow mounting a subvolume directly, btrfs uses mount_subtree()
1641+
* which needs vfsmount* of device's root (/). This means device's root has to
1642+
* be mounted internally in any case.
1643+
*
1644+
* Operation flow:
1645+
* 1. Parse subvol id related options for later use in mount_subvol().
1646+
*
1647+
* 2. Mount device's root (/) by calling vfs_kern_mount().
1648+
*
1649+
* NOTE: vfs_kern_mount() is used by VFS to call btrfs_mount() in the
1650+
* first place. In order to avoid calling btrfs_mount() again, we use
1651+
* different file_system_type which is not registered to VFS by
1652+
* register_filesystem() (btrfs_root_fs_type). As a result,
1653+
* btrfs_mount_root() is called. The return value will be used by
1654+
* mount_subtree() in mount_subvol().
1655+
*
1656+
* 3. Call mount_subvol() to get the dentry of subvolume. Since there is
1657+
* "btrfs subvolume set-default", mount_subvol() is called always.
16711658
*/
16721659
static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
16731660
const char *device_name, void *data)
16741661
{
1675-
struct block_device *bdev = NULL;
1676-
struct super_block *s;
16771662
struct btrfs_fs_devices *fs_devices = NULL;
1678-
struct btrfs_fs_info *fs_info = NULL;
1679-
struct security_mnt_opts new_sec_opts;
1663+
struct vfsmount *mnt_root;
1664+
struct dentry *root;
16801665
fmode_t mode = FMODE_READ;
16811666
char *subvol_name = NULL;
16821667
u64 subvol_objectid = 0;
@@ -1693,93 +1678,41 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
16931678
return ERR_PTR(error);
16941679
}
16951680

1696-
if (subvol_name || subvol_objectid != BTRFS_FS_TREE_OBJECTID) {
1697-
/* mount_subvol() will free subvol_name. */
1698-
return mount_subvol(subvol_name, subvol_objectid, flags,
1699-
device_name, data);
1700-
}
1701-
1702-
security_init_mnt_opts(&new_sec_opts);
1703-
if (data) {
1704-
error = parse_security_options(data, &new_sec_opts);
1705-
if (error)
1706-
return ERR_PTR(error);
1707-
}
1708-
1709-
error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices);
1710-
if (error)
1711-
goto error_sec_opts;
1712-
1713-
/*
1714-
* Setup a dummy root and fs_info for test/set super. This is because
1715-
* we don't actually fill this stuff out until open_ctree, but we need
1716-
* it for searching for existing supers, so this lets us do that and
1717-
* then open_ctree will properly initialize everything later.
1718-
*/
1719-
fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_KERNEL);
1720-
if (!fs_info) {
1721-
error = -ENOMEM;
1722-
goto error_sec_opts;
1723-
}
1724-
1725-
fs_info->fs_devices = fs_devices;
1726-
1727-
fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
1728-
fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_KERNEL);
1729-
security_init_mnt_opts(&fs_info->security_opts);
1730-
if (!fs_info->super_copy || !fs_info->super_for_commit) {
1731-
error = -ENOMEM;
1732-
goto error_fs_info;
1733-
}
1734-
1735-
error = btrfs_open_devices(fs_devices, mode, fs_type);
1736-
if (error)
1737-
goto error_fs_info;
1738-
1739-
if (!(flags & SB_RDONLY) && fs_devices->rw_devices == 0) {
1740-
error = -EACCES;
1741-
goto error_close_devices;
1742-
}
1743-
1744-
bdev = fs_devices->latest_bdev;
1745-
s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | SB_NOSEC,
1746-
fs_info);
1747-
if (IS_ERR(s)) {
1748-
error = PTR_ERR(s);
1749-
goto error_close_devices;
1750-
}
1681+
/* mount device's root (/) */
1682+
mnt_root = vfs_kern_mount(&btrfs_root_fs_type, flags, device_name, data);
1683+
if (PTR_ERR_OR_ZERO(mnt_root) == -EBUSY) {
1684+
if (flags & SB_RDONLY) {
1685+
mnt_root = vfs_kern_mount(&btrfs_root_fs_type,
1686+
flags & ~SB_RDONLY, device_name, data);
1687+
} else {
1688+
mnt_root = vfs_kern_mount(&btrfs_root_fs_type,
1689+
flags | SB_RDONLY, device_name, data);
1690+
if (IS_ERR(mnt_root)) {
1691+
root = ERR_CAST(mnt_root);
1692+
goto out;
1693+
}
17511694

1752-
if (s->s_root) {
1753-
btrfs_close_devices(fs_devices);
1754-
free_fs_info(fs_info);
1755-
if ((flags ^ s->s_flags) & SB_RDONLY)
1756-
error = -EBUSY;
1757-
} else {
1758-
snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
1759-
btrfs_sb(s)->bdev_holder = fs_type;
1760-
error = btrfs_fill_super(s, fs_devices, data);
1761-
}
1762-
if (error) {
1763-
deactivate_locked_super(s);
1764-
goto error_sec_opts;
1695+
down_write(&mnt_root->mnt_sb->s_umount);
1696+
error = btrfs_remount(mnt_root->mnt_sb, &flags, NULL);
1697+
up_write(&mnt_root->mnt_sb->s_umount);
1698+
if (error < 0) {
1699+
root = ERR_PTR(error);
1700+
mntput(mnt_root);
1701+
goto out;
1702+
}
1703+
}
17651704
}
1766-
1767-
fs_info = btrfs_sb(s);
1768-
error = setup_security_options(fs_info, s, &new_sec_opts);
1769-
if (error) {
1770-
deactivate_locked_super(s);
1771-
goto error_sec_opts;
1705+
if (IS_ERR(mnt_root)) {
1706+
root = ERR_CAST(mnt_root);
1707+
goto out;
17721708
}
17731709

1774-
return dget(s->s_root);
1710+
/* mount_subvol() will free subvol_name and mnt_root */
1711+
root = mount_subvol(subvol_name, subvol_objectid, flags, device_name,
1712+
data, mnt_root);
17751713

1776-
error_close_devices:
1777-
btrfs_close_devices(fs_devices);
1778-
error_fs_info:
1779-
free_fs_info(fs_info);
1780-
error_sec_opts:
1781-
security_free_mnt_opts(&new_sec_opts);
1782-
return ERR_PTR(error);
1714+
out:
1715+
return root;
17831716
}
17841717

17851718
static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
@@ -2326,11 +2259,11 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
23262259
switch (cmd) {
23272260
case BTRFS_IOC_SCAN_DEV:
23282261
ret = btrfs_scan_one_device(vol->name, FMODE_READ,
2329-
&btrfs_fs_type, &fs_devices);
2262+
&btrfs_root_fs_type, &fs_devices);
23302263
break;
23312264
case BTRFS_IOC_DEVICES_READY:
23322265
ret = btrfs_scan_one_device(vol->name, FMODE_READ,
2333-
&btrfs_fs_type, &fs_devices);
2266+
&btrfs_root_fs_type, &fs_devices);
23342267
if (ret)
23352268
break;
23362269
ret = !(fs_devices->num_devices == fs_devices->total_devices);

0 commit comments

Comments
 (0)