summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-02-09 11:52:01 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-02-09 12:20:35 -0500
commit9d3f6be80f7f9f68a85ea1135c742e66703cea0d (patch)
treeb47b0d4f8508a76de8314872c4f4243dfb5d5a8c
parent8d2c1b6408d46b54234e3c6011fe2b7dc0218788 (diff)
bcachefs: fix an inconsistency with replicas tracking
-rw-r--r--fs/bcachefs/btree_gc.c5
-rw-r--r--fs/bcachefs/btree_update_interior.c8
-rw-r--r--fs/bcachefs/extents.c4
-rw-r--r--fs/bcachefs/extents.h34
-rw-r--r--fs/bcachefs/io.c3
-rw-r--r--fs/bcachefs/journal.c9
-rw-r--r--fs/bcachefs/migrate.c13
-rw-r--r--fs/bcachefs/move.c12
-rw-r--r--fs/bcachefs/super-io.c94
-rw-r--r--fs/bcachefs/super-io.h12
-rw-r--r--fs/bcachefs/super.c4
-rw-r--r--fs/bcachefs/super.h5
-rw-r--r--fs/bcachefs/super_types.h2
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 {