* [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts
@ 2015-05-18 9:16 Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 1/6] Btrfs: lock superblock before remounting for rw subvol Omar Sandoval
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
Now that we've reached an agreement, I've rebased this series on top of
v4.1-rc3 (there were some minor conflicts with the ->d_inode to
d_inode() conversion merged in v4.1-rc1, no other code changes).
This change makes things just a little bit friendlier for users and also
cleans up the mount path. David mentioned that he's also using this
patchset as a base for per-subvolume mount flag support. He's reviewed
all of the patches in this series. Please consider for 4.2!
v2: https://lkml.org/lkml/2015/4/9/906
v1: https://lkml.org/lkml/2015/4/8/16
Omar Sandoval (6):
Btrfs: lock superblock before remounting for rw subvol
Btrfs: remove all subvol options before mounting top-level
Btrfs: clean up error handling in mount_subvol()
Btrfs: fail on mismatched subvol and subvolid mount options
Btrfs: unify subvol= and subvolid= mounting
Btrfs: show subvol= and subvolid= in /proc/mounts
fs/btrfs/super.c | 386 ++++++++++++++++++++++++++++++++++++-------------------
fs/seq_file.c | 1 +
2 files changed, 252 insertions(+), 135 deletions(-)
--
2.4.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 1/6] Btrfs: lock superblock before remounting for rw subvol
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
@ 2015-05-18 9:16 ` Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 2/6] Btrfs: remove all subvol options before mounting top-level Omar Sandoval
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
Since commit 0723a0473fb4 ("btrfs: allow mounting btrfs subvolumes with
different ro/rw options"), when mounting a subvolume read/write when
another subvolume has previously been mounted read-only, we first do a
remount. However, this should be done with the superblock locked, as per
sync_filesystem():
/*
* We need to be protected against the filesystem going from
* r/o to r/w or vice versa.
*/
WARN_ON(!rwsem_is_locked(&sb->s_umount));
This WARN_ON can easily be hit with:
mkfs.btrfs -f /dev/vdb
mount /dev/vdb /mnt
btrfs subvol create /mnt/vol1
btrfs subvol create /mnt/vol2
umount /mnt
mount -oro,subvol=/vol1 /dev/vdb /mnt
mount -orw,subvol=/vol2 /dev/vdb /mnt2
Fixes: 0723a0473fb4 ("btrfs: allow mounting btrfs subvolumes with different ro/rw options")
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
fs/btrfs/super.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 9e66f5e..0576750 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1214,7 +1214,9 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
return ERR_CAST(mnt);
}
+ down_write(&mnt->mnt_sb->s_umount);
r = btrfs_remount(mnt->mnt_sb, &flags, NULL);
+ up_write(&mnt->mnt_sb->s_umount);
if (r < 0) {
/* FIXME: release vfsmount mnt ??*/
kfree(newargs);
--
2.4.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 2/6] Btrfs: remove all subvol options before mounting top-level
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 1/6] Btrfs: lock superblock before remounting for rw subvol Omar Sandoval
@ 2015-05-18 9:16 ` Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 3/6] Btrfs: clean up error handling in mount_subvol() Omar Sandoval
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
Currently, setup_root_args() substitutes 's/subvol=[^,]*/subvolid=0/'.
But, this means that if the user passes both a subvol and subvolid for
some reason, we won't actually mount the top-level when we recursively
mount. For example, consider:
mkfs.btrfs -f /dev/sdb
mount /dev/sdb /mnt
btrfs subvol create /mnt/subvol1 # subvolid=257
btrfs subvol create /mnt/subvol2 # subvolid=258
umount /mnt
mount -osubvol=/subvol1,subvolid=258 /dev/sdb /mnt
In the final mount, subvol=/subvol1,subvolid=258 becomes
subvolid=0,subvolid=258, and the last option takes precedence, so we
mount subvol2 and try to look up subvol1 inside of it, which fails.
So, instead, do a thorough scan through the argument list and remove any
subvol= and subvolid= options, then append subvolid=0 to the end. This
implicitly makes subvol= take precedence over subvolid=, but we're about
to add a stricter check for that. This also makes setup_root_args() more
generic, which we'll need soon.
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
fs/btrfs/super.c | 56 ++++++++++++++++++++------------------------------------
1 file changed, 20 insertions(+), 36 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 0576750..b5d04e4 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1138,52 +1138,36 @@ static inline int is_subvolume_inode(struct inode *inode)
}
/*
- * This will strip out the subvol=%s argument for an argument string and add
- * subvolid=0 to make sure we get the actual tree root for path walking to the
- * subvol we want.
+ * This will add subvolid=0 to the argument string while removing any subvol=
+ * and subvolid= arguments to make sure we get the top-level root for path
+ * walking to the subvol we want.
*/
static char *setup_root_args(char *args)
{
- unsigned len = strlen(args) + 2 + 1;
- char *src, *dst, *buf;
+ char *buf, *dst, *sep;
- /*
- * We need the same args as before, but with this substitution:
- * s!subvol=[^,]+!subvolid=0!
- *
- * Since the replacement string is up to 2 bytes longer than the
- * original, allocate strlen(args) + 2 + 1 bytes.
- */
-
- src = strstr(args, "subvol=");
- /* This shouldn't happen, but just in case.. */
- if (!src)
- return NULL;
+ if (!args)
+ return kstrdup("subvolid=0", GFP_NOFS);
- buf = dst = kmalloc(len, GFP_NOFS);
+ /* The worst case is that we add ",subvolid=0" to the end. */
+ buf = dst = kmalloc(strlen(args) + strlen(",subvolid=0") + 1, GFP_NOFS);
if (!buf)
return NULL;
- /*
- * If the subvol= arg is not at the start of the string,
- * copy whatever precedes it into buf.
- */
- if (src != args) {
- *src++ = '\0';
- strcpy(buf, args);
- dst += strlen(args);
+ while (1) {
+ sep = strchrnul(args, ',');
+ if (!strstarts(args, "subvol=") &&
+ !strstarts(args, "subvolid=")) {
+ memcpy(dst, args, sep - args);
+ dst += sep - args;
+ *dst++ = ',';
+ }
+ if (*sep)
+ args = sep + 1;
+ else
+ break;
}
-
strcpy(dst, "subvolid=0");
- dst += strlen("subvolid=0");
-
- /*
- * If there is a "," after the original subvol=... string,
- * copy that suffix into our buffer. Otherwise, we're done.
- */
- src = strchr(src, ',');
- if (src)
- strcpy(dst, src);
return buf;
}
--
2.4.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 3/6] Btrfs: clean up error handling in mount_subvol()
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 1/6] Btrfs: lock superblock before remounting for rw subvol Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 2/6] Btrfs: remove all subvol options before mounting top-level Omar Sandoval
@ 2015-05-18 9:16 ` Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 4/6] Btrfs: fail on mismatched subvol and subvolid mount options Omar Sandoval
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
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>
---
fs/btrfs/super.c | 61 ++++++++++++++++++++++++++++++--------------------------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index b5d04e4..460e0ea 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1176,55 +1176,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;
}
@@ -1310,9 +1316,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);
--
2.4.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 4/6] Btrfs: fail on mismatched subvol and subvolid mount options
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
` (2 preceding siblings ...)
2015-05-18 9:16 ` [PATCH v3 3/6] Btrfs: clean up error handling in mount_subvol() Omar Sandoval
@ 2015-05-18 9:16 ` Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 5/6] Btrfs: unify subvol= and subvolid= mounting Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 6/6] Btrfs: show subvol= and subvolid= in /proc/mounts Omar Sandoval
5 siblings, 0 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
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 <dsterba@suse.cz>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
fs/btrfs/super.c | 33 +++++++++++++++++++++++++--------
1 file changed, 25 insertions(+), 8 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 460e0ea..d3e312b 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1172,8 +1172,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;
@@ -1219,12 +1220,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:
@@ -1317,7 +1333,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);
--
2.4.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 5/6] Btrfs: unify subvol= and subvolid= mounting
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
` (3 preceding siblings ...)
2015-05-18 9:16 ` [PATCH v3 4/6] Btrfs: fail on mismatched subvol and subvolid mount options Omar Sandoval
@ 2015-05-18 9:16 ` Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 6/6] Btrfs: show subvol= and subvolid= in /proc/mounts Omar Sandoval
5 siblings, 0 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
Currently, mounting a subvolume with subvolid= takes a different code
path than mounting with subvol=. This isn't really a big deal except for
the fact that mounts done with subvolid= or the default subvolume don't
have a dentry that's connected to the dentry tree like in the subvol=
case. To unify the code paths, when given subvolid= or using the default
subvolume ID, translate it into a subvolume name by walking
ROOT_BACKREFs in the root tree and INODE_REFs in the filesystem trees.
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
fs/btrfs/super.c | 238 +++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 171 insertions(+), 67 deletions(-)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index d3e312b..dc51a51 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -841,33 +841,153 @@ out:
return error;
}
-static struct dentry *get_default_root(struct super_block *sb,
- u64 subvol_objectid)
+static char *get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info,
+ u64 subvol_objectid)
{
- struct btrfs_fs_info *fs_info = btrfs_sb(sb);
struct btrfs_root *root = fs_info->tree_root;
- struct btrfs_root *new_root;
- struct btrfs_dir_item *di;
- struct btrfs_path *path;
- struct btrfs_key location;
- struct inode *inode;
- u64 dir_id;
- int new = 0;
+ struct btrfs_root *fs_root;
+ struct btrfs_root_ref *root_ref;
+ struct btrfs_inode_ref *inode_ref;
+ struct btrfs_key key;
+ struct btrfs_path *path = NULL;
+ char *name = NULL, *ptr;
+ u64 dirid;
+ int len;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ path->leave_spinning = 1;
+
+ name = kmalloc(PATH_MAX, GFP_NOFS);
+ if (!name) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ ptr = name + PATH_MAX - 1;
+ ptr[0] = '\0';
/*
- * We have a specific subvol we want to mount, just setup location and
- * go look up the root.
+ * Walk up the subvolume trees in the tree of tree roots by root
+ * backrefs until we hit the top-level subvolume.
*/
- if (subvol_objectid) {
- location.objectid = subvol_objectid;
- location.type = BTRFS_ROOT_ITEM_KEY;
- location.offset = (u64)-1;
- goto find_root;
+ while (subvol_objectid != BTRFS_FS_TREE_OBJECTID) {
+ key.objectid = subvol_objectid;
+ key.type = BTRFS_ROOT_BACKREF_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+ if (ret < 0) {
+ goto err;
+ } else if (ret > 0) {
+ ret = btrfs_previous_item(root, path, subvol_objectid,
+ BTRFS_ROOT_BACKREF_KEY);
+ if (ret < 0) {
+ goto err;
+ } else if (ret > 0) {
+ ret = -ENOENT;
+ goto err;
+ }
+ }
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ subvol_objectid = key.offset;
+
+ root_ref = btrfs_item_ptr(path->nodes[0], path->slots[0],
+ struct btrfs_root_ref);
+ len = btrfs_root_ref_name_len(path->nodes[0], root_ref);
+ ptr -= len + 1;
+ if (ptr < name) {
+ ret = -ENAMETOOLONG;
+ goto err;
+ }
+ read_extent_buffer(path->nodes[0], ptr + 1,
+ (unsigned long)(root_ref + 1), len);
+ ptr[0] = '/';
+ dirid = btrfs_root_ref_dirid(path->nodes[0], root_ref);
+ btrfs_release_path(path);
+
+ key.objectid = subvol_objectid;
+ key.type = BTRFS_ROOT_ITEM_KEY;
+ key.offset = (u64)-1;
+ fs_root = btrfs_read_fs_root_no_name(fs_info, &key);
+ if (IS_ERR(fs_root)) {
+ ret = PTR_ERR(fs_root);
+ goto err;
+ }
+
+ /*
+ * Walk up the filesystem tree by inode refs until we hit the
+ * root directory.
+ */
+ while (dirid != BTRFS_FIRST_FREE_OBJECTID) {
+ key.objectid = dirid;
+ key.type = BTRFS_INODE_REF_KEY;
+ key.offset = (u64)-1;
+
+ ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
+ if (ret < 0) {
+ goto err;
+ } else if (ret > 0) {
+ ret = btrfs_previous_item(fs_root, path, dirid,
+ BTRFS_INODE_REF_KEY);
+ if (ret < 0) {
+ goto err;
+ } else if (ret > 0) {
+ ret = -ENOENT;
+ goto err;
+ }
+ }
+
+ btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+ dirid = key.offset;
+
+ inode_ref = btrfs_item_ptr(path->nodes[0],
+ path->slots[0],
+ struct btrfs_inode_ref);
+ len = btrfs_inode_ref_name_len(path->nodes[0],
+ inode_ref);
+ ptr -= len + 1;
+ if (ptr < name) {
+ ret = -ENAMETOOLONG;
+ goto err;
+ }
+ read_extent_buffer(path->nodes[0], ptr + 1,
+ (unsigned long)(inode_ref + 1), len);
+ ptr[0] = '/';
+ btrfs_release_path(path);
+ }
}
+ btrfs_free_path(path);
+ if (ptr == name + PATH_MAX - 1) {
+ name[0] = '/';
+ name[1] = '\0';
+ } else {
+ memmove(name, ptr, name + PATH_MAX - ptr);
+ }
+ return name;
+
+err:
+ btrfs_free_path(path);
+ kfree(name);
+ return ERR_PTR(ret);
+}
+
+static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objectid)
+{
+ struct btrfs_root *root = fs_info->tree_root;
+ struct btrfs_dir_item *di;
+ struct btrfs_path *path;
+ struct btrfs_key location;
+ u64 dir_id;
+
path = btrfs_alloc_path();
if (!path)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
path->leave_spinning = 1;
/*
@@ -879,58 +999,23 @@ static struct dentry *get_default_root(struct super_block *sb,
di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
if (IS_ERR(di)) {
btrfs_free_path(path);
- return ERR_CAST(di);
+ return PTR_ERR(di);
}
if (!di) {
/*
* Ok the default dir item isn't there. This is weird since
* it's always been there, but don't freak out, just try and
- * mount to root most subvolume.
+ * mount the top-level subvolume.
*/
btrfs_free_path(path);
- dir_id = BTRFS_FIRST_FREE_OBJECTID;
- new_root = fs_info->fs_root;
- goto setup_root;
+ *objectid = BTRFS_FS_TREE_OBJECTID;
+ return 0;
}
btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location);
btrfs_free_path(path);
-
-find_root:
- new_root = btrfs_read_fs_root_no_name(fs_info, &location);
- if (IS_ERR(new_root))
- return ERR_CAST(new_root);
-
- if (!(sb->s_flags & MS_RDONLY)) {
- int ret;
- down_read(&fs_info->cleanup_work_sem);
- ret = btrfs_orphan_cleanup(new_root);
- up_read(&fs_info->cleanup_work_sem);
- if (ret)
- return ERR_PTR(ret);
- }
-
- dir_id = btrfs_root_dirid(&new_root->root_item);
-setup_root:
- location.objectid = dir_id;
- location.type = BTRFS_INODE_ITEM_KEY;
- location.offset = 0;
-
- inode = btrfs_iget(sb, &location, new_root, &new);
- if (IS_ERR(inode))
- return ERR_CAST(inode);
-
- /*
- * If we're just mounting the root most subvol put the inode and return
- * a reference to the dentry. We will have already gotten a reference
- * to the inode in btrfs_fill_super so we're good to go.
- */
- if (!new && d_inode(sb->s_root) == inode) {
- iput(inode);
- return dget(sb->s_root);
- }
-
- return d_obtain_root(inode);
+ *objectid = location.objectid;
+ return 0;
}
static int btrfs_fill_super(struct super_block *sb,
@@ -1216,6 +1301,25 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
goto out;
}
+ if (!subvol_name) {
+ if (!subvol_objectid) {
+ ret = get_default_subvol_objectid(btrfs_sb(mnt->mnt_sb),
+ &subvol_objectid);
+ if (ret) {
+ root = ERR_PTR(ret);
+ goto out;
+ }
+ }
+ subvol_name = get_subvol_name_from_objectid(btrfs_sb(mnt->mnt_sb),
+ subvol_objectid);
+ if (IS_ERR(subvol_name)) {
+ root = ERR_CAST(subvol_name);
+ subvol_name = NULL;
+ goto out;
+ }
+
+ }
+
root = mount_subtree(mnt, subvol_name);
/* mount_subtree() drops our reference on the vfsmount. */
mnt = NULL;
@@ -1232,6 +1336,11 @@ static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid,
ret = -EINVAL;
}
if (subvol_objectid && root_objectid != subvol_objectid) {
+ /*
+ * This will also catch a race condition where a
+ * subvolume which was passed by ID is renamed and
+ * another subvolume is renamed over the old location.
+ */
pr_err("BTRFS: subvol '%s' does not match subvolid %llu\n",
subvol_name, subvol_objectid);
ret = -EINVAL;
@@ -1311,7 +1420,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
{
struct block_device *bdev = NULL;
struct super_block *s;
- struct dentry *root;
struct btrfs_fs_devices *fs_devices = NULL;
struct btrfs_fs_info *fs_info = NULL;
struct security_mnt_opts new_sec_opts;
@@ -1331,7 +1439,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
return ERR_PTR(error);
}
- if (subvol_name) {
+ if (subvol_name || subvol_objectid != BTRFS_FS_TREE_OBJECTID) {
/* mount_subvol() will free subvol_name. */
return mount_subvol(subvol_name, subvol_objectid, flags,
device_name, data);
@@ -1400,23 +1508,19 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
error = btrfs_fill_super(s, fs_devices, data,
flags & MS_SILENT ? 1 : 0);
}
-
- root = !error ? get_default_root(s, subvol_objectid) : ERR_PTR(error);
- if (IS_ERR(root)) {
+ if (error) {
deactivate_locked_super(s);
- error = PTR_ERR(root);
goto error_sec_opts;
}
fs_info = btrfs_sb(s);
error = setup_security_options(fs_info, s, &new_sec_opts);
if (error) {
- dput(root);
deactivate_locked_super(s);
goto error_sec_opts;
}
- return root;
+ return dget(s->s_root);
error_close_devices:
btrfs_close_devices(fs_devices);
--
2.4.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 6/6] Btrfs: show subvol= and subvolid= in /proc/mounts
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
` (4 preceding siblings ...)
2015-05-18 9:16 ` [PATCH v3 5/6] Btrfs: unify subvol= and subvolid= mounting Omar Sandoval
@ 2015-05-18 9:16 ` Omar Sandoval
5 siblings, 0 replies; 7+ messages in thread
From: Omar Sandoval @ 2015-05-18 9:16 UTC (permalink / raw)
To: Chris Mason, Josef Bacik, David Sterba, linux-btrfs
Cc: Qu Wenruo, Omar Sandoval
Now that we're guaranteed to have a meaningful root dentry, we can just
export seq_dentry() and use it in btrfs_show_options(). The subvolume ID
is easy to get and can also be useful, so put that in there, too.
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
---
fs/btrfs/super.c | 4 ++++
fs/seq_file.c | 1 +
2 files changed, 5 insertions(+)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index dc51a51..dd70f75 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1193,6 +1193,10 @@ static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry)
seq_puts(seq, ",fatal_errors=panic");
if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL)
seq_printf(seq, ",commit=%d", info->commit_interval);
+ seq_printf(seq, ",subvolid=%llu",
+ BTRFS_I(d_inode(dentry))->root->root_key.objectid);
+ seq_puts(seq, ",subvol=");
+ seq_dentry(seq, dentry, " \t\n\\");
return 0;
}
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 555f821..52b4927 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -538,6 +538,7 @@ int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc)
return res;
}
+EXPORT_SYMBOL(seq_dentry);
static void *single_start(struct seq_file *p, loff_t *pos)
{
--
2.4.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-05-18 9:16 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-18 9:16 [PATCH v3 0/6] Btrfs: show subvolume name and ID in /proc/mounts Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 1/6] Btrfs: lock superblock before remounting for rw subvol Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 2/6] Btrfs: remove all subvol options before mounting top-level Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 3/6] Btrfs: clean up error handling in mount_subvol() Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 4/6] Btrfs: fail on mismatched subvol and subvolid mount options Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 5/6] Btrfs: unify subvol= and subvolid= mounting Omar Sandoval
2015-05-18 9:16 ` [PATCH v3 6/6] Btrfs: show subvol= and subvolid= in /proc/mounts Omar Sandoval
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).