]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bcachefs: get_inodes_all_snapshots() now includes whiteouts
authorKent Overstreet <kent.overstreet@linux.dev>
Sat, 3 May 2025 20:48:00 +0000 (16:48 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Thu, 22 May 2025 00:14:43 +0000 (20:14 -0400)
The next patch is going to change lookup_inode_for_snapshot to
rigorously require that a extent/dirent/xattr keys have a corresponding
inode key present - whiteouts included, so this simplifies the checks
lookup_inode_for_snapshot() will have to do.

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fsck.c

index 256e3907cd0435e971c1cc64eb15da81eee8d5cf..1daa3d970919e0b8ef0ff9bbc0ce03796ad649e7 100644 (file)
@@ -792,6 +792,7 @@ static int ref_visible2(struct bch_fs *c,
 
 struct inode_walker_entry {
        struct bch_inode_unpacked inode;
+       bool                    whiteout;
        u64                     count;
        u64                     i_size;
 };
@@ -820,12 +821,20 @@ static struct inode_walker inode_walker_init(void)
 static int add_inode(struct bch_fs *c, struct inode_walker *w,
                     struct bkey_s_c inode)
 {
-       struct bch_inode_unpacked u;
-
-       return bch2_inode_unpack(inode, &u) ?:
-               darray_push(&w->inodes, ((struct inode_walker_entry) {
-               .inode          = u,
+       int ret = darray_push(&w->inodes, ((struct inode_walker_entry) {
+               .whiteout       = !bkey_is_inode(inode.k),
        }));
+       if (ret)
+               return ret;
+
+       struct inode_walker_entry *n = &darray_last(w->inodes);
+       if (!n->whiteout) {
+               return bch2_inode_unpack(inode, &n->inode);
+       } else {
+               n->inode.bi_inum        = inode.k->p.inode;
+               n->inode.bi_snapshot    = inode.k->p.snapshot;
+               return 0;
+       }
 }
 
 static int get_inodes_all_snapshots(struct btree_trans *trans,
@@ -845,13 +854,12 @@ static int get_inodes_all_snapshots(struct btree_trans *trans,
        w->recalculate_sums = false;
        w->inodes.nr = 0;
 
-       for_each_btree_key_norestart(trans, iter, BTREE_ID_inodes, POS(0, inum),
-                                    BTREE_ITER_all_snapshots, k, ret) {
-               if (k.k->p.offset != inum)
+       for_each_btree_key_max_norestart(trans, iter,
+                       BTREE_ID_inodes, POS(0, inum), SPOS(0, inum, U32_MAX),
+                       BTREE_ITER_all_snapshots, k, ret) {
+               ret = add_inode(c, w, k);
+               if (ret)
                        break;
-
-               if (bkey_is_inode(k.k))
-                       add_inode(c, w, k);
        }
        bch2_trans_iter_exit(trans, &iter);
 
@@ -863,6 +871,41 @@ static int get_inodes_all_snapshots(struct btree_trans *trans,
        return 0;
 }
 
+static int get_visible_inodes(struct btree_trans *trans,
+                             struct inode_walker *w,
+                             struct snapshots_seen *s,
+                             u64 inum)
+{
+       struct bch_fs *c = trans->c;
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       int ret;
+
+       w->inodes.nr = 0;
+       w->deletes.nr = 0;
+
+       for_each_btree_key_reverse_norestart(trans, iter, BTREE_ID_inodes, SPOS(0, inum, s->pos.snapshot),
+                          BTREE_ITER_all_snapshots, k, ret) {
+               if (k.k->p.offset != inum)
+                       break;
+
+               if (!ref_visible(c, s, s->pos.snapshot, k.k->p.snapshot))
+                       continue;
+
+               if (snapshot_list_has_ancestor(c, &w->deletes, k.k->p.snapshot))
+                       continue;
+
+               ret = bkey_is_inode(k.k)
+                       ? add_inode(c, w, k)
+                       : snapshot_list_add(c, &w->deletes, k.k->p.snapshot);
+               if (ret)
+                       break;
+       }
+       bch2_trans_iter_exit(trans, &iter);
+
+       return ret;
+}
+
 static struct inode_walker_entry *
 lookup_inode_for_snapshot(struct bch_fs *c, struct inode_walker *w, struct bkey_s_c k)
 {
@@ -922,41 +965,6 @@ static struct inode_walker_entry *walk_inode(struct btree_trans *trans,
        return lookup_inode_for_snapshot(trans->c, w, k);
 }
 
-static int get_visible_inodes(struct btree_trans *trans,
-                             struct inode_walker *w,
-                             struct snapshots_seen *s,
-                             u64 inum)
-{
-       struct bch_fs *c = trans->c;
-       struct btree_iter iter;
-       struct bkey_s_c k;
-       int ret;
-
-       w->inodes.nr = 0;
-       w->deletes.nr = 0;
-
-       for_each_btree_key_reverse_norestart(trans, iter, BTREE_ID_inodes, SPOS(0, inum, s->pos.snapshot),
-                          BTREE_ITER_all_snapshots, k, ret) {
-               if (k.k->p.offset != inum)
-                       break;
-
-               if (!ref_visible(c, s, s->pos.snapshot, k.k->p.snapshot))
-                       continue;
-
-               if (snapshot_list_has_ancestor(c, &w->deletes, k.k->p.snapshot))
-                       continue;
-
-               ret = bkey_is_inode(k.k)
-                       ? add_inode(c, w, k)
-                       : snapshot_list_add(c, &w->deletes, k.k->p.snapshot);
-               if (ret)
-                       break;
-       }
-       bch2_trans_iter_exit(trans, &iter);
-
-       return ret;
-}
-
 /*
  * Prefer to delete the first one, since that will be the one at the wrong
  * offset:
@@ -1450,7 +1458,9 @@ static int check_key_has_inode(struct btree_trans *trans,
        if (k.k->type == KEY_TYPE_whiteout)
                goto out;
 
-       if (!i && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) {
+       bool have_inode = i && !i->whiteout;
+
+       if (!have_inode && (c->sb.btrees_lost_data & BIT_ULL(BTREE_ID_inodes))) {
                ret =   reconstruct_inode(trans, iter->btree_id, k.k->p.snapshot, k.k->p.inode) ?:
                        bch2_trans_commit(trans, NULL, NULL, BCH_TRANS_COMMIT_no_enospc);
                if (ret)
@@ -1461,14 +1471,14 @@ static int check_key_has_inode(struct btree_trans *trans,
                goto err;
        }
 
-       if (fsck_err_on(!i,
+       if (fsck_err_on(!have_inode,
                        trans, key_in_missing_inode,
                        "key 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 && !btree_matches_i_mode(iter->btree_id, i->inode.bi_mode),
+       if (fsck_err_on(have_inode && !btree_matches_i_mode(iter->btree_id, i->inode.bi_mode),
                        trans, key_in_wrong_inode_type,
                        "key for wrong inode mode %o:\n%s",
                        i->inode.bi_mode,
@@ -1856,7 +1866,8 @@ static int check_extent(struct btree_trans *trans, struct btree_iter *iter,
                for (struct inode_walker_entry *i = extent_i ?: &darray_last(inode->inodes);
                     inode->inodes.data && i >= inode->inodes.data;
                     --i) {
-                       if (i->inode.bi_snapshot > k.k->p.snapshot ||
+                       if (i->whiteout ||
+                           i->inode.bi_snapshot > k.k->p.snapshot ||
                            !key_visible_in_snapshot(c, s, i->inode.bi_snapshot, k.k->p.snapshot))
                                continue;
 
@@ -2167,7 +2178,7 @@ static int check_dirent(struct btree_trans *trans, struct btree_iter *iter,
        if (ret)
                goto err;
 
-       if (!i)
+       if (!i || i->whiteout)
                goto out;
 
        if (dir->first_this_inode)
@@ -2342,7 +2353,7 @@ static int check_xattr(struct btree_trans *trans, struct btree_iter *iter,
        if (ret)
                return ret;
 
-       if (!i)
+       if (!i || i->whiteout)
                return 0;
 
        if (inode->first_this_inode)