summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNeil Brown <neilb@cse.unsw.edu.au>2002-06-18 04:17:40 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-06-18 04:17:40 -0700
commit2d35e42d1cdb08f940a9c302c04bd6b24c44cedc (patch)
tree6c33508266499568cbe1e5c199607f1a13073370 /drivers
parent7145dd2494f8e704342850325d04f5567c33cda1 (diff)
[PATCH] md 19 of 22 - Improve serialisation of md syncing
If two md arrays which share real devices (i.e they each own a partition on some device) need to sync/reconstruct at the same time, it is much more efficient to have one wait while the other completes. The current code uses interruptible_sleep_on which isn't SMP safe (without the BKL). This patch re-does this code to make it more secure. Even it two start simultaneously, one will reliably get priority, and the other wont wait for ever.
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/md.c54
1 files changed, 30 insertions, 24 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 6f8426adbceb..1fccd7c3a4aa 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -3160,7 +3160,7 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
{
mddev_t *mddev2;
unsigned int max_sectors, currspeed = 0,
- j, window, err, serialize;
+ j, window, err;
unsigned long mark[SYNC_MARKS];
unsigned long mark_cnt[SYNC_MARKS];
int last_mark,m;
@@ -3168,30 +3168,36 @@ int md_do_sync(mddev_t *mddev, mdp_disk_t *spare)
unsigned long last_check;
-recheck:
- serialize = 0;
- ITERATE_MDDEV(mddev2,tmp) {
- if (mddev2 == mddev)
- continue;
- if (mddev2->curr_resync && match_mddev_units(mddev,mddev2)) {
- printk(KERN_INFO "md: delaying resync of md%d until md%d "
- "has finished resync (they share one or more physical units)\n",
- mdidx(mddev), mdidx(mddev2));
- serialize = 1;
- break;
- }
- }
- if (serialize) {
- interruptible_sleep_on(&resync_wait);
- if (signal_pending(current)) {
- flush_curr_signals();
- err = -EINTR;
- goto out;
+ /* we overload curr_resync somewhat here.
+ * 0 == not engaged in resync at all
+ * 2 == checking that there is no conflict with another sync
+ * 1 == like 2, but have yielded to allow conflicting resync to
+ * commense
+ * other == active in resync - this many blocks
+ */
+ do {
+ mddev->curr_resync = 2;
+
+ ITERATE_MDDEV(mddev2,tmp) {
+ if (mddev2 == mddev)
+ continue;
+ if (mddev2->curr_resync &&
+ match_mddev_units(mddev,mddev2)) {
+ printk(KERN_INFO "md: delaying resync of md%d until md%d "
+ "has finished resync (they share one or more physical units)\n",
+ mdidx(mddev), mdidx(mddev2));
+ if (mddev < mddev2) /* arbitrarily yield */
+ mddev->curr_resync = 1;
+ if (wait_event_interruptible(resync_wait,
+ mddev2->curr_resync < 2)) {
+ flush_curr_signals();
+ err = -EINTR;
+ goto out;
+ }
+ }
}
- goto recheck;
- }
+ } while (mddev->curr_resync < 2);
- mddev->curr_resync = 1;
max_sectors = mddev->sb->size << 1;
printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev));
@@ -3229,7 +3235,7 @@ recheck:
}
atomic_add(sectors, &mddev->recovery_active);
j += sectors;
- mddev->curr_resync = j;
+ if (j>1) mddev->curr_resync = j;
if (last_check + window > j)
continue;