Loading fs/btrfs/backref.c +5 −12 Original line number Original line Diff line number Diff line Loading @@ -179,7 +179,8 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id, static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, struct ulist *parents, int level, struct ulist *parents, int level, struct btrfs_key *key, u64 wanted_disk_byte, struct btrfs_key *key, u64 time_seq, u64 wanted_disk_byte, const u64 *extent_item_pos) const u64 *extent_item_pos) { { int ret; int ret; Loading Loading @@ -212,7 +213,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, */ */ while (1) { while (1) { eie = NULL; eie = NULL; ret = btrfs_next_leaf(root, path); ret = btrfs_next_old_leaf(root, path, time_seq); if (ret < 0) if (ret < 0) return ret; return ret; if (ret) if (ret) Loading Loading @@ -294,18 +295,10 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, goto out; goto out; } } if (level == 0) { if (level == 0) if (ret == 1 && path->slots[0] >= btrfs_header_nritems(eb)) { ret = btrfs_next_leaf(root, path); if (ret) goto out; eb = path->nodes[0]; } btrfs_item_key_to_cpu(eb, &key, path->slots[0]); btrfs_item_key_to_cpu(eb, &key, path->slots[0]); } ret = add_all_parents(root, path, parents, level, &key, ret = add_all_parents(root, path, parents, level, &key, time_seq, ref->wanted_disk_byte, extent_item_pos); ref->wanted_disk_byte, extent_item_pos); out: out: btrfs_free_path(path); btrfs_free_path(path); Loading fs/btrfs/ctree.c +63 −23 Original line number Original line Diff line number Diff line Loading @@ -467,6 +467,15 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, return 0; return 0; } } /* * This allocates memory and gets a tree modification sequence number when * needed. * * Returns 0 when no sequence number is needed, < 0 on error. * Returns 1 when a sequence number was added. In this case, * fs_info->tree_mod_seq_lock was acquired and must be released by the caller * after inserting into the rb tree. */ static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, struct tree_mod_elem **tm_ret) struct tree_mod_elem **tm_ret) { { Loading @@ -491,11 +500,11 @@ static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, */ */ kfree(tm); kfree(tm); seq = 0; seq = 0; spin_unlock(&fs_info->tree_mod_seq_lock); } else { } else { __get_tree_mod_seq(fs_info, &tm->elem); __get_tree_mod_seq(fs_info, &tm->elem); seq = tm->elem.seq; seq = tm->elem.seq; } } spin_unlock(&fs_info->tree_mod_seq_lock); return seq; return seq; } } Loading @@ -521,7 +530,9 @@ tree_mod_log_insert_key_mask(struct btrfs_fs_info *fs_info, tm->slot = slot; tm->slot = slot; tm->generation = btrfs_node_ptr_generation(eb, slot); tm->generation = btrfs_node_ptr_generation(eb, slot); return __tree_mod_log_insert(fs_info, tm); ret = __tree_mod_log_insert(fs_info, tm); spin_unlock(&fs_info->tree_mod_seq_lock); return ret; } } static noinline int static noinline int Loading Loading @@ -559,7 +570,9 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, tm->move.nr_items = nr_items; tm->move.nr_items = nr_items; tm->op = MOD_LOG_MOVE_KEYS; tm->op = MOD_LOG_MOVE_KEYS; return __tree_mod_log_insert(fs_info, tm); ret = __tree_mod_log_insert(fs_info, tm); spin_unlock(&fs_info->tree_mod_seq_lock); return ret; } } static noinline int static noinline int Loading @@ -580,7 +593,9 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, tm->generation = btrfs_header_generation(old_root); tm->generation = btrfs_header_generation(old_root); tm->op = MOD_LOG_ROOT_REPLACE; tm->op = MOD_LOG_ROOT_REPLACE; return __tree_mod_log_insert(fs_info, tm); ret = __tree_mod_log_insert(fs_info, tm); spin_unlock(&fs_info->tree_mod_seq_lock); return ret; } } static struct tree_mod_elem * static struct tree_mod_elem * Loading Loading @@ -1023,6 +1038,10 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, looped = 1; looped = 1; } } /* if there's no old root to return, return what we found instead */ if (!found) found = tm; return found; return found; } } Loading Loading @@ -1143,22 +1162,36 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, return eb_rewin; 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 * static inline struct extent_buffer * get_old_root(struct btrfs_root *root, u64 time_seq) get_old_root(struct btrfs_root *root, u64 time_seq) { { struct tree_mod_elem *tm; struct tree_mod_elem *tm; struct extent_buffer *eb; struct extent_buffer *eb; struct tree_mod_root *old_root; struct tree_mod_root *old_root = NULL; u64 old_generation; u64 old_generation; u64 logical; eb = btrfs_read_lock_root_node(root); tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); if (!tm) if (!tm) return root->node; return root->node; if (tm->op == MOD_LOG_ROOT_REPLACE) { old_root = &tm->old_root; old_root = &tm->old_root; old_generation = tm->generation; old_generation = tm->generation; logical = old_root->logical; } else { logical = root->node->start; } tm = tree_mod_log_search(root->fs_info, old_root->logical, time_seq); tm = tree_mod_log_search(root->fs_info, logical, time_seq); /* /* * there was an item in the log when __tree_mod_log_oldest_root * there was an item in the log when __tree_mod_log_oldest_root * returned. this one must not go away, because the time_seq passed to * returned. this one must not go away, because the time_seq passed to Loading @@ -1166,22 +1199,25 @@ get_old_root(struct btrfs_root *root, u64 time_seq) */ */ BUG_ON(!tm); BUG_ON(!tm); if (old_root->logical == root->node->start) { if (old_root) /* there are logged operations for the current root */ eb = btrfs_clone_extent_buffer(root->node); } else { /* there's a root replace operation for the current root */ eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, root->nodesize); root->nodesize); else eb = btrfs_clone_extent_buffer(root->node); btrfs_tree_read_unlock(root->node); free_extent_buffer(root->node); if (!eb) return NULL; btrfs_tree_read_lock(eb); if (old_root) { btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(eb, root->root_key.objectid); btrfs_set_header_owner(eb, root->root_key.objectid); } if (!eb) return NULL; btrfs_set_header_level(eb, old_root->level); btrfs_set_header_level(eb, old_root->level); btrfs_set_header_generation(eb, old_generation); btrfs_set_header_generation(eb, old_generation); } __tree_mod_log_rewind(eb, time_seq, tm); __tree_mod_log_rewind(eb, time_seq, tm); extent_buffer_get(eb); return eb; return eb; } } Loading Loading @@ -1650,8 +1686,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, BTRFS_NODEPTRS_PER_BLOCK(root) / 4) BTRFS_NODEPTRS_PER_BLOCK(root) / 4) return 0; return 0; btrfs_header_nritems(mid); left = read_node_slot(root, parent, pslot - 1); left = read_node_slot(root, parent, pslot - 1); if (left) { if (left) { btrfs_tree_lock(left); btrfs_tree_lock(left); Loading Loading @@ -1681,7 +1715,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, wret = push_node_left(trans, root, left, mid, 1); wret = push_node_left(trans, root, left, mid, 1); if (wret < 0) if (wret < 0) ret = wret; ret = wret; btrfs_header_nritems(mid); } } /* /* Loading Loading @@ -2615,9 +2648,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key, again: again: b = get_old_root(root, time_seq); b = get_old_root(root, time_seq); extent_buffer_get(b); level = btrfs_header_level(b); level = btrfs_header_level(b); btrfs_tree_read_lock(b); p->locks[level] = BTRFS_READ_LOCK; p->locks[level] = BTRFS_READ_LOCK; while (b) { while (b) { Loading Loading @@ -5000,6 +5031,12 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, * returns < 0 on io errors. * returns < 0 on io errors. */ */ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) { return btrfs_next_old_leaf(root, path, 0); } int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq) { { int slot; int slot; int level; int level; Loading @@ -5025,6 +5062,9 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) path->keep_locks = 1; path->keep_locks = 1; path->leave_spinning = 1; path->leave_spinning = 1; if (time_seq) ret = btrfs_search_old_slot(root, &key, path, time_seq); else ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); path->keep_locks = 0; path->keep_locks = 0; Loading fs/btrfs/ctree.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -2753,6 +2753,8 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, } } int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq); static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) { { ++p->slots[0]; ++p->slots[0]; Loading Loading
fs/btrfs/backref.c +5 −12 Original line number Original line Diff line number Diff line Loading @@ -179,7 +179,8 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id, static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, struct ulist *parents, int level, struct ulist *parents, int level, struct btrfs_key *key, u64 wanted_disk_byte, struct btrfs_key *key, u64 time_seq, u64 wanted_disk_byte, const u64 *extent_item_pos) const u64 *extent_item_pos) { { int ret; int ret; Loading Loading @@ -212,7 +213,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, */ */ while (1) { while (1) { eie = NULL; eie = NULL; ret = btrfs_next_leaf(root, path); ret = btrfs_next_old_leaf(root, path, time_seq); if (ret < 0) if (ret < 0) return ret; return ret; if (ret) if (ret) Loading Loading @@ -294,18 +295,10 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, goto out; goto out; } } if (level == 0) { if (level == 0) if (ret == 1 && path->slots[0] >= btrfs_header_nritems(eb)) { ret = btrfs_next_leaf(root, path); if (ret) goto out; eb = path->nodes[0]; } btrfs_item_key_to_cpu(eb, &key, path->slots[0]); btrfs_item_key_to_cpu(eb, &key, path->slots[0]); } ret = add_all_parents(root, path, parents, level, &key, ret = add_all_parents(root, path, parents, level, &key, time_seq, ref->wanted_disk_byte, extent_item_pos); ref->wanted_disk_byte, extent_item_pos); out: out: btrfs_free_path(path); btrfs_free_path(path); Loading
fs/btrfs/ctree.c +63 −23 Original line number Original line Diff line number Diff line Loading @@ -467,6 +467,15 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, return 0; return 0; } } /* * This allocates memory and gets a tree modification sequence number when * needed. * * Returns 0 when no sequence number is needed, < 0 on error. * Returns 1 when a sequence number was added. In this case, * fs_info->tree_mod_seq_lock was acquired and must be released by the caller * after inserting into the rb tree. */ static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, struct tree_mod_elem **tm_ret) struct tree_mod_elem **tm_ret) { { Loading @@ -491,11 +500,11 @@ static inline int tree_mod_alloc(struct btrfs_fs_info *fs_info, gfp_t flags, */ */ kfree(tm); kfree(tm); seq = 0; seq = 0; spin_unlock(&fs_info->tree_mod_seq_lock); } else { } else { __get_tree_mod_seq(fs_info, &tm->elem); __get_tree_mod_seq(fs_info, &tm->elem); seq = tm->elem.seq; seq = tm->elem.seq; } } spin_unlock(&fs_info->tree_mod_seq_lock); return seq; return seq; } } Loading @@ -521,7 +530,9 @@ tree_mod_log_insert_key_mask(struct btrfs_fs_info *fs_info, tm->slot = slot; tm->slot = slot; tm->generation = btrfs_node_ptr_generation(eb, slot); tm->generation = btrfs_node_ptr_generation(eb, slot); return __tree_mod_log_insert(fs_info, tm); ret = __tree_mod_log_insert(fs_info, tm); spin_unlock(&fs_info->tree_mod_seq_lock); return ret; } } static noinline int static noinline int Loading Loading @@ -559,7 +570,9 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, tm->move.nr_items = nr_items; tm->move.nr_items = nr_items; tm->op = MOD_LOG_MOVE_KEYS; tm->op = MOD_LOG_MOVE_KEYS; return __tree_mod_log_insert(fs_info, tm); ret = __tree_mod_log_insert(fs_info, tm); spin_unlock(&fs_info->tree_mod_seq_lock); return ret; } } static noinline int static noinline int Loading @@ -580,7 +593,9 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, tm->generation = btrfs_header_generation(old_root); tm->generation = btrfs_header_generation(old_root); tm->op = MOD_LOG_ROOT_REPLACE; tm->op = MOD_LOG_ROOT_REPLACE; return __tree_mod_log_insert(fs_info, tm); ret = __tree_mod_log_insert(fs_info, tm); spin_unlock(&fs_info->tree_mod_seq_lock); return ret; } } static struct tree_mod_elem * static struct tree_mod_elem * Loading Loading @@ -1023,6 +1038,10 @@ __tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, looped = 1; looped = 1; } } /* if there's no old root to return, return what we found instead */ if (!found) found = tm; return found; return found; } } Loading Loading @@ -1143,22 +1162,36 @@ tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, return eb_rewin; 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 * static inline struct extent_buffer * get_old_root(struct btrfs_root *root, u64 time_seq) get_old_root(struct btrfs_root *root, u64 time_seq) { { struct tree_mod_elem *tm; struct tree_mod_elem *tm; struct extent_buffer *eb; struct extent_buffer *eb; struct tree_mod_root *old_root; struct tree_mod_root *old_root = NULL; u64 old_generation; u64 old_generation; u64 logical; eb = btrfs_read_lock_root_node(root); tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); tm = __tree_mod_log_oldest_root(root->fs_info, root, time_seq); if (!tm) if (!tm) return root->node; return root->node; if (tm->op == MOD_LOG_ROOT_REPLACE) { old_root = &tm->old_root; old_root = &tm->old_root; old_generation = tm->generation; old_generation = tm->generation; logical = old_root->logical; } else { logical = root->node->start; } tm = tree_mod_log_search(root->fs_info, old_root->logical, time_seq); tm = tree_mod_log_search(root->fs_info, logical, time_seq); /* /* * there was an item in the log when __tree_mod_log_oldest_root * there was an item in the log when __tree_mod_log_oldest_root * returned. this one must not go away, because the time_seq passed to * returned. this one must not go away, because the time_seq passed to Loading @@ -1166,22 +1199,25 @@ get_old_root(struct btrfs_root *root, u64 time_seq) */ */ BUG_ON(!tm); BUG_ON(!tm); if (old_root->logical == root->node->start) { if (old_root) /* there are logged operations for the current root */ eb = btrfs_clone_extent_buffer(root->node); } else { /* there's a root replace operation for the current root */ eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, eb = alloc_dummy_extent_buffer(tm->index << PAGE_CACHE_SHIFT, root->nodesize); root->nodesize); else eb = btrfs_clone_extent_buffer(root->node); btrfs_tree_read_unlock(root->node); free_extent_buffer(root->node); if (!eb) return NULL; btrfs_tree_read_lock(eb); if (old_root) { btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_bytenr(eb, eb->start); btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); btrfs_set_header_owner(eb, root->root_key.objectid); btrfs_set_header_owner(eb, root->root_key.objectid); } if (!eb) return NULL; btrfs_set_header_level(eb, old_root->level); btrfs_set_header_level(eb, old_root->level); btrfs_set_header_generation(eb, old_generation); btrfs_set_header_generation(eb, old_generation); } __tree_mod_log_rewind(eb, time_seq, tm); __tree_mod_log_rewind(eb, time_seq, tm); extent_buffer_get(eb); return eb; return eb; } } Loading Loading @@ -1650,8 +1686,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, BTRFS_NODEPTRS_PER_BLOCK(root) / 4) BTRFS_NODEPTRS_PER_BLOCK(root) / 4) return 0; return 0; btrfs_header_nritems(mid); left = read_node_slot(root, parent, pslot - 1); left = read_node_slot(root, parent, pslot - 1); if (left) { if (left) { btrfs_tree_lock(left); btrfs_tree_lock(left); Loading Loading @@ -1681,7 +1715,6 @@ static noinline int balance_level(struct btrfs_trans_handle *trans, wret = push_node_left(trans, root, left, mid, 1); wret = push_node_left(trans, root, left, mid, 1); if (wret < 0) if (wret < 0) ret = wret; ret = wret; btrfs_header_nritems(mid); } } /* /* Loading Loading @@ -2615,9 +2648,7 @@ int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key, again: again: b = get_old_root(root, time_seq); b = get_old_root(root, time_seq); extent_buffer_get(b); level = btrfs_header_level(b); level = btrfs_header_level(b); btrfs_tree_read_lock(b); p->locks[level] = BTRFS_READ_LOCK; p->locks[level] = BTRFS_READ_LOCK; while (b) { while (b) { Loading Loading @@ -5000,6 +5031,12 @@ int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, * returns < 0 on io errors. * returns < 0 on io errors. */ */ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) { return btrfs_next_old_leaf(root, path, 0); } int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq) { { int slot; int slot; int level; int level; Loading @@ -5025,6 +5062,9 @@ int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) path->keep_locks = 1; path->keep_locks = 1; path->leave_spinning = 1; path->leave_spinning = 1; if (time_seq) ret = btrfs_search_old_slot(root, &key, path, time_seq); else ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); path->keep_locks = 0; path->keep_locks = 0; Loading
fs/btrfs/ctree.h +2 −0 Original line number Original line Diff line number Diff line Loading @@ -2753,6 +2753,8 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, } } int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, u64 time_seq); static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) { { ++p->slots[0]; ++p->slots[0]; Loading