diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-02-09 11:52:01 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2018-02-09 12:20:35 -0500 |
commit | 9d3f6be80f7f9f68a85ea1135c742e66703cea0d (patch) | |
tree | b47b0d4f8508a76de8314872c4f4243dfb5d5a8c | |
parent | 8d2c1b6408d46b54234e3c6011fe2b7dc0218788 (diff) |
bcachefs: fix an inconsistency with replicas tracking
-rw-r--r-- | fs/bcachefs/btree_gc.c | 5 | ||||
-rw-r--r-- | fs/bcachefs/btree_update_interior.c | 8 | ||||
-rw-r--r-- | fs/bcachefs/extents.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/extents.h | 34 | ||||
-rw-r--r-- | fs/bcachefs/io.c | 3 | ||||
-rw-r--r-- | fs/bcachefs/journal.c | 9 | ||||
-rw-r--r-- | fs/bcachefs/migrate.c | 13 | ||||
-rw-r--r-- | fs/bcachefs/move.c | 12 | ||||
-rw-r--r-- | fs/bcachefs/super-io.c | 94 | ||||
-rw-r--r-- | fs/bcachefs/super-io.h | 12 | ||||
-rw-r--r-- | fs/bcachefs/super.c | 4 | ||||
-rw-r--r-- | fs/bcachefs/super.h | 5 | ||||
-rw-r--r-- | fs/bcachefs/super_types.h | 2 |
13 files changed, 136 insertions, 69 deletions
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 635086638ba8..f2e9c10e4efe 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -148,14 +148,13 @@ int bch2_btree_mark_key_initial(struct bch_fs *c, enum bkey_type type, { enum bch_data_type data_type = type == BKEY_TYPE_BTREE ? BCH_DATA_BTREE : BCH_DATA_USER; - struct bch_devs_list devs = bch2_bkey_devs(k); int ret = 0; if (test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) || - fsck_err_on(!bch2_sb_has_replicas(c, data_type, devs), c, + fsck_err_on(!bch2_bkey_replicas_marked(c, data_type, k), c, "superblock not marked as containing replicas (type %u)", data_type)) { - ret = bch2_check_mark_super(c, data_type, devs); + ret = bch2_mark_bkey_replicas(c, data_type, k); if (ret) return ret; } diff --git a/fs/bcachefs/btree_update_interior.c b/fs/bcachefs/btree_update_interior.c index c45527a2fa86..6d563bba4af2 100644 --- a/fs/bcachefs/btree_update_interior.c +++ b/fs/bcachefs/btree_update_interior.c @@ -559,8 +559,8 @@ static struct btree_reserve *bch2_btree_reserve_get(struct bch_fs *c, goto err_free; } - ret = bch2_check_mark_super(c, BCH_DATA_BTREE, - bch2_bkey_devs(bkey_i_to_s_c(&b->key))); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_BTREE, + bkey_i_to_s_c(&b->key)); if (ret) goto err_free; @@ -2019,8 +2019,8 @@ int bch2_btree_node_update_key(struct bch_fs *c, struct btree_iter *iter, goto err; } - ret = bch2_check_mark_super(c, BCH_DATA_BTREE, - bch2_extent_devs(extent_i_to_s_c(new_key))); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_BTREE, + extent_i_to_s_c(new_key).s_c); if (ret) goto err_free_update; diff --git a/fs/bcachefs/extents.c b/fs/bcachefs/extents.c index f5dccfad15d6..e9ed165ff6dd 100644 --- a/fs/bcachefs/extents.c +++ b/fs/bcachefs/extents.c @@ -694,7 +694,7 @@ static void btree_ptr_debugcheck(struct bch_fs *c, struct btree *b, goto err; } - if (!bch2_sb_has_replicas(c, BCH_DATA_BTREE, bch2_extent_devs(e))) { + if (!bch2_bkey_replicas_marked(c, BCH_DATA_BTREE, e.s_c)) { bch2_bkey_val_to_text(c, btree_node_type(b), buf, sizeof(buf), k); bch2_fs_bug(c, @@ -1834,7 +1834,7 @@ static void bch2_extent_debugcheck_extent(struct bch_fs *c, struct btree *b, } if (!bkey_extent_is_cached(e.k) && - !bch2_sb_has_replicas(c, BCH_DATA_USER, bch2_extent_devs(e))) { + !bch2_bkey_replicas_marked(c, BCH_DATA_USER, e.s_c)) { bch2_bkey_val_to_text(c, btree_node_type(b), buf, sizeof(buf), e.s_c); bch2_fs_bug(c, diff --git a/fs/bcachefs/extents.h b/fs/bcachefs/extents.h index e8f54f2e9acb..a0cdfbfe3d98 100644 --- a/fs/bcachefs/extents.h +++ b/fs/bcachefs/extents.h @@ -430,6 +430,18 @@ static inline struct bch_devs_list bch2_extent_dirty_devs(struct bkey_s_c_extent return ret; } +static inline struct bch_devs_list bch2_extent_cached_devs(struct bkey_s_c_extent e) +{ + struct bch_devs_list ret = (struct bch_devs_list) { 0 }; + const struct bch_extent_ptr *ptr; + + extent_for_each_ptr(e, ptr) + if (ptr->cached) + ret.devs[ret.nr++] = ptr->dev; + + return ret; +} + static inline struct bch_devs_list bch2_bkey_devs(struct bkey_s_c k) { switch (k.k->type) { @@ -441,6 +453,28 @@ static inline struct bch_devs_list bch2_bkey_devs(struct bkey_s_c k) } } +static inline struct bch_devs_list bch2_bkey_dirty_devs(struct bkey_s_c k) +{ + switch (k.k->type) { + case BCH_EXTENT: + case BCH_EXTENT_CACHED: + return bch2_extent_dirty_devs(bkey_s_c_to_extent(k)); + default: + return (struct bch_devs_list) { .nr = 0 }; + } +} + +static inline struct bch_devs_list bch2_bkey_cached_devs(struct bkey_s_c k) +{ + switch (k.k->type) { + case BCH_EXTENT: + case BCH_EXTENT_CACHED: + return bch2_extent_cached_devs(bkey_s_c_to_extent(k)); + default: + return (struct bch_devs_list) { .nr = 0 }; + } +} + bool bch2_can_narrow_extent_crcs(struct bkey_s_c_extent, struct bch_extent_crc_unpacked); bool bch2_extent_narrow_crcs(struct bkey_i_extent *, struct bch_extent_crc_unpacked); diff --git a/fs/bcachefs/io.c b/fs/bcachefs/io.c index 7cddbccd1938..163a94f1ce67 100644 --- a/fs/bcachefs/io.c +++ b/fs/bcachefs/io.c @@ -268,8 +268,7 @@ static void bch2_write_index(struct closure *cl) } if (!(op->flags & BCH_WRITE_NOMARK_REPLICAS)) { - ret = bch2_check_mark_super(c, BCH_DATA_USER, - bch2_extent_devs(e.c)); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER, e.s_c); if (ret) goto err; } diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index a1e45625704a..7302e4fd2101 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -1046,12 +1046,11 @@ int bch2_journal_read(struct bch_fs *c, struct list_head *list) if (!degraded && (test_bit(BCH_FS_REBUILD_REPLICAS, &c->flags) || - fsck_err_on(!bch2_sb_has_replicas(c, BCH_DATA_JOURNAL, + fsck_err_on(!bch2_replicas_marked(c, BCH_DATA_JOURNAL, i->devs), c, "superblock not marked as containing replicas (type %u)", BCH_DATA_JOURNAL))) { - ret = bch2_check_mark_super(c, BCH_DATA_JOURNAL, - i->devs); + ret = bch2_mark_replicas(c, BCH_DATA_JOURNAL, i->devs); if (ret) return ret; } @@ -2232,7 +2231,7 @@ static void journal_write_done(struct closure *cl) goto err; } - if (bch2_check_mark_super(c, BCH_DATA_JOURNAL, devs)) + if (bch2_mark_replicas(c, BCH_DATA_JOURNAL, devs)) goto err; out: __bch2_time_stats_update(j->write_time, j->write_start_time); @@ -2851,7 +2850,7 @@ int bch2_journal_flush_device(struct journal *j, int dev_idx) seq++; spin_unlock(&j->lock); - ret = bch2_check_mark_super(c, BCH_DATA_JOURNAL, devs); + ret = bch2_mark_replicas(c, BCH_DATA_JOURNAL, devs); spin_lock(&j->lock); } spin_unlock(&j->lock); diff --git a/fs/bcachefs/migrate.c b/fs/bcachefs/migrate.c index 3b8ecca68ca7..9200ed9f591c 100644 --- a/fs/bcachefs/migrate.c +++ b/fs/bcachefs/migrate.c @@ -40,7 +40,7 @@ static int bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags) int ret = 0; mutex_lock(&c->replicas_gc_lock); - bch2_replicas_gc_start(c, 1 << BCH_DATA_USER); + bch2_replicas_gc_start(c, (1 << BCH_DATA_USER)|(1 << BCH_DATA_CACHED)); bch2_btree_iter_init(&iter, c, BTREE_ID_EXTENTS, POS_MIN, BTREE_ITER_PREFETCH); @@ -49,8 +49,7 @@ static int bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags) !(ret = btree_iter_err(k))) { if (!bkey_extent_is_data(k.k) || !bch2_extent_has_device(bkey_s_c_to_extent(k), dev_idx)) { - ret = bch2_check_mark_super(c, BCH_DATA_USER, - bch2_bkey_devs(k)); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER, k); if (ret) break; bch2_btree_iter_next(&iter); @@ -71,8 +70,8 @@ static int bch2_dev_usrdata_drop(struct bch_fs *c, unsigned dev_idx, int flags) */ bch2_extent_normalize(c, e.s); - ret = bch2_check_mark_super(c, BCH_DATA_USER, - bch2_bkey_devs(bkey_i_to_s_c(&tmp.key))); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER, + bkey_i_to_s_c(&tmp.key)); if (ret) break; @@ -128,8 +127,8 @@ retry: dev_idx)) { bch2_btree_iter_set_locks_want(&iter, 0); - ret = bch2_check_mark_super(c, BCH_DATA_BTREE, - bch2_bkey_devs(bkey_i_to_s_c(&b->key))); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_BTREE, + bkey_i_to_s_c(&b->key)); if (ret) goto err; } else { diff --git a/fs/bcachefs/move.c b/fs/bcachefs/move.c index e5a46ba6d03f..54641c791fce 100644 --- a/fs/bcachefs/move.c +++ b/fs/bcachefs/move.c @@ -110,8 +110,8 @@ static int bch2_migrate_index_update(struct bch_write_op *op) bch2_extent_normalize(c, extent_i_to_s(insert).s); bch2_extent_mark_replicas_cached(c, extent_i_to_s(insert)); - ret = bch2_check_mark_super(c, BCH_DATA_USER, - bch2_extent_devs(extent_i_to_s_c(insert))); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER, + extent_i_to_s_c(insert).s_c); if (ret) break; @@ -486,11 +486,11 @@ static int bch2_gc_data_replicas(struct bch_fs *c) int ret; mutex_lock(&c->replicas_gc_lock); - bch2_replicas_gc_start(c, 1 << BCH_DATA_USER); + bch2_replicas_gc_start(c, (1 << BCH_DATA_USER)|(1 << BCH_DATA_CACHED)); for_each_btree_key(&iter, c, BTREE_ID_EXTENTS, POS_MIN, BTREE_ITER_PREFETCH, k) { - ret = bch2_check_mark_super(c, BCH_DATA_USER, bch2_bkey_devs(k)); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_USER, k); if (ret) break; } @@ -514,8 +514,8 @@ static int bch2_gc_btree_replicas(struct bch_fs *c) for (id = 0; id < BTREE_ID_NR; id++) { for_each_btree_node(&iter, c, id, POS_MIN, BTREE_ITER_PREFETCH, b) { - ret = bch2_check_mark_super(c, BCH_DATA_BTREE, - bch2_bkey_devs(bkey_i_to_s_c(&b->key))); + ret = bch2_mark_bkey_replicas(c, BCH_DATA_BTREE, + bkey_i_to_s_c(&b->key)); bch2_btree_iter_cond_resched(&iter); } diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index f333b8fad58a..445ac9a8dd3b 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -744,17 +744,15 @@ void bch2_write_super(struct bch_fs *c) nr_wrote = dev_mask_nr(&sb_written); can_mount_with_written = - bch2_have_enough_devs(c, - __bch2_replicas_status(c, sb_written), - BCH_FORCE_IF_DEGRADED); + bch2_have_enough_devs(__bch2_replicas_status(c, sb_written), + BCH_FORCE_IF_DEGRADED); for (i = 0; i < ARRAY_SIZE(sb_written.d); i++) sb_written.d[i] = ~sb_written.d[i]; can_mount_without_written = - bch2_have_enough_devs(c, - __bch2_replicas_status(c, sb_written), - BCH_FORCE_IF_DEGRADED); + bch2_have_enough_devs(__bch2_replicas_status(c, sb_written), + BCH_FORCE_IF_DEGRADED); /* * If we would be able to mount _without_ the devices we successfully @@ -1052,7 +1050,7 @@ static bool replicas_has_entry(struct bch_replicas_cpu *r, } noinline -static int bch2_check_mark_super_slowpath(struct bch_fs *c, +static int bch2_mark_replicas_slowpath(struct bch_fs *c, struct bch_replicas_cpu_entry new_entry, unsigned max_dev) { @@ -1109,9 +1107,9 @@ err: return ret; } -int bch2_check_mark_super(struct bch_fs *c, - enum bch_data_type data_type, - struct bch_devs_list devs) +int bch2_mark_replicas(struct bch_fs *c, + enum bch_data_type data_type, + struct bch_devs_list devs) { struct bch_replicas_cpu_entry search; struct bch_replicas_cpu *r, *gc_r; @@ -1121,6 +1119,8 @@ int bch2_check_mark_super(struct bch_fs *c, if (!devs.nr) return 0; + BUG_ON(devs.nr >= BCH_REPLICAS_MAX); + devlist_to_replicas(devs, data_type, &search, &max_dev); rcu_read_lock(); @@ -1131,7 +1131,23 @@ int bch2_check_mark_super(struct bch_fs *c, rcu_read_unlock(); return likely(marked) ? 0 - : bch2_check_mark_super_slowpath(c, search, max_dev); + : bch2_mark_replicas_slowpath(c, search, max_dev); +} + +int bch2_mark_bkey_replicas(struct bch_fs *c, + enum bch_data_type data_type, + struct bkey_s_c k) +{ + struct bch_devs_list cached = bch2_bkey_cached_devs(k); + unsigned i; + int ret; + + for (i = 0; i < cached.nr; i++) + if ((ret = bch2_mark_replicas(c, BCH_DATA_CACHED, + bch2_dev_list_single(cached.devs[i])))) + return ret; + + return bch2_mark_replicas(c, data_type, bch2_bkey_dirty_devs(k)); } int bch2_replicas_gc_end(struct bch_fs *c, int err) @@ -1417,7 +1433,7 @@ int bch2_sb_replicas_to_text(struct bch_sb_field_replicas *r, char *buf, size_t /* Query replicas: */ -bool bch2_sb_has_replicas(struct bch_fs *c, +bool bch2_replicas_marked(struct bch_fs *c, enum bch_data_type data_type, struct bch_devs_list devs) { @@ -1438,6 +1454,21 @@ bool bch2_sb_has_replicas(struct bch_fs *c, return ret; } +bool bch2_bkey_replicas_marked(struct bch_fs *c, + enum bch_data_type data_type, + struct bkey_s_c k) +{ + struct bch_devs_list cached = bch2_bkey_cached_devs(k); + unsigned i; + + for (i = 0; i < cached.nr; i++) + if (!bch2_replicas_marked(c, BCH_DATA_CACHED, + bch2_dev_list_single(cached.devs[i]))) + return false; + + return bch2_replicas_marked(c, data_type, bch2_bkey_dirty_devs(k)); +} + struct replicas_status __bch2_replicas_status(struct bch_fs *c, struct bch_devs_mask online_devs) { @@ -1495,29 +1526,26 @@ struct replicas_status bch2_replicas_status(struct bch_fs *c) return __bch2_replicas_status(c, bch2_online_devs(c)); } -bool bch2_have_enough_devs(struct bch_fs *c, - struct replicas_status s, - unsigned flags) +static bool have_enough_devs(struct replicas_status s, + enum bch_data_type type, + bool force_if_degraded, + bool force_if_lost) { - if ((s.replicas[BCH_DATA_JOURNAL].nr_offline || - s.replicas[BCH_DATA_BTREE].nr_offline) && - !(flags & BCH_FORCE_IF_METADATA_DEGRADED)) - return false; - - if ((!s.replicas[BCH_DATA_JOURNAL].nr_online || - !s.replicas[BCH_DATA_BTREE].nr_online) && - !(flags & BCH_FORCE_IF_METADATA_LOST)) - return false; - - if (s.replicas[BCH_DATA_USER].nr_offline && - !(flags & BCH_FORCE_IF_DATA_DEGRADED)) - return false; - - if (!s.replicas[BCH_DATA_USER].nr_online && - !(flags & BCH_FORCE_IF_DATA_LOST)) - return false; + return (!s.replicas[type].nr_offline || force_if_degraded) && + (s.replicas[type].nr_online || force_if_lost); +} - return true; +bool bch2_have_enough_devs(struct replicas_status s, unsigned flags) +{ + return (have_enough_devs(s, BCH_DATA_JOURNAL, + flags & BCH_FORCE_IF_METADATA_DEGRADED, + flags & BCH_FORCE_IF_METADATA_LOST) && + have_enough_devs(s, BCH_DATA_BTREE, + flags & BCH_FORCE_IF_METADATA_DEGRADED, + flags & BCH_FORCE_IF_METADATA_LOST) && + have_enough_devs(s, BCH_DATA_USER, + flags & BCH_FORCE_IF_DATA_DEGRADED, + flags & BCH_FORCE_IF_DATA_LOST)); } unsigned bch2_replicas_online(struct bch_fs *c, bool meta) diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h index eb85410c5f16..d7fecf02f81c 100644 --- a/fs/bcachefs/super-io.h +++ b/fs/bcachefs/super-io.h @@ -139,10 +139,14 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) /* BCH_SB_FIELD_replicas: */ -bool bch2_sb_has_replicas(struct bch_fs *, enum bch_data_type, - struct bch_devs_list); -int bch2_check_mark_super(struct bch_fs *, enum bch_data_type, +bool bch2_replicas_marked(struct bch_fs *, enum bch_data_type, struct bch_devs_list); +bool bch2_bkey_replicas_marked(struct bch_fs *, enum bch_data_type, + struct bkey_s_c); +int bch2_mark_replicas(struct bch_fs *, enum bch_data_type, + struct bch_devs_list); +int bch2_mark_bkey_replicas(struct bch_fs *, enum bch_data_type, + struct bkey_s_c); int bch2_cpu_replicas_to_text(struct bch_replicas_cpu *, char *, size_t); int bch2_sb_replicas_to_text(struct bch_sb_field_replicas *, char *, size_t); @@ -157,7 +161,7 @@ struct replicas_status { struct replicas_status __bch2_replicas_status(struct bch_fs *, struct bch_devs_mask); struct replicas_status bch2_replicas_status(struct bch_fs *); -bool bch2_have_enough_devs(struct bch_fs *, struct replicas_status, unsigned); +bool bch2_have_enough_devs(struct replicas_status, unsigned); unsigned bch2_replicas_online(struct bch_fs *, bool); unsigned bch2_dev_has_data(struct bch_fs *, struct bch_dev *); diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c index f836c199e06b..84d1381546cf 100644 --- a/fs/bcachefs/super.c +++ b/fs/bcachefs/super.c @@ -1262,7 +1262,7 @@ bool bch2_dev_state_allowed(struct bch_fs *c, struct bch_dev *ca, s = __bch2_replicas_status(c, new_online_devs); - return bch2_have_enough_devs(c, s, flags); + return bch2_have_enough_devs(s, flags); default: BUG(); } @@ -1299,7 +1299,7 @@ static bool bch2_fs_may_start(struct bch_fs *c) s = bch2_replicas_status(c); - return bch2_have_enough_devs(c, s, flags); + return bch2_have_enough_devs(s, flags); } static void __bch2_dev_read_only(struct bch_fs *c, struct bch_dev *ca) diff --git a/fs/bcachefs/super.h b/fs/bcachefs/super.h index d0a38cf67508..1718f5c10303 100644 --- a/fs/bcachefs/super.h +++ b/fs/bcachefs/super.h @@ -67,6 +67,11 @@ static inline void bch2_dev_list_add_dev(struct bch_devs_list *devs, devs->devs[devs->nr++] = dev; } +static inline struct bch_devs_list bch2_dev_list_single(unsigned dev) +{ + return (struct bch_devs_list) { .nr = 1, .devs[0] = dev }; +} + static inline struct bch_dev *__bch2_next_dev(struct bch_fs *c, unsigned *iter, const struct bch_devs_mask *mask) { diff --git a/fs/bcachefs/super_types.h b/fs/bcachefs/super_types.h index 966da4afbeda..d76d917cb039 100644 --- a/fs/bcachefs/super_types.h +++ b/fs/bcachefs/super_types.h @@ -15,7 +15,7 @@ struct bch_devs_mask { struct bch_devs_list { u8 nr; - u8 devs[BCH_REPLICAS_MAX]; + u8 devs[BCH_REPLICAS_MAX + 1]; }; struct bch_member_cpu { |