Commit 85d8cf16 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet
Browse files

bcachefs: bch2_btree_iter_peek_upto()



In BTREE_ITER_FILTER_SNAPHOTS mode, we skip over keys in unrelated
snapshots. When we hit the end of an inode, if the next inode(s) are in
a different subvolume, we could potentially have to skip past many keys
before finding a key we can return to the caller, so they can terminate
the iteration.

This adds a peek_upto() variant to solve this problem, to be used when
we know the range we're searching within.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent d4d24a65
Loading
Loading
Loading
Loading
+26 −10
Original line number Diff line number Diff line
@@ -2346,11 +2346,12 @@ static struct bkey_s_c __bch2_btree_iter_peek(struct btree_iter *iter, struct bp
 * bch2_btree_iter_peek: returns first key greater than or equal to iterator's
 * current position
 */
struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *iter, struct bpos end)
{
	struct btree_trans *trans = iter->trans;
	struct bpos search_key = btree_iter_search_key(iter);
	struct bkey_s_c k;
	struct bpos iter_pos;
	int ret;

	if (iter->update_path) {
@@ -2366,6 +2367,24 @@ struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
		if (!k.k || bkey_err(k))
			goto out;

		/*
		 * iter->pos should be mononotically increasing, and always be
		 * equal to the key we just returned - except extents can
		 * straddle iter->pos:
		 */
		if (!(iter->flags & BTREE_ITER_IS_EXTENTS))
			iter_pos = k.k->p;
		else if (bkey_cmp(bkey_start_pos(k.k), iter->pos) > 0)
			iter_pos = bkey_start_pos(k.k);
		else
			iter_pos = iter->pos;

		if (bkey_cmp(iter_pos, end) > 0) {
			bch2_btree_iter_set_pos(iter, end);
			k = bkey_s_c_null;
			goto out;
		}

		if (iter->update_path &&
		    bkey_cmp(iter->update_path->pos, k.k->p)) {
			bch2_path_put(trans, iter->update_path,
@@ -2419,14 +2438,7 @@ struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
		break;
	}

	/*
	 * iter->pos should be mononotically increasing, and always be equal to
	 * the key we just returned - except extents can straddle iter->pos:
	 */
	if (!(iter->flags & BTREE_ITER_IS_EXTENTS))
		iter->pos = k.k->p;
	else if (bkey_cmp(bkey_start_pos(k.k), iter->pos) > 0)
		iter->pos = bkey_start_pos(k.k);
	iter->pos = iter_pos;

	iter->path = bch2_btree_path_set_pos(trans, iter->path, k.k->p,
				iter->flags & BTREE_ITER_INTENT);
@@ -2658,9 +2670,13 @@ struct bkey_s_c bch2_btree_iter_peek_slot(struct btree_iter *iter)

		if (iter->flags & BTREE_ITER_INTENT) {
			struct btree_iter iter2;
			struct bpos end = iter->pos;

			if (iter->flags & BTREE_ITER_IS_EXTENTS)
				end.offset = U64_MAX;

			bch2_trans_copy_iter(&iter2, iter);
			k = bch2_btree_iter_peek(&iter2);
			k = bch2_btree_iter_peek_upto(&iter2, end);

			if (k.k && !bkey_err(k)) {
				iter->k = iter2.k;
+28 −2
Original line number Diff line number Diff line
@@ -245,9 +245,14 @@ int __must_check bch2_btree_iter_traverse(struct btree_iter *);
struct btree *bch2_btree_iter_peek_node(struct btree_iter *);
struct btree *bch2_btree_iter_next_node(struct btree_iter *);

struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *);
struct bkey_s_c bch2_btree_iter_peek_upto(struct btree_iter *, struct bpos);
struct bkey_s_c bch2_btree_iter_next(struct btree_iter *);

static inline struct bkey_s_c bch2_btree_iter_peek(struct btree_iter *iter)
{
	return bch2_btree_iter_peek_upto(iter, SPOS_MAX);
}

struct bkey_s_c bch2_btree_iter_peek_prev(struct btree_iter *);
struct bkey_s_c bch2_btree_iter_prev(struct btree_iter *);

@@ -349,6 +354,19 @@ static inline struct bkey_s_c bch2_btree_iter_peek_type(struct btree_iter *iter,
		: bch2_btree_iter_peek(iter);
}

static inline struct bkey_s_c bch2_btree_iter_peek_upto_type(struct btree_iter *iter,
							     struct bpos end,
							     unsigned flags)
{
	if (!(flags & BTREE_ITER_SLOTS))
		return bch2_btree_iter_peek_upto(iter, end);

	if (bkey_cmp(iter->pos, end) > 0)
		return bkey_s_c_null;

	return bch2_btree_iter_peek_slot(iter);
}

static inline int btree_trans_too_many_iters(struct btree_trans *trans)
{
	return hweight64(trans->paths_allocated) > BTREE_ITER_MAX / 2
@@ -385,6 +403,14 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans,
	     !((_ret) = bkey_err(_k)) && (_k).k;			\
	     bch2_btree_iter_advance(&(_iter)))

#define for_each_btree_key_upto_norestart(_trans, _iter, _btree_id,	\
			   _start, _end, _flags, _k, _ret)		\
	for (bch2_trans_iter_init((_trans), &(_iter), (_btree_id),	\
				  (_start), (_flags));			\
	     (_k) = bch2_btree_iter_peek_upto_type(&(_iter), _end, _flags),\
	     !((_ret) = bkey_err(_k)) && (_k).k;			\
	     bch2_btree_iter_advance(&(_iter)))

#define for_each_btree_key_continue(_trans, _iter, _flags, _k, _ret)	\
	for (;								\
	     (_k) = __bch2_btree_iter_peek_and_restart((_trans), &(_iter), _flags),\
+3 −2
Original line number Diff line number Diff line
@@ -1286,7 +1286,7 @@ int bch2_trans_update_extent(struct btree_trans *trans,
			     BTREE_ITER_INTENT|
			     BTREE_ITER_WITH_UPDATES|
			     BTREE_ITER_NOT_EXTENTS);
	k = bch2_btree_iter_peek(&iter);
	k = bch2_btree_iter_peek_upto(&iter, POS(insert->k.p.inode, U64_MAX));
	if ((ret = bkey_err(k)))
		goto err;
	if (!k.k)
@@ -1405,7 +1405,8 @@ int bch2_trans_update_extent(struct btree_trans *trans,
			goto out;
		}
next:
		k = bch2_btree_iter_next(&iter);
		bch2_btree_iter_advance(&iter);
		k = bch2_btree_iter_peek_upto(&iter, POS(insert->k.p.inode, U64_MAX));
		if ((ret = bkey_err(k)))
			goto err;
		if (!k.k)
+6 −11
Original line number Diff line number Diff line
@@ -470,16 +470,13 @@ int bch2_empty_dir_trans(struct btree_trans *trans, subvol_inum dir)
	if (ret)
		return ret;

	for_each_btree_key_norestart(trans, iter, BTREE_ID_dirents,
			   SPOS(dir.inum, 0, snapshot), 0, k, ret) {
		if (k.k->p.inode > dir.inum)
			break;

	for_each_btree_key_upto_norestart(trans, iter, BTREE_ID_dirents,
			   SPOS(dir.inum, 0, snapshot),
			   POS(dir.inum, U64_MAX), 0, k, ret)
		if (k.k->type == KEY_TYPE_dirent) {
			ret = -ENOTEMPTY;
			break;
		}
	}
	bch2_trans_iter_exit(trans, &iter);

	return ret;
@@ -503,11 +500,9 @@ int bch2_readdir(struct bch_fs *c, subvol_inum inum, struct dir_context *ctx)
	if (ret)
		goto err;

	for_each_btree_key_norestart(&trans, iter, BTREE_ID_dirents,
			   SPOS(inum.inum, ctx->pos, snapshot), 0, k, ret) {
		if (k.k->p.inode > inum.inum)
			break;

	for_each_btree_key_upto_norestart(&trans, iter, BTREE_ID_dirents,
			   SPOS(inum.inum, ctx->pos, snapshot),
			   POS(inum.inum, U64_MAX), 0, k, ret) {
		if (k.k->type != KEY_TYPE_dirent)
			continue;

+2 −3
Original line number Diff line number Diff line
@@ -936,9 +936,8 @@ static int bch2_fiemap(struct inode *vinode, struct fiemap_extent_info *info,
			     SPOS(ei->v.i_ino, start, snapshot), 0);

	while (!(ret = btree_trans_too_many_iters(&trans)) &&
	       (k = bch2_btree_iter_peek(&iter)).k &&
	       !(ret = bkey_err(k)) &&
	       bkey_cmp(iter.pos, end) < 0) {
	       (k = bch2_btree_iter_peek_upto(&iter, end)).k &&
	       !(ret = bkey_err(k))) {
		enum btree_id data_btree = BTREE_ID_extents;

		if (!bkey_extent_is_data(k.k) &&
Loading