Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit acbcabd2 authored by Chris Mason's avatar Chris Mason Committed by Chris Mason
Browse files

Merge branch 'for-chris' of git://git.jan-o-sch.net/btrfs-unstable into for-linus

parents 69e380d1 3310c36e
Loading
Loading
Loading
Loading
+5 −12
Original line number Original line Diff line number Diff line
@@ -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 @@ 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)
@@ -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);
+63 −23
Original line number Original line Diff line number Diff line
@@ -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;


	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
@@ -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;
}
}
@@ -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 @@ 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;
@@ -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;


+2 −0
Original line number Original line Diff line number Diff line
@@ -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];