mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/kdave/btrfs-progs.git
synced 2024-11-23 12:14:24 +08:00
btrfs-progs: track csum, extent, and free space trees in a rb tree
We are going to have multiples of these trees with extent tree v2, so add a rb tree to track them based on their root key value. This works for both v1 and v2, so we can remove the direct pointers to these roots in our fs_info. Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
0b23744de5
commit
b057607325
@ -1163,15 +1163,13 @@ struct btrfs_fs_info {
|
||||
u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
|
||||
u8 *new_chunk_tree_uuid;
|
||||
struct btrfs_root *fs_root;
|
||||
struct btrfs_root *_extent_root;
|
||||
struct btrfs_root *tree_root;
|
||||
struct btrfs_root *chunk_root;
|
||||
struct btrfs_root *dev_root;
|
||||
struct btrfs_root *_csum_root;
|
||||
struct btrfs_root *quota_root;
|
||||
struct btrfs_root *_free_space_root;
|
||||
struct btrfs_root *uuid_root;
|
||||
|
||||
struct rb_root global_roots_tree;
|
||||
struct rb_root fs_root_tree;
|
||||
|
||||
/* the log root tree is a directory of all the other log roots */
|
||||
|
@ -732,6 +732,23 @@ insert:
|
||||
return root;
|
||||
}
|
||||
|
||||
static int btrfs_global_roots_compare_keys(struct rb_node *node,
|
||||
void *data)
|
||||
{
|
||||
struct btrfs_key *key = (struct btrfs_key *)data;
|
||||
struct btrfs_root *root;
|
||||
|
||||
root = rb_entry(node, struct btrfs_root, rb_node);
|
||||
return btrfs_comp_cpu_keys(key, &root->root_key);
|
||||
}
|
||||
|
||||
static int btrfs_global_roots_compare(struct rb_node *node1,
|
||||
struct rb_node *node2)
|
||||
{
|
||||
struct btrfs_root *root = rb_entry(node2, struct btrfs_root, rb_node);
|
||||
return btrfs_global_roots_compare_keys(node1, &root->root_key);
|
||||
}
|
||||
|
||||
static int btrfs_fs_roots_compare_objectids(struct rb_node *node,
|
||||
void *data)
|
||||
{
|
||||
@ -755,16 +772,54 @@ int btrfs_fs_roots_compare_roots(struct rb_node *node1, struct rb_node *node2)
|
||||
return btrfs_fs_roots_compare_objectids(node1, (void *)&root->objectid);
|
||||
}
|
||||
|
||||
int btrfs_global_root_insert(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
return rb_insert(&fs_info->global_roots_tree, &root->rb_node,
|
||||
btrfs_global_roots_compare);
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *key)
|
||||
{
|
||||
struct rb_node *node;
|
||||
|
||||
/*
|
||||
* Some callers use the key->offset = (u64)-1 convention for looking up
|
||||
* roots, so set this to 0 if we ended up here from that.
|
||||
*/
|
||||
if (key->offset == (u64)-1)
|
||||
key->offset = 0;
|
||||
|
||||
node = rb_search(&fs_info->global_roots_tree, (void *)key,
|
||||
btrfs_global_roots_compare_keys, NULL);
|
||||
if (node)
|
||||
return rb_entry(node, struct btrfs_root, rb_node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info,
|
||||
u64 bytenr)
|
||||
{
|
||||
return fs_info->_csum_root;
|
||||
struct btrfs_key key = {
|
||||
.objectid = BTRFS_CSUM_TREE_OBJECTID,
|
||||
.type = BTRFS_ROOT_ITEM_KEY,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
return btrfs_global_root(fs_info, &key);
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_info,
|
||||
u64 bytenr)
|
||||
{
|
||||
return fs_info->_extent_root;
|
||||
struct btrfs_key key = {
|
||||
.objectid = BTRFS_EXTENT_TREE_OBJECTID,
|
||||
.type = BTRFS_ROOT_ITEM_KEY,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
return btrfs_global_root(fs_info, &key);
|
||||
}
|
||||
|
||||
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
|
||||
@ -778,21 +833,22 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
|
||||
if (location->objectid == BTRFS_ROOT_TREE_OBJECTID)
|
||||
return fs_info->tree_root;
|
||||
if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID)
|
||||
return fs_info->_extent_root;
|
||||
return btrfs_global_root(fs_info, location);
|
||||
if (location->objectid == BTRFS_CHUNK_TREE_OBJECTID)
|
||||
return fs_info->chunk_root;
|
||||
if (location->objectid == BTRFS_DEV_TREE_OBJECTID)
|
||||
return fs_info->dev_root;
|
||||
if (location->objectid == BTRFS_CSUM_TREE_OBJECTID)
|
||||
return btrfs_csum_root(fs_info, location->offset);
|
||||
return btrfs_global_root(fs_info, location);
|
||||
if (location->objectid == BTRFS_UUID_TREE_OBJECTID)
|
||||
return fs_info->uuid_root ? fs_info->uuid_root : ERR_PTR(-ENOENT);
|
||||
if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID)
|
||||
return fs_info->quota_enabled ? fs_info->quota_root :
|
||||
ERR_PTR(-ENOENT);
|
||||
if (location->objectid == BTRFS_FREE_SPACE_TREE_OBJECTID)
|
||||
return fs_info->_free_space_root ? fs_info->_free_space_root :
|
||||
ERR_PTR(-ENOENT);
|
||||
if (location->objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) {
|
||||
root = btrfs_global_root(fs_info, location);
|
||||
return root ? root : ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
BUG_ON(location->objectid == BTRFS_TREE_RELOC_OBJECTID);
|
||||
|
||||
@ -811,17 +867,25 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
|
||||
return root;
|
||||
}
|
||||
|
||||
static void __free_global_root(struct rb_node *node)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
|
||||
root = rb_entry(node, struct btrfs_root, rb_node);
|
||||
kfree(root);
|
||||
}
|
||||
|
||||
FREE_RB_BASED_TREE(global_roots, __free_global_root);
|
||||
|
||||
void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
if (fs_info->quota_root)
|
||||
free(fs_info->quota_root);
|
||||
|
||||
free_global_roots_tree(&fs_info->global_roots_tree);
|
||||
free(fs_info->tree_root);
|
||||
free(fs_info->_extent_root);
|
||||
free(fs_info->chunk_root);
|
||||
free(fs_info->dev_root);
|
||||
free(fs_info->_csum_root);
|
||||
free(fs_info->_free_space_root);
|
||||
free(fs_info->uuid_root);
|
||||
free(fs_info->super_copy);
|
||||
free(fs_info->log_root_tree);
|
||||
@ -837,20 +901,14 @@ struct btrfs_fs_info *btrfs_new_fs_info(int writable, u64 sb_bytenr)
|
||||
return NULL;
|
||||
|
||||
fs_info->tree_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->_extent_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->chunk_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->dev_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->_csum_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->quota_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->_free_space_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->uuid_root = calloc(1, sizeof(struct btrfs_root));
|
||||
fs_info->super_copy = calloc(1, BTRFS_SUPER_INFO_SIZE);
|
||||
|
||||
if (!fs_info->tree_root || !fs_info->_extent_root ||
|
||||
!fs_info->chunk_root || !fs_info->dev_root ||
|
||||
!fs_info->_csum_root || !fs_info->quota_root ||
|
||||
!fs_info->_free_space_root || !fs_info->uuid_root ||
|
||||
!fs_info->super_copy)
|
||||
if (!fs_info->tree_root || !fs_info->chunk_root || !fs_info->dev_root ||
|
||||
!fs_info->quota_root || !fs_info->uuid_root || !fs_info->super_copy)
|
||||
goto free_all;
|
||||
|
||||
extent_io_tree_init(&fs_info->extent_cache);
|
||||
@ -940,15 +998,14 @@ static int find_best_backup_root(struct btrfs_super_block *super)
|
||||
return best_index;
|
||||
}
|
||||
|
||||
static int setup_root_or_create_block(struct btrfs_fs_info *fs_info,
|
||||
unsigned flags,
|
||||
struct btrfs_root *info_root,
|
||||
u64 objectid, char *str)
|
||||
static int read_root_or_create_block(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_root *root, u64 bytenr,
|
||||
u64 gen, int level, unsigned flags,
|
||||
char *str)
|
||||
{
|
||||
struct btrfs_root *root = fs_info->tree_root;
|
||||
int ret;
|
||||
|
||||
ret = find_and_setup_root(root, fs_info, objectid, info_root);
|
||||
ret = read_root_node(fs_info, root, bytenr, gen, level);
|
||||
if (ret) {
|
||||
if (!(flags & OPEN_CTREE_PARTIAL)) {
|
||||
error("could not setup %s tree", str);
|
||||
@ -959,16 +1016,128 @@ static int setup_root_or_create_block(struct btrfs_fs_info *fs_info,
|
||||
* Need a blank node here just so we don't screw up in the
|
||||
* million of places that assume a root has a valid ->node
|
||||
*/
|
||||
info_root->node =
|
||||
btrfs_find_create_tree_block(fs_info, 0);
|
||||
if (!info_root->node)
|
||||
root->node = btrfs_find_create_tree_block(fs_info, 0);
|
||||
if (!root->node)
|
||||
return -ENOMEM;
|
||||
clear_extent_buffer_uptodate(info_root->node);
|
||||
clear_extent_buffer_uptodate(root->node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool maybe_load_block_groups(struct btrfs_fs_info *fs_info,
|
||||
u64 flags)
|
||||
{
|
||||
struct btrfs_root *root = btrfs_extent_root(fs_info, 0);
|
||||
|
||||
if (flags & OPEN_CTREE_NO_BLOCK_GROUPS)
|
||||
return false;
|
||||
|
||||
if (root && extent_buffer_uptodate(root->node))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static int load_global_roots_objectid(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_path *path, u64 objectid,
|
||||
unsigned flags, char *str)
|
||||
{
|
||||
struct btrfs_root *tree_root = fs_info->tree_root;
|
||||
struct btrfs_root *root;
|
||||
int ret;
|
||||
struct btrfs_key key = {
|
||||
.objectid = objectid,
|
||||
.type = BTRFS_ROOT_ITEM_KEY,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
|
||||
ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
|
||||
if (ret < 0) {
|
||||
error("could not find %s tree", str);
|
||||
return ret;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
while (1) {
|
||||
if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) {
|
||||
ret = btrfs_next_leaf(tree_root, path);
|
||||
if (ret) {
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
btrfs_item_key_to_cpu(path->nodes[0], &key,
|
||||
path->slots[0]);
|
||||
if (key.objectid != objectid)
|
||||
break;
|
||||
|
||||
root = calloc(1, sizeof(*root));
|
||||
if (!root) {
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
btrfs_setup_root(root, fs_info, objectid);
|
||||
read_extent_buffer(path->nodes[0], &root->root_item,
|
||||
btrfs_item_ptr_offset(path->nodes[0],
|
||||
path->slots[0]),
|
||||
sizeof(root->root_item));
|
||||
memcpy(&root->root_key, &key, sizeof(key));
|
||||
ret = read_root_or_create_block(fs_info, root,
|
||||
btrfs_root_bytenr(&root->root_item),
|
||||
btrfs_root_generation(&root->root_item),
|
||||
btrfs_root_level(&root->root_item),
|
||||
flags, str);
|
||||
if (ret) {
|
||||
free(root);
|
||||
break;
|
||||
}
|
||||
root->track_dirty = 1;
|
||||
|
||||
ret = btrfs_global_root_insert(fs_info, root);
|
||||
if (ret) {
|
||||
free_extent_buffer(root->node);
|
||||
free(root);
|
||||
break;
|
||||
}
|
||||
|
||||
path->slots[0]++;
|
||||
}
|
||||
btrfs_release_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int load_global_roots(struct btrfs_fs_info *fs_info, unsigned flags)
|
||||
{
|
||||
struct btrfs_path *path;
|
||||
int ret = 0;
|
||||
|
||||
path = btrfs_alloc_path();
|
||||
if (!path)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = load_global_roots_objectid(fs_info, path,
|
||||
BTRFS_EXTENT_TREE_OBJECTID, flags,
|
||||
"extent");
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = load_global_roots_objectid(fs_info, path,
|
||||
BTRFS_CSUM_TREE_OBJECTID, flags,
|
||||
"csum");
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = load_global_roots_objectid(fs_info, path,
|
||||
BTRFS_FREE_SPACE_TREE_OBJECTID, flags,
|
||||
"free space");
|
||||
out:
|
||||
btrfs_free_path(path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
|
||||
unsigned flags)
|
||||
{
|
||||
@ -1006,11 +1175,9 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ret = setup_root_or_create_block(fs_info, flags, fs_info->_extent_root,
|
||||
BTRFS_EXTENT_TREE_OBJECTID, "extent");
|
||||
ret = load_global_roots(fs_info, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
fs_info->_extent_root->track_dirty = 1;
|
||||
|
||||
ret = find_and_setup_root(root, fs_info, BTRFS_DEV_TREE_OBJECTID,
|
||||
fs_info->dev_root);
|
||||
@ -1020,12 +1187,6 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
|
||||
}
|
||||
fs_info->dev_root->track_dirty = 1;
|
||||
|
||||
ret = setup_root_or_create_block(fs_info, flags, fs_info->_csum_root,
|
||||
BTRFS_CSUM_TREE_OBJECTID, "csum");
|
||||
if (ret)
|
||||
return ret;
|
||||
fs_info->_csum_root->track_dirty = 1;
|
||||
|
||||
ret = find_and_setup_root(root, fs_info, BTRFS_UUID_TREE_OBJECTID,
|
||||
fs_info->uuid_root);
|
||||
if (ret) {
|
||||
@ -1044,21 +1205,6 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
|
||||
fs_info->quota_enabled = 1;
|
||||
}
|
||||
|
||||
if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) {
|
||||
ret = find_and_setup_root(root, fs_info, BTRFS_FREE_SPACE_TREE_OBJECTID,
|
||||
fs_info->_free_space_root);
|
||||
if (ret) {
|
||||
free(fs_info->_free_space_root);
|
||||
fs_info->_free_space_root = NULL;
|
||||
printk("Couldn't read free space tree\n");
|
||||
return -EIO;
|
||||
}
|
||||
fs_info->_free_space_root->track_dirty = 1;
|
||||
} else {
|
||||
free(fs_info->_free_space_root);
|
||||
fs_info->_free_space_root = NULL;
|
||||
}
|
||||
|
||||
ret = find_and_setup_log_root(root, fs_info, sb);
|
||||
if (ret) {
|
||||
printk("Couldn't setup log root tree\n");
|
||||
@ -1068,8 +1214,7 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
|
||||
|
||||
fs_info->generation = generation;
|
||||
fs_info->last_trans_committed = generation;
|
||||
if (extent_buffer_uptodate(fs_info->_extent_root->node) &&
|
||||
!(flags & OPEN_CTREE_NO_BLOCK_GROUPS)) {
|
||||
if (maybe_load_block_groups(fs_info, flags)) {
|
||||
ret = btrfs_read_block_groups(fs_info);
|
||||
/*
|
||||
* If we don't find any blockgroups (ENOENT) we're either
|
||||
@ -1093,18 +1238,29 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, u64 root_tree_bytenr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void release_global_roots(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct rb_node *n;
|
||||
|
||||
for (n = rb_first(&fs_info->global_roots_tree); n; n = rb_next(n)) {
|
||||
root = rb_entry(n, struct btrfs_root, rb_node);
|
||||
if (root->node)
|
||||
free_extent_buffer(root->node);
|
||||
if (root->commit_root)
|
||||
free_extent_buffer(root->commit_root);
|
||||
root->node = NULL;
|
||||
root->commit_root = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void btrfs_release_all_roots(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
if (fs_info->_free_space_root)
|
||||
free_extent_buffer(fs_info->_free_space_root->node);
|
||||
release_global_roots(fs_info);
|
||||
if (fs_info->quota_root)
|
||||
free_extent_buffer(fs_info->quota_root->node);
|
||||
if (fs_info->_csum_root)
|
||||
free_extent_buffer(fs_info->_csum_root->node);
|
||||
if (fs_info->dev_root)
|
||||
free_extent_buffer(fs_info->dev_root->node);
|
||||
if (fs_info->_extent_root)
|
||||
free_extent_buffer(fs_info->_extent_root->node);
|
||||
if (fs_info->tree_root)
|
||||
free_extent_buffer(fs_info->tree_root->node);
|
||||
if (fs_info->log_root_tree)
|
||||
@ -1827,6 +1983,8 @@ static int write_dev_supers(struct btrfs_fs_info *fs_info,
|
||||
static void backup_super_roots(struct btrfs_fs_info *info)
|
||||
{
|
||||
struct btrfs_root_backup *root_backup;
|
||||
struct btrfs_root *csum_root = btrfs_csum_root(info, 0);
|
||||
struct btrfs_root *extent_root = btrfs_extent_root(info, 0);
|
||||
int next_backup;
|
||||
int last_backup;
|
||||
|
||||
@ -1858,11 +2016,11 @@ static void backup_super_roots(struct btrfs_fs_info *info)
|
||||
btrfs_set_backup_chunk_root_level(root_backup,
|
||||
btrfs_header_level(info->chunk_root->node));
|
||||
|
||||
btrfs_set_backup_extent_root(root_backup, info->_extent_root->node->start);
|
||||
btrfs_set_backup_extent_root(root_backup, extent_root->node->start);
|
||||
btrfs_set_backup_extent_root_gen(root_backup,
|
||||
btrfs_header_generation(info->_extent_root->node));
|
||||
btrfs_header_generation(extent_root->node));
|
||||
btrfs_set_backup_extent_root_level(root_backup,
|
||||
btrfs_header_level(info->_extent_root->node));
|
||||
btrfs_header_level(extent_root->node));
|
||||
/*
|
||||
* we might commit during log recovery, which happens before we set
|
||||
* the fs_root. Make sure it is valid before we fill it in.
|
||||
@ -1882,11 +2040,11 @@ static void backup_super_roots(struct btrfs_fs_info *info)
|
||||
btrfs_set_backup_dev_root_level(root_backup,
|
||||
btrfs_header_level(info->dev_root->node));
|
||||
|
||||
btrfs_set_backup_csum_root(root_backup, info->_csum_root->node->start);
|
||||
btrfs_set_backup_csum_root(root_backup, csum_root->node->start);
|
||||
btrfs_set_backup_csum_root_gen(root_backup,
|
||||
btrfs_header_generation(info->_csum_root->node));
|
||||
btrfs_header_generation(csum_root->node));
|
||||
btrfs_set_backup_csum_root_level(root_backup,
|
||||
btrfs_header_level(info->_csum_root->node));
|
||||
btrfs_header_level(csum_root->node));
|
||||
|
||||
btrfs_set_backup_total_bytes(root_backup,
|
||||
btrfs_super_total_bytes(info->super_copy));
|
||||
@ -1894,7 +2052,7 @@ static void backup_super_roots(struct btrfs_fs_info *info)
|
||||
btrfs_super_bytes_used(info->super_copy));
|
||||
btrfs_set_backup_num_devices(root_backup,
|
||||
btrfs_super_num_devices(info->super_copy));
|
||||
};
|
||||
}
|
||||
|
||||
int write_all_supers(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
|
@ -216,4 +216,9 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
|
||||
u64 objectid);
|
||||
struct btrfs_root *btrfs_csum_root(struct btrfs_fs_info *fs_info, u64 bytenr);
|
||||
struct btrfs_root *btrfs_extent_root(struct btrfs_fs_info *fs_inf, u64 bytenr);
|
||||
struct btrfs_root *btrfs_block_group_root(struct btrfs_fs_info *fs_info);
|
||||
struct btrfs_root *btrfs_global_root(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_key *key);
|
||||
int btrfs_global_root_insert(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_root *root);
|
||||
#endif
|
||||
|
@ -28,7 +28,13 @@
|
||||
static struct btrfs_root *btrfs_free_space_root(struct btrfs_fs_info *fs_info,
|
||||
struct btrfs_block_group *block_group)
|
||||
{
|
||||
return fs_info->_free_space_root;
|
||||
struct btrfs_key key = {
|
||||
.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID,
|
||||
.type = BTRFS_ROOT_ITEM_KEY,
|
||||
.offset = 0,
|
||||
};
|
||||
|
||||
return btrfs_global_root(fs_info, &key);
|
||||
}
|
||||
|
||||
static struct btrfs_free_space_info *
|
||||
@ -1238,7 +1244,6 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
|
||||
features &= ~(BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID |
|
||||
BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE);
|
||||
btrfs_set_super_compat_ro_flags(fs_info->super_copy, features);
|
||||
fs_info->_free_space_root = NULL;
|
||||
|
||||
ret = clear_free_space_tree(trans, free_space_root);
|
||||
if (ret)
|
||||
@ -1258,6 +1263,7 @@ int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info)
|
||||
if (ret)
|
||||
goto abort;
|
||||
|
||||
rb_erase(&free_space_root->rb_node, &fs_info->global_roots_tree);
|
||||
free_extent_buffer(free_space_root->node);
|
||||
free_extent_buffer(free_space_root->commit_root);
|
||||
kfree(free_space_root);
|
||||
@ -1474,7 +1480,10 @@ int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info)
|
||||
ret = PTR_ERR(free_space_root);
|
||||
goto abort;
|
||||
}
|
||||
fs_info->_free_space_root = free_space_root;
|
||||
|
||||
ret = btrfs_global_root_insert(fs_info, free_space_root);
|
||||
if (ret)
|
||||
goto abort;
|
||||
add_root_to_dirty_list(free_space_root);
|
||||
|
||||
do {
|
||||
|
28
mkfs/main.c
28
mkfs/main.c
@ -264,20 +264,33 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int recow_global_roots(struct btrfs_trans_handle *trans)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = trans->fs_info;
|
||||
struct btrfs_root *root;
|
||||
struct rb_node *n;
|
||||
int ret = 0;
|
||||
|
||||
for (n = rb_first(&fs_info->global_roots_tree); n; n = rb_next(n)) {
|
||||
root = rb_entry(n, struct btrfs_root, rb_node);
|
||||
ret = __recow_root(trans, root);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int recow_roots(struct btrfs_trans_handle *trans,
|
||||
struct btrfs_root *root)
|
||||
{
|
||||
struct btrfs_fs_info *info = root->fs_info;
|
||||
struct btrfs_root *csum_root = btrfs_csum_root(info, 0);
|
||||
int ret;
|
||||
|
||||
ret = __recow_root(trans, info->fs_root);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = __recow_root(trans, info->tree_root);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = __recow_root(trans, info->_extent_root);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = __recow_root(trans, info->chunk_root);
|
||||
@ -286,14 +299,9 @@ static int recow_roots(struct btrfs_trans_handle *trans,
|
||||
ret = __recow_root(trans, info->dev_root);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = __recow_root(trans, csum_root);
|
||||
ret = recow_global_roots(trans);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (info->_free_space_root) {
|
||||
ret = __recow_root(trans, info->_free_space_root);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user