lkml.org 
[lkml]   [2009]   [Mar]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 029/114] md: avoid races when stopping resync.
    2.6.28-stable review patch.  If anyone has any objections, please let us know.

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

    From: NeilBrown <neilb@suse.de>

    commit 73d5c38a9536142e062c35997b044e89166e063b upstream.

    There has been a race in raid10 and raid1 for a long time
    which has only recently started showing up due to a scheduler changed.

    When a sync_read request finishes, as soon as reschedule_retry
    is called, another thread can mark the resync request as having
    completed, so md_do_sync can finish, ->stop can be called, and
    ->conf can be freed. So using conf after reschedule_retry is not
    safe.

    Similarly, when finishing a sync_write, calling md_done_sync must be
    the last thing we do, as it allows a chain of events which will free
    conf and other data structures.

    The first of these requires action in raid10.c
    The second requires action in raid1.c and raid10.c

    Signed-off-by: NeilBrown <neilb@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/md/raid1.c | 3 ++-
    drivers/md/raid10.c | 7 ++++---
    2 files changed, 6 insertions(+), 4 deletions(-)

    --- a/drivers/md/raid10.c
    +++ b/drivers/md/raid10.c
    @@ -1236,6 +1236,7 @@ static void end_sync_read(struct bio *bi
    /* for reconstruct, we always reschedule after a read.
    * for resync, only after all reads
    */
    + rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
    if (test_bit(R10BIO_IsRecover, &r10_bio->state) ||
    atomic_dec_and_test(&r10_bio->remaining)) {
    /* we have read all the blocks,
    @@ -1243,7 +1244,6 @@ static void end_sync_read(struct bio *bi
    */
    reschedule_retry(r10_bio);
    }
    - rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
    }

    static void end_sync_write(struct bio *bio, int error)
    @@ -1264,11 +1264,13 @@ static void end_sync_write(struct bio *b

    update_head_pos(i, r10_bio);

    + rdev_dec_pending(conf->mirrors[d].rdev, mddev);
    while (atomic_dec_and_test(&r10_bio->remaining)) {
    if (r10_bio->master_bio == NULL) {
    /* the primary of several recovery bios */
    - md_done_sync(mddev, r10_bio->sectors, 1);
    + sector_t s = r10_bio->sectors;
    put_buf(r10_bio);
    + md_done_sync(mddev, s, 1);
    break;
    } else {
    r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio;
    @@ -1276,7 +1278,6 @@ static void end_sync_write(struct bio *b
    r10_bio = r10_bio2;
    }
    }
    - rdev_dec_pending(conf->mirrors[d].rdev, mddev);
    }

    /*
    --- a/drivers/md/raid1.c
    +++ b/drivers/md/raid1.c
    @@ -1233,8 +1233,9 @@ static void end_sync_write(struct bio *b
    update_head_pos(mirror, r1_bio);

    if (atomic_dec_and_test(&r1_bio->remaining)) {
    - md_done_sync(mddev, r1_bio->sectors, uptodate);
    + sector_t s = r1_bio->sectors;
    put_buf(r1_bio);
    + md_done_sync(mddev, s, uptodate);
    }
    }




    \
     
     \ /
      Last update: 2009-03-14 02:35    [W:0.023 / U:1.456 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site