bcachefs: Don't drop replicas when copygcing ec data
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com> Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
af4d05c46b
commit
b88e971e45
@ -979,6 +979,9 @@ static int bucket_set_stripe(struct bch_fs *c, struct bkey_s_c k,
|
|||||||
char buf[200];
|
char buf[200];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
g->ec_redundancy = s->nr_redundant;
|
||||||
|
|
||||||
old = bucket_cmpxchg(g, new, ({
|
old = bucket_cmpxchg(g, new, ({
|
||||||
ret = check_bucket_ref(c, k, ptr, 0, 0, new.gen, new.data_type,
|
ret = check_bucket_ref(c, k, ptr, 0, 0, new.gen, new.data_type,
|
||||||
new.dirty_sectors, new.cached_sectors);
|
new.dirty_sectors, new.cached_sectors);
|
||||||
@ -1010,6 +1013,9 @@ static int bucket_set_stripe(struct bch_fs *c, struct bkey_s_c k,
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
g->ec_redundancy = 0;
|
||||||
|
|
||||||
bch2_dev_usage_update(c, ca, fs_usage, old, new, gc);
|
bch2_dev_usage_update(c, ca, fs_usage, old, new, gc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ struct bucket {
|
|||||||
u8 oldest_gen;
|
u8 oldest_gen;
|
||||||
u8 gc_gen;
|
u8 gc_gen;
|
||||||
unsigned gen_valid:1;
|
unsigned gen_valid:1;
|
||||||
|
u8 ec_redundancy;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bucket_array {
|
struct bucket_array {
|
||||||
@ -123,6 +124,7 @@ struct disk_reservation {
|
|||||||
struct copygc_heap_entry {
|
struct copygc_heap_entry {
|
||||||
u8 dev;
|
u8 dev;
|
||||||
u8 gen;
|
u8 gen;
|
||||||
|
u8 replicas;
|
||||||
u16 fragmentation;
|
u16 fragmentation;
|
||||||
u32 sectors;
|
u32 sectors;
|
||||||
u64 offset;
|
u64 offset;
|
||||||
|
@ -1466,7 +1466,8 @@ static struct promote_op *__promote_alloc(struct bch_fs *c,
|
|||||||
opts,
|
opts,
|
||||||
DATA_PROMOTE,
|
DATA_PROMOTE,
|
||||||
(struct data_opts) {
|
(struct data_opts) {
|
||||||
.target = opts.promote_target
|
.target = opts.promote_target,
|
||||||
|
.nr_replicas = 1,
|
||||||
},
|
},
|
||||||
btree_id, k);
|
btree_id, k);
|
||||||
BUG_ON(ret);
|
BUG_ON(ret);
|
||||||
|
@ -265,8 +265,8 @@ int bch2_migrate_write_init(struct bch_fs *c, struct migrate_write *m,
|
|||||||
BCH_WRITE_DATA_ENCODED|
|
BCH_WRITE_DATA_ENCODED|
|
||||||
BCH_WRITE_FROM_INTERNAL;
|
BCH_WRITE_FROM_INTERNAL;
|
||||||
|
|
||||||
m->op.nr_replicas = 1;
|
m->op.nr_replicas = data_opts.nr_replicas;
|
||||||
m->op.nr_replicas_required = 1;
|
m->op.nr_replicas_required = data_opts.nr_replicas;
|
||||||
m->op.index_update_fn = bch2_migrate_index_update;
|
m->op.index_update_fn = bch2_migrate_index_update;
|
||||||
|
|
||||||
switch (data_cmd) {
|
switch (data_cmd) {
|
||||||
@ -754,6 +754,7 @@ static enum data_cmd rereplicate_pred(struct bch_fs *c, void *arg,
|
|||||||
return DATA_SKIP;
|
return DATA_SKIP;
|
||||||
|
|
||||||
data_opts->target = 0;
|
data_opts->target = 0;
|
||||||
|
data_opts->nr_replicas = 1;
|
||||||
data_opts->btree_insert_flags = 0;
|
data_opts->btree_insert_flags = 0;
|
||||||
return DATA_ADD_REPLICAS;
|
return DATA_ADD_REPLICAS;
|
||||||
}
|
}
|
||||||
@ -769,6 +770,7 @@ static enum data_cmd migrate_pred(struct bch_fs *c, void *arg,
|
|||||||
return DATA_SKIP;
|
return DATA_SKIP;
|
||||||
|
|
||||||
data_opts->target = 0;
|
data_opts->target = 0;
|
||||||
|
data_opts->nr_replicas = 1;
|
||||||
data_opts->btree_insert_flags = 0;
|
data_opts->btree_insert_flags = 0;
|
||||||
data_opts->rewrite_dev = op->migrate.dev;
|
data_opts->rewrite_dev = op->migrate.dev;
|
||||||
return DATA_REWRITE;
|
return DATA_REWRITE;
|
||||||
|
@ -20,7 +20,8 @@ enum data_cmd {
|
|||||||
|
|
||||||
struct data_opts {
|
struct data_opts {
|
||||||
u16 target;
|
u16 target;
|
||||||
unsigned rewrite_dev;
|
u8 rewrite_dev;
|
||||||
|
u8 nr_replicas;
|
||||||
int btree_insert_flags;
|
int btree_insert_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,17 +53,21 @@ static int bucket_offset_cmp(const void *_l, const void *_r, size_t size)
|
|||||||
cmp_int(l->offset, r->offset);
|
cmp_int(l->offset, r->offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __copygc_pred(struct bch_fs *c, struct bkey_s_c k)
|
static enum data_cmd copygc_pred(struct bch_fs *c, void *arg,
|
||||||
|
struct bkey_s_c k,
|
||||||
|
struct bch_io_opts *io_opts,
|
||||||
|
struct data_opts *data_opts)
|
||||||
{
|
{
|
||||||
copygc_heap *h = &c->copygc_heap;
|
copygc_heap *h = &c->copygc_heap;
|
||||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||||
const struct bch_extent_ptr *ptr;
|
const union bch_extent_entry *entry;
|
||||||
|
struct extent_ptr_decoded p;
|
||||||
|
|
||||||
bkey_for_each_ptr(ptrs, ptr) {
|
bkey_for_each_ptr_decode(k.k, ptrs, p, entry) {
|
||||||
struct bch_dev *ca = bch_dev_bkey_exists(c, ptr->dev);
|
struct bch_dev *ca = bch_dev_bkey_exists(c, p.ptr.dev);
|
||||||
struct copygc_heap_entry search = {
|
struct copygc_heap_entry search = {
|
||||||
.dev = ptr->dev,
|
.dev = p.ptr.dev,
|
||||||
.offset = ptr->offset
|
.offset = p.ptr.offset,
|
||||||
};
|
};
|
||||||
|
|
||||||
ssize_t i = eytzinger0_find_le(h->data, h->used,
|
ssize_t i = eytzinger0_find_le(h->data, h->used,
|
||||||
@ -81,27 +85,24 @@ static int __copygc_pred(struct bch_fs *c, struct bkey_s_c k)
|
|||||||
BUG_ON(i != j);
|
BUG_ON(i != j);
|
||||||
#endif
|
#endif
|
||||||
if (i >= 0 &&
|
if (i >= 0 &&
|
||||||
ptr->offset < h->data[i].offset + ca->mi.bucket_size &&
|
p.ptr.offset < h->data[i].offset + ca->mi.bucket_size &&
|
||||||
ptr->gen == h->data[i].gen)
|
p.ptr.gen == h->data[i].gen) {
|
||||||
return ptr->dev;
|
data_opts->target = io_opts->background_target;
|
||||||
|
data_opts->nr_replicas = 1;
|
||||||
|
data_opts->btree_insert_flags = BTREE_INSERT_USE_RESERVE;
|
||||||
|
data_opts->rewrite_dev = p.ptr.dev;
|
||||||
|
|
||||||
|
if (p.has_ec) {
|
||||||
|
struct stripe *m = genradix_ptr(&c->stripes[0], p.ec.idx);
|
||||||
|
|
||||||
|
data_opts->nr_replicas += m->nr_redundant;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DATA_REWRITE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return DATA_SKIP;
|
||||||
}
|
|
||||||
|
|
||||||
static enum data_cmd copygc_pred(struct bch_fs *c, void *arg,
|
|
||||||
struct bkey_s_c k,
|
|
||||||
struct bch_io_opts *io_opts,
|
|
||||||
struct data_opts *data_opts)
|
|
||||||
{
|
|
||||||
int dev_idx = __copygc_pred(c, k);
|
|
||||||
if (dev_idx < 0)
|
|
||||||
return DATA_SKIP;
|
|
||||||
|
|
||||||
data_opts->target = io_opts->background_target;
|
|
||||||
data_opts->btree_insert_flags = BTREE_INSERT_USE_RESERVE;
|
|
||||||
data_opts->rewrite_dev = dev_idx;
|
|
||||||
return DATA_REWRITE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool have_copygc_reserve(struct bch_dev *ca)
|
static bool have_copygc_reserve(struct bch_dev *ca)
|
||||||
@ -168,7 +169,8 @@ static int bch2_copygc(struct bch_fs *c)
|
|||||||
buckets = bucket_array(ca);
|
buckets = bucket_array(ca);
|
||||||
|
|
||||||
for (b = buckets->first_bucket; b < buckets->nbuckets; b++) {
|
for (b = buckets->first_bucket; b < buckets->nbuckets; b++) {
|
||||||
struct bucket_mark m = READ_ONCE(buckets->b[b].mark);
|
struct bucket *g = buckets->b + b;
|
||||||
|
struct bucket_mark m = READ_ONCE(g->mark);
|
||||||
struct copygc_heap_entry e;
|
struct copygc_heap_entry e;
|
||||||
|
|
||||||
if (m.owned_by_allocator ||
|
if (m.owned_by_allocator ||
|
||||||
@ -177,9 +179,12 @@ static int bch2_copygc(struct bch_fs *c)
|
|||||||
bucket_sectors_used(m) >= ca->mi.bucket_size)
|
bucket_sectors_used(m) >= ca->mi.bucket_size)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
WARN_ON(m.stripe && !g->ec_redundancy);
|
||||||
|
|
||||||
e = (struct copygc_heap_entry) {
|
e = (struct copygc_heap_entry) {
|
||||||
.dev = dev_idx,
|
.dev = dev_idx,
|
||||||
.gen = m.gen,
|
.gen = m.gen,
|
||||||
|
.replicas = 1 + g->ec_redundancy,
|
||||||
.fragmentation = bucket_sectors_used(m) * (1U << 15)
|
.fragmentation = bucket_sectors_used(m) * (1U << 15)
|
||||||
/ ca->mi.bucket_size,
|
/ ca->mi.bucket_size,
|
||||||
.sectors = bucket_sectors_used(m),
|
.sectors = bucket_sectors_used(m),
|
||||||
@ -196,11 +201,11 @@ static int bch2_copygc(struct bch_fs *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (i = h->data; i < h->data + h->used; i++)
|
for (i = h->data; i < h->data + h->used; i++)
|
||||||
sectors_to_move += i->sectors;
|
sectors_to_move += i->sectors * i->replicas;
|
||||||
|
|
||||||
while (sectors_to_move > sectors_reserved) {
|
while (sectors_to_move > sectors_reserved) {
|
||||||
BUG_ON(!heap_pop(h, e, -fragmentation_cmp, NULL));
|
BUG_ON(!heap_pop(h, e, -fragmentation_cmp, NULL));
|
||||||
sectors_to_move -= e.sectors;
|
sectors_to_move -= e.sectors * e.replicas;
|
||||||
}
|
}
|
||||||
|
|
||||||
buckets_to_move = h->used;
|
buckets_to_move = h->used;
|
||||||
|
@ -73,6 +73,7 @@ static enum data_cmd rebalance_pred(struct bch_fs *c, void *arg,
|
|||||||
{
|
{
|
||||||
if (__bch2_rebalance_pred(c, k, io_opts) >= 0) {
|
if (__bch2_rebalance_pred(c, k, io_opts) >= 0) {
|
||||||
data_opts->target = io_opts->background_target;
|
data_opts->target = io_opts->background_target;
|
||||||
|
data_opts->nr_replicas = 1;
|
||||||
data_opts->btree_insert_flags = 0;
|
data_opts->btree_insert_flags = 0;
|
||||||
return DATA_ADD_REPLICAS;
|
return DATA_ADD_REPLICAS;
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user