[dm-devel] [PATCH v2 5/9] dm: improve noclone bio support
Mikulas Patocka
mpatocka at redhat.com
Fri Feb 22 10:59:01 UTC 2019
Hi
I've fonud out that this patch causes timeout in the lvm test
shell/activate-missing-segment.sh and some others.
Mikulas
On Wed, 20 Feb 2019, Mike Snitzer wrote:
> Leverage fact that dm_queue_split() enables use of noclone support even
> for targets that require additional splitting (via ti->max_io_len).
>
> To achieve this move noclone processing from dm_make_request() to
> dm_process_bio() and check if bio->bi_end_io is already set to
> noclone_endio. This also fixes dm_wq_work() to be able to support
> noclone bios (because it calls dm_process_bio()).
>
> While at it, clean up ->map() return processing to be comparable to
> __map_bio() and add some code comments that explain why certain
> conditionals exist to prevent the use of noclone.
>
> Signed-off-by: Mike Snitzer <snitzer at redhat.com>
> ---
> drivers/md/dm.c | 103 ++++++++++++++++++++++++++++++++++----------------------
> 1 file changed, 62 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/md/dm.c b/drivers/md/dm.c
> index 57919f211acc..d84735be6927 100644
> --- a/drivers/md/dm.c
> +++ b/drivers/md/dm.c
> @@ -1764,14 +1764,75 @@ static blk_qc_t dm_process_bio(struct mapped_device *md,
> * If in ->make_request_fn we need to use blk_queue_split(), otherwise
> * queue_limits for abnormal requests (e.g. discard, writesame, etc)
> * won't be imposed.
> + *
> + * For normal READ and WRITE requests we benefit from upfront splitting
> + * via dm_queue_split() because we can then leverage noclone support below.
> */
> - if (current->bio_list) {
> + if (current->bio_list && (bio->bi_end_io != noclone_endio)) {
> + /*
> + * It is fine to use {blk,dm}_queue_split() before opting to use noclone
> + * because any ->bi_private and ->bi_end_io will get saved off below.
> + * Once noclone_endio() is called the bio_chain's endio will kick in.
> + * - __split_and_process_bio() can split further, but any targets that
> + * require late _DM_ initiated splitting (e.g. dm_accept_partial_bio()
> + * callers) shouldn't set ti->no_clone.
> + */
> if (is_abnormal_io(bio))
> blk_queue_split(md->queue, &bio);
> else
> dm_queue_split(md, ti, &bio);
> }
>
> + if (dm_table_supports_noclone(map) &&
> + (bio_op(bio) == REQ_OP_READ || bio_op(bio) == REQ_OP_WRITE) &&
> + likely(!(bio->bi_opf & REQ_PREFLUSH)) &&
> + likely(!bio_integrity(bio)) && /* integrity requires specialized processing */
> + likely(!dm_stats_used(&md->stats))) { /* noclone doesn't support dm-stats */
> + int r;
> + struct dm_noclone *noclone;
> +
> + /* Already been here if bio->bi_end_io is noclone_endio, reentered via dm_wq_work() */
> + if (bio->bi_end_io != noclone_endio) {
> + noclone = kmalloc_node(sizeof(*noclone), GFP_NOWAIT, md->numa_node_id);
> + if (unlikely(!noclone))
> + goto no_fast_path;
> +
> + noclone->md = md;
> + noclone->start_time = jiffies;
> + noclone->orig_bi_end_io = bio->bi_end_io;
> + noclone->orig_bi_private = bio->bi_private;
> + bio->bi_end_io = noclone_endio;
> + bio->bi_private = noclone;
> + } else
> + noclone = bio->bi_private;
> +
> + start_io_acct(md, bio);
> + r = ti->type->map(ti, bio);
> + switch (r) {
> + case DM_MAPIO_SUBMITTED:
> + break;
> + case DM_MAPIO_REMAPPED:
> + /* the bio has been remapped so dispatch it */
> + if (md->type == DM_TYPE_NVME_BIO_BASED)
> + ret = direct_make_request(bio);
> + else
> + ret = generic_make_request(bio);
> + break;
> + case DM_MAPIO_KILL:
> + bio_io_error(bio);
> + break;
> + case DM_MAPIO_REQUEUE:
> + bio->bi_status = BLK_STS_DM_REQUEUE;
> + noclone_endio(bio);
> + break;
> + default:
> + DMWARN("unimplemented target map return value: %d", r);
> + BUG();
> + }
> +
> + return ret;
> + }
> +no_fast_path:
> if (dm_get_md_type(md) == DM_TYPE_NVME_BIO_BASED)
> return __process_bio(md, map, bio, ti);
> else
> @@ -1798,48 +1859,8 @@ static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
> return ret;
> }
>
> - if (dm_table_supports_noclone(map) &&
> - (bio_op(bio) == REQ_OP_READ || bio_op(bio) == REQ_OP_WRITE) &&
> - likely(!(bio->bi_opf & REQ_PREFLUSH)) &&
> - !bio_flagged(bio, BIO_CHAIN) &&
> - likely(!bio_integrity(bio)) &&
> - likely(!dm_stats_used(&md->stats))) {
> - int r;
> - struct dm_noclone *noclone;
> - struct dm_target *ti = dm_table_find_target(map, bio->bi_iter.bi_sector);
> - if (unlikely(!dm_target_is_valid(ti)))
> - goto no_fast_path;
> - if (unlikely(bio_sectors(bio) > max_io_len(bio->bi_iter.bi_sector, ti)))
> - goto no_fast_path;
> - noclone = kmalloc_node(sizeof(*noclone), GFP_NOWAIT, md->numa_node_id);
> - if (unlikely(!noclone))
> - goto no_fast_path;
> - noclone->md = md;
> - noclone->start_time = jiffies;
> - noclone->orig_bi_end_io = bio->bi_end_io;
> - noclone->orig_bi_private = bio->bi_private;
> - bio->bi_end_io = noclone_endio;
> - bio->bi_private = noclone;
> - start_io_acct(md, bio);
> - r = ti->type->map(ti, bio);
> - ret = BLK_QC_T_NONE;
> - if (likely(r == DM_MAPIO_REMAPPED)) {
> - ret = generic_make_request(bio);
> - } else if (likely(r == DM_MAPIO_SUBMITTED)) {
> - } else if (r == DM_MAPIO_KILL) {
> - bio->bi_status = BLK_STS_IOERR;
> - noclone_endio(bio);
> - } else {
> - DMWARN("unimplemented target map return value: %d", r);
> - BUG();
> - }
> - goto put_table_ret;
> - }
> -
> -no_fast_path:
> ret = dm_process_bio(md, map, bio);
>
> -put_table_ret:
> dm_put_live_table(md, srcu_idx);
> return ret;
> }
> --
> 2.15.0
>
More information about the dm-devel
mailing list