summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/bcachefs/fsck.c99
1 files changed, 50 insertions, 49 deletions
diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c
index f3e3cf475c23..3a3d89bdf1c9 100644
--- a/fs/bcachefs/fsck.c
+++ b/fs/bcachefs/fsck.c
@@ -1345,13 +1345,6 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
goto out;
}
- ret = snapshots_seen_update(c, s, iter->btree_id, k.k->p);
- if (ret)
- goto err;
-
- if (k.k->type == KEY_TYPE_whiteout)
- goto out;
-
if (inode->last_pos.inode != k.k->p.inode) {
ret = check_i_sectors(trans, inode);
if (ret)
@@ -1365,66 +1358,74 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
if (ret)
goto err;
- ret = check_overlapping_extents(trans, s, extent_ends, k, iter);
- if (ret < 0)
- goto err;
-
- if (ret)
- inode->recalculate_sums = true;
-
- ret = extent_ends_at(extent_ends, s, k);
+ ret = snapshots_seen_update(c, s, iter->btree_id, k.k->p);
if (ret)
goto err;
- if (fsck_err_on(!i, c,
- "extent in missing inode:\n %s",
- (printbuf_reset(&buf),
- bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
- goto delete;
+ if (k.k->type != KEY_TYPE_whiteout) {
+ if (fsck_err_on(!i, c,
+ "extent in missing inode:\n %s",
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
+ goto delete;
+
+ if (fsck_err_on(i &&
+ !S_ISREG(i->inode.bi_mode) &&
+ !S_ISLNK(i->inode.bi_mode), c,
+ "extent in non regular inode mode %o:\n %s",
+ i->inode.bi_mode,
+ (printbuf_reset(&buf),
+ bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
+ goto delete;
- if (!i)
- goto out;
+ ret = check_overlapping_extents(trans, s, extent_ends, k, iter);
+ if (ret < 0)
+ goto err;
- if (fsck_err_on(!S_ISREG(i->inode.bi_mode) &&
- !S_ISLNK(i->inode.bi_mode), c,
- "extent in non regular inode mode %o:\n %s",
- i->inode.bi_mode,
- (printbuf_reset(&buf),
- bch2_bkey_val_to_text(&buf, c, k), buf.buf)))
- goto delete;
+ if (ret)
+ inode->recalculate_sums = true;
+
+ ret = extent_ends_at(extent_ends, s, k);
+ if (ret)
+ goto err;
+ }
/*
* Check inodes in reverse order, from oldest snapshots to newest, so
* that we emit the fewest number of whiteouts necessary:
*/
for (i = inode->inodes.data + inode->inodes.nr - 1;
- i >= inode->inodes.data;
+ inode->inodes.data && i >= inode->inodes.data;
--i) {
if (i->snapshot > equiv.snapshot ||
!key_visible_in_snapshot(c, s, i->snapshot, equiv.snapshot))
continue;
- if (fsck_err_on(!(i->inode.bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
- k.k->p.offset > round_up(i->inode.bi_size, block_bytes(c)) >> 9 &&
- !bkey_extent_is_reservation(k), c,
- "extent type past end of inode %llu:%u, i_size %llu\n %s",
- i->inode.bi_inum, i->snapshot, i->inode.bi_size,
- (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
- struct btree_iter iter2;
-
- bch2_trans_copy_iter(&iter2, iter);
- bch2_btree_iter_set_snapshot(&iter2, i->snapshot);
- ret = bch2_btree_iter_traverse(&iter2) ?:
- bch2_btree_delete_at(trans, &iter2,
- BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
- bch2_trans_iter_exit(trans, &iter2);
- if (ret)
- goto err;
-
- if (i->snapshot != equiv.snapshot) {
- ret = snapshots_seen_add(c, s, i->snapshot);
+ if (k.k->type != KEY_TYPE_whiteout) {
+ if (fsck_err_on(!(i->inode.bi_flags & BCH_INODE_I_SIZE_DIRTY) &&
+ k.k->p.offset > round_up(i->inode.bi_size, block_bytes(c)) >> 9 &&
+ !bkey_extent_is_reservation(k), c,
+ "extent type past end of inode %llu:%u, i_size %llu\n %s",
+ i->inode.bi_inum, i->snapshot, i->inode.bi_size,
+ (bch2_bkey_val_to_text(&buf, c, k), buf.buf))) {
+ struct btree_iter iter2;
+
+ bch2_trans_copy_iter(&iter2, iter);
+ bch2_btree_iter_set_snapshot(&iter2, i->snapshot);
+ ret = bch2_btree_iter_traverse(&iter2) ?:
+ bch2_btree_delete_at(trans, &iter2,
+ BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE);
+ bch2_trans_iter_exit(trans, &iter2);
if (ret)
goto err;
+
+ if (i->snapshot != equiv.snapshot) {
+ ret = snapshots_seen_add(c, s, i->snapshot);
+ if (ret)
+ goto err;
+ }
+
+ iter->k.type = KEY_TYPE_whiteout;
}
}
}