PATCH: raid1 on alpha

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Driven by desperation :-) I have churned out a patch that works around a
long-standing problem with software RAID1 on Alpha platforms. gcc (at least
2.95 and 3.2) generated code for alpha apparently has a problem that is
exercised by the form of the loops in raid1_read_balance.

My admittedly lame patch, against 2.4.20, has been working for my SMP
Alphaserver 4100 for a couple of weeks now without ill effect. (Everything,
including root, on LVM on RAID1.) But I think I cut a corner or two in order
to get it working and keep it simple. I'm hoping a more artful/knowledgeable
programmer can massage this so it is acceptable for inclusion in the
mainline kernels.

Cheers,

	Scott Bailey
	scott.bailey@eds.com | rscottbailey@comcast.net


--- linux-2.4.20/drivers/md/raid1.c	2003-01-17 17:43:45.000000000 -0500
+++ linux-2.4.20-rsb/drivers/md/raid1.c	2003-01-17 17:43:20.000000000 -0500
@@ -11,6 +11,7 @@
  *
  * Fixes to reconstruction by Jakob Østergaard" <jakob@ostenfeld.dk>
  * Various fixes by Neil Brown <neilb@cse.unsw.edu.au>
+ * Spastic hacks on raid1_read_balance by Scott Bailey
<scott.bailey@eds.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -475,6 +476,8 @@
 	int new_disk = conf->last_used;
 	const int sectors = bh->b_size >> 9;
 	const unsigned long this_sector = bh->b_rsector;
+	const int max_disk = conf->raid_disks;
+	const int loop_disk = max_disk - 1; /* optimizer is stooopid */
 	int disk = new_disk;
 	unsigned long new_distance;
 	unsigned long current_distance;
@@ -488,22 +491,18 @@


 	/* make sure that disk is operational */
-	while( !conf->mirrors[new_disk].operational) {
-		if (new_disk <= 0) new_disk = conf->raid_disks;
-		new_disk--;
-		if (new_disk == disk) {
-			/*
-			 * This means no working disk was found
-			 * Nothing much to do, lets not change anything
-			 * and hope for the best...
-			 */
-
-			new_disk = conf->last_used;
+	/* RSB: if not, be simple-minded and choose first readable disk */

-			goto rb_out;
+	if (!conf->mirrors[new_disk].operational) {
+		for (disk = loop_disk; disk >= 0; disk--) {
+			if ((conf->mirrors[disk].operational) &&
+				(!conf->mirrors[disk].write_only)) break;
 		}
+		if (disk < 0) /* If no usable disk was found */
+			goto rb_out;
+		new_disk = disk;
 	}
-	disk = new_disk;
+
 	/* now disk == new_disk == starting point for search */

 	/*
@@ -519,35 +518,26 @@
 	 * This is for kicking those idling disks so that
 	 * they would find work near some hotspot.
 	 */
-
-	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
-		conf->sect_count = 0;

-#if defined(CONFIG_SPARC64) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 92)
-		/* Work around a compiler bug in egcs-2.92.11 19980921 */
-		new_disk = *(volatile int *)&new_disk;
-#endif
-		do {
-			if (new_disk<=0)
-				new_disk = conf->raid_disks;
-			new_disk--;
-			if (new_disk == disk)
-				break;
-		} while ((conf->mirrors[new_disk].write_only) ||
-			 (!conf->mirrors[new_disk].operational));
+	/*
+	 * RSB: Instead of making a scan for some other disk explicitly, just
+	 * mark the head position as being at start of the disk. Then the next
+	 * loop checking for "close" disks is almost certain to pick somebody
+	 * else. Except for hot spots at front of disk, sigh.
+	 */

-		goto rb_out;
+	if (conf->sect_count >= conf->mirrors[new_disk].sect_limit) {
+		conf->sect_count = 0;
+		conf->mirrors[new_disk].head_position = 0;
 	}

-	current_distance = abs(this_sector -
-				conf->mirrors[disk].head_position);
-
 	/* Find the disk which is closest */
+	/* current_distance is initialized to guaranteed worse-than-worst
+	   so that we can simplify loop logic */
+
+	current_distance = conf->mirrors[0].sect_limit + 1;

-	do {
-		if (disk <= 0)
-			disk = conf->raid_disks;
-		disk--;
+	for (disk = loop_disk; disk >= 0; disk--) {

 		if ((conf->mirrors[disk].write_only) ||
 				(!conf->mirrors[disk].operational))
@@ -561,7 +551,7 @@
 			current_distance = new_distance;
 			new_disk = disk;
 		}
-	} while (disk != conf->last_used);
+	}

 rb_out:
 	conf->mirrors[new_disk].head_position = this_sector + sectors;

-
To unsubscribe from this list: send the line "unsubscribe linux-raid" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux RAID Wiki]     [ATA RAID]     [Linux SCSI Target Infrastructure]     [Linux Block]     [Linux IDE]     [Linux SCSI]     [Linux Hams]     [Device Mapper]     [Device Mapper Cryptographics]     [Kernel]     [Linux Admin]     [Linux Net]     [GFS]     [RPM]     [git]     [Yosemite Forum]


  Powered by Linux