Skip to content

Commit 635f641

Browse files
committed
md/raid10: locking changes for 'enough()'.
As 'enough' accesses conf->prev and conf->geo, which can change spontanously, it should guard against changes. This can be done with device_lock as start_reshape holds device_lock while updating 'geo' and end_reshape holds it while updating 'prev'. So 'error' needs to hold 'device_lock'. On the other hand, raid10_end_read_request knows which of the two it really wants to access, and as it is an active request on that one, the value cannot change underneath it. So change _enough to take flag rather than a pointer, pass the appropriate flag from raid10_end_read_request(), and remove the locking. All other calls to 'enough' are made with reconfig_mutex held, so neither 'prev' nor 'geo' can change. Signed-off-by: NeilBrown <[email protected]>
1 parent b29bebd commit 635f641

File tree

1 file changed

+29
-16
lines changed

1 file changed

+29
-16
lines changed

drivers/md/raid10.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ static int max_queued_requests = 1024;
9797

9898
static void allow_barrier(struct r10conf *conf);
9999
static void lower_barrier(struct r10conf *conf);
100-
static int enough(struct r10conf *conf, int ignore);
100+
static int _enough(struct r10conf *conf, int previous, int ignore);
101101
static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
102102
int *skipped);
103103
static void reshape_request_write(struct mddev *mddev, struct r10bio *r10_bio);
@@ -392,11 +392,9 @@ static void raid10_end_read_request(struct bio *bio, int error)
392392
* than fail the last device. Here we redefine
393393
* "uptodate" to mean "Don't want to retry"
394394
*/
395-
unsigned long flags;
396-
spin_lock_irqsave(&conf->device_lock, flags);
397-
if (!enough(conf, rdev->raid_disk))
395+
if (!_enough(conf, test_bit(R10BIO_Previous, &r10_bio->state),
396+
rdev->raid_disk))
398397
uptodate = 1;
399-
spin_unlock_irqrestore(&conf->device_lock, flags);
400398
}
401399
if (uptodate) {
402400
raid_end_bio_io(r10_bio);
@@ -1632,9 +1630,17 @@ static void status(struct seq_file *seq, struct mddev *mddev)
16321630
* Don't consider the device numbered 'ignore'
16331631
* as we might be about to remove it.
16341632
*/
1635-
static int _enough(struct r10conf *conf, struct geom *geo, int ignore)
1633+
static int _enough(struct r10conf *conf, int previous, int ignore)
16361634
{
16371635
int first = 0;
1636+
int disks, ncopies;
1637+
if (previous) {
1638+
disks = conf->prev.raid_disks;
1639+
ncopies = conf->prev.near_copies;
1640+
} else {
1641+
disks = conf->geo.raid_disks;
1642+
ncopies = conf->geo.near_copies;
1643+
}
16381644

16391645
do {
16401646
int n = conf->copies;
@@ -1644,51 +1650,58 @@ static int _enough(struct r10conf *conf, struct geom *geo, int ignore)
16441650
if (conf->mirrors[this].rdev &&
16451651
this != ignore)
16461652
cnt++;
1647-
this = (this+1) % geo->raid_disks;
1653+
this = (this+1) % disks;
16481654
}
16491655
if (cnt == 0)
16501656
return 0;
1651-
first = (first + geo->near_copies) % geo->raid_disks;
1657+
first = (first + ncopies) % disks;
16521658
} while (first != 0);
16531659
return 1;
16541660
}
16551661

16561662
static int enough(struct r10conf *conf, int ignore)
16571663
{
1658-
return _enough(conf, &conf->geo, ignore) &&
1659-
_enough(conf, &conf->prev, ignore);
1664+
/* when calling 'enough', both 'prev' and 'geo' must
1665+
* be stable.
1666+
* This is ensured if ->reconfig_mutex or ->device_lock
1667+
* is held.
1668+
*/
1669+
return _enough(conf, 0, ignore) &&
1670+
_enough(conf, 1, ignore);
16601671
}
16611672

16621673
static void error(struct mddev *mddev, struct md_rdev *rdev)
16631674
{
16641675
char b[BDEVNAME_SIZE];
16651676
struct r10conf *conf = mddev->private;
1677+
unsigned long flags;
16661678

16671679
/*
16681680
* If it is not operational, then we have already marked it as dead
16691681
* else if it is the last working disks, ignore the error, let the
16701682
* next level up know.
16711683
* else mark the drive as failed
16721684
*/
1685+
spin_lock_irqsave(&conf->device_lock, flags);
16731686
if (test_bit(In_sync, &rdev->flags)
1674-
&& !enough(conf, rdev->raid_disk))
1687+
&& !enough(conf, rdev->raid_disk)) {
16751688
/*
16761689
* Don't fail the drive, just return an IO error.
16771690
*/
1691+
spin_unlock_irqrestore(&conf->device_lock, flags);
16781692
return;
1693+
}
16791694
if (test_and_clear_bit(In_sync, &rdev->flags)) {
1680-
unsigned long flags;
1681-
spin_lock_irqsave(&conf->device_lock, flags);
16821695
mddev->degraded++;
1683-
spin_unlock_irqrestore(&conf->device_lock, flags);
1684-
/*
1696+
/*
16851697
* if recovery is running, make sure it aborts.
16861698
*/
16871699
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
16881700
}
16891701
set_bit(Blocked, &rdev->flags);
16901702
set_bit(Faulty, &rdev->flags);
16911703
set_bit(MD_CHANGE_DEVS, &mddev->flags);
1704+
spin_unlock_irqrestore(&conf->device_lock, flags);
16921705
printk(KERN_ALERT
16931706
"md/raid10:%s: Disk failure on %s, disabling device.\n"
16941707
"md/raid10:%s: Operation continuing on %d devices.\n",
@@ -1791,7 +1804,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
17911804
* very different from resync
17921805
*/
17931806
return -EBUSY;
1794-
if (rdev->saved_raid_disk < 0 && !_enough(conf, &conf->prev, -1))
1807+
if (rdev->saved_raid_disk < 0 && !_enough(conf, 1, -1))
17951808
return -EINVAL;
17961809

17971810
if (rdev->raid_disk >= 0)

0 commit comments

Comments
 (0)