Commit cb517eab authored by Miao Xie's avatar Miao Xie Committed by Josef Bacik

Btrfs: cleanup the similar code of the fs root read

There are several functions whose code is similar, such as
  btrfs_find_last_root()
  btrfs_read_fs_root_no_radix()

Besides that, some functions are invoked twice, it is unnecessary,
for example, we are sure that all roots which is found in
  btrfs_find_orphan_roots()
have their orphan items, so it is unnecessary to check the orphan
item again.

So cleanup it.
Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarJosef Bacik <jbacik@fusionio.com>
parent babbf170
...@@ -3376,9 +3376,9 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans, ...@@ -3376,9 +3376,9 @@ int __must_check btrfs_update_root(struct btrfs_trans_handle *trans,
struct btrfs_root_item *item); struct btrfs_root_item *item);
void btrfs_read_root_item(struct extent_buffer *eb, int slot, void btrfs_read_root_item(struct extent_buffer *eb, int slot,
struct btrfs_root_item *item); struct btrfs_root_item *item);
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, struct int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key,
btrfs_root_item *item, struct btrfs_key *key); struct btrfs_path *path, struct btrfs_root_item *root_item,
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid); struct btrfs_key *root_key);
int btrfs_find_orphan_roots(struct btrfs_root *tree_root); int btrfs_find_orphan_roots(struct btrfs_root *tree_root);
void btrfs_set_root_node(struct btrfs_root_item *item, void btrfs_set_root_node(struct btrfs_root_item *item,
struct extent_buffer *node); struct extent_buffer *node);
......
...@@ -1234,39 +1234,6 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize, ...@@ -1234,39 +1234,6 @@ static void __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
spin_lock_init(&root->root_item_lock); spin_lock_init(&root->root_item_lock);
} }
static int __must_check find_and_setup_root(struct btrfs_root *tree_root,
struct btrfs_fs_info *fs_info,
u64 objectid,
struct btrfs_root *root)
{
int ret;
u32 blocksize;
u64 generation;
__setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize,
root, fs_info, objectid);
ret = btrfs_find_last_root(tree_root, objectid,
&root->root_item, &root->root_key);
if (ret > 0)
return -ENOENT;
else if (ret < 0)
return ret;
generation = btrfs_root_generation(&root->root_item);
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
root->commit_root = NULL;
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation);
if (!root->node || !btrfs_buffer_uptodate(root->node, generation, 0)) {
free_extent_buffer(root->node);
root->node = NULL;
return -EIO;
}
root->commit_root = btrfs_root_node(root);
return 0;
}
static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info) static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info)
{ {
struct btrfs_root *root = kzalloc(sizeof(*root), GFP_NOFS); struct btrfs_root *root = kzalloc(sizeof(*root), GFP_NOFS);
...@@ -1451,70 +1418,73 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans, ...@@ -1451,70 +1418,73 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
return 0; return 0;
} }
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root,
struct btrfs_key *location) struct btrfs_key *key)
{ {
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_fs_info *fs_info = tree_root->fs_info; struct btrfs_fs_info *fs_info = tree_root->fs_info;
struct btrfs_path *path; struct btrfs_path *path;
struct extent_buffer *l;
u64 generation; u64 generation;
u32 blocksize; u32 blocksize;
int ret = 0; int ret;
int slot;
root = btrfs_alloc_root(fs_info); path = btrfs_alloc_path();
if (!root) if (!path)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
if (location->offset == (u64)-1) {
ret = find_and_setup_root(tree_root, fs_info, root = btrfs_alloc_root(fs_info);
location->objectid, root); if (!root) {
if (ret) { ret = -ENOMEM;
kfree(root); goto alloc_fail;
return ERR_PTR(ret);
}
goto out;
} }
__setup_root(tree_root->nodesize, tree_root->leafsize, __setup_root(tree_root->nodesize, tree_root->leafsize,
tree_root->sectorsize, tree_root->stripesize, tree_root->sectorsize, tree_root->stripesize,
root, fs_info, location->objectid); root, fs_info, key->objectid);
path = btrfs_alloc_path(); ret = btrfs_find_root(tree_root, key, path,
if (!path) { &root->root_item, &root->root_key);
kfree(root);
return ERR_PTR(-ENOMEM);
}
ret = btrfs_search_slot(NULL, tree_root, location, path, 0, 0);
if (ret == 0) {
l = path->nodes[0];
slot = path->slots[0];
btrfs_read_root_item(l, slot, &root->root_item);
memcpy(&root->root_key, location, sizeof(*location));
}
btrfs_free_path(path);
if (ret) { if (ret) {
kfree(root);
if (ret > 0) if (ret > 0)
ret = -ENOENT; ret = -ENOENT;
return ERR_PTR(ret); goto find_fail;
} }
generation = btrfs_root_generation(&root->root_item); generation = btrfs_root_generation(&root->root_item);
blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item)); blocksize = btrfs_level_size(root, btrfs_root_level(&root->root_item));
root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item),
blocksize, generation); blocksize, generation);
if (!root->node || !extent_buffer_uptodate(root->node)) { if (!root->node) {
ret = (!root->node) ? -ENOMEM : -EIO; ret = -ENOMEM;
goto find_fail;
} else if (!btrfs_buffer_uptodate(root->node, generation, 0)) {
ret = -EIO;
goto read_fail;
}
root->commit_root = btrfs_root_node(root);
out:
btrfs_free_path(path);
return root;
read_fail:
free_extent_buffer(root->node); free_extent_buffer(root->node);
find_fail:
kfree(root); kfree(root);
return ERR_PTR(ret); alloc_fail:
} root = ERR_PTR(ret);
goto out;
}
root->commit_root = btrfs_root_node(root); struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
out: struct btrfs_key *location)
if (location->objectid != BTRFS_TREE_LOG_OBJECTID) { {
struct btrfs_root *root;
root = btrfs_read_tree_root(tree_root, location);
if (IS_ERR(root))
return root;
if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) {
root->ref_cows = 1; root->ref_cows = 1;
btrfs_check_and_init_root_item(&root->root_item); btrfs_check_and_init_root_item(&root->root_item);
} }
...@@ -1522,6 +1492,66 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, ...@@ -1522,6 +1492,66 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root,
return root; return root;
} }
int btrfs_init_fs_root(struct btrfs_root *root)
{
int ret;
root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS);
root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned),
GFP_NOFS);
if (!root->free_ino_pinned || !root->free_ino_ctl) {
ret = -ENOMEM;
goto fail;
}
btrfs_init_free_ino_ctl(root);
mutex_init(&root->fs_commit_mutex);
spin_lock_init(&root->cache_lock);
init_waitqueue_head(&root->cache_wait);
ret = get_anon_bdev(&root->anon_dev);
if (ret)
goto fail;
return 0;
fail:
kfree(root->free_ino_ctl);
kfree(root->free_ino_pinned);
return ret;
}
struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info,
u64 root_id)
{
struct btrfs_root *root;
spin_lock(&fs_info->fs_roots_radix_lock);
root = radix_tree_lookup(&fs_info->fs_roots_radix,
(unsigned long)root_id);
spin_unlock(&fs_info->fs_roots_radix_lock);
return root;
}
int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root)
{
int ret;
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
if (ret)
return ret;
spin_lock(&fs_info->fs_roots_radix_lock);
ret = radix_tree_insert(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid,
root);
if (ret == 0)
root->in_radix = 1;
spin_unlock(&fs_info->fs_roots_radix_lock);
radix_tree_preload_end();
return ret;
}
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
struct btrfs_key *location) struct btrfs_key *location)
{ {
...@@ -1542,58 +1572,30 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1542,58 +1572,30 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
return fs_info->quota_root ? fs_info->quota_root : return fs_info->quota_root ? fs_info->quota_root :
ERR_PTR(-ENOENT); ERR_PTR(-ENOENT);
again: again:
spin_lock(&fs_info->fs_roots_radix_lock); root = btrfs_lookup_fs_root(fs_info, location->objectid);
root = radix_tree_lookup(&fs_info->fs_roots_radix,
(unsigned long)location->objectid);
spin_unlock(&fs_info->fs_roots_radix_lock);
if (root) if (root)
return root; return root;
root = btrfs_read_fs_root_no_radix(fs_info->tree_root, location); root = btrfs_read_fs_root(fs_info->tree_root, location);
if (IS_ERR(root)) if (IS_ERR(root))
return root; return root;
root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS); if (btrfs_root_refs(&root->root_item) == 0) {
root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned), ret = -ENOENT;
GFP_NOFS);
if (!root->free_ino_pinned || !root->free_ino_ctl) {
ret = -ENOMEM;
goto fail; goto fail;
} }
btrfs_init_free_ino_ctl(root); ret = btrfs_init_fs_root(root);
mutex_init(&root->fs_commit_mutex);
spin_lock_init(&root->cache_lock);
init_waitqueue_head(&root->cache_wait);
ret = get_anon_bdev(&root->anon_dev);
if (ret) if (ret)
goto fail; goto fail;
if (btrfs_root_refs(&root->root_item) == 0) {
ret = -ENOENT;
goto fail;
}
ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid); ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
if (ret < 0) if (ret < 0)
goto fail; goto fail;
if (ret == 0) if (ret == 0)
root->orphan_item_inserted = 1; root->orphan_item_inserted = 1;
ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); ret = btrfs_insert_fs_root(fs_info, root);
if (ret)
goto fail;
spin_lock(&fs_info->fs_roots_radix_lock);
ret = radix_tree_insert(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid,
root);
if (ret == 0)
root->in_radix = 1;
spin_unlock(&fs_info->fs_roots_radix_lock);
radix_tree_preload_end();
if (ret) { if (ret) {
if (ret == -EEXIST) { if (ret == -EEXIST) {
free_fs_root(root); free_fs_root(root);
...@@ -1601,10 +1603,6 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, ...@@ -1601,10 +1603,6 @@ struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
} }
goto fail; goto fail;
} }
ret = btrfs_find_dead_roots(fs_info->tree_root,
root->root_key.objectid);
WARN_ON(ret);
return root; return root;
fail: fail:
free_fs_root(root); free_fs_root(root);
...@@ -2050,7 +2048,7 @@ static void del_fs_roots(struct btrfs_fs_info *fs_info) ...@@ -2050,7 +2048,7 @@ static void del_fs_roots(struct btrfs_fs_info *fs_info)
list_del(&gang[0]->root_list); list_del(&gang[0]->root_list);
if (gang[0]->in_radix) { if (gang[0]->in_radix) {
btrfs_free_fs_root(fs_info, gang[0]); btrfs_drop_and_free_fs_root(fs_info, gang[0]);
} else { } else {
free_extent_buffer(gang[0]->node); free_extent_buffer(gang[0]->node);
free_extent_buffer(gang[0]->commit_root); free_extent_buffer(gang[0]->commit_root);
...@@ -2065,7 +2063,7 @@ static void del_fs_roots(struct btrfs_fs_info *fs_info) ...@@ -2065,7 +2063,7 @@ static void del_fs_roots(struct btrfs_fs_info *fs_info)
if (!ret) if (!ret)
break; break;
for (i = 0; i < ret; i++) for (i = 0; i < ret; i++)
btrfs_free_fs_root(fs_info, gang[i]); btrfs_drop_and_free_fs_root(fs_info, gang[i]);
} }
} }
...@@ -2097,14 +2095,8 @@ int open_ctree(struct super_block *sb, ...@@ -2097,14 +2095,8 @@ int open_ctree(struct super_block *sb,
int backup_index = 0; int backup_index = 0;
tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info); tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info);
extent_root = fs_info->extent_root = btrfs_alloc_root(fs_info);
csum_root = fs_info->csum_root = btrfs_alloc_root(fs_info);
chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info); chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info);
dev_root = fs_info->dev_root = btrfs_alloc_root(fs_info); if (!tree_root || !chunk_root) {
quota_root = fs_info->quota_root = btrfs_alloc_root(fs_info);
if (!tree_root || !extent_root || !csum_root ||
!chunk_root || !dev_root || !quota_root) {
err = -ENOMEM; err = -ENOMEM;
goto fail; goto fail;
} }
...@@ -2655,33 +2647,44 @@ int open_ctree(struct super_block *sb, ...@@ -2655,33 +2647,44 @@ int open_ctree(struct super_block *sb,
btrfs_set_root_node(&tree_root->root_item, tree_root->node); btrfs_set_root_node(&tree_root->root_item, tree_root->node);
tree_root->commit_root = btrfs_root_node(tree_root); tree_root->commit_root = btrfs_root_node(tree_root);
ret = find_and_setup_root(tree_root, fs_info, location.objectid = BTRFS_EXTENT_TREE_OBJECTID;
BTRFS_EXTENT_TREE_OBJECTID, extent_root); location.type = BTRFS_ROOT_ITEM_KEY;
if (ret) location.offset = 0;
extent_root = btrfs_read_tree_root(tree_root, &location);
if (IS_ERR(extent_root)) {
ret = PTR_ERR(extent_root);
goto recovery_tree_root; goto recovery_tree_root;
}
extent_root->track_dirty = 1; extent_root->track_dirty = 1;
fs_info->extent_root = extent_root;
ret = find_and_setup_root(tree_root, fs_info, location.objectid = BTRFS_DEV_TREE_OBJECTID;
BTRFS_DEV_TREE_OBJECTID, dev_root); dev_root = btrfs_read_tree_root(tree_root, &location);
if (ret) if (IS_ERR(dev_root)) {
ret = PTR_ERR(dev_root);
goto recovery_tree_root; goto recovery_tree_root;
}
dev_root->track_dirty = 1; dev_root->track_dirty = 1;
fs_info->dev_root = dev_root;
btrfs_init_devices_late(fs_info);
ret = find_and_setup_root(tree_root, fs_info, location.objectid = BTRFS_CSUM_TREE_OBJECTID;
BTRFS_CSUM_TREE_OBJECTID, csum_root); csum_root = btrfs_read_tree_root(tree_root, &location);
if (ret) if (IS_ERR(csum_root)) {
ret = PTR_ERR(csum_root);
goto recovery_tree_root; goto recovery_tree_root;
}
csum_root->track_dirty = 1; csum_root->track_dirty = 1;
fs_info->csum_root = csum_root;
ret = find_and_setup_root(tree_root, fs_info, location.objectid = BTRFS_QUOTA_TREE_OBJECTID;
BTRFS_QUOTA_TREE_OBJECTID, quota_root); quota_root = btrfs_read_tree_root(tree_root, &location);
if (ret) { if (!IS_ERR(quota_root)) {
kfree(quota_root);
quota_root = fs_info->quota_root = NULL;
} else {
quota_root->track_dirty = 1; quota_root->track_dirty = 1;
fs_info->quota_enabled = 1; fs_info->quota_enabled = 1;
fs_info->pending_quota_state = 1; fs_info->pending_quota_state = 1;
fs_info->quota_root = quota_root;
} }
fs_info->generation = generation; fs_info->generation = generation;
...@@ -2834,7 +2837,7 @@ int open_ctree(struct super_block *sb, ...@@ -2834,7 +2837,7 @@ int open_ctree(struct super_block *sb,
location.objectid = BTRFS_FS_TREE_OBJECTID; location.objectid = BTRFS_FS_TREE_OBJECTID;
location.type = BTRFS_ROOT_ITEM_KEY; location.type = BTRFS_ROOT_ITEM_KEY;
location.offset = (u64)-1; location.offset = 0;
fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location); fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location);
if (IS_ERR(fs_info->fs_root)) { if (IS_ERR(fs_info->fs_root)) {
...@@ -3381,7 +3384,9 @@ int write_ctree_super(struct btrfs_trans_handle *trans, ...@@ -3381,7 +3384,9 @@ int write_ctree_super(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) /* Drop a fs root from the radix tree and free it. */
void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root)
{ {
spin_lock(&fs_info->fs_roots_radix_lock); spin_lock(&fs_info->fs_roots_radix_lock);
radix_tree_delete(&fs_info->fs_roots_radix, radix_tree_delete(&fs_info->fs_roots_radix,
...@@ -3415,6 +3420,11 @@ static void free_fs_root(struct btrfs_root *root) ...@@ -3415,6 +3420,11 @@ static void free_fs_root(struct btrfs_root *root)
kfree(root); kfree(root);
} }
void btrfs_free_fs_root(struct btrfs_root *root)
{
free_fs_root(root);
}
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info)
{ {
u64 root_objectid = 0; u64 root_objectid = 0;
......
...@@ -63,14 +63,19 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); ...@@ -63,14 +63,19 @@ struct buffer_head *btrfs_read_dev_super(struct block_device *bdev);
int btrfs_commit_super(struct btrfs_root *root); int btrfs_commit_super(struct btrfs_root *root);
struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root, struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
u64 bytenr, u32 blocksize); u64 bytenr, u32 blocksize);
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_root *tree_root, struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
struct btrfs_key *location); struct btrfs_key *location);
int btrfs_init_fs_root(struct btrfs_root *root);
int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root);
struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info,
struct btrfs_key *location); struct btrfs_key *location);
int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info);
void btrfs_btree_balance_dirty(struct btrfs_root *root); void btrfs_btree_balance_dirty(struct btrfs_root *root);
void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root); void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root);
void btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root); void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_root *root);
void btrfs_free_fs_root(struct btrfs_root *root);
void btrfs_mark_buffer_dirty(struct extent_buffer *buf); void btrfs_mark_buffer_dirty(struct extent_buffer *buf);
int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid,
int atomic); int atomic);
......
...@@ -7447,7 +7447,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, ...@@ -7447,7 +7447,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
} }
if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) { if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) {
ret = btrfs_find_last_root(tree_root, root->root_key.objectid, ret = btrfs_find_root(tree_root, &root->root_key, path,
NULL, NULL); NULL, NULL);
if (ret < 0) { if (ret < 0) {
btrfs_abort_transaction(trans, tree_root, ret); btrfs_abort_transaction(trans, tree_root, ret);
...@@ -7465,7 +7465,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root, ...@@ -7465,7 +7465,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
} }
if (root->in_radix) { if (root->in_radix) {
btrfs_free_fs_root(tree_root->fs_info, root); btrfs_drop_and_free_fs_root(tree_root->fs_info, root);
} else { } else {
free_extent_buffer(root->node); free_extent_buffer(root->node);
free_extent_buffer(root->commit_root); free_extent_buffer(root->commit_root);
......
...@@ -1355,8 +1355,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, ...@@ -1355,8 +1355,7 @@ static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans,
BUG_ON(ret); BUG_ON(ret);
kfree(root_item); kfree(root_item);
reloc_root = btrfs_read_fs_root_no_radix(root->fs_info->tree_root, reloc_root = btrfs_read_fs_root(root->fs_info->tree_root, &root_key);
&root_key);
BUG_ON(IS_ERR(reloc_root)); BUG_ON(IS_ERR(reloc_root));
reloc_root->last_trans = trans->transid; reloc_root->last_trans = trans->transid;
return reloc_root; return reloc_root;
...@@ -4277,7 +4276,7 @@ int btrfs_recover_relocation(struct btrfs_root *root) ...@@ -4277,7 +4276,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
key.type != BTRFS_ROOT_ITEM_KEY) key.type != BTRFS_ROOT_ITEM_KEY)
break; break;
reloc_root = btrfs_read_fs_root_no_radix(root, &key); reloc_root = btrfs_read_fs_root(root, &key);
if (IS_ERR(reloc_root)) { if (IS_ERR(reloc_root)) {
err = PTR_ERR(reloc_root); err = PTR_ERR(reloc_root);
goto out; goto out;
......
...@@ -64,52 +64,59 @@ void btrfs_read_root_item(struct extent_buffer *eb, int slot, ...@@ -64,52 +64,59 @@ void btrfs_read_root_item(struct extent_buffer *eb, int slot,
} }
/* /*
* lookup the root with the highest offset for a given objectid. The key we do * btrfs_find_root - lookup the root by the key.
* find is copied into 'key'. If we find something return 0, otherwise 1, < 0 * root: the root of the root tree
* on error. * search_key: the key to search
* path: the path we search
* root_item: the root item of the tree we look for
* root_key: the reak key of the tree we look for
*
* If ->offset of 'seach_key' is -1ULL, it means we are not sure the offset
* of the search key, just lookup the root with the highest offset for a
* given objectid.
*
* If we find something return 0, otherwise > 0, < 0 on error.
*/ */
int btrfs_find_last_root(struct btrfs_root *root, u64 objectid, int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key,
struct btrfs_root_item *item, struct btrfs_key *key) struct btrfs_path *path, struct btrfs_root_item *root_item,
struct btrfs_key *root_key)
{ {
struct btrfs_path *path;
struct btrfs_key search_key;
struct btrfs_key found_key; struct btrfs_key found_key;
struct extent_buffer *l; struct extent_buffer *l;
int ret; int ret;
int slot; int slot;
search_key.objectid = objectid; ret = btrfs_search_slot(NULL, root, search_key, path, 0, 0);
search_key.type = BTRFS_ROOT_ITEM_KEY;
search_key.offset = (u64)-1;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0);
if (ret < 0) if (ret < 0)
goto out; return ret;
BUG_ON(ret == 0); if (search_key->offset != -1ULL) { /* the search key is exact */
if (path->slots[0] == 0) { if (ret > 0)
ret = 1; goto out;
} else {
BUG_ON(ret == 0); /* Logical error */
if (path->slots[0] == 0)
goto out; goto out;
path->slots[0]--;
ret = 0;
} }
l = path->nodes[0]; l = path->nodes[0];
slot = path->slots[0] - 1; slot = path->slots[0];
btrfs_item_key_to_cpu(l, &found_key, slot); btrfs_item_key_to_cpu(l, &found_key, slot);
if (found_key.objectid != objectid || if (found_key.objectid != search_key->objectid ||
found_key.type != BTRFS_ROOT_ITEM_KEY) { found_key.type != BTRFS_ROOT_ITEM_KEY) {
ret = 1; ret = 1;
goto out; goto out;
} }
if (item)
btrfs_read_root_item(l, slot, item);
if (key)
memcpy(key, &found_key, sizeof(found_key));
ret = 0; if (root_item)
btrfs_read_root_item(l, slot, root_item);
if (root_key)
memcpy(root_key, &found_key, sizeof(found_key));
out: out:
btrfs_free_path(path); btrfs_release_path(path);
return ret; return ret;
} }
...@@ -212,86 +219,6 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, ...@@ -212,86 +219,6 @@ int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root,
return btrfs_insert_item(trans, root, key, item, sizeof(*item)); return btrfs_insert_item(trans, root, key, item, sizeof(*item));
} }
/*
* at mount time we want to find all the old transaction snapshots that were in
* the process of being deleted if we crashed. This is any root item with an
* offset lower than the latest root. They need to be queued for deletion to
* finish what was happening when we crashed.
*/
int btrfs_find_dead_roots(struct btrfs_root *root, u64 objectid)
{
struct btrfs_root *dead_root;
struct btrfs_root_item *ri;
struct btrfs_key key;
struct btrfs_key found_key;
struct btrfs_path *path;
int ret;
u32 nritems;
struct extent_buffer *leaf;
int slot;
key.objectid = objectid;
btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY);
key.offset = 0;
path = btrfs_alloc_path();
if (!path)
return -ENOMEM;
again:
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
if (ret < 0)
goto err;
while (1) {
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
slot = path->slots[0];
if (slot >= nritems) {
ret = btrfs_next_leaf(root, path);
if (ret)
break;
leaf = path->nodes[0];
nritems = btrfs_header_nritems(leaf);
slot = path->slots[0];
}
btrfs_item_key_to_cpu(leaf, &key, slot);
if (btrfs_key_type(&key) != BTRFS_ROOT_ITEM_KEY)
goto next;
if (key.objectid < objectid)
goto next;
if (key.objectid > objectid)
break;
ri = btrfs_item_ptr(leaf, slot, struct btrfs_root_item);
if (btrfs_disk_root_refs(leaf, ri) != 0)
goto next;
memcpy(&found_key, &key, sizeof(key));
key.offset++;
btrfs_release_path(path);
dead_root =
btrfs_read_fs_root_no_radix(root->fs_info->tree_root,
&found_key);
if (IS_ERR(dead_root)) {
ret = PTR_ERR(dead_root);
goto err;
}
ret = btrfs_add_dead_root(dead_root);
if (ret)
goto err;
goto again;
next:
slot++;
path->slots[0]++;
}
ret = 0;
err:
btrfs_free_path(path);
return ret;
}
int btrfs_find_orphan_roots(struct btrfs_root *tree_root) int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
{ {
struct extent_buffer *leaf; struct extent_buffer *leaf;
...@@ -340,20 +267,29 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root) ...@@ -340,20 +267,29 @@ int btrfs_find_orphan_roots(struct btrfs_root *tree_root)
root_key.objectid = key.offset; root_key.objectid = key.offset;
key.offset++; key.offset++;
root = btrfs_read_fs_root_no_name(tree_root->fs_info, root = btrfs_read_fs_root(tree_root, &root_key);
&root_key); if (IS_ERR(root)) {
if (!IS_ERR(root)) err = PTR_ERR(root);
break;
}
if (btrfs_root_refs(&root->root_item) == 0) {
btrfs_add_dead_root(root);
continue; continue;
}
ret = PTR_ERR(root); err = btrfs_init_fs_root(root);
if (ret != -ENOENT) { if (err) {
err = ret; btrfs_free_fs_root(root);
break; break;
} }
ret = btrfs_find_dead_roots(tree_root, root_key.objectid); root->orphan_item_inserted = 1;
if (ret) {
err = ret; err = btrfs_insert_fs_root(root->fs_info, root);
if (err) {
BUG_ON(err == -EEXIST);
btrfs_free_fs_root(root);
break; break;
} }
} }
......
...@@ -4016,8 +4016,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) ...@@ -4016,8 +4016,7 @@ int btrfs_recover_log_trees(struct btrfs_root *log_root_tree)
if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID) if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID)
break; break;
log = btrfs_read_fs_root_no_radix(log_root_tree, log = btrfs_read_fs_root(log_root_tree, &found_key);
&found_key);
if (IS_ERR(log)) { if (IS_ERR(log)) {
ret = PTR_ERR(log); ret = PTR_ERR(log);
btrfs_error(fs_info, ret, btrfs_error(fs_info, ret,
......
...@@ -5367,7 +5367,6 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root, ...@@ -5367,7 +5367,6 @@ static struct btrfs_device *add_missing_dev(struct btrfs_root *root,
return NULL; return NULL;
list_add(&device->dev_list, list_add(&device->dev_list,
&fs_devices->devices); &fs_devices->devices);
device->dev_root = root->fs_info->dev_root;
device->devid = devid; device->devid = devid;
device->work.func = pending_bios_fn; device->work.func = pending_bios_fn;
device->fs_devices = fs_devices; device->fs_devices = fs_devices;
...@@ -5593,7 +5592,6 @@ static int read_one_dev(struct btrfs_root *root, ...@@ -5593,7 +5592,6 @@ static int read_one_dev(struct btrfs_root *root,
} }
fill_device_from_item(leaf, dev_item, device); fill_device_from_item(leaf, dev_item, device);
device->dev_root = root->fs_info->dev_root;
device->in_fs_metadata = 1; device->in_fs_metadata = 1;
if (device->writeable && !device->is_tgtdev_for_dev_replace) { if (device->writeable && !device->is_tgtdev_for_dev_replace) {
device->fs_devices->total_rw_bytes += device->total_bytes; device->fs_devices->total_rw_bytes += device->total_bytes;
...@@ -5751,6 +5749,17 @@ int btrfs_read_chunk_tree(struct btrfs_root *root) ...@@ -5751,6 +5749,17 @@ int btrfs_read_chunk_tree(struct btrfs_root *root)
return ret; return ret;
} }
void btrfs_init_devices_late(struct btrfs_fs_info *fs_info)
{
struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
struct btrfs_device *device;
mutex_lock(&fs_devices->device_list_mutex);
list_for_each_entry(device, &fs_devices->devices, dev_list)
device->dev_root = fs_info->dev_root;
mutex_unlock(&fs_devices->device_list_mutex);
}
static void __btrfs_reset_dev_stats(struct btrfs_device *dev) static void __btrfs_reset_dev_stats(struct btrfs_device *dev)
{ {
int i; int i;
......
...@@ -321,6 +321,7 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes, ...@@ -321,6 +321,7 @@ int find_free_dev_extent(struct btrfs_device *device, u64 num_bytes,
void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
int btrfs_get_dev_stats(struct btrfs_root *root, int btrfs_get_dev_stats(struct btrfs_root *root,
struct btrfs_ioctl_get_dev_stats *stats); struct btrfs_ioctl_get_dev_stats *stats);
void btrfs_init_devices_late(struct btrfs_fs_info *fs_info);
int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info); int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *fs_info); struct btrfs_fs_info *fs_info);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment