summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2025-06-24 14:07:32 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2025-06-30 17:52:46 -0400
commit5d92d2d7d711a5ccae12a8c52241c4dea4b5ba0b (patch)
treec7c32d7f1ed9a17fa976a34b34f6c8ae356ccf16
parent6bd0a3ec1fff38fa320cd447a7eae19a2ca718ba (diff)
bcachefs: Improve inode deletion
Don't delete dirents or extents if it's the wrong type of inode. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/inode.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c
index 99cd2a47f853..a0621006aee5 100644
--- a/fs/bcachefs/inode.c
+++ b/fs/bcachefs/inode.c
@@ -38,7 +38,7 @@ static const char * const bch2_inode_flag_strs[] = {
#undef x
static int delete_ancestor_snapshot_inodes(struct btree_trans *, struct bpos);
-static int may_delete_deleted_inum(struct btree_trans *, subvol_inum);
+static int may_delete_deleted_inum(struct btree_trans *, subvol_inum, struct bch_inode_unpacked *);
static const u8 byte_table[8] = { 1, 2, 3, 4, 6, 8, 10, 13 };
@@ -1128,10 +1128,11 @@ int bch2_inode_rm(struct bch_fs *c, subvol_inum inum)
struct btree_trans *trans = bch2_trans_get(c);
struct btree_iter iter = {};
struct bkey_s_c k;
+ struct bch_inode_unpacked inode;
u32 snapshot;
int ret;
- ret = lockrestart_do(trans, may_delete_deleted_inum(trans, inum));
+ ret = lockrestart_do(trans, may_delete_deleted_inum(trans, inum, &inode));
if (ret)
goto err2;
@@ -1143,9 +1144,10 @@ int bch2_inode_rm(struct bch_fs *c, subvol_inum inum)
* XXX: the dirent code ideally would delete whiteouts when they're no
* longer needed
*/
- ret = bch2_inode_delete_keys(trans, inum, BTREE_ID_extents) ?:
- bch2_inode_delete_keys(trans, inum, BTREE_ID_xattrs) ?:
- bch2_inode_delete_keys(trans, inum, BTREE_ID_dirents);
+ ret = (!S_ISDIR(inode.bi_mode)
+ ? bch2_inode_delete_keys(trans, inum, BTREE_ID_extents)
+ : bch2_inode_delete_keys(trans, inum, BTREE_ID_dirents)) ?:
+ bch2_inode_delete_keys(trans, inum, BTREE_ID_xattrs);
if (ret)
goto err2;
retry:
@@ -1398,12 +1400,12 @@ int bch2_inode_rm_snapshot(struct btree_trans *trans, u64 inum, u32 snapshot)
}
static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos,
+ struct bch_inode_unpacked *inode,
bool from_deleted_inodes)
{
struct bch_fs *c = trans->c;
struct btree_iter inode_iter;
struct bkey_s_c k;
- struct bch_inode_unpacked inode;
struct printbuf buf = PRINTBUF;
int ret;
@@ -1421,11 +1423,11 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos,
if (ret)
goto out;
- ret = bch2_inode_unpack(k, &inode);
+ ret = bch2_inode_unpack(k, inode);
if (ret)
goto out;
- if (S_ISDIR(inode.bi_mode)) {
+ if (S_ISDIR(inode->bi_mode)) {
ret = bch2_empty_dir_snapshot(trans, pos.offset, 0, pos.snapshot);
if (fsck_err_on(from_deleted_inodes &&
bch2_err_matches(ret, ENOTEMPTY),
@@ -1437,7 +1439,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos,
goto out;
}
- ret = inode.bi_flags & BCH_INODE_unlinked ? 0 : bch_err_throw(c, inode_not_unlinked);
+ ret = inode->bi_flags & BCH_INODE_unlinked ? 0 : bch_err_throw(c, inode_not_unlinked);
if (fsck_err_on(from_deleted_inodes && ret,
trans, deleted_inode_not_unlinked,
"non-deleted inode %llu:%u in deleted_inodes btree",
@@ -1446,7 +1448,7 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos,
if (ret)
goto out;
- ret = !(inode.bi_flags & BCH_INODE_has_child_snapshot)
+ ret = !(inode->bi_flags & BCH_INODE_has_child_snapshot)
? 0 : bch_err_throw(c, inode_has_child_snapshot);
if (fsck_err_on(from_deleted_inodes && ret,
@@ -1465,10 +1467,10 @@ static int may_delete_deleted_inode(struct btree_trans *trans, struct bpos pos,
if (fsck_err(trans, inode_has_child_snapshots_wrong,
"inode has_child_snapshots flag wrong (should be set)\n%s",
(printbuf_reset(&buf),
- bch2_inode_unpacked_to_text(&buf, &inode),
+ bch2_inode_unpacked_to_text(&buf, inode),
buf.buf))) {
- inode.bi_flags |= BCH_INODE_has_child_snapshot;
- ret = __bch2_fsck_write_inode(trans, &inode);
+ inode->bi_flags |= BCH_INODE_has_child_snapshot;
+ ret = __bch2_fsck_write_inode(trans, inode);
if (ret)
goto out;
}
@@ -1504,12 +1506,13 @@ delete:
goto out;
}
-static int may_delete_deleted_inum(struct btree_trans *trans, subvol_inum inum)
+static int may_delete_deleted_inum(struct btree_trans *trans, subvol_inum inum,
+ struct bch_inode_unpacked *inode)
{
u32 snapshot;
return bch2_subvolume_get_snapshot(trans, inum.subvol, &snapshot) ?:
- may_delete_deleted_inode(trans, SPOS(0, inum.inum, snapshot), false);
+ may_delete_deleted_inode(trans, SPOS(0, inum.inum, snapshot), inode, false);
}
int bch2_delete_dead_inodes(struct bch_fs *c)
@@ -1535,7 +1538,8 @@ int bch2_delete_dead_inodes(struct bch_fs *c)
ret = for_each_btree_key_commit(trans, iter, BTREE_ID_deleted_inodes, POS_MIN,
BTREE_ITER_prefetch|BTREE_ITER_all_snapshots, k,
NULL, NULL, BCH_TRANS_COMMIT_no_enospc, ({
- ret = may_delete_deleted_inode(trans, k.k->p, true);
+ struct bch_inode_unpacked inode;
+ ret = may_delete_deleted_inode(trans, k.k->p, &inode, true);
if (ret > 0) {
bch_verbose_ratelimited(c, "deleting unlinked inode %llu:%u",
k.k->p.offset, k.k->p.snapshot);