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

Merge tag 'bcachefs-2025-02-20' of git://evilpiepirate.org/bcachefs

Pull bcachefs fixes from Kent Overstreet:
 "Small stuff:

   - The fsck code for Hongbo's directory i_size patch was wrong, caught
     by transaction restart injection: we now have the CI running
     another test variant with restart injection enabled

   - Another fixup for reflink pointers to missing indirect extents:
     previous fix was for fsck code, this fixes the normal runtime paths

   - Another small srcu lock hold time fix, reported by jpsollie"

* tag 'bcachefs-2025-02-20' of git://evilpiepirate.org/bcachefs:
  bcachefs: Fix srcu lock warning in btree_update_nodes_written()
  bcachefs: Fix bch2_indirect_extent_missing_error()
  bcachefs: Fix fsck directory i_size checking
parents 770b7eec b04974f7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -681,9 +681,11 @@ static void btree_update_nodes_written(struct btree_update *as)

		b = as->old_nodes[i];

		bch2_trans_begin(trans);
		btree_node_lock_nopath_nofail(trans, &b->c, SIX_LOCK_read);
		seq = b->data ? b->data->keys.seq : 0;
		six_unlock_read(&b->c.lock);
		bch2_trans_unlock_long(trans);

		if (seq == as->old_nodes_seq[i])
			wait_on_bit_io(&b->flags, BTREE_NODE_write_in_flight_inner,
+31 −47
Original line number Diff line number Diff line
@@ -823,6 +823,7 @@ struct inode_walker_entry {
	struct bch_inode_unpacked inode;
	u32			snapshot;
	u64			count;
	u64			i_size;
};

struct inode_walker {
@@ -912,6 +913,7 @@ lookup_inode_for_snapshot(struct bch_fs *c, struct inode_walker *w, struct bkey_

		new.snapshot	= k.k->p.snapshot;
		new.count	= 0;
		new.i_size	= 0;

		struct printbuf buf = PRINTBUF;
		bch2_bkey_val_to_text(&buf, c, k);
@@ -1116,37 +1118,6 @@ static int get_snapshot_root_inode(struct btree_trans *trans,
	return ret;
}

static int check_directory_size(struct btree_trans *trans,
				struct bch_inode_unpacked *inode_u,
				struct bkey_s_c inode_k, bool *write_inode)
{
	struct btree_iter iter;
	struct bkey_s_c k;
	u64 new_size = 0;
	int ret;

	for_each_btree_key_max_norestart(trans, iter, BTREE_ID_dirents,
			SPOS(inode_k.k->p.offset, 0, inode_k.k->p.snapshot),
			POS(inode_k.k->p.offset, U64_MAX),
			0, k, ret) {
		if (k.k->type != KEY_TYPE_dirent)
			continue;

		struct bkey_s_c_dirent dirent = bkey_s_c_to_dirent(k);
		struct qstr name = bch2_dirent_get_name(dirent);

		new_size += dirent_occupied_size(&name);
	}
	bch2_trans_iter_exit(trans, &iter);

	if (!ret && inode_u->bi_size != new_size) {
		inode_u->bi_size = new_size;
		*write_inode = true;
	}

	return ret;
}

static int check_inode(struct btree_trans *trans,
		       struct btree_iter *iter,
		       struct bkey_s_c k,
@@ -1335,16 +1306,6 @@ static int check_inode(struct btree_trans *trans,
		u.bi_journal_seq = journal_cur_seq(&c->journal);
		do_update = true;
	}

	if (S_ISDIR(u.bi_mode)) {
		ret = check_directory_size(trans, &u, k, &do_update);

		fsck_err_on(ret,
			    trans, directory_size_mismatch,
			    "directory inode %llu:%u with the mismatch directory size",
			    u.bi_inum, k.k->p.snapshot);
		ret = 0;
	}
do_update:
	if (do_update) {
		ret = __bch2_fsck_write_inode(trans, &u);
@@ -2017,10 +1978,31 @@ static int check_subdir_count_notnested(struct btree_trans *trans, struct inode_
	return ret;
}

static int check_subdir_count(struct btree_trans *trans, struct inode_walker *w)
static int check_dir_i_size_notnested(struct btree_trans *trans, struct inode_walker *w)
{
	struct bch_fs *c = trans->c;
	int ret = 0;

	darray_for_each(w->inodes, i)
		if (fsck_err_on(i->inode.bi_size != i->i_size,
				trans, inode_dir_wrong_nlink,
				"directory %llu:%u with wrong i_size: got %llu, should be %llu",
				w->last_pos.inode, i->snapshot, i->inode.bi_size, i->i_size)) {
			i->inode.bi_size = i->i_size;
			ret = bch2_fsck_write_inode(trans, &i->inode);
			if (ret)
				break;
		}
fsck_err:
	bch_err_fn(c, ret);
	return ret;
}

static int check_subdir_dirents_count(struct btree_trans *trans, struct inode_walker *w)
{
	u32 restart_count = trans->restart_count;
	return check_subdir_count_notnested(trans, w) ?:
		check_dir_i_size_notnested(trans, w) ?:
		trans_was_restarted(trans, restart_count);
}

@@ -2367,7 +2349,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
		goto out;

	if (dir->last_pos.inode != k.k->p.inode && dir->have_inodes) {
		ret = check_subdir_count(trans, dir);
		ret = check_subdir_dirents_count(trans, dir);
		if (ret)
			goto err;
	}
@@ -2457,9 +2439,11 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
	if (ret)
		goto err;

	for_each_visible_inode(c, s, dir, d.k->p.snapshot, i) {
		if (d.v->d_type == DT_DIR)
		for_each_visible_inode(c, s, dir, d.k->p.snapshot, i)
			i->count++;
		i->i_size += bkey_bytes(d.k);
	}
out:
err:
fsck_err:
+8 −10
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ static int bch2_indirect_extent_missing_error(struct btree_trans *trans,
					      bool should_commit)
{
	if (REFLINK_P_ERROR(p.v))
		return -BCH_ERR_missing_indirect_extent;
		return 0;

	struct bch_fs *c = trans->c;
	u64 live_start	= REFLINK_P_IDX(p.v);
@@ -259,8 +259,6 @@ struct bkey_s_c bch2_lookup_indirect_extent(struct btree_trans *trans,
		return k;

	if (unlikely(!bkey_extent_is_reflink_data(k.k))) {
		bch2_trans_iter_exit(trans, iter);

		unsigned size = min((u64) k.k->size,
				    REFLINK_P_IDX(p.v) + p.k->size + le32_to_cpu(p.v->back_pad) -
				    reflink_offset);
@@ -268,15 +266,17 @@ struct bkey_s_c bch2_lookup_indirect_extent(struct btree_trans *trans,

		int ret = bch2_indirect_extent_missing_error(trans, p, reflink_offset,
							     k.k->p.offset, should_commit);
		if (ret)
		if (ret) {
			bch2_trans_iter_exit(trans, iter);
			return bkey_s_c_err(ret);
		}
	} else if (unlikely(REFLINK_P_ERROR(p.v))) {
		bch2_trans_iter_exit(trans, iter);

		int ret = bch2_indirect_extent_not_missing(trans, p, should_commit);
		if (ret)
		if (ret) {
			bch2_trans_iter_exit(trans, iter);
			return bkey_s_c_err(ret);
		}
	}

	*offset_into_extent = reflink_offset - bkey_start_offset(k.k);
	return k;
@@ -300,7 +300,7 @@ static int trans_trigger_reflink_p_segment(struct btree_trans *trans,
	if (ret)
		return ret;

	if (bkey_deleted(k.k)) {
	if (!bkey_refcount_c(k)) {
		if (!(flags & BTREE_TRIGGER_overwrite))
			ret = -BCH_ERR_missing_indirect_extent;
		goto next;
@@ -381,8 +381,6 @@ static s64 gc_trigger_reflink_p_segment(struct btree_trans *trans,
not_found:
	if (flags & BTREE_TRIGGER_check_repair) {
		ret = bch2_indirect_extent_missing_error(trans, p, *idx, next_idx, false);
		if (ret == -BCH_ERR_missing_indirect_extent)
			ret = 0;
		if (ret)
			goto err;
	}
+1 −1
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@
	  BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0,	\
	  BCH_FSCK_ERR_accounting_key_junk_at_end)		\
	x(directory_size,					\
	  BIT_ULL(BCH_RECOVERY_PASS_check_inodes),		\
	  BIT_ULL(BCH_RECOVERY_PASS_check_dirents),		\
	  BCH_FSCK_ERR_directory_size_mismatch)			\

#define DOWNGRADE_TABLE()					\