Skip to content

Commit 299b3b3

Browse files
committed
btrfs-progs: introduce btrfs_make_subvolume()
There are two different subvolume/data reloc tree creation routines: - create_subvol() from convert/main.c * calls btrfs_copy_root() to create an empty root This is not safe, as it relies on the source root to be empty. * calls btrfs_read_fs_root() to add it to the cache and trace it properly * calls btrfs_make_root_dir() to initialize the empty new root - create_data_reloc_tree() from mkfs/main.c * calls btrfs_create_tree() to create an empty rooo * Manually add the root to fs_root cache This is only safe for data reloc tree as it's never updated inside btrfs-progs. But not safe for other subvolume trees. * manually setup the root dir Both has its good and bad aspects, so here we introduce a new helper, btrfs_make_subvolume(): - Calls btrfs_create_tree() to create an empty root - Calls btrfs_read_fs_root() to setup the cache and tracking properly - Calls btrfs_make_root_dir() to initialize the root dir - Calls btrfs_update_root() to reflect the rootdir change So this new helper can replace both create_subvol() and create_data_reloc_tree(). Signed-off-by: Qu Wenruo <[email protected]>
1 parent 7547080 commit 299b3b3

File tree

8 files changed

+140
-151
lines changed

8 files changed

+140
-151
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ objects = \
221221
common/device-utils.o \
222222
common/extent-cache.o \
223223
common/extent-tree-utils.o \
224+
common/root-tree-utils.o \
224225
common/filesystem-utils.o \
225226
common/format-output.o \
226227
common/fsfeatures.o \

check/main.c

+1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
#include "common/open-utils.h"
6060
#include "common/string-utils.h"
6161
#include "common/clear-cache.h"
62+
#include "common/root-tree-utils.h"
6263
#include "cmds/commands.h"
6364
#include "mkfs/common.h"
6465
#include "check/common.h"

common/root-tree-utils.c

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* This program is free software; you can redistribute it and/or
3+
* modify it under the terms of the GNU General Public
4+
* License v2 as published by the Free Software Foundation.
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
* General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public
12+
* License along with this program; if not, write to the
13+
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14+
* Boston, MA 021110-1307, USA.
15+
*/
16+
17+
#include <time.h>
18+
#include "common/root-tree-utils.h"
19+
#include "common/messages.h"
20+
#include "kernel-shared/disk-io.h"
21+
22+
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
23+
struct btrfs_root *root, u64 objectid)
24+
{
25+
int ret;
26+
struct btrfs_inode_item inode_item;
27+
time_t now = time(NULL);
28+
29+
memset(&inode_item, 0, sizeof(inode_item));
30+
btrfs_set_stack_inode_generation(&inode_item, trans->transid);
31+
btrfs_set_stack_inode_size(&inode_item, 0);
32+
btrfs_set_stack_inode_nlink(&inode_item, 1);
33+
btrfs_set_stack_inode_nbytes(&inode_item, root->fs_info->nodesize);
34+
btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755);
35+
btrfs_set_stack_timespec_sec(&inode_item.atime, now);
36+
btrfs_set_stack_timespec_nsec(&inode_item.atime, 0);
37+
btrfs_set_stack_timespec_sec(&inode_item.ctime, now);
38+
btrfs_set_stack_timespec_nsec(&inode_item.ctime, 0);
39+
btrfs_set_stack_timespec_sec(&inode_item.mtime, now);
40+
btrfs_set_stack_timespec_nsec(&inode_item.mtime, 0);
41+
btrfs_set_stack_timespec_sec(&inode_item.otime, now);
42+
btrfs_set_stack_timespec_nsec(&inode_item.otime, 0);
43+
44+
if (root->fs_info->tree_root == root)
45+
btrfs_set_super_root_dir(root->fs_info->super_copy, objectid);
46+
47+
ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
48+
if (ret)
49+
goto error;
50+
51+
ret = btrfs_insert_inode_ref(trans, root, "..", 2, objectid, objectid, 0);
52+
if (ret)
53+
goto error;
54+
55+
btrfs_set_root_dirid(&root->root_item, objectid);
56+
ret = 0;
57+
error:
58+
return ret;
59+
}
60+
61+
/*
62+
* Create a subvolume and initialize its content with the top inode.
63+
*
64+
* The created tree root would have its root_ref as 1.
65+
* Thus for subvolumes caller needs to properly add ROOT_BACKREF items.
66+
*/
67+
int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid)
68+
{
69+
struct btrfs_fs_info *fs_info = trans->fs_info;
70+
struct btrfs_root *root;
71+
struct btrfs_key key = {
72+
.objectid = objectid,
73+
.type = BTRFS_ROOT_ITEM_KEY,
74+
};
75+
int ret;
76+
77+
/* FSTREE is different and can not be created by this function. */
78+
UASSERT(objectid != BTRFS_FS_TREE_OBJECTID);
79+
UASSERT(is_fstree(objectid) || objectid == BTRFS_DATA_RELOC_TREE_OBJECTID);
80+
81+
root = btrfs_create_tree(trans, &key);
82+
if (IS_ERR(root)) {
83+
ret = PTR_ERR(root);
84+
goto error;
85+
}
86+
/*
87+
* Free it for now, and re-read it from disk to setup cache and
88+
* tracking.
89+
*/
90+
btrfs_free_fs_root(root);
91+
root = btrfs_read_fs_root(fs_info, &key);
92+
if (IS_ERR(root)) {
93+
ret = PTR_ERR(root);
94+
goto error;
95+
}
96+
ret = btrfs_make_root_dir(trans, root, BTRFS_FIRST_FREE_OBJECTID);
97+
if (ret < 0)
98+
goto error;
99+
ret = btrfs_update_root(trans, fs_info->tree_root, &root->root_key,
100+
&root->root_item);
101+
if (ret < 0)
102+
goto error;
103+
return 0;
104+
error:
105+
btrfs_abort_transaction(trans, ret);
106+
return ret;
107+
}

common/root-tree-utils.h

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* This program is free software; you can redistribute it and/or
3+
* modify it under the terms of the GNU General Public
4+
* License v2 as published by the Free Software Foundation.
5+
*
6+
* This program is distributed in the hope that it will be useful,
7+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
8+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9+
* General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public
12+
* License along with this program; if not, write to the
13+
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14+
* Boston, MA 021110-1307, USA.
15+
*/
16+
17+
#ifndef __ROOT_TREE_UTILS_H__
18+
#define __ROOT_TREE_UTILS_H__
19+
20+
#include "kernel-shared/transaction.h"
21+
22+
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
23+
struct btrfs_root *root, u64 objectid);
24+
int btrfs_make_subvolume(struct btrfs_trans_handle *trans, u64 objectid);
25+
26+
#endif

convert/main.c

+3-40
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
#include "common/box.h"
121121
#include "common/open-utils.h"
122122
#include "common/extent-tree-utils.h"
123+
#include "common/root-tree-utils.h"
123124
#include "common/clear-cache.h"
124125
#include "cmds/commands.h"
125126
#include "check/repair.h"
@@ -916,44 +917,6 @@ static int create_image(struct btrfs_root *root,
916917
return ret;
917918
}
918919

919-
static int create_subvol(struct btrfs_trans_handle *trans,
920-
struct btrfs_root *root, u64 root_objectid)
921-
{
922-
struct extent_buffer *tmp;
923-
struct btrfs_root *new_root;
924-
struct btrfs_key key;
925-
struct btrfs_root_item root_item;
926-
int ret;
927-
928-
ret = btrfs_copy_root(trans, root, root->node, &tmp,
929-
root_objectid);
930-
if (ret)
931-
return ret;
932-
933-
memcpy(&root_item, &root->root_item, sizeof(root_item));
934-
btrfs_set_root_bytenr(&root_item, tmp->start);
935-
btrfs_set_root_level(&root_item, btrfs_header_level(tmp));
936-
btrfs_set_root_generation(&root_item, trans->transid);
937-
free_extent_buffer(tmp);
938-
939-
key.objectid = root_objectid;
940-
key.type = BTRFS_ROOT_ITEM_KEY;
941-
key.offset = trans->transid;
942-
ret = btrfs_insert_root(trans, root->fs_info->tree_root,
943-
&key, &root_item);
944-
945-
key.offset = (u64)-1;
946-
new_root = btrfs_read_fs_root(root->fs_info, &key);
947-
if (!new_root || IS_ERR(new_root)) {
948-
error("unable to fs read root: %lu", PTR_ERR(new_root));
949-
return PTR_ERR(new_root);
950-
}
951-
952-
ret = btrfs_make_root_dir(trans, new_root, BTRFS_FIRST_FREE_OBJECTID);
953-
954-
return ret;
955-
}
956-
957920
/*
958921
* New make_btrfs() has handle system and meta chunks quite well.
959922
* So only need to add remaining data chunks.
@@ -1059,13 +1022,13 @@ static int init_btrfs(struct btrfs_mkfs_config *cfg, struct btrfs_root *root,
10591022
BTRFS_FIRST_FREE_OBJECTID);
10601023

10611024
/* subvol for fs image file */
1062-
ret = create_subvol(trans, root, CONV_IMAGE_SUBVOL_OBJECTID);
1025+
ret = btrfs_make_subvolume(trans, CONV_IMAGE_SUBVOL_OBJECTID);
10631026
if (ret < 0) {
10641027
error("failed to create subvolume image root: %d", ret);
10651028
goto err;
10661029
}
10671030
/* subvol for data relocation tree */
1068-
ret = create_subvol(trans, root, BTRFS_DATA_RELOC_TREE_OBJECTID);
1031+
ret = btrfs_make_subvolume(trans, BTRFS_DATA_RELOC_TREE_OBJECTID);
10691032
if (ret < 0) {
10701033
error("failed to create DATA_RELOC root: %d", ret);
10711034
goto err;

mkfs/common.c

-39
Original file line numberDiff line numberDiff line change
@@ -758,45 +758,6 @@ int make_btrfs(int fd, struct btrfs_mkfs_config *cfg)
758758
return ret;
759759
}
760760

761-
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
762-
struct btrfs_root *root, u64 objectid)
763-
{
764-
int ret;
765-
struct btrfs_inode_item inode_item;
766-
time_t now = time(NULL);
767-
768-
memset(&inode_item, 0, sizeof(inode_item));
769-
btrfs_set_stack_inode_generation(&inode_item, trans->transid);
770-
btrfs_set_stack_inode_size(&inode_item, 0);
771-
btrfs_set_stack_inode_nlink(&inode_item, 1);
772-
btrfs_set_stack_inode_nbytes(&inode_item, root->fs_info->nodesize);
773-
btrfs_set_stack_inode_mode(&inode_item, S_IFDIR | 0755);
774-
btrfs_set_stack_timespec_sec(&inode_item.atime, now);
775-
btrfs_set_stack_timespec_nsec(&inode_item.atime, 0);
776-
btrfs_set_stack_timespec_sec(&inode_item.ctime, now);
777-
btrfs_set_stack_timespec_nsec(&inode_item.ctime, 0);
778-
btrfs_set_stack_timespec_sec(&inode_item.mtime, now);
779-
btrfs_set_stack_timespec_nsec(&inode_item.mtime, 0);
780-
btrfs_set_stack_timespec_sec(&inode_item.otime, now);
781-
btrfs_set_stack_timespec_nsec(&inode_item.otime, 0);
782-
783-
if (root->fs_info->tree_root == root)
784-
btrfs_set_super_root_dir(root->fs_info->super_copy, objectid);
785-
786-
ret = btrfs_insert_inode(trans, root, objectid, &inode_item);
787-
if (ret)
788-
goto error;
789-
790-
ret = btrfs_insert_inode_ref(trans, root, "..", 2, objectid, objectid, 0);
791-
if (ret)
792-
goto error;
793-
794-
btrfs_set_root_dirid(&root->root_item, objectid);
795-
ret = 0;
796-
error:
797-
return ret;
798-
}
799-
800761
/*
801762
* Btrfs minimum size calculation is complicated, it should include at least:
802763
* 1. system group size

mkfs/common.h

-2
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ struct btrfs_mkfs_config {
103103
};
104104

105105
int make_btrfs(int fd, struct btrfs_mkfs_config *cfg);
106-
int btrfs_make_root_dir(struct btrfs_trans_handle *trans,
107-
struct btrfs_root *root, u64 objectid);
108106
u64 btrfs_min_dev_size(u32 nodesize, bool mixed, u64 zone_size, u64 meta_profile,
109107
u64 data_profile);
110108
int test_minimum_size(const char *file, u64 min_dev_size);

mkfs/main.c

+2-70
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include "common/units.h"
5959
#include "common/string-utils.h"
6060
#include "common/string-table.h"
61+
#include "common/root-tree-utils.h"
6162
#include "cmds/commands.h"
6263
#include "check/qgroup-verify.h"
6364
#include "mkfs/common.h"
@@ -734,75 +735,6 @@ static void update_chunk_allocation(struct btrfs_fs_info *fs_info,
734735
}
735736
}
736737

737-
static int create_data_reloc_tree(struct btrfs_trans_handle *trans)
738-
{
739-
struct btrfs_fs_info *fs_info = trans->fs_info;
740-
struct btrfs_inode_item *inode;
741-
struct btrfs_root *root;
742-
struct btrfs_path path = { 0 };
743-
struct btrfs_key key = {
744-
.objectid = BTRFS_DATA_RELOC_TREE_OBJECTID,
745-
.type = BTRFS_ROOT_ITEM_KEY,
746-
};
747-
u64 ino = BTRFS_FIRST_FREE_OBJECTID;
748-
char *name = "..";
749-
int ret;
750-
751-
root = btrfs_create_tree(trans, &key);
752-
if (IS_ERR(root)) {
753-
ret = PTR_ERR(root);
754-
goto out;
755-
}
756-
/* Update dirid as created tree has default dirid 0 */
757-
btrfs_set_root_dirid(&root->root_item, ino);
758-
ret = btrfs_update_root(trans, fs_info->tree_root, &root->root_key,
759-
&root->root_item);
760-
if (ret < 0)
761-
goto out;
762-
763-
/* Cache this tree so it can be cleaned up at close_ctree() */
764-
ret = rb_insert(&fs_info->fs_root_tree, &root->rb_node,
765-
btrfs_fs_roots_compare_roots);
766-
if (ret < 0)
767-
goto out;
768-
769-
/* Insert INODE_ITEM */
770-
ret = btrfs_new_inode(trans, root, ino, 0755 | S_IFDIR);
771-
if (ret < 0)
772-
goto out;
773-
774-
/* then INODE_REF */
775-
ret = btrfs_insert_inode_ref(trans, root, name, strlen(name), ino, ino,
776-
0);
777-
if (ret < 0)
778-
goto out;
779-
780-
/* Update nlink of that inode item */
781-
key.objectid = ino;
782-
key.type = BTRFS_INODE_ITEM_KEY;
783-
key.offset = 0;
784-
785-
ret = btrfs_search_slot(trans, root, &key, &path, 0, 1);
786-
if (ret > 0) {
787-
ret = -ENOENT;
788-
btrfs_release_path(&path);
789-
goto out;
790-
}
791-
if (ret < 0) {
792-
btrfs_release_path(&path);
793-
goto out;
794-
}
795-
inode = btrfs_item_ptr(path.nodes[0], path.slots[0],
796-
struct btrfs_inode_item);
797-
btrfs_set_inode_nlink(path.nodes[0], inode, 1);
798-
btrfs_mark_buffer_dirty(path.nodes[0]);
799-
btrfs_release_path(&path);
800-
return 0;
801-
out:
802-
btrfs_abort_transaction(trans, ret);
803-
return ret;
804-
}
805-
806738
static int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, u8 *uuid,
807739
u8 type, u64 subvol_id_cpu)
808740
{
@@ -1939,7 +1871,7 @@ int BOX_MAIN(mkfs)(int argc, char **argv)
19391871
goto out;
19401872
}
19411873

1942-
ret = create_data_reloc_tree(trans);
1874+
ret = btrfs_make_subvolume(trans, BTRFS_DATA_RELOC_TREE_OBJECTID);
19431875
if (ret) {
19441876
error("unable to create data reloc tree: %d", ret);
19451877
goto out;

0 commit comments

Comments
 (0)