Merge branch 'for-chris' of git://git.jan-o-sch.net/btrfs-unstable into for-linus
This commit is contained in:
Коммит
acbcabd2de
|
@ -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;
|
||||||
|
@ -212,7 +213,7 @@ add_parent:
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 *
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
old_root = &tm->old_root;
|
if (tm->op == MOD_LOG_ROOT_REPLACE) {
|
||||||
old_generation = tm->generation;
|
old_root = &tm->old_root;
|
||||||
|
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
|
||||||
|
@ -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);
|
||||||
|
btrfs_set_header_level(eb, old_root->level);
|
||||||
|
btrfs_set_header_generation(eb, old_generation);
|
||||||
}
|
}
|
||||||
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);
|
__tree_mod_log_rewind(eb, time_seq, tm);
|
||||||
|
extent_buffer_get(eb);
|
||||||
|
|
||||||
return eb;
|
return eb;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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) {
|
||||||
|
@ -5000,6 +5031,12 @@ next:
|
||||||
* 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;
|
||||||
|
@ -5025,7 +5062,10 @@ again:
|
||||||
path->keep_locks = 1;
|
path->keep_locks = 1;
|
||||||
path->leave_spinning = 1;
|
path->leave_spinning = 1;
|
||||||
|
|
||||||
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
if (time_seq)
|
||||||
|
ret = btrfs_search_old_slot(root, &key, path, time_seq);
|
||||||
|
else
|
||||||
|
ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
|
||||||
path->keep_locks = 0;
|
path->keep_locks = 0;
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
|
@ -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];
|
||||||
|
|
Загрузка…
Ссылка в новой задаче