Commit 4abcd80f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'bcachefs-2024-11-13' of git://evilpiepirate.org/bcachefs

Pull bcachefs fixes from Kent Overstreet:
 "This fixes one minor regression from the btree cache fixes (in the
  scan_for_btree_nodes repair path) - and the shutdown path fix is the
  big one here, in terms of bugs closed:

   - Assorted tiny syzbot fixes

   - Shutdown path fix: "bch2_btree_write_buffer_flush_going_ro()"

     The shutdown path wasn't flushing the btree write buffer, leading
     to shutting down while we still had operations in flight. This
     fixes a whole slew of syzbot bugs, and undoubtedly other strange
     heisenbugs.

* tag 'bcachefs-2024-11-13' of git://evilpiepirate.org/bcachefs:
  bcachefs: Fix assertion pop in bch2_ptr_swab()
  bcachefs: Fix journal_entry_dev_usage_to_text() overrun
  bcachefs: Allow for unknown key types in backpointers fsck
  bcachefs: Fix assertion pop in topology repair
  bcachefs: Fix hidden btree errors when reading roots
  bcachefs: Fix validate_bset() repair path
  bcachefs: Fix missing validation for bch_backpointer.level
  bcachefs: Fix bch_member.btree_bitmap_shift validation
  bcachefs: bch2_btree_write_buffer_flush_going_ro()
parents 0a9b9d17 840c2fbc
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
@@ -52,6 +52,12 @@ int bch2_backpointer_validate(struct bch_fs *c, struct bkey_s_c k,
			      enum bch_validate_flags flags)
{
	struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(k);
	int ret = 0;

	bkey_fsck_err_on(bp.v->level > BTREE_MAX_DEPTH,
			 c, backpointer_level_bad,
			 "backpointer level bad: %u >= %u",
			 bp.v->level, BTREE_MAX_DEPTH);

	rcu_read_lock();
	struct bch_dev *ca = bch2_dev_rcu_noerror(c, bp.k->p.inode);
@@ -64,7 +70,6 @@ int bch2_backpointer_validate(struct bch_fs *c, struct bkey_s_c k,
	struct bpos bucket = bp_pos_to_bucket(ca, bp.k->p);
	struct bpos bp_pos = bucket_pos_to_bp_noerror(ca, bucket, bp.v->bucket_offset);
	rcu_read_unlock();
	int ret = 0;

	bkey_fsck_err_on((bp.v->bucket_offset >> MAX_EXTENT_COMPRESS_RATIO_SHIFT) >= ca->mi.bucket_size ||
			 !bpos_eq(bp.k->p, bp_pos),
@@ -947,9 +952,13 @@ int bch2_check_extents_to_backpointers(struct bch_fs *c)
static int check_one_backpointer(struct btree_trans *trans,
				 struct bbpos start,
				 struct bbpos end,
				 struct bkey_s_c_backpointer bp,
				 struct bkey_s_c bp_k,
				 struct bkey_buf *last_flushed)
{
	if (bp_k.k->type != KEY_TYPE_backpointer)
		return 0;

	struct bkey_s_c_backpointer bp = bkey_s_c_to_backpointer(bp_k);
	struct bch_fs *c = trans->c;
	struct btree_iter iter;
	struct bbpos pos = bp_to_bbpos(*bp.v);
@@ -1004,9 +1013,7 @@ static int bch2_check_backpointers_to_extents_pass(struct btree_trans *trans,
				  POS_MIN, BTREE_ITER_prefetch, k,
				  NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
			progress_update_iter(trans, &progress, &iter, "backpointers_to_extents");
			check_one_backpointer(trans, start, end,
					      bkey_s_c_to_backpointer(k),
					      &last_flushed);
			check_one_backpointer(trans, start, end, k, &last_flushed);
	}));

	bch2_bkey_buf_exit(&last_flushed, c);
+1 −1
Original line number Diff line number Diff line
@@ -182,7 +182,7 @@ static int set_node_max(struct bch_fs *c, struct btree *b, struct bpos new_max)
	bch2_btree_node_drop_keys_outside_node(b);

	mutex_lock(&c->btree_cache.lock);
	bch2_btree_node_hash_remove(&c->btree_cache, b);
	__bch2_btree_node_hash_remove(&c->btree_cache, b);

	bkey_copy(&b->key, &new->k_i);
	ret = __bch2_btree_node_hash_insert(&c->btree_cache, b);
+1 −5
Original line number Diff line number Diff line
@@ -733,11 +733,8 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
			 c, ca, b, i, NULL,
			 bset_past_end_of_btree_node,
			 "bset past end of btree node (offset %u len %u but written %zu)",
			 offset, sectors, ptr_written ?: btree_sectors(c))) {
			 offset, sectors, ptr_written ?: btree_sectors(c)))
		i->u64s = 0;
		ret = 0;
		goto out;
	}

	btree_err_on(offset && !i->u64s,
		     -BCH_ERR_btree_node_read_err_fixable,
@@ -829,7 +826,6 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
			       BSET_BIG_ENDIAN(i), write,
			       &bn->format);
	}
out:
fsck_err:
	printbuf_exit(&buf2);
	printbuf_exit(&buf1);
+2 −1
Original line number Diff line number Diff line
@@ -2398,7 +2398,8 @@ static int __bch2_btree_node_update_key(struct btree_trans *trans,
	if (new_hash) {
		mutex_lock(&c->btree_cache.lock);
		bch2_btree_node_hash_remove(&c->btree_cache, new_hash);
		bch2_btree_node_hash_remove(&c->btree_cache, b);

		__bch2_btree_node_hash_remove(&c->btree_cache, b);

		bkey_copy(&b->key, new_key);
		ret = __bch2_btree_node_hash_insert(&c->btree_cache, b);
+27 −3
Original line number Diff line number Diff line
@@ -277,6 +277,10 @@ static int bch2_btree_write_buffer_flush_locked(struct btree_trans *trans)
	bool accounting_replay_done = test_bit(BCH_FS_accounting_replay_done, &c->flags);
	int ret = 0;

	ret = bch2_journal_error(&c->journal);
	if (ret)
		return ret;

	bch2_trans_unlock(trans);
	bch2_trans_begin(trans);

@@ -491,7 +495,8 @@ static int fetch_wb_keys_from_journal(struct bch_fs *c, u64 seq)
	return ret;
}

static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq)
static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq,
					bool *did_work)
{
	struct bch_fs *c = trans->c;
	struct btree_write_buffer *wb = &c->btree_write_buffer;
@@ -502,6 +507,8 @@ static int btree_write_buffer_flush_seq(struct btree_trans *trans, u64 seq)

		fetch_from_journal_err = fetch_wb_keys_from_journal(c, seq);

		*did_work |= wb->inc.keys.nr || wb->flushing.keys.nr;

		/*
		 * On memory allocation failure, bch2_btree_write_buffer_flush_locked()
		 * is not guaranteed to empty wb->inc:
@@ -521,17 +528,34 @@ static int bch2_btree_write_buffer_journal_flush(struct journal *j,
				struct journal_entry_pin *_pin, u64 seq)
{
	struct bch_fs *c = container_of(j, struct bch_fs, journal);
	bool did_work = false;

	return bch2_trans_run(c, btree_write_buffer_flush_seq(trans, seq));
	return bch2_trans_run(c, btree_write_buffer_flush_seq(trans, seq, &did_work));
}

int bch2_btree_write_buffer_flush_sync(struct btree_trans *trans)
{
	struct bch_fs *c = trans->c;
	bool did_work = false;

	trace_and_count(c, write_buffer_flush_sync, trans, _RET_IP_);

	return btree_write_buffer_flush_seq(trans, journal_cur_seq(&c->journal));
	return btree_write_buffer_flush_seq(trans, journal_cur_seq(&c->journal), &did_work);
}

/*
 * The write buffer requires flushing when going RO: keys in the journal for the
 * write buffer don't have a journal pin yet
 */
bool bch2_btree_write_buffer_flush_going_ro(struct bch_fs *c)
{
	if (bch2_journal_error(&c->journal))
		return false;

	bool did_work = false;
	bch2_trans_run(c, btree_write_buffer_flush_seq(trans,
				journal_cur_seq(&c->journal), &did_work));
	return did_work;
}

int bch2_btree_write_buffer_flush_nocheck_rw(struct btree_trans *trans)
Loading