diff options
-rw-r--r-- | drivers/md/bcache/debug.c | 98 | ||||
-rw-r--r-- | drivers/md/bcache/debug.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/fs-gc.c | 103 | ||||
-rw-r--r-- | drivers/md/bcache/fs-gc.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 2 |
5 files changed, 105 insertions, 101 deletions
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 9cb105cfd4cb..9d69872dc777 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -183,104 +183,6 @@ out_put: bio_put(check); } -void bch_verify_inode_refs(struct cache_set *c) -{ - struct btree_iter iter; - struct bkey_s_c k; - struct bkey_i_inode inode; - u64 cur_inum = 0; - u64 i_size, i_sectors; - u16 i_mode; - char buf[100]; - - for_each_btree_key(&iter, c, BTREE_ID_EXTENTS, - POS(BCACHE_ROOT_INO, 0), k) { - if (k.k->type == KEY_TYPE_DISCARD || - k.k->type == BCH_RESERVATION) - continue; - - if (k.k->p.inode != cur_inum && - bch_inode_find_by_inum(c, k.k->p.inode, &inode)) { - bch_bkey_val_to_text(c, BTREE_ID_EXTENTS, buf, - sizeof(buf), k); - cache_set_inconsistent(c, - "extent for missing inode %llu\n%s", - k.k->p.inode, buf); - bch_btree_iter_unlock(&iter); - return; - } - - if (k.k->p.inode != cur_inum) { - BUG_ON(le32_to_cpu(inode.v.i_flags) & BCH_INODE_I_SIZE_DIRTY); - BUG_ON(le32_to_cpu(inode.v.i_flags) & BCH_INODE_I_SECTORS_DIRTY); - - i_sectors = bch_count_inode_sectors(c, inode.k.p.inode); - cache_set_inconsistent_on(i_sectors != - le64_to_cpu(inode.v.i_sectors), c, - "i_sectors wrong: got %llu, should be %llu", - le64_to_cpu(inode.v.i_sectors), i_sectors); - } - - cur_inum = k.k->p.inode; - i_mode = le16_to_cpu(inode.v.i_mode); - i_size = le64_to_cpu(inode.v.i_size); - - if (!S_ISREG(i_mode) && - !S_ISLNK(i_mode)) - cache_set_inconsistent(c, - "extent for non regular file, inode %llu mode %u", - k.k->p.inode, i_mode); - - if (k.k->p.offset > round_up(i_size, PAGE_SIZE) >> 9) { - bch_bkey_val_to_text(c, BTREE_ID_EXTENTS, buf, - sizeof(buf), k); - cache_set_inconsistent(c, - "extent past end of inode %llu: i_size %llu extent\n%s", - k.k->p.inode, i_size, buf); - } - } - bch_btree_iter_unlock(&iter); - - for_each_btree_key(&iter, c, BTREE_ID_DIRENTS, - POS(BCACHE_ROOT_INO, 0), k) { - /* XXX: skipping whiteouts for now */ - if (k.k->type != BCH_DIRENT) - continue; - - if (k.k->p.inode != cur_inum && - bch_inode_find_by_inum(c, k.k->p.inode, &inode)) { - cache_set_inconsistent(c, "dirent for missing inode %llu", - k.k->p.inode); - bch_btree_iter_unlock(&iter); - return; - } - - cur_inum = k.k->p.inode; - i_mode = le16_to_cpu(inode.v.i_mode); - - if (!S_ISDIR(i_mode)) - cache_set_inconsistent(c, - "dirent for non directory, inode %llu mode %u", - k.k->p.inode, i_mode); - } - bch_btree_iter_unlock(&iter); - - for_each_btree_key(&iter, c, BTREE_ID_XATTRS, - POS(BCACHE_ROOT_INO, 0), k) { - if (k.k->p.inode != cur_inum && - bch_inode_find_by_inum(c, k.k->p.inode, &inode)) { - cache_set_inconsistent(c, - "xattr for missing inode %llu", - k.k->p.inode); - bch_btree_iter_unlock(&iter); - return; - } - - cur_inum = k.k->p.inode; - } - bch_btree_iter_unlock(&iter); -} - #endif #ifdef CONFIG_DEBUG_FS diff --git a/drivers/md/bcache/debug.h b/drivers/md/bcache/debug.h index ad7c79a1e5ba..c8f3ae64bd7d 100644 --- a/drivers/md/bcache/debug.h +++ b/drivers/md/bcache/debug.h @@ -28,7 +28,6 @@ BCH_DEBUG_PARAMS_DEBUG() void __bch_btree_verify(struct cache_set *, struct btree *); void bch_data_verify(struct cached_dev *, struct bio *); -void bch_verify_inode_refs(struct cache_set *); #define bypass_torture_test(d) ((d)->bypass_torture_test) @@ -41,7 +40,6 @@ BCH_DEBUG_PARAMS_DEBUG() static inline void __bch_btree_verify(struct cache_set *c, struct btree *b) {} static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {} -static inline void bch_verify_inode_refs(struct cache_set *c) {} #define bypass_torture_test(d) 0 diff --git a/drivers/md/bcache/fs-gc.c b/drivers/md/bcache/fs-gc.c index 168d56f90d99..b54105aa0521 100644 --- a/drivers/md/bcache/fs-gc.c +++ b/drivers/md/bcache/fs-gc.c @@ -271,3 +271,106 @@ int bch_gc_inode_nlinks(struct cache_set *c) return ret; } + +static inline bool next_inode(struct cache_set *c, struct bkey_s_c k, + u64 *cur_inum, + struct bkey_i_inode *inode, + struct bch_inode **bi, + u64 *i_size, u16 *i_mode) +{ + if (k.k->p.inode == *cur_inum) + return false; + + if (!bch_inode_find_by_inum(c, k.k->p.inode, inode)) { + *i_mode = le16_to_cpu(inode->v.i_mode); + *i_size = le64_to_cpu(inode->v.i_size); + *bi = &inode->v; + } else { + *bi = NULL; + } + + *cur_inum = k.k->p.inode; + return true; +} + +#define fsck_err(c, fmt, ...) \ +do { \ + bch_err(c, fmt, ##__VA_ARGS__); \ +} while (0) + +/* + * Checks for inconsistencies that shouldn't happen, unless we have a bug. + * Doesn't fix them yet, mainly because they haven't yet been observed: + */ +void bch_fsck(struct cache_set *c) +{ + struct btree_iter iter; + struct bkey_s_c k; + struct bkey_i_inode inode; + struct bch_inode *bi = NULL; + u64 i_size = 0; + u16 i_mode = 0; + u64 cur_inum; + char buf[100]; + + cur_inum = -1; + for_each_btree_key(&iter, c, BTREE_ID_EXTENTS, + POS(BCACHE_ROOT_INO, 0), k) { + if (k.k->type == KEY_TYPE_DISCARD) + continue; + + if (next_inode(c, k, &cur_inum, &inode, &bi, + &i_size, &i_mode) && + bi && + !(le32_to_cpu(bi->i_flags) & BCH_INODE_I_SECTORS_DIRTY)) { + u64 i_sectors = bch_count_inode_sectors(c, cur_inum); + + if (i_sectors != le64_to_cpu(bi->i_sectors)) + fsck_err(c, + "i_sectors wrong: got %llu, should be %llu", + le64_to_cpu(bi->i_sectors), i_sectors); + } + + if (!S_ISREG(i_mode) && + !S_ISLNK(i_mode)) + fsck_err(c, + "extent type %u for non regular file, inode %llu mode %o", + k.k->type, k.k->p.inode, i_mode); + + if (k.k->type != BCH_RESERVATION && + k.k->p.offset > round_up(i_size, PAGE_SIZE) >> 9) { + bch_bkey_val_to_text(c, BTREE_ID_EXTENTS, buf, + sizeof(buf), k); + fsck_err(c, + "extent past end of inode %llu: i_size %llu extent\n%s", + k.k->p.inode, i_size, buf); + } + } + bch_btree_iter_unlock(&iter); + + cur_inum = -1; + for_each_btree_key(&iter, c, BTREE_ID_DIRENTS, + POS(BCACHE_ROOT_INO, 0), k) { + next_inode(c, k, &cur_inum, &inode, &bi, &i_size, &i_mode); + + if (!bi) + fsck_err(c, "dirent for missing inode %llu", k.k->p.inode); + + if (!S_ISDIR(i_mode)) + fsck_err(c, + "dirent for non directory, inode %llu mode %o", + k.k->p.inode, i_mode); + } + bch_btree_iter_unlock(&iter); + + cur_inum = -1; + for_each_btree_key(&iter, c, BTREE_ID_XATTRS, + POS(BCACHE_ROOT_INO, 0), k) { + next_inode(c, k, &cur_inum, &inode, &bi, &i_size, &i_mode); + + if (!bi) + fsck_err(c, "xattr for missing inode %llu", + k.k->p.inode); + } + bch_btree_iter_unlock(&iter); +} diff --git a/drivers/md/bcache/fs-gc.h b/drivers/md/bcache/fs-gc.h index 9e0a34cc2e5f..04f08978af3a 100644 --- a/drivers/md/bcache/fs-gc.h +++ b/drivers/md/bcache/fs-gc.h @@ -3,5 +3,6 @@ s64 bch_count_inode_sectors(struct cache_set *, u64); int bch_gc_inode_nlinks(struct cache_set *); +void bch_fsck(struct cache_set *); #endif /* _BCACHE_FS_GC_H */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 61394008e18f..4aa5aa0abbd9 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1362,7 +1362,7 @@ static const char *run_cache_set(struct cache_set *c) if (bch_gc_inode_nlinks(c)) goto err; - bch_verify_inode_refs(c); + bch_fsck(c); } else { struct bkey_i_inode inode; struct closure cl; |