|
@@ -1143,6 +1143,13 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,
|
|
|
return eb_rewin;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * get_old_root() rewinds the state of @root's root node to the given @time_seq
|
|
|
+ * value. If there are no changes, the current root->root_node is returned. If
|
|
|
+ * anything changed in between, there's a fresh buffer allocated on which the
|
|
|
+ * rewind operations are done. In any case, the returned buffer is read locked.
|
|
|
+ * Returns NULL on error (with no locks held).
|
|
|
+ */
|
|
|
static inline struct extent_buffer *
|
|
|
get_old_root(struct btrfs_root *root, u64 time_seq)
|
|
|
{
|
|
@@ -1151,6 +1158,7 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
|
|
|
struct tree_mod_root *old_root;
|
|
|
u64 old_generation;
|
|
|
|
|
|
+ eb = btrfs_read_lock_root_node(root);
|
|
|
tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq);
|
|
|
if (!tm)
|
|
|
return root->node;
|
|
@@ -1173,15 +1181,21 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
|
|
|
/* there's a root replace operation for the current root */
|
|
|
eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT,
|
|
|
root->nodesize);
|
|
|
+ }
|
|
|
+ btrfs_tree_read_unlock(root->node);
|
|
|
+ free_extent_buffer(root->node);
|
|
|
+ if (!eb)
|
|
|
+ return NULL;
|
|
|
+ btrfs_tree_read_lock(eb);
|
|
|
+ if (old_root->logical != root->node->start) {
|
|
|
btrfs_set_header_bytenr(eb, eb->start);
|
|
|
btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV);
|
|
|
btrfs_set_header_owner(eb, root->root_key.objectid);
|
|
|
}
|
|
|
- if (!eb)
|
|
|
- return NULL;
|
|
|
btrfs_set_header_level(eb, old_root->level);
|
|
|
btrfs_set_header_generation(eb, old_generation);
|
|
|
__tree_mod_log_rewind(eb, time_seq, tm);
|
|
|
+ extent_buffer_get(eb);
|
|
|
|
|
|
return eb;
|
|
|
}
|
|
@@ -2612,9 +2626,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key,
|
|
|
|
|
|
again:
|
|
|
b = get_old_root(root, time_seq);
|
|
|
- extent_buffer_get(b);
|
|
|
level = btrfs_header_level(b);
|
|
|
- btrfs_tree_read_lock(b);
|
|
|
p->locks[level] = BTRFS_READ_LOCK;
|
|
|
|
|
|
while (b) {
|