[dm-devel] Re: [PATCH 1/7] dm core: add core functions for request-based dm
Hannes Reinecke
hare at suse.de
Fri Apr 24 08:45:52 UTC 2009
Kiyoshi Ueda wrote:
> This patch adds core functions for request-based dm.
>
> When struct mapped device (md) is initialized, md->queue has
> an I/O scheduler and the following functions are used for
> request-based dm as the queue functions:
> make_request_fn: dm_make_request()
> pref_fn: dm_prep_fn()
> request_fn: dm_request_fn()
> softirq_done_fn: dm_softirq_done()
> lld_busy_fn: dm_lld_busy()
> Actual initializations are done in another patch (PATCH 3).
>
> Below is a brief summary of how request-based dm behaves, including:
> - making request from bio
> - cloning, mapping and dispatching request
> - completing request and bio
> - suspending md
> - resuming md
>
>
> bio to request
> ==============
> md->queue->make_request_fn() (dm_make_request()) calls__make_request()
> for a bio submitted to the md.
> Then, the bio is kept in the queue as a new request or merged into
> another request in the queue if possible.
>
>
> Cloning and Mapping
> ===================
> Cloning and mapping are done in md->queue->request_fn() (dm_request_fn()),
> when requests are dispatched after they are sorted by the I/O scheduler.
>
> dm_request_fn() checks busy state of underlying devices using
> target's busy() function and stops dispatching requests to keep them
> on the dm device's queue if busy.
> It helps better I/O merging, since no merge is done for a request
> once it is dispatched to underlying devices.
>
> Actual cloning and mapping are done in dm_prep_fn() and map_request()
> called from dm_request_fn().
> dm_prep_fn() clones not only request but also bios of the request
> so that dm can hold bio completion in error cases and prevent
> the bio submitter from noticing the error.
> (See the "Completion" section below for details.)
>
> After the cloning, the clone is mapped by target's map_rq() function
> and inserted to underlying device's queue using
> blk_insert_cloned_request().
>
>
> Completion
> ==========
> Request completion can be hooked by rq->end_io(), but then, all bios
> in the request will have been completed even error cases, and the bio
> submitter will have noticed the error.
> To prevent the bio completion in error cases, request-based dm clones
> both bio and request and hooks both bio->bi_end_io() and rq->end_io():
> bio->bi_end_io(): end_clone_bio()
> rq->end_io(): end_clone_request()
>
> Summary of the request completion flow is below:
> blk_end_request() for a clone request
> => __end_that_request_first()
> => bio->bi_end_io() == end_clone_bio() for each clone bio
> => Free the clone bio
> => Success: Complete the original bio (blk_update_request())
> Error: Don't complete the original bio
> => end_that_request_last()
> => rq->end_io() == end_clone_request()
> => blk_complete_request()
> => dm_softirq_done()
> => Free the clone request
> => Success: Complete the original request (blk_end_request())
> Error: Requeue the original request
>
> end_clone_bio() completes the original request on the size of
> the original bio in successful cases.
> Even if all bios in the original request are completed by that
> completion, the original request must not be completed yet to keep
> the ordering of request completion for the stacking.
> So end_clone_bio() uses blk_update_request() instead of
> blk_end_request().
> In error cases, end_clone_bio() doesn't complete the original bio.
> It just frees the cloned bio and gives over the error handling to
> end_clone_request().
>
> end_clone_request(), which is called with queue lock held, completes
> the clone request and the original request in a softirq context
> (dm_softirq_done()), which has no queue lock, to avoid a deadlock
> issue on submission of another request during the completion:
> - The submitted request may be mapped to the same device
> - Request submission requires queue lock, but the queue lock
> has been held by itself and it doesn't know that
>
> The clone request has no clone bio when dm_softirq_done() is called.
> So target drivers can't resubmit it again even error cases.
> Instead, they can ask dm core for requeueing and remapping
> the original request in that cases.
>
>
> suspend
> =======
> Request-based dm uses stopping md->queue as suspend of the md.
> For noflush suspend, just stops md->queue.
>
> For flush suspend, inserts a marker request to the tail of md->queue.
> And dispatches all requests in md->queue until the marker comes to
> the front of md->queue. Then, stops dispatching request and waits
> for the all dispatched requests to complete.
> After that, completes the marker request, stops md->queue and
> wake up the waiter on the suspend queue, md->wait.
>
>
> resume
> ======
> Starts md->queue.
>
>
> Signed-off-by: Kiyoshi Ueda <k-ueda at ct.jp.nec.com>
> Signed-off-by: Jun'ichi Nomura <j-nomura at ce.jp.nec.com>
Acked-by: Hannes Reinecke <hare at suse.de>
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare at suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: Markus Rex, HRB 16746 (AG Nürnberg)
More information about the dm-devel
mailing list