bcachefs: Don't BUG_ON() inode link count underflow
authorKent Overstreet <kent.overstreet@gmail.com>
Thu, 23 Jun 2022 22:26:01 +0000 (18:26 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:34 +0000 (17:09 -0400)
This switches that assertion to a bch2_trans_inconsistent() call, as it
should be.

Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
fs/bcachefs/fs-common.c
fs/bcachefs/inode.c
fs/bcachefs/inode.h

index d543480be111796702d9f5c5f2ced168f4815e16..53ffc684223cf30486693f615b6de27054de347b 100644 (file)
@@ -204,7 +204,9 @@ int bch2_link_trans(struct btree_trans *trans,
                goto err;
 
        inode_u->bi_ctime = now;
-       bch2_inode_nlink_inc(inode_u);
+       ret = bch2_inode_nlink_inc(inode_u);
+       if (ret)
+               return ret;
 
        ret = bch2_inode_peek(trans, &dir_iter, dir_u, dir, BTREE_ITER_INTENT);
        if (ret)
@@ -297,7 +299,7 @@ int bch2_unlink_trans(struct btree_trans *trans,
                if (ret)
                        goto err;
        } else {
-               bch2_inode_nlink_dec(inode_u);
+               bch2_inode_nlink_dec(trans, inode_u);
        }
 
        if (inode_u->bi_dir             == dirent_iter.pos.inode &&
@@ -462,7 +464,7 @@ int bch2_rename_trans(struct btree_trans *trans,
        }
 
        if (mode == BCH_RENAME_OVERWRITE)
-               bch2_inode_nlink_dec(dst_inode_u);
+               bch2_inode_nlink_dec(trans, dst_inode_u);
 
        src_dir_u->bi_mtime             = now;
        src_dir_u->bi_ctime             = now;
index 6c0547151d507d1f817d689f833436fedddfa470..5de66d62028b2d1287046d7d8b3089613f32a84e 100644 (file)
@@ -716,3 +716,36 @@ int bch2_inode_find_by_inum(struct bch_fs *c, subvol_inum inum,
        return bch2_trans_do(c, NULL, NULL, 0,
                bch2_inode_find_by_inum_trans(&trans, inum, inode));
 }
+
+int bch2_inode_nlink_inc(struct bch_inode_unpacked *bi)
+{
+       if (bi->bi_flags & BCH_INODE_UNLINKED)
+               bi->bi_flags &= ~BCH_INODE_UNLINKED;
+       else {
+               if (bi->bi_nlink == U32_MAX)
+                       return -EINVAL;
+
+               bi->bi_nlink++;
+       }
+
+       return 0;
+}
+
+void bch2_inode_nlink_dec(struct btree_trans *trans, struct bch_inode_unpacked *bi)
+{
+       if (bi->bi_nlink && (bi->bi_flags & BCH_INODE_UNLINKED)) {
+               bch2_trans_inconsistent(trans, "inode %llu unlinked but link count nonzero",
+                                       bi->bi_inum);
+               return;
+       }
+
+       if (bi->bi_flags & BCH_INODE_UNLINKED) {
+               bch2_trans_inconsistent(trans, "inode %llu link count underflow", bi->bi_inum);
+               return;
+       }
+
+       if (bi->bi_nlink)
+               bi->bi_nlink--;
+       else
+               bi->bi_flags |= BCH_INODE_UNLINKED;
+}
index 9442600a7440e6c471d152d86a66be932147896e..2ac2fc10513bb3162521e7eea1af4575f0b85fa0 100644 (file)
@@ -164,23 +164,6 @@ static inline unsigned nlink_bias(umode_t mode)
        return S_ISDIR(mode) ? 2 : 1;
 }
 
-static inline void bch2_inode_nlink_inc(struct bch_inode_unpacked *bi)
-{
-       if (bi->bi_flags & BCH_INODE_UNLINKED)
-               bi->bi_flags &= ~BCH_INODE_UNLINKED;
-       else
-               bi->bi_nlink++;
-}
-
-static inline void bch2_inode_nlink_dec(struct bch_inode_unpacked *bi)
-{
-       BUG_ON(bi->bi_flags & BCH_INODE_UNLINKED);
-       if (bi->bi_nlink)
-               bi->bi_nlink--;
-       else
-               bi->bi_flags |= BCH_INODE_UNLINKED;
-}
-
 static inline unsigned bch2_inode_nlink_get(struct bch_inode_unpacked *bi)
 {
        return bi->bi_flags & BCH_INODE_UNLINKED
@@ -200,4 +183,7 @@ static inline void bch2_inode_nlink_set(struct bch_inode_unpacked *bi,
        }
 }
 
+int bch2_inode_nlink_inc(struct bch_inode_unpacked *);
+void bch2_inode_nlink_dec(struct btree_trans *, struct bch_inode_unpacked *);
+
 #endif /* _BCACHEFS_INODE_H */