]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/fsck.c
improve kmalloc performance
[bcachefs-tools-debian] / libbcachefs / fsck.c
index 9f3e9bd3d767a75fb1a0734c0413193a671f3206..b1c89a4821f5e176f4b7b96710f9fc8de0a236e5 100644 (file)
@@ -208,8 +208,8 @@ static int fsck_write_inode(struct btree_trans *trans,
                            u32 snapshot)
 {
        int ret = commit_do(trans, NULL, NULL,
-                                 BTREE_INSERT_NOFAIL|
-                                 BTREE_INSERT_LAZY_RW,
+                                 BCH_TRANS_COMMIT_no_enospc|
+                                 BCH_TRANS_COMMIT_lazy_rw,
                                  __write_inode(trans, inode, snapshot));
        if (ret)
                bch_err_fn(trans->c, ret);
@@ -354,8 +354,8 @@ static int reattach_inode(struct btree_trans *trans,
                          u32 inode_snapshot)
 {
        int ret = commit_do(trans, NULL, NULL,
-                                 BTREE_INSERT_LAZY_RW|
-                                 BTREE_INSERT_NOFAIL,
+                                 BCH_TRANS_COMMIT_lazy_rw|
+                                 BCH_TRANS_COMMIT_no_enospc,
                        __reattach_inode(trans, inode, inode_snapshot));
        bch_err_msg(trans->c, ret, "reattaching inode %llu", inode->bi_inum);
        return ret;
@@ -757,8 +757,8 @@ static int hash_redo_key(struct btree_trans *trans,
                                       BCH_HASH_SET_MUST_CREATE,
                                       BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
                bch2_trans_commit(trans, NULL, NULL,
-                                 BTREE_INSERT_NOFAIL|
-                                 BTREE_INSERT_LAZY_RW);
+                                 BCH_TRANS_COMMIT_no_enospc|
+                                 BCH_TRANS_COMMIT_lazy_rw);
 }
 
 static int hash_check_key(struct btree_trans *trans,
@@ -826,6 +826,18 @@ fsck_err:
        goto out;
 }
 
+static int check_inode_deleted_list(struct btree_trans *trans, struct bpos p)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_deleted_inodes, p, 0);
+       int ret = bkey_err(k);
+       if (ret)
+               return ret;
+
+       bch2_trans_iter_exit(trans, &iter);
+       return k.k->type == KEY_TYPE_set;
+}
+
 static int check_inode(struct btree_trans *trans,
                       struct btree_iter *iter,
                       struct bkey_s_c k,
@@ -890,6 +902,17 @@ static int check_inode(struct btree_trans *trans,
                return 0;
        }
 
+       if (u.bi_flags & BCH_INODE_unlinked &&
+           c->sb.version >= bcachefs_metadata_version_deleted_inodes) {
+               ret = check_inode_deleted_list(trans, k.k->p);
+               if (ret)
+                       return ret;
+
+               fsck_err_on(ret, c, unlinked_inode_not_on_deleted_list,
+                           "inode %llu:%u unlinked, but not on deleted list",
+                           u.bi_inum, k.k->p.snapshot);
+       }
+
        if (u.bi_flags & BCH_INODE_unlinked &&
            (!c->sb.clean ||
             fsck_err(c, inode_unlinked_but_clean,
@@ -992,7 +1015,7 @@ int bch2_check_inodes(struct bch_fs *c)
        ret = for_each_btree_key_commit(trans, iter, BTREE_ID_inodes,
                        POS_MIN,
                        BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
-                       NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
+                       NULL, NULL, BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc,
                check_inode(trans, &iter, k, &prev, &s, full));
 
        snapshots_seen_exit(&s);
@@ -1023,25 +1046,6 @@ static bool dirent_points_to_inode(struct bkey_s_c_dirent d,
                : le64_to_cpu(d.v->d_inum)              == inode->bi_inum;
 }
 
-static int inode_backpointer_exists(struct btree_trans *trans,
-                                   struct bch_inode_unpacked *inode,
-                                   u32 snapshot)
-{
-       struct btree_iter iter;
-       struct bkey_s_c_dirent d;
-       int ret;
-
-       d = dirent_get_by_pos(trans, &iter,
-                       SPOS(inode->bi_dir, inode->bi_dir_offset, snapshot));
-       ret = bkey_err(d);
-       if (ret)
-               return bch2_err_matches(ret, ENOENT) ? 0 : ret;
-
-       ret = dirent_points_to_inode(d, inode);
-       bch2_trans_iter_exit(trans, &iter);
-       return ret;
-}
-
 static int check_i_sectors(struct btree_trans *trans, struct inode_walker *w)
 {
        struct bch_fs *c = trans->c;
@@ -1226,7 +1230,7 @@ static int overlapping_extents_found(struct btree_trans *trans,
                                BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE,
                                k1, k2) ?:
                        bch2_trans_commit(trans, &res, NULL,
-                               BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL);
+                               BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc);
                bch2_disk_reservation_put(c, &res);
 
                if (ret)
@@ -1465,7 +1469,7 @@ int bch2_check_extents(struct bch_fs *c)
                        POS(BCACHEFS_ROOT_INO, 0),
                        BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
                        &res, NULL,
-                       BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, ({
+                       BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc, ({
                bch2_disk_reservation_put(c, &res);
                check_extent(trans, &iter, k, &w, &s, &extent_ends) ?:
                check_extent_overbig(trans, &iter, k);
@@ -1494,7 +1498,7 @@ int bch2_check_indirect_extents(struct bch_fs *c)
                        POS_MIN,
                        BTREE_ITER_PREFETCH, k,
                        &res, NULL,
-                       BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, ({
+                       BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc, ({
                bch2_disk_reservation_put(c, &res);
                check_extent_overbig(trans, &iter, k);
        }));
@@ -1553,8 +1557,8 @@ static int check_dirent_target(struct btree_trans *trans,
 {
        struct bch_fs *c = trans->c;
        struct bkey_i_dirent *n;
-       bool backpointer_exists = true;
        struct printbuf buf = PRINTBUF;
+       struct btree_iter bp_iter = { NULL };
        int ret = 0;
 
        if (!target->bi_dir &&
@@ -1568,25 +1572,37 @@ static int check_dirent_target(struct btree_trans *trans,
        }
 
        if (!inode_points_to_dirent(target, d)) {
-               ret = inode_backpointer_exists(trans, target, d.k->p.snapshot);
-               if (ret < 0)
+               struct bkey_s_c_dirent bp_dirent = dirent_get_by_pos(trans, &bp_iter,
+                                     SPOS(target->bi_dir, target->bi_dir_offset, target_snapshot));
+               ret = bkey_err(bp_dirent);
+               if (ret && !bch2_err_matches(ret, ENOENT))
                        goto err;
 
-               backpointer_exists = ret;
+               bool backpointer_exists = !ret;
                ret = 0;
 
+               bch2_bkey_val_to_text(&buf, c, d.s_c);
+               prt_newline(&buf);
+               if (backpointer_exists)
+                       bch2_bkey_val_to_text(&buf, c, bp_dirent.s_c);
+
                if (fsck_err_on(S_ISDIR(target->bi_mode) && backpointer_exists,
                                c, inode_dir_multiple_links,
-                               "directory %llu with multiple links",
-                               target->bi_inum)) {
+                               "directory %llu:%u with multiple links\n%s",
+                               target->bi_inum, target_snapshot, buf.buf)) {
                        ret = __remove_dirent(trans, d.k->p);
                        goto out;
                }
 
+               /*
+                * hardlinked file with nlink 0:
+                * We're just adjusting nlink here so check_nlinks() will pick
+                * it up, it ignores inodes with nlink 0
+                */
                if (fsck_err_on(backpointer_exists && !target->bi_nlink,
                                c, inode_multiple_links_but_nlink_0,
-                               "inode %llu type %s has multiple links but i_nlink 0",
-                               target->bi_inum, bch2_d_types[d.v->d_type])) {
+                               "inode %llu:%u type %s has multiple links but i_nlink 0\n%s",
+                               target->bi_inum, target_snapshot, bch2_d_types[d.v->d_type], buf.buf)) {
                        target->bi_nlink++;
                        target->bi_flags &= ~BCH_INODE_unlinked;
 
@@ -1660,6 +1676,7 @@ static int check_dirent_target(struct btree_trans *trans,
 out:
 err:
 fsck_err:
+       bch2_trans_iter_exit(trans, &bp_iter);
        printbuf_exit(&buf);
        bch_err_fn(c, ret);
        return ret;
@@ -1854,7 +1871,7 @@ int bch2_check_dirents(struct bch_fs *c)
                        BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS,
                        k,
                        NULL, NULL,
-                       BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
+                       BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc,
                check_dirent(trans, &iter, k, &hash_info, &dir, &target, &s));
 
        bch2_trans_put(trans);
@@ -1918,7 +1935,7 @@ int bch2_check_xattrs(struct bch_fs *c)
                        BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS,
                        k,
                        NULL, NULL,
-                       BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
+                       BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc,
                check_xattr(trans, &iter, k, &hash_info, &inode)));
        bch_err_fn(c, ret);
        return ret;
@@ -1949,8 +1966,8 @@ static int check_root_trans(struct btree_trans *trans)
                root_subvol.v.snapshot  = cpu_to_le32(snapshot);
                root_subvol.v.inode     = cpu_to_le64(inum);
                ret = commit_do(trans, NULL, NULL,
-                                     BTREE_INSERT_NOFAIL|
-                                     BTREE_INSERT_LAZY_RW,
+                                     BCH_TRANS_COMMIT_no_enospc|
+                                     BCH_TRANS_COMMIT_lazy_rw,
                        bch2_btree_insert_trans(trans, BTREE_ID_subvolumes,
                                            &root_subvol.k_i, 0));
                bch_err_msg(c, ret, "writing root subvol");
@@ -1986,8 +2003,8 @@ int bch2_check_root(struct bch_fs *c)
        int ret;
 
        ret = bch2_trans_do(c, NULL, NULL,
-                            BTREE_INSERT_NOFAIL|
-                            BTREE_INSERT_LAZY_RW,
+                            BCH_TRANS_COMMIT_no_enospc|
+                            BCH_TRANS_COMMIT_lazy_rw,
                check_root_trans(trans));
        bch_err_fn(c, ret);
        return ret;
@@ -2116,8 +2133,8 @@ static int check_path(struct btree_trans *trans,
                                return 0;
 
                        ret = commit_do(trans, NULL, NULL,
-                                             BTREE_INSERT_NOFAIL|
-                                             BTREE_INSERT_LAZY_RW,
+                                             BCH_TRANS_COMMIT_no_enospc|
+                                             BCH_TRANS_COMMIT_lazy_rw,
                                        remove_backpointer(trans, inode));
                        if (ret) {
                                bch_err(c, "error removing dirent: %i", ret);
@@ -2220,7 +2237,7 @@ static int nlink_cmp(const void *_l, const void *_r)
        const struct nlink *l = _l;
        const struct nlink *r = _r;
 
-       return cmp_int(l->inum, r->inum) ?: cmp_int(l->snapshot, r->snapshot);
+       return cmp_int(l->inum, r->inum);
 }
 
 static void inc_link(struct bch_fs *c, struct snapshots_seen *s,
@@ -2398,10 +2415,10 @@ static int check_nlinks_update_hardlinks(struct bch_fs *c,
                for_each_btree_key_commit(trans, iter, BTREE_ID_inodes,
                                POS(0, range_start),
                                BTREE_ITER_INTENT|BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k,
-                               NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL,
+                               NULL, NULL, BCH_TRANS_COMMIT_lazy_rw|BCH_TRANS_COMMIT_no_enospc,
                        check_nlinks_update_inode(trans, &iter, k, links, &idx, range_end)));
        if (ret < 0) {
-               bch_err(c, "error in fsck: btree error %i while walking inodes", ret);
+               bch_err(c, "error in fsck walking inodes: %s", bch2_err_str(ret));
                return ret;
        }
 
@@ -2483,7 +2500,7 @@ int bch2_fix_reflink_p(struct bch_fs *c)
                                BTREE_ID_extents, POS_MIN,
                                BTREE_ITER_INTENT|BTREE_ITER_PREFETCH|
                                BTREE_ITER_ALL_SNAPSHOTS, k,
-                               NULL, NULL, BTREE_INSERT_NOFAIL|BTREE_INSERT_LAZY_RW,
+                               NULL, NULL, BCH_TRANS_COMMIT_no_enospc|BCH_TRANS_COMMIT_lazy_rw,
                        fix_reflink_p_key(trans, &iter, k)));
        bch_err_fn(c, ret);
        return ret;