mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: Edoardo Codeglia <bcachefs@404.blue> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
94426e4201
commit
63d6e93119
3 changed files with 35 additions and 27 deletions
|
@ -12,6 +12,7 @@
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
#include "fsck.h"
|
#include "fsck.h"
|
||||||
#include "inode.h"
|
#include "inode.h"
|
||||||
|
#include "io_misc.h"
|
||||||
#include "keylist.h"
|
#include "keylist.h"
|
||||||
#include "namei.h"
|
#include "namei.h"
|
||||||
#include "recovery_passes.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",
|
"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,
|
i->inode.bi_inum, i->inode.bi_snapshot, i->inode.bi_size,
|
||||||
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
|
(bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
|
||||||
struct bkey_i *whiteout = bch2_trans_kmalloc(trans, sizeof(*whiteout));
|
ret = bch2_fpunch_snapshot(trans,
|
||||||
ret = PTR_ERR_OR_ZERO(whiteout);
|
SPOS(i->inode.bi_inum,
|
||||||
if (ret)
|
last_block,
|
||||||
goto err;
|
i->inode.bi_snapshot),
|
||||||
|
POS(i->inode.bi_inum, U64_MAX));
|
||||||
bkey_init(&whiteout->k);
|
|
||||||
whiteout->k.p = SPOS(k.k->p.inode,
|
|
||||||
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);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
|
|
@ -135,6 +135,33 @@ err_noprint:
|
||||||
return ret;
|
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:
|
* Returns -BCH_ERR_transacton_restart if we had to drop locks:
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
int bch2_extent_fallocate(struct btree_trans *, subvol_inum, struct btree_iter *,
|
int bch2_extent_fallocate(struct btree_trans *, subvol_inum, struct btree_iter *,
|
||||||
u64, struct bch_io_opts, s64 *,
|
u64, struct bch_io_opts, s64 *,
|
||||||
struct write_point_specifier);
|
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 *,
|
int bch2_fpunch_at(struct btree_trans *, struct btree_iter *,
|
||||||
subvol_inum, u64, s64 *);
|
subvol_inum, u64, s64 *);
|
||||||
int bch2_fpunch(struct bch_fs *c, subvol_inum, u64, u64, s64 *);
|
int bch2_fpunch(struct bch_fs *c, subvol_inum, u64, u64, s64 *);
|
||||||
|
|
Loading…
Add table
Reference in a new issue