]> git.hungrycats.org Git - linux/commitdiff
[PATCH] md 19 of 22 - Improve serialisation of md syncing
authorNeil Brown <neilb@cse.unsw.edu.au>
Tue, 18 Jun 2002 11:17:40 +0000 (04:17 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Tue, 18 Jun 2002 11:17:40 +0000 (04:17 -0700)
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.

drivers/md/md.c

index 6f8426adbcebc9744842904869236c5346081986..1fccd7c3a4aa52183673463790dab4356976489a 100644 (file)
@@ -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;