summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/debug.c98
-rw-r--r--drivers/md/bcache/debug.h2
-rw-r--r--drivers/md/bcache/fs-gc.c103
-rw-r--r--drivers/md/bcache/fs-gc.h1
-rw-r--r--drivers/md/bcache/super.c2
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;