Commit f6963ab4 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'bcachefs-2024-07-10' of https://evilpiepirate.org/git/bcachefs

Pull bcachefs fixes from Kent Overstreet:

 - Switch some asserts to WARN()

 - Fix a few "transaction not locked" asserts in the data read retry
   paths and backpointers gc

 - Fix a race that would cause the journal to get stuck on a flush
   commit

 - Add missing fsck checks for the fragmentation LRU

 - The usual assorted ssorted syzbot fixes

* tag 'bcachefs-2024-07-10' of https://evilpiepirate.org/git/bcachefs: (22 commits)
  bcachefs: Add missing bch2_trans_begin()
  bcachefs: Fix missing error check in journal_entry_btree_keys_validate()
  bcachefs: Warn on attempting a move with no replicas
  bcachefs: bch2_data_update_to_text()
  bcachefs: Log mount failure error code
  bcachefs: Fix undefined behaviour in eytzinger1_first()
  bcachefs: Mark bch_inode_info as SLAB_ACCOUNT
  bcachefs: Fix bch2_inode_insert() race path for tmpfiles
  closures: fix closure_sync + closure debugging
  bcachefs: Fix journal getting stuck on a flush commit
  bcachefs: io clock: run timer fns under clock lock
  bcachefs: Repair fragmentation_lru in alloc_write_key()
  bcachefs: add check for missing fragmentation in check_alloc_to_lru_ref()
  bcachefs: bch2_btree_write_buffer_maybe_flush()
  bcachefs: Add missing printbuf_tabstops_reset() calls
  bcachefs: Fix loop restart in bch2_btree_transactions_read()
  bcachefs: Fix bch2_read_retry_nodecode()
  bcachefs: Don't use the new_fs() bucket alloc path on an initialized fs
  bcachefs: Fix shift greater than integer size
  bcachefs: Change bch2_fs_journal_stop() BUG_ON() to warning
  ...
parents a19ea421 7d7f71cd
Loading
Loading
Loading
Loading
+23 −25
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#include "alloc_background.h"
#include "alloc_foreground.h"
#include "backpointers.h"
#include "bkey_buf.h"
#include "btree_cache.h"
#include "btree_io.h"
#include "btree_key_cache.h"
@@ -1553,13 +1554,13 @@ int bch2_check_alloc_info(struct bch_fs *c)
}

static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
				       struct btree_iter *alloc_iter)
				       struct btree_iter *alloc_iter,
				       struct bkey_buf *last_flushed)
{
	struct bch_fs *c = trans->c;
	struct btree_iter lru_iter;
	struct bch_alloc_v4 a_convert;
	const struct bch_alloc_v4 *a;
	struct bkey_s_c alloc_k, lru_k;
	struct bkey_s_c alloc_k;
	struct printbuf buf = PRINTBUF;
	int ret;

@@ -1573,6 +1574,14 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,

	a = bch2_alloc_to_v4(alloc_k, &a_convert);

	if (a->fragmentation_lru) {
		ret = bch2_lru_check_set(trans, BCH_LRU_FRAGMENTATION_START,
					 a->fragmentation_lru,
					 alloc_k, last_flushed);
		if (ret)
			return ret;
	}

	if (a->data_type != BCH_DATA_cached)
		return 0;

@@ -1597,41 +1606,30 @@ static int bch2_check_alloc_to_lru_ref(struct btree_trans *trans,
		a = &a_mut->v;
	}

	lru_k = bch2_bkey_get_iter(trans, &lru_iter, BTREE_ID_lru,
			     lru_pos(alloc_k.k->p.inode,
				     bucket_to_u64(alloc_k.k->p),
				     a->io_time[READ]), 0);
	ret = bkey_err(lru_k);
	if (ret)
		return ret;

	if (fsck_err_on(lru_k.k->type != KEY_TYPE_set, c,
			alloc_key_to_missing_lru_entry,
			"missing lru entry\n"
			"  %s",
			(printbuf_reset(&buf),
			 bch2_bkey_val_to_text(&buf, c, alloc_k), buf.buf))) {
		ret = bch2_lru_set(trans,
				   alloc_k.k->p.inode,
				   bucket_to_u64(alloc_k.k->p),
				   a->io_time[READ]);
	ret = bch2_lru_check_set(trans, alloc_k.k->p.inode, a->io_time[READ],
				 alloc_k, last_flushed);
	if (ret)
		goto err;
	}
err:
fsck_err:
	bch2_trans_iter_exit(trans, &lru_iter);
	printbuf_exit(&buf);
	return ret;
}

int bch2_check_alloc_to_lru_refs(struct bch_fs *c)
{
	struct bkey_buf last_flushed;

	bch2_bkey_buf_init(&last_flushed);
	bkey_init(&last_flushed.k->k);

	int ret = bch2_trans_run(c,
		for_each_btree_key_commit(trans, iter, BTREE_ID_alloc,
				POS_MIN, BTREE_ITER_prefetch, k,
				NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
			bch2_check_alloc_to_lru_ref(trans, &iter)));
			bch2_check_alloc_to_lru_ref(trans, &iter, &last_flushed)));

	bch2_bkey_buf_exit(&last_flushed, c);
	bch_err_fn(c, ret);
	return ret;
}
+2 −0
Original line number Diff line number Diff line
@@ -1703,6 +1703,7 @@ void bch2_fs_alloc_debug_to_text(struct printbuf *out, struct bch_fs *c)
	for (unsigned i = 0; i < ARRAY_SIZE(c->open_buckets); i++)
		nr[c->open_buckets[i].data_type]++;

	printbuf_tabstops_reset(out);
	printbuf_tabstop_push(out, 24);

	percpu_down_read(&c->mark_lock);
@@ -1736,6 +1737,7 @@ void bch2_dev_alloc_debug_to_text(struct printbuf *out, struct bch_dev *ca)
	for (unsigned i = 0; i < ARRAY_SIZE(c->open_buckets); i++)
		nr[c->open_buckets[i].data_type]++;

	printbuf_tabstops_reset(out);
	printbuf_tabstop_push(out, 12);
	printbuf_tabstop_push(out, 16);
	printbuf_tabstop_push(out, 16);
+26 −44
Original line number Diff line number Diff line
@@ -434,13 +434,6 @@ int bch2_check_btree_backpointers(struct bch_fs *c)
	return ret;
}

static inline bool bkey_and_val_eq(struct bkey_s_c l, struct bkey_s_c r)
{
	return bpos_eq(l.k->p, r.k->p) &&
		bkey_bytes(l.k) == bkey_bytes(r.k) &&
		!memcmp(l.v, r.v, bkey_val_bytes(l.k));
}

struct extents_to_bp_state {
	struct bpos	bucket_start;
	struct bpos	bucket_end;
@@ -536,11 +529,8 @@ static int check_bp_exists(struct btree_trans *trans,
	struct btree_iter other_extent_iter = {};
	struct printbuf buf = PRINTBUF;
	struct bkey_s_c bp_k;
	struct bkey_buf tmp;
	int ret = 0;

	bch2_bkey_buf_init(&tmp);

	struct bch_dev *ca = bch2_dev_bucket_tryget(c, bucket);
	if (!ca) {
		prt_str(&buf, "extent for nonexistent device:bucket ");
@@ -565,23 +555,10 @@ static int check_bp_exists(struct btree_trans *trans,

	if (bp_k.k->type != KEY_TYPE_backpointer ||
	    memcmp(bkey_s_c_to_backpointer(bp_k).v, &bp, sizeof(bp))) {
		bch2_bkey_buf_reassemble(&tmp, c, orig_k);

		if (!bkey_and_val_eq(orig_k, bkey_i_to_s_c(s->last_flushed.k))) {
			if (bp.level) {
				bch2_trans_unlock(trans);
				bch2_btree_interior_updates_flush(c);
			}

			ret = bch2_btree_write_buffer_flush_sync(trans);
		ret = bch2_btree_write_buffer_maybe_flush(trans, orig_k, &s->last_flushed);
		if (ret)
			goto err;

			bch2_bkey_buf_copy(&s->last_flushed, c, tmp.k);
			ret = -BCH_ERR_transaction_restart_write_buffer_flush;
			goto out;
		}

		goto check_existing_bp;
	}
out:
@@ -589,7 +566,6 @@ static int check_bp_exists(struct btree_trans *trans,
fsck_err:
	bch2_trans_iter_exit(trans, &other_extent_iter);
	bch2_trans_iter_exit(trans, &bp_iter);
	bch2_bkey_buf_exit(&tmp, c);
	bch2_dev_put(ca);
	printbuf_exit(&buf);
	return ret;
@@ -794,6 +770,8 @@ static int bch2_get_btree_in_memory_pos(struct btree_trans *trans,
		    !((1U << btree) & btree_interior_mask))
			continue;

		bch2_trans_begin(trans);

		__for_each_btree_node(trans, iter, btree,
				      btree == start.btree ? start.pos : POS_MIN,
				      0, depth, BTREE_ITER_prefetch, b, ret) {
@@ -905,7 +883,7 @@ static int check_one_backpointer(struct btree_trans *trans,
				 struct bbpos start,
				 struct bbpos end,
				 struct bkey_s_c_backpointer bp,
				 struct bpos *last_flushed_pos)
				 struct bkey_buf *last_flushed)
{
	struct bch_fs *c = trans->c;
	struct btree_iter iter;
@@ -925,21 +903,19 @@ static int check_one_backpointer(struct btree_trans *trans,
	if (ret)
		return ret;

	if (!k.k && !bpos_eq(*last_flushed_pos, bp.k->p)) {
		*last_flushed_pos = bp.k->p;
		ret = bch2_btree_write_buffer_flush_sync(trans) ?:
			-BCH_ERR_transaction_restart_write_buffer_flush;
	if (!k.k) {
		ret = bch2_btree_write_buffer_maybe_flush(trans, bp.s_c, last_flushed);
		if (ret)
			goto out;
	}

	if (fsck_err_on(!k.k, c,
			backpointer_to_missing_ptr,
		if (fsck_err(c, backpointer_to_missing_ptr,
			     "backpointer for missing %s\n  %s",
			     bp.v->level ? "btree node" : "extent",
			     (bch2_bkey_val_to_text(&buf, c, bp.s_c), buf.buf))) {
			ret = bch2_btree_delete_at_buffered(trans, BTREE_ID_backpointers, bp.k->p);
			goto out;
		}
	}
out:
fsck_err:
	bch2_trans_iter_exit(trans, &iter);
@@ -951,14 +927,20 @@ static int bch2_check_backpointers_to_extents_pass(struct btree_trans *trans,
						   struct bbpos start,
						   struct bbpos end)
{
	struct bpos last_flushed_pos = SPOS_MAX;
	struct bkey_buf last_flushed;

	bch2_bkey_buf_init(&last_flushed);
	bkey_init(&last_flushed.k->k);

	return for_each_btree_key_commit(trans, iter, BTREE_ID_backpointers,
	int ret = for_each_btree_key_commit(trans, iter, BTREE_ID_backpointers,
				  POS_MIN, BTREE_ITER_prefetch, k,
				  NULL, NULL, BCH_TRANS_COMMIT_no_enospc,
		check_one_backpointer(trans, start, end,
				      bkey_s_c_to_backpointer(k),
				      &last_flushed_pos));
				      &last_flushed));

	bch2_bkey_buf_exit(&last_flushed, trans->c);
	return ret;
}

int bch2_check_backpointers_to_extents(struct bch_fs *c)
+3 −2
Original line number Diff line number Diff line
@@ -660,8 +660,9 @@ int bch2_bkey_format_invalid(struct bch_fs *c,
		    bch2_bkey_format_field_overflows(f, i)) {
			unsigned unpacked_bits = bch2_bkey_format_current.bits_per_field[i];
			u64 unpacked_max = ~((~0ULL << 1) << (unpacked_bits - 1));
			u64 packed_max = f->bits_per_field[i]
				? ~((~0ULL << 1) << (f->bits_per_field[i] - 1))
			unsigned packed_bits = min(64, f->bits_per_field[i]);
			u64 packed_max = packed_bits
				? ~((~0ULL << 1) << (packed_bits - 1))
				: 0;

			prt_printf(err, "field %u too large: %llu + %llu > %llu",
+7 −0
Original line number Diff line number Diff line
@@ -194,6 +194,13 @@ static inline struct bpos bkey_max(struct bpos l, struct bpos r)
	return bkey_gt(l, r) ? l : r;
}

static inline bool bkey_and_val_eq(struct bkey_s_c l, struct bkey_s_c r)
{
	return bpos_eq(l.k->p, r.k->p) &&
		bkey_bytes(l.k) == bkey_bytes(r.k) &&
		!memcmp(l.v, r.v, bkey_val_bytes(l.k));
}

void bch2_bpos_swab(struct bpos *);
void bch2_bkey_swab_key(const struct bkey_format *, struct bkey_packed *);

Loading