bcachefs: Data update support for unwritten extents
The data update path requires special support for unwritten extents - we still need to be able to move them, but there's no need to read or write anything. This patch adds a new error code to tell bch2_move_extent() that we're short circuiting the read, and adds bch2_update_unwritten_extent() to create a reservation then call __bch2_data_update_index_update(). Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
792031116b
commit
4dcd1cae72
@ -96,10 +96,10 @@ static void bch2_bkey_mark_dev_cached(struct bkey_s k, unsigned dev)
|
|||||||
ptr->cached = true;
|
ptr->cached = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bch2_data_update_index_update(struct bch_write_op *op)
|
static int __bch2_data_update_index_update(struct btree_trans *trans,
|
||||||
|
struct bch_write_op *op)
|
||||||
{
|
{
|
||||||
struct bch_fs *c = op->c;
|
struct bch_fs *c = op->c;
|
||||||
struct btree_trans trans;
|
|
||||||
struct btree_iter iter;
|
struct btree_iter iter;
|
||||||
struct data_update *m =
|
struct data_update *m =
|
||||||
container_of(op, struct data_update, op);
|
container_of(op, struct data_update, op);
|
||||||
@ -111,9 +111,7 @@ int bch2_data_update_index_update(struct bch_write_op *op)
|
|||||||
bch2_bkey_buf_init(&_insert);
|
bch2_bkey_buf_init(&_insert);
|
||||||
bch2_bkey_buf_realloc(&_insert, c, U8_MAX);
|
bch2_bkey_buf_realloc(&_insert, c, U8_MAX);
|
||||||
|
|
||||||
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024);
|
bch2_trans_iter_init(trans, &iter, m->btree_id,
|
||||||
|
|
||||||
bch2_trans_iter_init(&trans, &iter, m->btree_id,
|
|
||||||
bkey_start_pos(&bch2_keylist_front(keys)->k),
|
bkey_start_pos(&bch2_keylist_front(keys)->k),
|
||||||
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
|
BTREE_ITER_SLOTS|BTREE_ITER_INTENT);
|
||||||
|
|
||||||
@ -130,7 +128,7 @@ int bch2_data_update_index_update(struct bch_write_op *op)
|
|||||||
s64 i_sectors_delta = 0, disk_sectors_delta = 0;
|
s64 i_sectors_delta = 0, disk_sectors_delta = 0;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
bch2_trans_begin(&trans);
|
bch2_trans_begin(trans);
|
||||||
|
|
||||||
k = bch2_btree_iter_peek_slot(&iter);
|
k = bch2_btree_iter_peek_slot(&iter);
|
||||||
ret = bkey_err(k);
|
ret = bkey_err(k);
|
||||||
@ -211,7 +209,7 @@ int bch2_data_update_index_update(struct bch_write_op *op)
|
|||||||
bch2_bkey_narrow_crcs(insert, (struct bch_extent_crc_unpacked) { 0 });
|
bch2_bkey_narrow_crcs(insert, (struct bch_extent_crc_unpacked) { 0 });
|
||||||
bch2_extent_normalize(c, bkey_i_to_s(insert));
|
bch2_extent_normalize(c, bkey_i_to_s(insert));
|
||||||
|
|
||||||
ret = bch2_sum_sector_overwrites(&trans, &iter, insert,
|
ret = bch2_sum_sector_overwrites(trans, &iter, insert,
|
||||||
&should_check_enospc,
|
&should_check_enospc,
|
||||||
&i_sectors_delta,
|
&i_sectors_delta,
|
||||||
&disk_sectors_delta);
|
&disk_sectors_delta);
|
||||||
@ -229,11 +227,11 @@ int bch2_data_update_index_update(struct bch_write_op *op)
|
|||||||
|
|
||||||
next_pos = insert->k.p;
|
next_pos = insert->k.p;
|
||||||
|
|
||||||
ret = insert_snapshot_whiteouts(&trans, m->btree_id,
|
ret = insert_snapshot_whiteouts(trans, m->btree_id,
|
||||||
k.k->p, insert->k.p) ?:
|
k.k->p, insert->k.p) ?:
|
||||||
bch2_trans_update(&trans, &iter, insert,
|
bch2_trans_update(trans, &iter, insert,
|
||||||
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
|
BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?:
|
||||||
bch2_trans_commit(&trans, &op->res,
|
bch2_trans_commit(trans, &op->res,
|
||||||
NULL,
|
NULL,
|
||||||
BTREE_INSERT_NOFAIL|
|
BTREE_INSERT_NOFAIL|
|
||||||
m->data_opts.btree_insert_flags);
|
m->data_opts.btree_insert_flags);
|
||||||
@ -270,14 +268,26 @@ nomatch:
|
|||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
bch2_trans_iter_exit(&trans, &iter);
|
bch2_trans_iter_exit(trans, &iter);
|
||||||
bch2_trans_exit(&trans);
|
|
||||||
bch2_bkey_buf_exit(&_insert, c);
|
bch2_bkey_buf_exit(&_insert, c);
|
||||||
bch2_bkey_buf_exit(&_new, c);
|
bch2_bkey_buf_exit(&_new, c);
|
||||||
BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart));
|
BUG_ON(bch2_err_matches(ret, BCH_ERR_transaction_restart));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bch2_data_update_index_update(struct bch_write_op *op)
|
||||||
|
{
|
||||||
|
struct bch_fs *c = op->c;
|
||||||
|
struct btree_trans trans;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 1024);
|
||||||
|
ret = __bch2_data_update_index_update(&trans, op);
|
||||||
|
bch2_trans_exit(&trans);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void bch2_data_update_read_done(struct data_update *m,
|
void bch2_data_update_read_done(struct data_update *m,
|
||||||
struct bch_extent_crc_unpacked crc)
|
struct bch_extent_crc_unpacked crc)
|
||||||
{
|
{
|
||||||
@ -299,6 +309,86 @@ void bch2_data_update_exit(struct data_update *update)
|
|||||||
bch2_bio_free_pages_pool(c, &update->op.wbio.bio);
|
bch2_bio_free_pages_pool(c, &update->op.wbio.bio);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bch2_update_unwritten_extent(struct btree_trans *trans,
|
||||||
|
struct data_update *update)
|
||||||
|
{
|
||||||
|
struct bch_fs *c = update->op.c;
|
||||||
|
struct bio *bio = &update->op.wbio.bio;
|
||||||
|
struct bkey_i_extent *e;
|
||||||
|
struct write_point *wp;
|
||||||
|
struct bch_extent_ptr *ptr;
|
||||||
|
struct closure cl;
|
||||||
|
struct btree_iter iter;
|
||||||
|
struct bkey_s_c k;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
closure_init_stack(&cl);
|
||||||
|
bch2_keylist_init(&update->op.insert_keys, update->op.inline_keys);
|
||||||
|
|
||||||
|
while (bio_sectors(bio)) {
|
||||||
|
unsigned sectors = bio_sectors(bio);
|
||||||
|
|
||||||
|
bch2_trans_iter_init(trans, &iter, update->btree_id, update->op.pos,
|
||||||
|
BTREE_ITER_SLOTS);
|
||||||
|
ret = lockrestart_do(trans, ({
|
||||||
|
k = bch2_btree_iter_peek_slot(&iter);
|
||||||
|
bkey_err(k);
|
||||||
|
}));
|
||||||
|
bch2_trans_iter_exit(trans, &iter);
|
||||||
|
|
||||||
|
if (ret || !bch2_extents_match(k, bkey_i_to_s_c(update->k.k)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
e = bkey_extent_init(update->op.insert_keys.top);
|
||||||
|
e->k.p = update->op.pos;
|
||||||
|
|
||||||
|
ret = bch2_alloc_sectors_start_trans(trans,
|
||||||
|
update->op.target,
|
||||||
|
false,
|
||||||
|
update->op.write_point,
|
||||||
|
&update->op.devs_have,
|
||||||
|
update->op.nr_replicas,
|
||||||
|
update->op.nr_replicas,
|
||||||
|
update->op.alloc_reserve,
|
||||||
|
0, &cl, &wp);
|
||||||
|
if (bch2_err_matches(ret, BCH_ERR_operation_blocked)) {
|
||||||
|
bch2_trans_unlock(trans);
|
||||||
|
closure_sync(&cl);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sectors = min(sectors, wp->sectors_free);
|
||||||
|
|
||||||
|
bch2_key_resize(&e->k, sectors);
|
||||||
|
|
||||||
|
bch2_open_bucket_get(c, wp, &update->op.open_buckets);
|
||||||
|
bch2_alloc_sectors_append_ptrs(c, wp, &e->k_i, sectors, false);
|
||||||
|
bch2_alloc_sectors_done(c, wp);
|
||||||
|
|
||||||
|
bio_advance(bio, sectors << 9);
|
||||||
|
update->op.pos.offset += sectors;
|
||||||
|
|
||||||
|
extent_for_each_ptr(extent_i_to_s(e), ptr)
|
||||||
|
ptr->unwritten = true;
|
||||||
|
bch2_keylist_push(&update->op.insert_keys);
|
||||||
|
|
||||||
|
ret = __bch2_data_update_index_update(trans, &update->op);
|
||||||
|
|
||||||
|
bch2_open_buckets_put(c, &update->op.open_buckets);
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((atomic_read(&cl.remaining) & CLOSURE_REMAINING_MASK) != 1) {
|
||||||
|
bch2_trans_unlock(trans);
|
||||||
|
closure_sync(&cl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int bch2_data_update_init(struct bch_fs *c, struct data_update *m,
|
int bch2_data_update_init(struct bch_fs *c, struct data_update *m,
|
||||||
struct write_point_specifier wp,
|
struct write_point_specifier wp,
|
||||||
struct bch_io_opts io_opts,
|
struct bch_io_opts io_opts,
|
||||||
@ -376,6 +466,10 @@ int bch2_data_update_init(struct bch_fs *c, struct data_update *m,
|
|||||||
hweight32(m->data_opts.rewrite_ptrs) + m->data_opts.extra_replicas;
|
hweight32(m->data_opts.rewrite_ptrs) + m->data_opts.extra_replicas;
|
||||||
|
|
||||||
BUG_ON(!m->op.nr_replicas);
|
BUG_ON(!m->op.nr_replicas);
|
||||||
|
|
||||||
|
/* Special handling required: */
|
||||||
|
if (bkey_extent_is_unwritten(k))
|
||||||
|
return -BCH_ERR_unwritten_extent_update;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ void bch2_data_update_read_done(struct data_update *,
|
|||||||
struct bch_extent_crc_unpacked);
|
struct bch_extent_crc_unpacked);
|
||||||
|
|
||||||
void bch2_data_update_exit(struct data_update *);
|
void bch2_data_update_exit(struct data_update *);
|
||||||
|
void bch2_update_unwritten_extent(struct btree_trans *, struct data_update *);
|
||||||
int bch2_data_update_init(struct bch_fs *, struct data_update *,
|
int bch2_data_update_init(struct bch_fs *, struct data_update *,
|
||||||
struct write_point_specifier,
|
struct write_point_specifier,
|
||||||
struct bch_io_opts, struct data_update_opts,
|
struct bch_io_opts, struct data_update_opts,
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
x(BCH_ERR_fsck, fsck_repair_impossible) \
|
x(BCH_ERR_fsck, fsck_repair_impossible) \
|
||||||
x(0, need_snapshot_cleanup) \
|
x(0, need_snapshot_cleanup) \
|
||||||
x(0, need_topology_repair) \
|
x(0, need_topology_repair) \
|
||||||
|
x(0, unwritten_extent_update) \
|
||||||
x(EINVAL, device_state_not_allowed) \
|
x(EINVAL, device_state_not_allowed) \
|
||||||
x(EINVAL, member_info_missing) \
|
x(EINVAL, member_info_missing) \
|
||||||
x(EINVAL, mismatched_block_size) \
|
x(EINVAL, mismatched_block_size) \
|
||||||
|
@ -295,7 +295,7 @@ static int bch2_move_extent(struct btree_trans *trans,
|
|||||||
|
|
||||||
ret = bch2_data_update_init(c, &io->write, ctxt->wp, io_opts,
|
ret = bch2_data_update_init(c, &io->write, ctxt->wp, io_opts,
|
||||||
data_opts, btree_id, k);
|
data_opts, btree_id, k);
|
||||||
if (ret)
|
if (ret && ret != -BCH_ERR_unwritten_extent_update)
|
||||||
goto err_free_pages;
|
goto err_free_pages;
|
||||||
|
|
||||||
io->write.ctxt = ctxt;
|
io->write.ctxt = ctxt;
|
||||||
@ -303,6 +303,15 @@ static int bch2_move_extent(struct btree_trans *trans,
|
|||||||
|
|
||||||
atomic64_inc(&ctxt->stats->keys_moved);
|
atomic64_inc(&ctxt->stats->keys_moved);
|
||||||
atomic64_add(k.k->size, &ctxt->stats->sectors_moved);
|
atomic64_add(k.k->size, &ctxt->stats->sectors_moved);
|
||||||
|
|
||||||
|
if (ret == -BCH_ERR_unwritten_extent_update) {
|
||||||
|
bch2_update_unwritten_extent(trans, &io->write);
|
||||||
|
move_free(io);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BUG_ON(ret);
|
||||||
|
|
||||||
this_cpu_add(c->counters[BCH_COUNTER_io_move], k.k->size);
|
this_cpu_add(c->counters[BCH_COUNTER_io_move], k.k->size);
|
||||||
this_cpu_add(c->counters[BCH_COUNTER_move_extent_read], k.k->size);
|
this_cpu_add(c->counters[BCH_COUNTER_move_extent_read], k.k->size);
|
||||||
trace_move_extent_read(k.k);
|
trace_move_extent_read(k.k);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user