• K
    dm: add request based barrier support · d0bcb878
    Kiyoshi Ueda 提交于
    This patch adds barrier support for request-based dm.
    
    CORE DESIGN
    
    The design is basically same as bio-based dm, which emulates barrier
    by mapping empty barrier bios before/after a barrier I/O.
    But request-based dm has been using struct request_queue for I/O
    queueing, so the block-layer's barrier mechanism can be used.
    
    o Summary of the block-layer's behavior (which is depended by dm-core)
      Request-based dm uses QUEUE_ORDERED_DRAIN_FLUSH ordered mode for
      I/O barrier.  It means that when an I/O requiring barrier is found
      in the request_queue, the block-layer makes pre-flush request and
      post-flush request just before and just after the I/O respectively.
    
      After the ordered sequence starts, the block-layer waits for all
      in-flight I/Os to complete, then gives drivers the pre-flush request,
      the barrier I/O and the post-flush request one by one.
      It means that the request_queue is stopped automatically by
      the block-layer until drivers complete each sequence.
    
    o dm-core
      For the barrier I/O, treats it as a normal I/O, so no additional
      code is needed.
    
      For the pre/post-flush request, flushes caches by the followings:
        1. Make the number of empty barrier requests required by target's
           num_flush_requests, and map them (dm_rq_barrier()).
        2. Waits for the mapped barriers to complete (dm_rq_barrier()).
           If error has occurred, save the error value to md->barrier_error
           (dm_end_request()).
           (*) Basically, the first reported error is taken.
               But -EOPNOTSUPP supersedes any error and DM_ENDIO_REQUEUE
               follows.
        3. Requeue the pre/post-flush request if the error value is
           DM_ENDIO_REQUEUE.  Otherwise, completes with the error value
           (dm_rq_barrier_work()).
      The pre/post-flush work above is done in the kernel thread (kdmflush)
      context, since memory allocation which might sleep is needed in
      dm_rq_barrier() but sleep is not allowed in dm_request_fn(), which is
      an irq-disabled context.
      Also, clones of the pre/post-flush request share an original, so
      such clones can't be completed using the softirq context.
      Instead, complete them in the context of underlying device drivers.
      It should be safe since there is no I/O dispatching during
      the completion of such clones.
    
      For suspend, the workqueue of kdmflush needs to be flushed after
      the request_queue has been stopped.  Otherwise, the next flush work
      can be kicked even after the suspend completes.
    
    TARGET INTERFACE
    
    No new interface is added.
    Just use the existing num_flush_requests in struct target_type
    as same as bio-based dm.
    Signed-off-by: NKiyoshi Ueda <k-ueda@ct.jp.nec.com>
    Signed-off-by: NJun'ichi Nomura <j-nomura@ce.jp.nec.com>
    Signed-off-by: NAlasdair G Kergon <agk@redhat.com>
    d0bcb878
dm.c 60.2 KB