From: TARUISI Hiroaki <taruishi.hiroak@jp.fujitsu.com>
To: josef@redhat.com
Cc: linux-btrfs@vger.kernel.org, chris.mason@oracle.com
Subject: Re: [PATCH] Btrfs: change how we mount subvolumes
Date: Mon, 07 Dec 2009 09:52:30 +0900 [thread overview]
Message-ID: <4B1C51CE.5070700@jp.fujitsu.com> (raw)
In-Reply-To: <20091204173827.GB5962@localhost.localdomain>
Hi,
When I made snapshot listing, I thought 'subvol' parameter
is not enough as G.Baroncelli wrote. I think nice feature too.
(I tried to expand subvol parameter feature, by iterating
dentry search(lookup_one_len) but I cannot treat dentries
correctly yet. :)
But, is 'subvol=name' not prohibited yet? When I specified
'subvol=name', mount command simply mounts filesystem root
without error.
Josef Bacik wrote:
> This work is in preperation for being able to set a different root as the
> default mounting root.
>
> There is currently a problem with how we mount subvolumes. We cannot currently
> mount a subvolume of a subvolume, you can only mount subvolumes/snapshots of the
> default subvolume. So say you take a snapshot of the default subvolume and call
> it snap1, and then take a snapshot of snap1 and call it snap2, so now you have
>
> /
> /snap1
> /snap1/snap2
>
> as your available volumes. Currently you can only mount / and /snap1, you
> cannot mount /snap1/snap2. To fix this problem instead of passing subvol=<name>
> you must pass in subvol=<treeid>, where <treeid> is the tree id that gets spit
> out via the subvolume listing you get from the subvolume listing patches
> (btrfsctl -l). This allows us to mount /, /snap1 and /snap1/snap2 as the root
> volume.
>
> In addition to the above, we also now read the default dir item in the tree root
> to get the root key that it points to. For now this just points at what has
> always been the default subvolme, but later on I plan to change it to point at
> whatever root you want to be the new default root, so you can just set the
> default mount and not have to mount with -o subvol=<treeid>. I tested this out
> with the above scenario and it worked perfectly. Thanks,
>
> Signed-off-by: Josef Bacik <josef@redhat.com>
> ---
> fs/btrfs/ctree.h | 2 +-
> fs/btrfs/export.c | 4 +-
> fs/btrfs/inode.c | 10 ++-
> fs/btrfs/relocation.c | 2 +-
> fs/btrfs/super.c | 167 +++++++++++++++++++++++++++++++++++-------------
> fs/btrfs/tree-log.c | 2 +-
> 6 files changed, 133 insertions(+), 54 deletions(-)
>
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index 444b3e9..464f688 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -2318,7 +2318,7 @@ int btrfs_init_cachep(void);
> void btrfs_destroy_cachep(void);
> long btrfs_ioctl_trans_end(struct file *file);
> struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
> - struct btrfs_root *root);
> + struct btrfs_root *root, int *was_new);
> int btrfs_commit_write(struct file *file, struct page *page,
> unsigned from, unsigned to);
> struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page,
> diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c
> index ba5c3fd..951ef09 100644
> --- a/fs/btrfs/export.c
> +++ b/fs/btrfs/export.c
> @@ -95,7 +95,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid,
> btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
> key.offset = 0;
>
> - inode = btrfs_iget(sb, &key, root);
> + inode = btrfs_iget(sb, &key, root, NULL);
> if (IS_ERR(inode)) {
> err = PTR_ERR(inode);
> goto fail;
> @@ -223,7 +223,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child)
>
> key.type = BTRFS_INODE_ITEM_KEY;
> key.offset = 0;
> - dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root));
> + dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL));
> if (!IS_ERR(dentry))
> dentry->d_op = &btrfs_dentry_operations;
> return dentry;
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index b3ad168..b383e53 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -2131,7 +2131,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root)
> found_key.objectid = found_key.offset;
> found_key.type = BTRFS_INODE_ITEM_KEY;
> found_key.offset = 0;
> - inode = btrfs_iget(root->fs_info->sb, &found_key, root);
> + inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL);
> if (IS_ERR(inode))
> break;
>
> @@ -3609,7 +3609,7 @@ static struct inode *btrfs_iget_locked(struct super_block *s,
> * Returns in *is_new if the inode was read from disk
> */
> struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
> - struct btrfs_root *root)
> + struct btrfs_root *root, int *new)
> {
> struct inode *inode;
>
> @@ -3624,6 +3624,8 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
>
> inode_tree_add(inode);
> unlock_new_inode(inode);
> + if (new)
> + *new = 1;
> }
>
> return inode;
> @@ -3676,7 +3678,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
> return NULL;
>
> if (location.type == BTRFS_INODE_ITEM_KEY) {
> - inode = btrfs_iget(dir->i_sb, &location, root);
> + inode = btrfs_iget(dir->i_sb, &location, root, NULL);
> return inode;
> }
>
> @@ -3691,7 +3693,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
> else
> inode = new_simple_dir(dir->i_sb, &location, sub_root);
> } else {
> - inode = btrfs_iget(dir->i_sb, &location, sub_root);
> + inode = btrfs_iget(dir->i_sb, &location, sub_root, NULL);
> }
> srcu_read_unlock(&root->fs_info->subvol_srcu, index);
>
> diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
> index cfcc93c..69fc10b 100644
> --- a/fs/btrfs/relocation.c
> +++ b/fs/btrfs/relocation.c
> @@ -3478,7 +3478,7 @@ static struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info,
> key.objectid = objectid;
> key.type = BTRFS_INODE_ITEM_KEY;
> key.offset = 0;
> - inode = btrfs_iget(root->fs_info->sb, &key, root);
> + inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
> BUG_ON(IS_ERR(inode) || is_bad_inode(inode));
> BTRFS_I(inode)->index_cnt = group->key.objectid;
>
> diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
> index 752a546..bcbdc1b 100644
> --- a/fs/btrfs/super.c
> +++ b/fs/btrfs/super.c
> @@ -72,7 +72,7 @@ enum {
>
> static match_table_t tokens = {
> {Opt_degraded, "degraded"},
> - {Opt_subvol, "subvol=%s"},
> + {Opt_subvol, "subvol=%d"},
> {Opt_device, "device=%s"},
> {Opt_nodatasum, "nodatasum"},
> {Opt_nodatacow, "nodatacow"},
> @@ -277,12 +277,13 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
> * only when we need to allocate a new super block.
> */
> static int btrfs_parse_early_options(const char *options, fmode_t flags,
> - void *holder, char **subvol_name,
> + void *holder, u64 *subvol_objectid,
> struct btrfs_fs_devices **fs_devices)
> {
> substring_t args[MAX_OPT_ARGS];
> char *opts, *p;
> int error = 0;
> + int intarg;
>
> if (!options)
> goto out;
> @@ -303,7 +304,10 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
> token = match_token(p, tokens, args);
> switch (token) {
> case Opt_subvol:
> - *subvol_name = match_strdup(&args[0]);
> + intarg = 0;
> + match_int(&args[0], &intarg);
> + if (intarg)
> + *subvol_objectid = intarg;
> break;
> case Opt_device:
> error = btrfs_scan_one_device(match_strdup(&args[0]),
> @@ -319,17 +323,110 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
> out_free_opts:
> kfree(opts);
> out:
> + return error;
> +}
> +
> +static struct dentry *get_default_root(struct super_block *sb, u64 subvol_objectid)
> +{
> + struct btrfs_root *root = sb->s_fs_info;
> + struct btrfs_root *new_root;
> + struct btrfs_dir_item *di;
> + struct btrfs_path *path;
> + struct btrfs_key location;
> + struct inode *inode;
> + struct dentry *dentry;
> + u64 dir_id;
> + int new = 0;
> +
> /*
> - * If no subvolume name is specified we use the default one. Allocate
> - * a copy of the string "." here so that code later in the
> - * mount path doesn't care if it's the default volume or another one.
> + * We have a specific subvol we want to mount, just setup location and
> + * go look up the root.
> */
> - if (!*subvol_name) {
> - *subvol_name = kstrdup(".", GFP_KERNEL);
> - if (!*subvol_name)
> - return -ENOMEM;
> + if (subvol_objectid) {
> + location.objectid = subvol_objectid;
> + location.type = BTRFS_ROOT_ITEM_KEY;
> + location.offset = (u64)-1;
> + goto find_root;
> }
> - return error;
> +
> + path = btrfs_alloc_path();
> + if (!path)
> + return ERR_PTR(-ENOMEM);
> + path->leave_spinning = 1;
> +
> + /*
> + * Find the "default" dir item which points to the root item that we
> + * will mount by default if we haven't been given a specific subvolume
> + * to mount.
> + */
> + dir_id = btrfs_super_root_dir(&root->fs_info->super_copy);
> + di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0);
> + 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.
> + */
> + btrfs_free_path(path);
> + dir_id = BTRFS_FIRST_FREE_OBJECTID;
> + new_root = root->fs_info->fs_root;
> + goto setup_root;
> + }
> +
> + 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(root->fs_info, &location);
> + if (IS_ERR(new_root))
> + return ERR_PTR(PTR_ERR(new_root));
> +
> + if (btrfs_root_refs(&new_root->root_item) == 0)
> + return ERR_PTR(-ENOENT);
> +
> + 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 (!inode)
> + return ERR_PTR(-ENOMEM);
> +
> + /*
> + * 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 && sb->s_root->d_inode == inode) {
> + iput(inode);
> + return dget(sb->s_root);
> + }
> +
> + if (new) {
> + const struct qstr name = { .name = "/", .len = 1 };
> +
> + /*
> + * New inode, we need to make the dentry a sibling of s_root so
> + * everything gets cleaned up properly on unmount.
> + */
> + dentry = d_alloc(sb->s_root, &name);
> + if (!dentry) {
> + iput(inode);
> + return ERR_PTR(-ENOMEM);
> + }
> + d_splice_alias(inode, dentry);
> + } else {
> + /*
> + * We found the inode in cache, just find a dentry for it and
> + * put the reference to the inode we just got.
> + */
> + dentry = d_find_alias(inode);
> + iput(inode);
> + }
> +
> + return dentry;
> }
>
> static int btrfs_fill_super(struct super_block *sb,
> @@ -365,7 +462,7 @@ static int btrfs_fill_super(struct super_block *sb,
> key.objectid = BTRFS_FIRST_FREE_OBJECTID;
> key.type = BTRFS_INODE_ITEM_KEY;
> key.offset = 0;
> - inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root);
> + inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root, NULL);
> if (IS_ERR(inode)) {
> err = PTR_ERR(inode);
> goto fail_close;
> @@ -377,12 +474,6 @@ static int btrfs_fill_super(struct super_block *sb,
> err = -ENOMEM;
> goto fail_close;
> }
> -#if 0
> - /* this does the super kobj at the same time */
> - err = btrfs_sysfs_add_super(tree_root->fs_info);
> - if (err)
> - goto fail_close;
> -#endif
>
> sb->s_root = root_dentry;
>
> @@ -472,29 +563,30 @@ static int btrfs_test_super(struct super_block *s, void *data)
> static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
> const char *dev_name, void *data, struct vfsmount *mnt)
> {
> - char *subvol_name = NULL;
> struct block_device *bdev = NULL;
> struct super_block *s;
> struct dentry *root;
> struct btrfs_fs_devices *fs_devices = NULL;
> fmode_t mode = FMODE_READ;
> + u64 subvol_objectid = 0;
> int error = 0;
> + int found = 0;
>
> if (!(flags & MS_RDONLY))
> mode |= FMODE_WRITE;
>
> error = btrfs_parse_early_options(data, mode, fs_type,
> - &subvol_name, &fs_devices);
> + &subvol_objectid, &fs_devices);
> if (error)
> return error;
>
> error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices);
> if (error)
> - goto error_free_subvol_name;
> + goto error;
>
> error = btrfs_open_devices(fs_devices, mode, fs_type);
> if (error)
> - goto error_free_subvol_name;
> + goto error;
>
> if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
> error = -EACCES;
> @@ -513,6 +605,7 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
> goto error_close_devices;
> }
>
> + found = 1;
> btrfs_close_devices(fs_devices);
> } else {
> char b[BDEVNAME_SIZE];
> @@ -523,46 +616,30 @@ static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
> flags & MS_SILENT ? 1 : 0);
> if (error) {
> deactivate_locked_super(s);
> - goto error_free_subvol_name;
> + goto error;
> }
>
> btrfs_sb(s)->fs_info->bdev_holder = fs_type;
> s->s_flags |= MS_ACTIVE;
> }
>
> - if (!strcmp(subvol_name, "."))
> - root = dget(s->s_root);
> - else {
> - mutex_lock(&s->s_root->d_inode->i_mutex);
> - root = lookup_one_len(subvol_name, s->s_root,
> - strlen(subvol_name));
> - mutex_unlock(&s->s_root->d_inode->i_mutex);
> -
> - if (IS_ERR(root)) {
> - deactivate_locked_super(s);
> - error = PTR_ERR(root);
> - goto error_free_subvol_name;
> - }
> - if (!root->d_inode) {
> - dput(root);
> - deactivate_locked_super(s);
> - error = -ENXIO;
> - goto error_free_subvol_name;
> - }
> + root = get_default_root(s, subvol_objectid);
> + if (IS_ERR(root)) {
> + error = PTR_ERR(root);
> + deactivate_locked_super(s);
> + goto error;
> }
>
> mnt->mnt_sb = s;
> mnt->mnt_root = root;
>
> - kfree(subvol_name);
> return 0;
>
> error_s:
> error = PTR_ERR(s);
> error_close_devices:
> btrfs_close_devices(fs_devices);
> -error_free_subvol_name:
> - kfree(subvol_name);
> +error:
> return error;
> }
>
> diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
> index 741666a..c0c2c1c 100644
> --- a/fs/btrfs/tree-log.c
> +++ b/fs/btrfs/tree-log.c
> @@ -445,7 +445,7 @@ static noinline struct inode *read_one_inode(struct btrfs_root *root,
> key.objectid = objectid;
> key.type = BTRFS_INODE_ITEM_KEY;
> key.offset = 0;
> - inode = btrfs_iget(root->fs_info->sb, &key, root);
> + inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
> if (IS_ERR(inode)) {
> inode = NULL;
> } else if (is_bad_inode(inode)) {
--
taruisi
prev parent reply other threads:[~2009-12-07 0:52 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-12-04 17:38 [PATCH] Btrfs: change how we mount subvolumes Josef Bacik
2009-12-04 18:49 ` Goffredo Baroncelli
2009-12-07 0:52 ` TARUISI Hiroaki [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B1C51CE.5070700@jp.fujitsu.com \
--to=taruishi.hiroak@jp.fujitsu.com \
--cc=chris.mason@oracle.com \
--cc=josef@redhat.com \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox