lkml.org 
[lkml]   [2018]   [Feb]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.15 134/163] dm: correctly handle chained bios in dec_pending()
    Date
    4.15-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: NeilBrown <neilb@suse.com>

    commit 8dd601fa8317243be887458c49f6c29c2f3d719f upstream.

    dec_pending() is given an error status (possibly 0) to be recorded
    against a bio. It can be called several times on the one 'struct
    dm_io', and it is careful to only assign a non-zero error to
    io->status. However when it then assigned io->status to bio->bi_status,
    it is not careful and could overwrite a genuine error status with 0.

    This can happen when chained bios are in use. If a bio is chained
    beneath the bio that this dm_io is handling, the child bio might
    complete and set bio->bi_status before the dm_io completes.

    This has been possible since chained bios were introduced in 3.14, and
    has become a lot easier to trigger with commit 18a25da84354 ("dm: ensure
    bio submission follows a depth-first tree walk") as that commit caused
    dm to start using chained bios itself.

    A particular failure mode is that if a bio spans an 'error' target and a
    working target, the 'error' fragment will complete instantly and set the
    ->bi_status, and the other fragment will normally complete a little
    later, and will clear ->bi_status.

    The fix is simply to only assign io_error to bio->bi_status when
    io_error is not zero.

    Reported-and-tested-by: Milan Broz <gmazyland@gmail.com>
    Cc: stable@vger.kernel.org (v3.14+)
    Signed-off-by: NeilBrown <neilb@suse.com>
    Signed-off-by: Mike Snitzer <snitzer@redhat.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    drivers/md/dm.c | 3 ++-
    1 file changed, 2 insertions(+), 1 deletion(-)

    --- a/drivers/md/dm.c
    +++ b/drivers/md/dm.c
    @@ -817,7 +817,8 @@ static void dec_pending(struct dm_io *io
    queue_io(md, bio);
    } else {
    /* done with normal IO or empty flush */
    - bio->bi_status = io_error;
    + if (io_error)
    + bio->bi_status = io_error;
    bio_endio(bio);
    }
    }

    \
     
     \ /
      Last update: 2018-02-21 14:14    [W:5.176 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site