From 962ad1a76669443126c6531352380f56d6e5d7d2 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Thu, 23 Jun 2022 18:26:01 -0400 Subject: [PATCH] bcachefs: Don't BUG_ON() inode link count underflow This switches that assertion to a bch2_trans_inconsistent() call, as it should be. Signed-off-by: Kent Overstreet --- fs/bcachefs/fs-common.c | 8 +++++--- fs/bcachefs/inode.c | 33 +++++++++++++++++++++++++++++++++ fs/bcachefs/inode.h | 20 +++----------------- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/fs/bcachefs/fs-common.c b/fs/bcachefs/fs-common.c index d543480be111..53ffc684223c 100644 --- a/fs/bcachefs/fs-common.c +++ b/fs/bcachefs/fs-common.c @@ -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; diff --git a/fs/bcachefs/inode.c b/fs/bcachefs/inode.c index 6c0547151d50..5de66d62028b 100644 --- a/fs/bcachefs/inode.c +++ b/fs/bcachefs/inode.c @@ -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; +} diff --git a/fs/bcachefs/inode.h b/fs/bcachefs/inode.h index 9442600a7440..2ac2fc10513b 100644 --- a/fs/bcachefs/inode.h +++ b/fs/bcachefs/inode.h @@ -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 */