Commit 63d6e931 authored by Kent Overstreet's avatar Kent Overstreet
Browse files

bcachefs: bch2_fpunch_snapshot()



Add a new version of fpunch for operating on a snapshot ID, not a
subvolume - and use it for "extent past end of inode" repair.

Previously, repair would try to delete everything at once, but deleting
too many extents at once can overflow the btree_trans bump allocator, as
well as causing other problems - the new helper properly uses
bch2_extent_trim_atomic().

Reported-and-tested-by: default avatarEdoardo Codeglia <bcachefs@404.blue>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 94426e42
Loading
Loading
Loading
Loading
+6 −27
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include "fs.h"
#include "fsck.h"
#include "inode.h"
#include "io_misc.h"
#include "keylist.h"
#include "namei.h"
#include "recovery_passes.h"
@@ -1919,33 +1920,11 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
					"extent type past end of inode %llu:%u, i_size %llu\n%s",
					i->inode.bi_inum, i->inode.bi_snapshot, i->inode.bi_size,
					(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
				struct bkey_i *whiteout = bch2_trans_kmalloc(trans, sizeof(*whiteout));
				ret = PTR_ERR_OR_ZERO(whiteout);
				if (ret)
					goto err;

				bkey_init(&whiteout->k);
				whiteout->k.p = SPOS(k.k->p.inode,
				ret = bch2_fpunch_snapshot(trans,
							   SPOS(i->inode.bi_inum,
								last_block,
						     i->inode.bi_snapshot);
				bch2_key_resize(&whiteout->k,
						min(KEY_SIZE_MAX & (~0 << c->block_bits),
						    U64_MAX - whiteout->k.p.offset));


				/*
				 * Need a normal (not BTREE_ITER_all_snapshots)
				 * iterator, if we're deleting in a different
				 * snapshot and need to emit a whiteout
				 */
				struct btree_iter iter2;
				bch2_trans_iter_init(trans, &iter2, BTREE_ID_extents,
						     bkey_start_pos(&whiteout->k),
						     BTREE_ITER_intent);
				ret =   bch2_btree_iter_traverse(trans, &iter2) ?:
					bch2_trans_update(trans, &iter2, whiteout,
						BTREE_UPDATE_internal_snapshot_node);
				bch2_trans_iter_exit(trans, &iter2);
								i->inode.bi_snapshot),
							   POS(i->inode.bi_inum, U64_MAX));
				if (ret)
					goto err;

+27 −0
Original line number Diff line number Diff line
@@ -135,6 +135,33 @@ int bch2_extent_fallocate(struct btree_trans *trans,
	return ret;
}

/* For fsck */
int bch2_fpunch_snapshot(struct btree_trans *trans, struct bpos start, struct bpos end)
{
	u32 restart_count = trans->restart_count;
	struct bch_fs *c = trans->c;
	struct disk_reservation disk_res = bch2_disk_reservation_init(c, 0);
	unsigned max_sectors	= KEY_SIZE_MAX & (~0 << c->block_bits);
	struct bkey_i delete;

	int ret = for_each_btree_key_max_commit(trans, iter, BTREE_ID_extents,
			start, end, 0, k,
			&disk_res, NULL, BCH_TRANS_COMMIT_no_enospc, ({
		bkey_init(&delete.k);
		delete.k.p = iter.pos;

		/* create the biggest key we can */
		bch2_key_resize(&delete.k, max_sectors);
		bch2_cut_back(end, &delete);

		bch2_extent_trim_atomic(trans, &iter, &delete) ?:
		bch2_trans_update(trans, &iter, &delete, 0);
	}));

	bch2_disk_reservation_put(c, &disk_res);
	return ret ?: trans_was_restarted(trans, restart_count);
}

/*
 * Returns -BCH_ERR_transacton_restart if we had to drop locks:
 */
+2 −0
Original line number Diff line number Diff line
@@ -5,6 +5,8 @@
int bch2_extent_fallocate(struct btree_trans *, subvol_inum, struct btree_iter *,
			  u64, struct bch_io_opts, s64 *,
			  struct write_point_specifier);

int bch2_fpunch_snapshot(struct btree_trans *, struct bpos, struct bpos);
int bch2_fpunch_at(struct btree_trans *, struct btree_iter *,
		   subvol_inum, u64, s64 *);
int bch2_fpunch(struct bch_fs *c, subvol_inum, u64, u64, s64 *);