lkml.org 
[lkml]   [2015]   [Sep]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3.19.y-ckt 028/102] md/raid1: extend spinlock to protect raid1_end_read_request against inconsistencies
    Date
    3.19.8-ckt7 -stable review patch.  If anyone has any objections, please let me know.

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

    From: NeilBrown <neilb@suse.com>

    commit 423f04d63cf421ea436bcc5be02543d549ce4b28 upstream.

    raid1_end_read_request() assumes that the In_sync bits are consistent
    with the ->degaded count.
    raid1_spare_active updates the In_sync bit before the ->degraded count
    and so exposes an inconsistency, as does error()
    So extend the spinlock in raid1_spare_active() and error() to hide those
    inconsistencies.

    This should probably be part of
    Commit: 34cab6f42003 ("md/raid1: fix test for 'was read error from
    last working device'.")
    as it addresses the same issue. It fixes the same bug and should go
    to -stable for same reasons.

    Fixes: 76073054c95b ("md/raid1: clean up read_balance.")
    Signed-off-by: NeilBrown <neilb@suse.com>
    Signed-off-by: Kamal Mostafa <kamal@canonical.com>
    ---
    drivers/md/raid1.c | 10 ++++++----
    1 file changed, 6 insertions(+), 4 deletions(-)

    diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
    index 8d9110f..d24245c 100644
    --- a/drivers/md/raid1.c
    +++ b/drivers/md/raid1.c
    @@ -1474,6 +1474,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
    {
    char b[BDEVNAME_SIZE];
    struct r1conf *conf = mddev->private;
    + unsigned long flags;

    /*
    * If it is not operational, then we have already marked it as dead
    @@ -1493,14 +1494,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev)
    return;
    }
    set_bit(Blocked, &rdev->flags);
    + spin_lock_irqsave(&conf->device_lock, flags);
    if (test_and_clear_bit(In_sync, &rdev->flags)) {
    - unsigned long flags;
    - spin_lock_irqsave(&conf->device_lock, flags);
    mddev->degraded++;
    set_bit(Faulty, &rdev->flags);
    - spin_unlock_irqrestore(&conf->device_lock, flags);
    } else
    set_bit(Faulty, &rdev->flags);
    + spin_unlock_irqrestore(&conf->device_lock, flags);
    /*
    * if recovery is running, make sure it aborts.
    */
    @@ -1566,7 +1566,10 @@ static int raid1_spare_active(struct mddev *mddev)
    * Find all failed disks within the RAID1 configuration
    * and mark them readable.
    * Called under mddev lock, so rcu protection not needed.
    + * device_lock used to avoid races with raid1_end_read_request
    + * which expects 'In_sync' flags and ->degraded to be consistent.
    */
    + spin_lock_irqsave(&conf->device_lock, flags);
    for (i = 0; i < conf->raid_disks; i++) {
    struct md_rdev *rdev = conf->mirrors[i].rdev;
    struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev;
    @@ -1596,7 +1599,6 @@ static int raid1_spare_active(struct mddev *mddev)
    sysfs_notify_dirent_safe(rdev->sysfs_state);
    }
    }
    - spin_lock_irqsave(&conf->device_lock, flags);
    mddev->degraded -= count;
    spin_unlock_irqrestore(&conf->device_lock, flags);

    --
    1.9.1


    \
     
     \ /
      Last update: 2015-09-22 20:21    [W:8.729 / U:0.128 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site