diff options
author | NeilBrown <neilb@suse.com> | 2015-07-26 21:48:52 -0400 |
---|---|---|
committer | NeilBrown <neilb@suse.com> | 2015-08-02 22:29:42 -0400 |
commit | 423f04d63cf421ea436bcc5be02543d549ce4b28 (patch) | |
tree | 0d98d3b3de62c7689fbe58a6229c7d760d998c55 /drivers/md/raid1.c | |
parent | 74d33293e467df61de1b1d8b2fbe29e550dec33b (diff) |
md/raid1: extend spinlock to protect raid1_end_read_request against inconsistencies
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.")
Cc: stable@vger.kernel.org (v3.0+)
Signed-off-by: NeilBrown <neilb@suse.com>
Diffstat (limited to 'drivers/md/raid1.c')
-rw-r--r-- | drivers/md/raid1.c | 10 |
1 files changed, 6 insertions, 4 deletions
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 94f5b55069e0..967a4ed73929 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -1476,6 +1476,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) | |||
1476 | { | 1476 | { |
1477 | char b[BDEVNAME_SIZE]; | 1477 | char b[BDEVNAME_SIZE]; |
1478 | struct r1conf *conf = mddev->private; | 1478 | struct r1conf *conf = mddev->private; |
1479 | unsigned long flags; | ||
1479 | 1480 | ||
1480 | /* | 1481 | /* |
1481 | * If it is not operational, then we have already marked it as dead | 1482 | * If it is not operational, then we have already marked it as dead |
@@ -1495,14 +1496,13 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) | |||
1495 | return; | 1496 | return; |
1496 | } | 1497 | } |
1497 | set_bit(Blocked, &rdev->flags); | 1498 | set_bit(Blocked, &rdev->flags); |
1499 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1498 | if (test_and_clear_bit(In_sync, &rdev->flags)) { | 1500 | if (test_and_clear_bit(In_sync, &rdev->flags)) { |
1499 | unsigned long flags; | ||
1500 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1501 | mddev->degraded++; | 1501 | mddev->degraded++; |
1502 | set_bit(Faulty, &rdev->flags); | 1502 | set_bit(Faulty, &rdev->flags); |
1503 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
1504 | } else | 1503 | } else |
1505 | set_bit(Faulty, &rdev->flags); | 1504 | set_bit(Faulty, &rdev->flags); |
1505 | spin_unlock_irqrestore(&conf->device_lock, flags); | ||
1506 | /* | 1506 | /* |
1507 | * if recovery is running, make sure it aborts. | 1507 | * if recovery is running, make sure it aborts. |
1508 | */ | 1508 | */ |
@@ -1568,7 +1568,10 @@ static int raid1_spare_active(struct mddev *mddev) | |||
1568 | * Find all failed disks within the RAID1 configuration | 1568 | * Find all failed disks within the RAID1 configuration |
1569 | * and mark them readable. | 1569 | * and mark them readable. |
1570 | * Called under mddev lock, so rcu protection not needed. | 1570 | * Called under mddev lock, so rcu protection not needed. |
1571 | * device_lock used to avoid races with raid1_end_read_request | ||
1572 | * which expects 'In_sync' flags and ->degraded to be consistent. | ||
1571 | */ | 1573 | */ |
1574 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1572 | for (i = 0; i < conf->raid_disks; i++) { | 1575 | for (i = 0; i < conf->raid_disks; i++) { |
1573 | struct md_rdev *rdev = conf->mirrors[i].rdev; | 1576 | struct md_rdev *rdev = conf->mirrors[i].rdev; |
1574 | struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev; | 1577 | struct md_rdev *repl = conf->mirrors[conf->raid_disks + i].rdev; |
@@ -1599,7 +1602,6 @@ static int raid1_spare_active(struct mddev *mddev) | |||
1599 | sysfs_notify_dirent_safe(rdev->sysfs_state); | 1602 | sysfs_notify_dirent_safe(rdev->sysfs_state); |
1600 | } | 1603 | } |
1601 | } | 1604 | } |
1602 | spin_lock_irqsave(&conf->device_lock, flags); | ||
1603 | mddev->degraded -= count; | 1605 | mddev->degraded -= count; |
1604 | spin_unlock_irqrestore(&conf->device_lock, flags); | 1606 | spin_unlock_irqrestore(&conf->device_lock, flags); |
1605 | 1607 | ||