diff options
-rw-r--r-- | drivers/md/bcache/alloc.c | 26 | ||||
-rw-r--r-- | drivers/md/bcache/error.h | 46 | ||||
-rw-r--r-- | drivers/md/bcache/fs-gc.c | 33 | ||||
-rw-r--r-- | drivers/md/bcache/fs-gc.h | 6 | ||||
-rw-r--r-- | drivers/md/bcache/journal.c | 249 | ||||
-rw-r--r-- | drivers/md/bcache/journal.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 56 |
7 files changed, 222 insertions, 196 deletions
diff --git a/drivers/md/bcache/alloc.c b/drivers/md/bcache/alloc.c index 45d5ab8c790e..270d9333e74e 100644 --- a/drivers/md/bcache/alloc.c +++ b/drivers/md/bcache/alloc.c @@ -347,7 +347,7 @@ int bch_prio_read(struct cache *ca) unsigned bucket_nr = 0; u64 bucket, expect, got; size_t b; - int ret; + int ret = 0; spin_lock(&c->journal.lock); bucket = le64_to_cpu(c->journal.prio_buckets[ca->sb.nr_this_dev]); @@ -359,11 +359,9 @@ int bch_prio_read(struct cache *ca) if (!bucket) return 0; - if ((bucket < ca->mi.first_bucket && bucket >= ca->mi.nbuckets) || - bch_meta_read_fault("prio")) { - cache_inconsistent(ca, "bad prio bucket %llu", bucket); - return -EIO; - } + unfixable_fsck_err_on(bucket < ca->mi.first_bucket || + bucket >= ca->mi.nbuckets, c, + "bad prio bucket %llu", bucket); for (b = 0; b < ca->mi.nbuckets; b++, d++) { if (d == end) { @@ -379,19 +377,17 @@ int bch_prio_read(struct cache *ca) got = le64_to_cpu(p->magic); expect = pset_magic(&c->disk_sb); - if (cache_inconsistent_on(got != expect, ca, - "bad magic (got %llu expect %llu) while reading prios from bucket %llu", - got, expect, bucket)) - return -EIO; + unfixable_fsck_err_on(got != expect, c, + "bad magic (got %llu expect %llu) while reading prios from bucket %llu", + got, expect, bucket); got = le64_to_cpu(p->csum); expect = bch_checksum(PSET_CSUM_TYPE(p), &p->magic, bucket_bytes(ca) - 8); - if (cache_inconsistent_on(got != expect, ca, - "bad checksum (got %llu expect %llu) while reading prios from bucket %llu", - got, expect, bucket)) - return -EIO; + unfixable_fsck_err_on(got != expect, c, + "bad checksum (got %llu expect %llu) while reading prios from bucket %llu", + got, expect, bucket); bucket = le64_to_cpu(p->next_bucket); d = p->data; @@ -402,7 +398,7 @@ int bch_prio_read(struct cache *ca) bucket_cmpxchg(&ca->buckets[b], new, new.gen = d->gen); } - +fsck_err: return 0; } diff --git a/drivers/md/bcache/error.h b/drivers/md/bcache/error.h index 48fccbe0d2de..9eb9335abaf7 100644 --- a/drivers/md/bcache/error.h +++ b/drivers/md/bcache/error.h @@ -89,6 +89,52 @@ do { \ }) /* + * Fsck errors: inconsistency errors we detect at mount time, and should ideally + * be able to repair: + */ + +enum { + BCH_FSCK_OK = 0, + BCH_FSCK_ERRORS_NOT_FIXED = 1, + BCH_FSCK_REPAIR_UNIMPLEMENTED = 2, + BCH_FSCK_REPAIR_IMPOSSIBLE = 3, + BCH_FSCK_UNKNOWN_VERSION = 4, +}; + +#define unfixable_fsck_err(c, msg, ...) \ +do { \ + bch_err(c, msg " (repair unimplemented)", ##__VA_ARGS__); \ + ret = BCH_FSCK_REPAIR_UNIMPLEMENTED; \ + goto fsck_err; \ +} while (0) + +#define unfixable_fsck_err_on(cond, c, ...) \ +do { \ + if (cond) \ + unfixable_fsck_err(c, __VA_ARGS__); \ +} while (0) + +#define fsck_err(c, msg, ...) \ +do { \ + if (!(c)->opts.fix_errors) { \ + bch_err(c, msg, ##__VA_ARGS__); \ + ret = BCH_FSCK_ERRORS_NOT_FIXED; \ + goto fsck_err; \ + } \ + set_bit(CACHE_SET_FSCK_FIXED_ERRORS, &(c)->flags); \ + bch_err(c, msg ", fixing", ##__VA_ARGS__); \ +} while (0) + +#define fsck_err_on(cond, c, ...) \ +({ \ + bool _ret = (cond); \ + \ + if (_ret) \ + fsck_err(c, __VA_ARGS__); \ + _ret; \ +}) + +/* * Fatal errors: these don't indicate a bug, but we can't continue running in RW * mode - pretty much just due to metadata IO errors: */ diff --git a/drivers/md/bcache/fs-gc.c b/drivers/md/bcache/fs-gc.c index 11c3657d22f8..bd2a86700e45 100644 --- a/drivers/md/bcache/fs-gc.c +++ b/drivers/md/bcache/fs-gc.c @@ -11,39 +11,6 @@ #include <linux/generic-radix-tree.h> -#define unfixable_fsck_err(c, msg, ...) \ -do { \ - bch_err(c, msg " (repair unimplemented)", ##__VA_ARGS__); \ - ret = BCH_FSCK_REPAIR_UNIMPLEMENTED; \ - goto fsck_err; \ -} while (0) - -#define unfixable_fsck_err_on(cond, c, ...) \ -do { \ - if (cond) \ - unfixable_fsck_err(c, __VA_ARGS__); \ -} while (0) - -#define fsck_err(c, msg, ...) \ -do { \ - if (!(c)->opts.fix_errors) { \ - bch_err(c, msg, ##__VA_ARGS__); \ - ret = BCH_FSCK_ERRORS_NOT_FIXED; \ - goto fsck_err; \ - } \ - set_bit(CACHE_SET_FSCK_FIXED_ERRORS, &(c)->flags); \ - bch_err(c, msg ", fixing", ##__VA_ARGS__); \ -} while (0) - -#define fsck_err_on(cond, c, ...) \ -({ \ - bool _ret = (cond); \ - \ - if (_ret) \ - fsck_err(c, __VA_ARGS__); \ - _ret; \ -}) - struct nlink { u32 count; u32 dir_count; diff --git a/drivers/md/bcache/fs-gc.h b/drivers/md/bcache/fs-gc.h index dc98c295204f..c44086c08921 100644 --- a/drivers/md/bcache/fs-gc.h +++ b/drivers/md/bcache/fs-gc.h @@ -1,12 +1,6 @@ #ifndef _BCACHE_FS_GC_H #define _BCACHE_FS_GC_H -enum { - BCH_FSCK_OK = 0, - BCH_FSCK_ERRORS_NOT_FIXED = 1, - BCH_FSCK_REPAIR_UNIMPLEMENTED = 2, -}; - s64 bch_count_inode_sectors(struct cache_set *, u64); int bch_gc_inode_nlinks(struct cache_set *); int bch_fsck(struct cache_set *); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index fb799ce47a4a..e038b51076ee 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -464,39 +464,39 @@ static void journal_entry_null_range(void *start, void *end) } } -static void journal_validate_key(struct cache *ca, struct jset *j, - struct jset_entry *entry, - struct bkey_i *k, enum bkey_type key_type, - const char *type) +static int journal_validate_key(struct cache_set *c, struct jset *j, + struct jset_entry *entry, + struct bkey_i *k, enum bkey_type key_type, + const char *type) { - struct cache_set *c = ca->set; void *next = jset_keys_next(entry); const char *invalid; char buf[160]; + int ret = 0; - if (cache_inconsistent_on(!k->k.u64s, ca, - "invalid %s in journal: k->u64s 0", type)) { + if (fsck_err_on(!k->k.u64s, c, + "invalid %s in journal: k->u64s 0", type)) { entry->u64s = cpu_to_le16((u64 *) k - entry->_data); journal_entry_null_range(jset_keys_next(entry), next); - return; + return 0; } - if (cache_inconsistent_on((void *) bkey_next(k) > - (void *) jset_keys_next(entry), ca, + if (fsck_err_on((void *) bkey_next(k) > + (void *) jset_keys_next(entry), c, "invalid %s in journal: extends past end of journal entry", type)) { entry->u64s = cpu_to_le16((u64 *) k - entry->_data); journal_entry_null_range(jset_keys_next(entry), next); - return; + return 0; } - if (cache_inconsistent_on(k->k.format != KEY_FORMAT_CURRENT, ca, + if (fsck_err_on(k->k.format != KEY_FORMAT_CURRENT, c, "invalid %s in journal: bad format %u", type, k->k.format)) { le16_add_cpu(&entry->u64s, -k->k.u64s); memmove(k, bkey_next(k), next - (void *) bkey_next(k)); journal_entry_null_range(jset_keys_next(entry), next); - return; + return 0; } if (JSET_BIG_ENDIAN(j) != CPU_BIG_ENDIAN) @@ -506,76 +506,70 @@ static void journal_validate_key(struct cache *ca, struct jset *j, if (invalid) { bch_bkey_val_to_text(c, key_type, buf, sizeof(buf), bkey_i_to_s_c(k)); - cache_inconsistent(ca, "invalid %s in journal: %s", type, buf); + fsck_err(c, "invalid %s in journal: %s", type, buf); le16_add_cpu(&entry->u64s, -k->k.u64s); memmove(k, bkey_next(k), next - (void *) bkey_next(k)); journal_entry_null_range(jset_keys_next(entry), next); - return; + return 0; } +fsck_err: + return ret; } -static enum { - JOURNAL_ENTRY_BAD, - JOURNAL_ENTRY_REREAD, - JOURNAL_ENTRY_OK, -} journal_entry_validate(struct cache *ca, struct jset *j, u64 sector, - unsigned bucket_sectors_left, unsigned sectors_read) +#define JOURNAL_ENTRY_REREAD 5 +#define JOURNAL_ENTRY_NONE 6 +#define JOURNAL_ENTRY_BAD 7 + +static int journal_entry_validate(struct cache_set *c, struct jset *j, u64 sector, + unsigned bucket_sectors_left, + unsigned sectors_read) { - struct cache_set *c = ca->set; struct jset_entry *entry; size_t bytes = __set_bytes(j, le32_to_cpu(j->u64s)); u64 got, expect; + int ret = 0; - if (bch_meta_read_fault("journal")) - return JOURNAL_ENTRY_BAD; + if (le64_to_cpu(j->magic) != jset_magic(&c->disk_sb)) + return JOURNAL_ENTRY_NONE; - if (le64_to_cpu(j->magic) != jset_magic(&c->disk_sb)) { - pr_debug("bad magic while reading journal from %llu", sector); - return JOURNAL_ENTRY_BAD; + if (le32_to_cpu(j->version) != BCACHE_JSET_VERSION) { + bch_err(c, "unknown journal entry version %u", + le32_to_cpu(j->version)); + return BCH_FSCK_UNKNOWN_VERSION; } - got = le32_to_cpu(j->version); - expect = BCACHE_JSET_VERSION; - - if (cache_inconsistent_on(got != expect, ca, - "bad journal version (got %llu expect %llu) sector %lluu", - got, expect, sector)) - return JOURNAL_ENTRY_BAD; - - if (cache_inconsistent_on(bytes > bucket_sectors_left << 9 || - bytes > c->journal.entry_size_max, ca, + if (fsck_err_on(bytes > bucket_sectors_left << 9 || + bytes > c->journal.entry_size_max, c, "journal entry too big (%zu bytes), sector %lluu", - bytes, sector)) + bytes, sector)) { + /* XXX: note we might have missing journal entries */ return JOURNAL_ENTRY_BAD; + } if (bytes > sectors_read << 9) return JOURNAL_ENTRY_REREAD; - /* XXX: retry on checksum error */ - got = le64_to_cpu(j->csum); expect = __csum_set(j, le32_to_cpu(j->u64s), JSET_CSUM_TYPE(j)); - if (cache_inconsistent_on(got != expect, ca, + if (fsck_err_on(got != expect, c, "journal checksum bad (got %llu expect %llu), sector %lluu", - got, expect, sector)) + got, expect, sector)) { + /* XXX: retry IO, when we start retrying checksum errors */ + /* XXX: note we might have missing journal entries */ return JOURNAL_ENTRY_BAD; + } - if (cache_inconsistent_on(le64_to_cpu(j->last_seq) > - le64_to_cpu(j->seq), ca, - "invalid journal entry: last_seq > seq")) - return JOURNAL_ENTRY_BAD; + if (fsck_err_on(le64_to_cpu(j->last_seq) > le64_to_cpu(j->seq), c, + "invalid journal entry: last_seq > seq")) + j->last_seq = j->seq; - /* - * XXX: return errors directly, key off of c->opts.fix_errors like - * fs-gc.c - */ for_each_jset_entry(entry, j) { struct bkey_i *k; - if (cache_inconsistent_on(jset_keys_next(entry) > - bkey_idx(j, le32_to_cpu(j->u64s)), ca, - "journal entry extents past end of jset")) { + if (fsck_err_on(jset_keys_next(entry) > + bkey_idx(j, le32_to_cpu(j->u64s)), c, + "journal entry extents past end of jset")) { j->u64s = cpu_to_le64((u64 *) entry - j->_data); break; } @@ -584,48 +578,58 @@ static enum { case JOURNAL_ENTRY_BTREE_KEYS: for (k = entry->start; k < bkey_idx(entry, le16_to_cpu(entry->u64s)); - k = bkey_next(k)) - journal_validate_key(ca, j, entry, k, - bkey_type(entry->level, entry->btree_id), - "key"); + k = bkey_next(k)) { + ret = journal_validate_key(c, j, entry, k, + bkey_type(entry->level, + entry->btree_id), + "key"); + if (ret) + goto fsck_err; + } break; case JOURNAL_ENTRY_BTREE_ROOT: k = entry->start; - if (cache_inconsistent_on(!entry->u64s || - le16_to_cpu(entry->u64s) != k->k.u64s, ca, + if (fsck_err_on(!entry->u64s || + le16_to_cpu(entry->u64s) != k->k.u64s, c, "invalid btree root journal entry: wrong number of keys")) { journal_entry_null_range(entry, jset_keys_next(entry)); continue; } - journal_validate_key(ca, j, entry, k, - BKEY_TYPE_BTREE, "btree root"); + ret = journal_validate_key(c, j, entry, k, + BKEY_TYPE_BTREE, "btree root"); + if (ret) + goto fsck_err; break; case JOURNAL_ENTRY_PRIO_PTRS: break; case JOURNAL_ENTRY_JOURNAL_SEQ_BLACKLISTED: - cache_inconsistent_on(le16_to_cpu(entry->u64s) != 1, ca, - "invalid journal seq blacklist entry: bad size"); + if (fsck_err_on(le16_to_cpu(entry->u64s) != 1, c, + "invalid journal seq blacklist entry: bad size")) { + journal_entry_null_range(entry, + jset_keys_next(entry)); + } break; default: - cache_inconsistent(ca, - "invalid journal entry type %llu", - JOURNAL_ENTRY_TYPE(entry)); + fsck_err(c, "invalid journal entry type %llu", + JOURNAL_ENTRY_TYPE(entry)); + journal_entry_null_range(entry, jset_keys_next(entry)); break; } } - return JOURNAL_ENTRY_OK; +fsck_err: + return ret; } static int journal_read_bucket(struct cache *ca, struct journal_list *jlist, - unsigned bucket, u64 *seq) + unsigned bucket, u64 *seq, bool *entries_found) { struct cache_set *c = ca->set; struct journal_device *ja = &ca->journal; @@ -635,7 +639,7 @@ static int journal_read_bucket(struct cache *ca, struct journal_list *jlist, unsigned max_entry_sectors = c->journal.entry_size_max >> 9; u64 sector = bucket_to_sector(ca, journal_bucket(ca->disk_sb.sb, bucket)); - bool entries_found = false; + bool saw_bad = false; int ret = 0; data = (void *) __get_free_pages(GFP_KERNEL, @@ -678,18 +682,26 @@ reread: j = data; while (sectors_read) { - switch (journal_entry_validate(ca, j, + ret = journal_entry_validate(c, j, sector + bucket_offset, ca->mi.bucket_size - bucket_offset, - sectors_read)) { - case JOURNAL_ENTRY_BAD: - /* XXX: don't skip rest of bucket if single - * checksum error */ - goto err; + sectors_read); + switch (ret) { + case BCH_FSCK_OK: + break; case JOURNAL_ENTRY_REREAD: goto reread; - case JOURNAL_ENTRY_OK: - break; + case JOURNAL_ENTRY_NONE: + if (!saw_bad) + goto out; + blocks = 1; + goto next_block; + case JOURNAL_ENTRY_BAD: + saw_bad = true; + blocks = 1; + goto next_block; + default: + goto err; } /* @@ -710,13 +722,13 @@ reread: case JOURNAL_ENTRY_ADD_OUT_OF_RANGE: break; case JOURNAL_ENTRY_ADD_OK: - entries_found = true; + *entries_found = true; break; } if (le64_to_cpu(j->seq) > *seq) *seq = le64_to_cpu(j->seq); - +next_block: blocks = __set_blocks(j, le32_to_cpu(j->u64s), block_bytes(c)); @@ -727,7 +739,7 @@ reread: } } out: - ret = entries_found; + ret = 0; err: if (data == c->journal.buf[0].data) mutex_unlock(&jlist->cache_set_buffer_lock); @@ -742,15 +754,17 @@ static void bch_journal_read_device(struct closure *cl) { #define read_bucket(b) \ ({ \ - int ret = journal_read_bucket(ca, jlist, b, &seq); \ + bool entries_found = false; \ + int ret = journal_read_bucket(ca, jlist, b, \ + &seq, &entries_found); \ __set_bit(b, bitmap); \ - if (ret < 0) { \ + if (ret) { \ mutex_lock(&jlist->lock); \ jlist->ret = ret; \ mutex_unlock(&jlist->lock); \ closure_return(cl); \ } \ - ret; \ + entries_found; \ }) struct journal_device *ja = @@ -776,9 +790,9 @@ static void bch_journal_read_device(struct closure *cl) * the fancy fibonacci hash/binary search because the live journal * entries might not form a contiguous range: */ - for (i = 0; i < nr_buckets; i++) - read_bucket(i); - goto search_done; + for (i = 0; i < nr_buckets; i++) + read_bucket(i); + goto search_done; if (!blk_queue_nonrot(q)) goto linear_scan; @@ -904,7 +918,7 @@ static int journal_seq_blacklist_read(struct journal *j, return 0; } -const char *bch_journal_read(struct cache_set *c, struct list_head *list) +int bch_journal_read(struct cache_set *c, struct list_head *list) { struct jset_entry *prio_ptrs; struct journal_list jlist; @@ -914,6 +928,7 @@ const char *bch_journal_read(struct cache_set *c, struct list_head *list) struct cache *ca; u64 cur_seq, end_seq; unsigned iter; + int ret = 0; closure_init_stack(&jlist.cl); mutex_init(&jlist.lock); @@ -929,22 +944,20 @@ const char *bch_journal_read(struct cache_set *c, struct list_head *list) closure_sync(&jlist.cl); - if (jlist.ret) { - bch_journal_entries_free(list); + if (jlist.ret) + return jlist.ret; - return jlist.ret == -ENOMEM - ? "cannot allocate memory for journal" - : "error reading journal"; + if (list_empty(list)){ + bch_err(c, "no journal entries found"); + return BCH_FSCK_REPAIR_IMPOSSIBLE; } - if (list_empty(list)) - return "no journal entries found"; - j = &list_entry(list->prev, struct journal_replay, list)->j; - if (le64_to_cpu(j->seq) - - le64_to_cpu(j->last_seq) + 1 > c->journal.pin.size) - return "too many journal entries open for refcount fifo"; + unfixable_fsck_err_on(le64_to_cpu(j->seq) - + le64_to_cpu(j->last_seq) + 1 > + c->journal.pin.size, c, + "too many journal entries open for refcount fifo"); c->journal.pin.back = le64_to_cpu(j->seq) - le64_to_cpu(j->last_seq) + 1; @@ -968,7 +981,7 @@ const char *bch_journal_read(struct cache_set *c, struct list_head *list) if (journal_seq_blacklist_read(&c->journal, i, p)) { mutex_unlock(&c->journal.blacklist_lock); - return "insufficient memory"; + return -ENOMEM; } i = list_is_last(&i->list, list) @@ -986,20 +999,22 @@ const char *bch_journal_read(struct cache_set *c, struct list_head *list) struct journal_replay, list)->j.seq); list_for_each_entry(i, list, list) { - mutex_lock(&c->journal.blacklist_lock); + bool blacklisted; + mutex_lock(&c->journal.blacklist_lock); while (cur_seq < le64_to_cpu(i->j.seq) && journal_seq_blacklist_find(&c->journal, cur_seq)) cur_seq++; - cache_set_inconsistent_on(journal_seq_blacklist_find(&c->journal, - le64_to_cpu(i->j.seq)), c, - "found blacklisted journal entry %llu", - le64_to_cpu(i->j.seq)); - + blacklisted = journal_seq_blacklist_find(&c->journal, + le64_to_cpu(i->j.seq)); mutex_unlock(&c->journal.blacklist_lock); - cache_set_inconsistent_on(le64_to_cpu(i->j.seq) != cur_seq, c, + fsck_err_on(blacklisted, c, + "found blacklisted journal entry %llu", + le64_to_cpu(i->j.seq)); + + fsck_err_on(le64_to_cpu(i->j.seq) != cur_seq, c, "journal entries %llu-%llu missing! (replaying %llu-%llu)", cur_seq, le64_to_cpu(i->j.seq) - 1, last_seq(&c->journal), end_seq); @@ -1008,20 +1023,14 @@ const char *bch_journal_read(struct cache_set *c, struct list_head *list) } prio_ptrs = bch_journal_find_entry(j, JOURNAL_ENTRY_PRIO_PTRS, 0); - if (!prio_ptrs) { - /* - * there weren't any prio bucket ptrs yet... XXX should change - * the allocator so this can't happen: - */ - return NULL; + if (prio_ptrs) { + memcpy_u64s(c->journal.prio_buckets, + prio_ptrs->_data, + le16_to_cpu(prio_ptrs->u64s)); + c->journal.nr_prio_buckets = le16_to_cpu(prio_ptrs->u64s); } - - memcpy_u64s(c->journal.prio_buckets, - prio_ptrs->_data, - le16_to_cpu(prio_ptrs->u64s)); - c->journal.nr_prio_buckets = le16_to_cpu(prio_ptrs->u64s); - - return NULL; +fsck_err: + return ret; } void bch_journal_mark(struct cache_set *c, struct list_head *list) @@ -1456,9 +1465,7 @@ int bch_journal_replay(struct cache_set *c, struct list_head *list) err: if (ret) bch_err(c, "journal replay error: %d", ret); - bch_journal_entries_free(list); - return ret; } diff --git a/drivers/md/bcache/journal.h b/drivers/md/bcache/journal.h index 1dc40c7467cd..a7d001bbbb58 100644 --- a/drivers/md/bcache/journal.h +++ b/drivers/md/bcache/journal.h @@ -340,7 +340,7 @@ static inline bool journal_flushes_device(struct cache *ca) void bch_journal_start(struct cache_set *); void bch_journal_mark(struct cache_set *, struct list_head *); void bch_journal_entries_free(struct list_head *); -const char *bch_journal_read(struct cache_set *, struct list_head *); +int bch_journal_read(struct cache_set *, struct list_head *); int bch_journal_replay(struct cache_set *, struct list_head *); static inline void bch_journal_set_replay_done(struct journal *j) diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index db76d50f4d8f..8016db503586 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1282,8 +1282,8 @@ static const char *run_cache_set(struct cache_set *c) */ if (CACHE_SET_SYNC(&c->disk_sb)) { - err = bch_journal_read(c, &journal); - if (err) + ret = bch_journal_read(c, &journal); + if (ret) goto err; pr_debug("btree_journal_read() done"); @@ -1291,11 +1291,13 @@ static const char *run_cache_set(struct cache_set *c) j = &list_entry(journal.prev, struct journal_replay, list)->j; err = "error reading priorities"; - for_each_cache(ca, c, i) - if (bch_prio_read(ca)) { + for_each_cache(ca, c, i) { + ret = bch_prio_read(ca); + if (ret) { percpu_ref_put(&ca->ref); goto err; } + } c->prio_clock[READ].hand = le16_to_cpu(j->read_clock); c->prio_clock[WRITE].hand = le16_to_cpu(j->write_clock); @@ -1355,7 +1357,8 @@ static const char *run_cache_set(struct cache_set *c) bch_verbose(c, "starting journal replay:"); err = "journal replay failed"; - if (bch_journal_replay(c, &journal)) + ret = bch_journal_replay(c, &journal); + if (ret) goto err; bch_verbose(c, "journal replay done"); @@ -1375,7 +1378,7 @@ static const char *run_cache_set(struct cache_set *c) err = "error in fs gc"; ret = bch_gc_inode_nlinks(c); if (ret) - goto fsck_err; + goto err; bch_verbose(c, "fs gc done"); if (!c->opts.nofsck) { @@ -1383,7 +1386,7 @@ static const char *run_cache_set(struct cache_set *c) err = "error in fsck"; ret = bch_fsck(c); if (ret) - goto fsck_err; + goto err; bch_verbose(c, "fsck done"); } } else { @@ -1487,27 +1490,40 @@ static const char *run_cache_set(struct cache_set *c) BUG_ON(!list_empty(&journal)); return NULL; err: - bch_journal_entries_free(&journal); - set_bit(CACHE_SET_ERROR, &c->flags); - bch_cache_set_unregister(c); - closure_put(&c->caching); - return err; -fsck_err: switch (ret) { - case BCH_FSCK_OK: - break; case BCH_FSCK_ERRORS_NOT_FIXED: + err = NULL; bch_err(c, "filesystem contains errors: please report this to the developers"); pr_cont("mount with -o fix_errors to repair"); - goto err; + break; case BCH_FSCK_REPAIR_UNIMPLEMENTED: + err = NULL; bch_err(c, "filesystem contains errors: please report this to the developers"); pr_cont("repair unimplemented: inform the developers so that it can be added"); - goto err; - default: - goto err; + break; + case BCH_FSCK_REPAIR_IMPOSSIBLE: + err = NULL; + bch_err(c, "filesystem contains errors, but repair impossible"); + break; + case BCH_FSCK_UNKNOWN_VERSION: + err = NULL; + bch_err(c, "cannot mount: unknown metadata version"); + break; + case -ENOMEM: + err = NULL; + bch_err(c, "cannot mount: insufficient memory"); + break; + case -EIO: + err = NULL; + bch_err(c, "cannot mount: IO error"); + break; } - goto err; + + bch_journal_entries_free(&journal); + set_bit(CACHE_SET_ERROR, &c->flags); + bch_cache_set_unregister(c); + closure_put(&c->caching); + return err; } static const char *can_add_cache(struct cache_sb *sb, |