The original btrfs_mksubvol is too specific to specify the directory that
the subvolume will link to. Furthermore, in this transaction, we don't only
need to create root_ref/dir-item, but also update the refs or flags of
root_item. Extract a generic btrfs_link_subvol that allow the caller pass a
trans argument for later subvolume undelete.

No functional changes for the btrfs_mksubvol.

Signed-off-by: Lu Fengqi <lufq.f...@cn.fujitsu.com>
---
 convert/main.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ctree.h        |  5 +++--
 inode.c        | 46 +++++++++++++++++++++-------------------------
 3 files changed, 81 insertions(+), 27 deletions(-)

diff --git a/convert/main.c b/convert/main.c
index b3ea31d7af43..e997bdb822c5 100644
--- a/convert/main.c
+++ b/convert/main.c
@@ -1002,6 +1002,63 @@ err:
        return ret;
 }
 
+/*
+ * Link the subvolume specified by @root_objectid to the root_dir of @root.
+ *
+ * @root               the root of the file tree which the subvolume will
+ *                     be linked to.
+ * @subvol_name                the name of the subvolume which will be linked.
+ * @root_objectid      specify the subvolume which will be linked.
+ * @convert            the flag to determine whether to try to resolve
+ *                     the name conflict.
+ *
+ * Return the root of the subvolume if success, otherwise return NULL.
+ */
+static struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
+                                        const char *subvol_name,
+                                        u64 root_objectid,
+                                        bool convert)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *subvol_root = NULL;
+       struct btrfs_key key;
+       u64 dirid = btrfs_root_dirid(&root->root_item);
+       int ret;
+
+
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans)) {
+               error("unable to start transaction");
+               goto fail;
+       }
+
+       ret = btrfs_link_subvol(trans, root, subvol_name, root_objectid, dirid,
+                               true);
+       if (ret) {
+               error("unable to link subvolume %s", subvol_name);
+               goto fail;
+       }
+
+       ret = btrfs_commit_transaction(trans, root);
+       if (ret) {
+               error("transaction commit failed: %d", ret);
+               goto fail;
+       }
+
+       key.objectid = root_objectid;
+       key.offset = (u64)-1;
+       key.type = BTRFS_ROOT_ITEM_KEY;
+
+       subvol_root = btrfs_read_fs_root(root->fs_info, &key);
+       if (!subvol_root) {
+               error("unable to link subvolume %s", subvol_name);
+               goto fail;
+       }
+
+fail:
+       return subvol_root;
+}
+
 /*
  * Migrate super block to its default position and zero 0 ~ 16k
  */
diff --git a/ctree.h b/ctree.h
index 84bad186a349..18f7c79ddeec 100644
--- a/ctree.h
+++ b/ctree.h
@@ -2788,8 +2788,9 @@ int btrfs_del_orphan_item(struct btrfs_trans_handle 
*trans,
                          struct btrfs_root *root, u64 offset);
 int btrfs_mkdir(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                char *name, int namelen, u64 parent_ino, u64 *ino, int mode);
-struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root, const char *base,
-                                 u64 root_objectid, bool convert);
+int btrfs_link_subvol(struct btrfs_trans_handle *trans, struct btrfs_root 
*root,
+                     const char *base, u64 root_objectid, u64 dirid,
+                     bool convert);
 
 /* file.c */
 int btrfs_get_extent(struct btrfs_trans_handle *trans,
diff --git a/inode.c b/inode.c
index 8d0812c7cf50..478036562652 100644
--- a/inode.c
+++ b/inode.c
@@ -606,19 +606,28 @@ out:
        return ret;
 }
 
-struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
-                                 const char *base, u64 root_objectid,
-                                 bool convert)
+/*
+ * Link the subvolume specified by @root_objectid to the directory specified by
+ * @dirid on the file tree specified by @root.
+ *
+ * @root               the root of the file tree where the directory on.
+ * @base               the name of the subvolume which will be linked.
+ * @root_objectid      specify the subvolume which will be linked.
+ * @dirid              specify the directory which the subvolume will be
+ *                     linked to.
+ * @convert            the flag to determine whether to try to resolve
+ *                     the name conflict.
+ */
+int btrfs_link_subvol(struct btrfs_trans_handle *trans, struct btrfs_root 
*root,
+                     const char *base, u64 root_objectid, u64 dirid,
+                     bool convert)
 {
-       struct btrfs_trans_handle *trans;
        struct btrfs_fs_info *fs_info = root->fs_info;
        struct btrfs_root *tree_root = fs_info->tree_root;
-       struct btrfs_root *new_root = NULL;
        struct btrfs_path path;
        struct btrfs_inode_item *inode_item;
        struct extent_buffer *leaf;
        struct btrfs_key key;
-       u64 dirid = btrfs_root_dirid(&root->root_item);
        u64 index = 2;
        char buf[BTRFS_NAME_LEN + 1]; /* for snprintf null */
        int len;
@@ -627,8 +636,9 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
 
        len = strlen(base);
        if (len == 0 || len > BTRFS_NAME_LEN)
-               return NULL;
+               return -EINVAL;
 
+       /* find the free dir_index */
        btrfs_init_path(&path);
        key.objectid = dirid;
        key.type = BTRFS_DIR_INDEX_KEY;
@@ -649,12 +659,7 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
        }
        btrfs_release_path(&path);
 
-       trans = btrfs_start_transaction(root, 1);
-       if (IS_ERR(trans)) {
-               error("unable to start transaction");
-               goto fail;
-       }
-
+       /* add the dir_item/dir_index */
        key.objectid = dirid;
        key.offset = 0;
        key.type =  BTRFS_INODE_ITEM_KEY;
@@ -675,6 +680,7 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
 
        memcpy(buf, base, len);
        if (convert) {
+               /* try to resolve name conflict by adding the number suffix */
                for (i = 0; i < 1024; i++) {
                        ret = btrfs_insert_dir_item(trans, root, buf, len,
                                        dirid, &key, BTRFS_FT_DIR, index);
@@ -719,18 +725,8 @@ struct btrfs_root *btrfs_mksubvol(struct btrfs_root *root,
                goto fail;
        }
 
-       ret = btrfs_commit_transaction(trans, root);
-       if (ret) {
-               error("transaction commit failed: %d", ret);
-               goto fail;
-       }
 
-       new_root = btrfs_read_fs_root(fs_info, &key);
-       if (IS_ERR(new_root)) {
-               error("unable to fs read root: %lu", PTR_ERR(new_root));
-               new_root = NULL;
-       }
 fail:
-       btrfs_init_path(&path);
-       return new_root;
+       btrfs_release_path(&path);
+       return ret;
 }
-- 
2.16.1



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to