svn commit: r218394 - projects/graid/head/sys/geom/raid

Alexander Motin mav at FreeBSD.org
Mon Feb 7 10:02:48 UTC 2011


Author: mav
Date: Mon Feb  7 10:02:47 2011
New Revision: 218394
URL: http://svn.freebsd.org/changeset/base/218394

Log:
  - Refactor RAID1 rebuild start. Make it invariant to receved events, only
  new subdisk state and fact of the change really matters.
  - Implement UNINITIALIZED -> REBUILD transition.
  - Rebuild abort/restart still needs some work.

Modified:
  projects/graid/head/sys/geom/raid/g_raid.c
  projects/graid/head/sys/geom/raid/g_raid.h
  projects/graid/head/sys/geom/raid/tr_raid1.c

Modified: projects/graid/head/sys/geom/raid/g_raid.c
==============================================================================
--- projects/graid/head/sys/geom/raid/g_raid.c	Mon Feb  7 08:12:24 2011	(r218393)
+++ projects/graid/head/sys/geom/raid/g_raid.c	Mon Feb  7 10:02:47 2011	(r218394)
@@ -187,10 +187,12 @@ g_raid_subdisk_state2str(int state)
 		return ("FAILED");
 	case G_RAID_SUBDISK_S_NEW:
 		return ("NEW");
-	case G_RAID_SUBDISK_S_STALE:
-		return ("STALE");
 	case G_RAID_SUBDISK_S_REBUILD:
 		return ("REBUILD");
+	case G_RAID_SUBDISK_S_UNINITIALIZED:
+		return ("UNINITIALIZED");
+	case G_RAID_SUBDISK_S_STALE:
+		return ("STALE");
 	case G_RAID_SUBDISK_S_RESYNC:
 		return ("RESYNC");
 	case G_RAID_SUBDISK_S_ACTIVE:
@@ -553,6 +555,30 @@ g_raid_nsubdisks(struct g_raid_volume *v
 	return (n);
 }
 
+/*
+ * Return the first subdisk in given state.
+ * If state is equal to -1, then the first connected disks.
+ */
+struct g_raid_subdisk *
+g_raid_get_subdisk(struct g_raid_volume *vol, int state)
+{
+	struct g_raid_subdisk *sd;
+	struct g_raid_softc *sc;
+	u_int i;
+
+	sc = vol->v_softc;
+	sx_assert(&sc->sc_lock, SX_LOCKED);
+
+	for (i = 0; i < vol->v_disks_count; i++) {
+		sd = &vol->v_subdisks[i];
+		if ((state == -1 &&
+		     sd->sd_state != G_RAID_SUBDISK_S_NONE) ||
+		    sd->sd_state == state)
+			return (sd);
+	}
+	return (NULL);
+}
+
 static u_int
 g_raid_nrequests(struct g_raid_softc *sc, struct g_consumer *cp)
 {

Modified: projects/graid/head/sys/geom/raid/g_raid.h
==============================================================================
--- projects/graid/head/sys/geom/raid/g_raid.h	Mon Feb  7 08:12:24 2011	(r218393)
+++ projects/graid/head/sys/geom/raid/g_raid.h	Mon Feb  7 10:02:47 2011	(r218394)
@@ -357,6 +357,8 @@ int g_raid_tr_kerneldump_common(struct g
 u_int g_raid_ndisks(struct g_raid_softc *sc, int state);
 u_int g_raid_nsubdisks(struct g_raid_volume *vol, int state);
 u_int g_raid_nopens(struct g_raid_softc *sc);
+struct g_raid_subdisk * g_raid_get_subdisk(struct g_raid_volume *vol,
+    int state);
 #define	G_RAID_DESTROY_SOFT		0
 #define	G_RAID_DESTROY_DELAYED	1
 #define	G_RAID_DESTROY_HARD		2

Modified: projects/graid/head/sys/geom/raid/tr_raid1.c
==============================================================================
--- projects/graid/head/sys/geom/raid/tr_raid1.c	Mon Feb  7 08:12:24 2011	(r218393)
+++ projects/graid/head/sys/geom/raid/tr_raid1.c	Mon Feb  7 10:02:47 2011	(r218394)
@@ -138,12 +138,9 @@ static struct g_raid_tr_class g_raid_tr_
 	.trc_priority = 100
 };
 
-static void g_raid_tr_raid1_rebuild_abort(struct g_raid_tr_object *tr,
-    struct g_raid_volume *vol);
-static struct g_raid_subdisk *g_raid_tr_raid1_find_good_drive(
-    struct g_raid_volume *vol);
+static void g_raid_tr_raid1_rebuild_abort(struct g_raid_tr_object *tr);
 static void g_raid_tr_raid1_maybe_rebuild(struct g_raid_tr_object *tr,
-    struct g_raid_volume *vol);
+    struct g_raid_subdisk *sd);
 
 static int
 g_raid_tr_taste_raid1(struct g_raid_tr_object *tr, struct g_raid_volume *vol)
@@ -160,10 +157,11 @@ g_raid_tr_taste_raid1(struct g_raid_tr_o
 }
 
 static int
-g_raid_tr_update_state_raid1(struct g_raid_volume *vol)
+g_raid_tr_update_state_raid1(struct g_raid_volume *vol,
+    struct g_raid_subdisk *sd)
 {
 	struct g_raid_tr_raid1_object *trs;
-	struct g_raid_subdisk *sd, *bestsd;
+	struct g_raid_subdisk *tsd, *bestsd;
 	u_int s;
 	int i, na, ns;
 
@@ -183,14 +181,14 @@ g_raid_tr_update_state_raid1(struct g_ra
 			 */
 			bestsd = &vol->v_subdisks[0];
 			for (i = 1; i < vol->v_disks_count; i++) {
-				sd = &vol->v_subdisks[i];
-				if (sd->sd_state > bestsd->sd_state)
-					bestsd = sd;
-				else if (sd->sd_state == bestsd->sd_state &&
-				    (sd->sd_state == G_RAID_SUBDISK_S_REBUILD ||
-				     sd->sd_state == G_RAID_SUBDISK_S_RESYNC) &&
-				    sd->sd_rebuild_pos > bestsd->sd_rebuild_pos)
-					bestsd = sd;
+				tsd = &vol->v_subdisks[i];
+				if (tsd->sd_state > bestsd->sd_state)
+					bestsd = tsd;
+				else if (tsd->sd_state == bestsd->sd_state &&
+				    (tsd->sd_state == G_RAID_SUBDISK_S_REBUILD ||
+				     tsd->sd_state == G_RAID_SUBDISK_S_RESYNC) &&
+				    tsd->sd_rebuild_pos > bestsd->sd_rebuild_pos)
+					bestsd = tsd;
 			}
 			if (bestsd->sd_state >= G_RAID_SUBDISK_S_UNINITIALIZED) {
 				/* We found reasonable candidate. */
@@ -215,8 +213,8 @@ g_raid_tr_update_state_raid1(struct g_ra
 			s = G_RAID_VOLUME_S_DEGRADED;
 		else
 			s = G_RAID_VOLUME_S_BROKEN;
+		g_raid_tr_raid1_maybe_rebuild(vol->v_tr, sd);
 	}
-	g_raid_tr_raid1_maybe_rebuild(vol->v_tr, vol);
 	if (s != vol->v_state) {
 		g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ?
 		    G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN,
@@ -237,9 +235,9 @@ g_raid_tr_raid1_rebuild_some(struct g_ra
 	trs = (struct g_raid_tr_raid1_object *)tr;
 	if (trs->trso_flags & TR_RAID1_F_DOING_SOME)
 		return;
-	good_sd = g_raid_tr_raid1_find_good_drive(sd->sd_volume);
+	good_sd = g_raid_get_subdisk(sd->sd_volume, G_RAID_SUBDISK_S_ACTIVE);
 	if (good_sd == NULL) {
-		g_raid_tr_raid1_rebuild_abort(tr, sd->sd_volume);
+		g_raid_tr_raid1_rebuild_abort(tr);
 		return;
 	}
 	bp = &trs->trso_bio;
@@ -259,13 +257,13 @@ g_raid_tr_raid1_rebuild_some(struct g_ra
 }
 
 static void
-g_raid_tr_raid1_rebuild_done(struct g_raid_tr_raid1_object *trs,
-    struct g_raid_volume *vol)
+g_raid_tr_raid1_rebuild_done(struct g_raid_tr_raid1_object *trs)
 {
+	struct g_raid_volume *vol;
 	struct g_raid_subdisk *sd;
 
+	vol = trs->trso_base.tro_volume;
 	sd = trs->trso_failed_sd;
-	sd->sd_rebuild_pos = 0;
 	g_raid_write_metadata(vol->v_softc, vol, sd, sd->sd_disk);
 	free(trs->trso_buffer, M_TR_RAID1);
 	trs->trso_buffer = NULL;
@@ -273,12 +271,11 @@ g_raid_tr_raid1_rebuild_done(struct g_ra
 	trs->trso_type = TR_RAID1_NONE;
 	trs->trso_recover_slabs = 0;
 	trs->trso_failed_sd = NULL;
-	g_raid_tr_update_state_raid1(vol);
+	g_raid_tr_update_state_raid1(vol, NULL);
 }
 
 static void
-g_raid_tr_raid1_rebuild_finish(struct g_raid_tr_object *tr,
-    struct g_raid_volume *vol)
+g_raid_tr_raid1_rebuild_finish(struct g_raid_tr_object *tr)
 {
 	struct g_raid_tr_raid1_object *trs;
 	struct g_raid_subdisk *sd;
@@ -286,66 +283,75 @@ g_raid_tr_raid1_rebuild_finish(struct g_
 	trs = (struct g_raid_tr_raid1_object *)tr;
 	sd = trs->trso_failed_sd;
 	g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE);
-	g_raid_tr_raid1_rebuild_done(trs, vol);
+	sd->sd_rebuild_pos = 0;
+	g_raid_tr_raid1_rebuild_done(trs);
 }
 
 static void
-g_raid_tr_raid1_rebuild_abort(struct g_raid_tr_object *tr,
-    struct g_raid_volume *vol)
+g_raid_tr_raid1_rebuild_abort(struct g_raid_tr_object *tr)
 {
 	struct g_raid_tr_raid1_object *trs;
 	struct g_raid_subdisk *sd;
+	struct g_raid_volume *vol;
 	off_t len;
 
+	vol = tr->tro_volume;
 	trs = (struct g_raid_tr_raid1_object *)tr;
 	sd = trs->trso_failed_sd;
 	len = MIN(g_raid1_rebuild_slab, vol->v_mediasize - sd->sd_rebuild_pos);
 	g_raid_unlock_range(tr->tro_volume, sd->sd_rebuild_pos, len);
-	g_raid_tr_raid1_rebuild_done(trs, vol);
-}
-
-static struct g_raid_subdisk *
-g_raid_tr_raid1_find_good_drive(struct g_raid_volume *vol)
-{
-	int i;
-
-	for (i = 0; i < vol->v_disks_count; i++)
-		if (vol->v_subdisks[i].sd_state == G_RAID_SUBDISK_S_ACTIVE)
-			return (&vol->v_subdisks[i]);
-	return (NULL);
-}
-
-static struct g_raid_subdisk *
-g_raid_tr_raid1_find_failed_drive(struct g_raid_volume *vol)
-{
-	int i;
-
-	for (i = 0; i < vol->v_disks_count; i++)
-		if (vol->v_subdisks[i].sd_state == G_RAID_SUBDISK_S_REBUILD ||
-		    vol->v_subdisks[i].sd_state == G_RAID_SUBDISK_S_RESYNC)
-			return (&vol->v_subdisks[i]);
-	return (NULL);
+	g_raid_tr_raid1_rebuild_done(trs);
 }
 
 static void
-g_raid_tr_raid1_rebuild_start(struct g_raid_tr_object *tr,
-    struct g_raid_volume *vol)
+g_raid_tr_raid1_rebuild_start(struct g_raid_tr_object *tr)
 {
+	struct g_raid_volume *vol;
 	struct g_raid_tr_raid1_object *trs;
-	struct g_raid_subdisk *sd;
+	struct g_raid_subdisk *sd, *fsd;
 
+	vol = tr->tro_volume;
 	trs = (struct g_raid_tr_raid1_object *)tr;
 	if (trs->trso_failed_sd) {
 		G_RAID_DEBUG(1, "Already rebuild in start rebuild. pos %jd\n",
 		    (intmax_t)trs->trso_failed_sd->sd_rebuild_pos);
 		return;
 	}
-	sd = g_raid_tr_raid1_find_good_drive(vol);
-	trs->trso_failed_sd = g_raid_tr_raid1_find_failed_drive(vol);
-	if (sd == NULL || trs->trso_failed_sd == NULL) {
+	sd = g_raid_get_subdisk(vol, G_RAID_SUBDISK_S_ACTIVE);
+	if (sd == NULL) {
+		G_RAID_DEBUG(1, "No active disk to rebuild.  night night.");
+		return;
+	}
+	fsd = g_raid_get_subdisk(vol, G_RAID_SUBDISK_S_RESYNC);
+	if (fsd == NULL)
+		fsd = g_raid_get_subdisk(vol, G_RAID_SUBDISK_S_REBUILD);
+	if (fsd == NULL) {
+		fsd = g_raid_get_subdisk(vol, G_RAID_SUBDISK_S_STALE);
+		if (fsd != NULL) {
+			fsd->sd_rebuild_pos = 0;
+			g_raid_change_subdisk_state(fsd,
+			    G_RAID_SUBDISK_S_RESYNC);
+			g_raid_write_metadata(vol->v_softc, vol, fsd, NULL);
+		} else {
+			fsd = g_raid_get_subdisk(vol,
+			    G_RAID_SUBDISK_S_UNINITIALIZED);
+			if (fsd == NULL)
+				fsd = g_raid_get_subdisk(vol,
+				    G_RAID_SUBDISK_S_NEW);
+			if (fsd != NULL) {
+				fsd->sd_rebuild_pos = 0;
+				g_raid_change_subdisk_state(fsd,
+				    G_RAID_SUBDISK_S_REBUILD);
+				g_raid_write_metadata(vol->v_softc,
+				    vol, fsd, NULL);
+			}
+		}
+	}
+	if (fsd == NULL) {
 		G_RAID_DEBUG(1, "No failed disk to rebuild.  night night.");
 		return;
 	}
+	trs->trso_failed_sd = fsd;
 	G_RAID_DEBUG(2, "Kicking off a rebuild at %jd...",
 	    trs->trso_failed_sd->sd_rebuild_pos);
 	trs->trso_type = TR_RAID1_REBUILD;
@@ -357,8 +363,9 @@ g_raid_tr_raid1_rebuild_start(struct g_r
 
 static void
 g_raid_tr_raid1_maybe_rebuild(struct g_raid_tr_object *tr,
-    struct g_raid_volume *vol)
+    struct g_raid_subdisk *sd)
 {
+	struct g_raid_volume *vol;
 	struct g_raid_tr_raid1_object *trs;
 	int na, nr;
 	
@@ -368,6 +375,7 @@ g_raid_tr_raid1_maybe_rebuild(struct g_r
 	 * 'good disk' stored in the trs, then we're in progress and we punt.
 	 * If we make it past all these checks, we need to rebuild.
 	 */
+	vol = tr->tro_volume;
 	trs = (struct g_raid_tr_raid1_object *)tr;
 	if (trs->trso_stopping)
 		return;
@@ -376,16 +384,20 @@ g_raid_tr_raid1_maybe_rebuild(struct g_r
 	    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_RESYNC);
 	switch(trs->trso_type) {
 	case TR_RAID1_NONE:
-		if (na == 0 || nr == 0)
-			return;
-		if (trs->trso_type != TR_RAID1_NONE)
+		if (na == 0)
 			return;
-		g_raid_tr_raid1_rebuild_start(tr, vol);
+		if (nr == 0) {
+			nr = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_NEW) +
+			    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_STALE) +
+			    g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_UNINITIALIZED);
+			if (nr == 0)
+				return;
+		}
+		g_raid_tr_raid1_rebuild_start(tr);
 		break;
 	case TR_RAID1_REBUILD:
-		/*
-		 * We're rebuilding, maybe we need to stop...
-		 */
+		if (na == 0 || nr == 0)
+			g_raid_tr_raid1_rebuild_abort(tr);
 		break;
 	case TR_RAID1_RESYNC:
 		break;
@@ -396,32 +408,8 @@ static int
 g_raid_tr_event_raid1(struct g_raid_tr_object *tr,
     struct g_raid_subdisk *sd, u_int event)
 {
-	struct g_raid_tr_raid1_object *trs;
-	struct g_raid_volume *vol;
 
-	trs = (struct g_raid_tr_raid1_object *)tr;
-	vol = tr->tro_volume;
-	switch (event) {
-	case G_RAID_SUBDISK_E_NEW:
-		if (sd->sd_state == G_RAID_SUBDISK_S_NEW) {
-			sd->sd_rebuild_pos = 0;
-			g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_REBUILD);
-		} else if (sd->sd_state == G_RAID_SUBDISK_S_STALE) {
-			sd->sd_rebuild_pos = 0;
-			g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_RESYNC);
-		}
-		break;
-	case G_RAID_SUBDISK_E_FAILED:
-		if (trs->trso_type == TR_RAID1_REBUILD ||
-		    trs->trso_type == TR_RAID1_RESYNC)
-			g_raid_tr_raid1_rebuild_abort(tr, vol);
-		break;
-	case G_RAID_SUBDISK_E_DISCONNECTED:
-		if (trs->trso_type == TR_RAID1_REBUILD)
-			g_raid_tr_raid1_rebuild_abort(tr, vol);
-		break;
-	}
-	g_raid_tr_update_state_raid1(vol);
+	g_raid_tr_update_state_raid1(tr->tro_volume, sd);
 	return (0);
 }
 
@@ -434,7 +422,7 @@ g_raid_tr_start_raid1(struct g_raid_tr_o
 	trs = (struct g_raid_tr_raid1_object *)tr;
 	vol = tr->tro_volume;
 	trs->trso_starting = 0;
-	g_raid_tr_update_state_raid1(vol);
+	g_raid_tr_update_state_raid1(vol, NULL);
 	return (0);
 }
 
@@ -448,7 +436,7 @@ g_raid_tr_stop_raid1(struct g_raid_tr_ob
 	vol = tr->tro_volume;
 	trs->trso_starting = 0;
 	trs->trso_stopping = 1;
-	g_raid_tr_update_state_raid1(vol);
+	g_raid_tr_update_state_raid1(vol, NULL);
 	return (0);
 }
 
@@ -641,7 +629,7 @@ g_raid_tr_iodone_raid1(struct g_raid_tr_
 				G_RAID_LOGREQ(4, bp, "rebuild read done. %d",
 				    bp->bio_error);
 				if (bp->bio_error != 0) {
-					g_raid_tr_raid1_rebuild_abort(tr, vol);
+					g_raid_tr_raid1_rebuild_abort(tr);
 					return;
 				}
 				bp->bio_cmd = BIO_WRITE;
@@ -664,7 +652,7 @@ g_raid_tr_iodone_raid1(struct g_raid_tr_
 				if (bp->bio_error != 0) {
 					g_raid_fail_disk(sd->sd_softc, nsd,
 					    nsd->sd_disk);
-					g_raid_tr_raid1_rebuild_abort(tr, vol);
+					g_raid_tr_raid1_rebuild_abort(tr);
 					return;
 				}
 /* XXX A lot of the following is needed when we kick of the work -- refactor */
@@ -672,14 +660,14 @@ g_raid_tr_iodone_raid1(struct g_raid_tr_
 				    bp->bio_offset, bp->bio_length);
 				nsd->sd_rebuild_pos += bp->bio_length;
 				if (nsd->sd_rebuild_pos >= vol->v_mediasize) {
-					g_raid_tr_raid1_rebuild_finish(tr, vol);
+					g_raid_tr_raid1_rebuild_finish(tr);
 					return;
 				}
 
 				/* Abort rebuild if we are stopping */
 				if (trs->trso_stopping) {
 					trs->trso_flags &= ~TR_RAID1_F_DOING_SOME;
-					g_raid_tr_update_state_raid1(vol);
+					g_raid_tr_update_state_raid1(vol, NULL);
 					return;
 				}
 
@@ -693,9 +681,10 @@ g_raid_tr_iodone_raid1(struct g_raid_tr_
 					trs->trso_flags &= ~TR_RAID1_F_DOING_SOME;
 					return;
 				}
-				good_sd = g_raid_tr_raid1_find_good_drive(vol);
+				good_sd = g_raid_get_subdisk(sd->sd_volume,
+				    G_RAID_SUBDISK_S_ACTIVE);
 				if (good_sd == NULL) {
-					g_raid_tr_raid1_rebuild_abort(tr, vol);
+					g_raid_tr_raid1_rebuild_abort(tr);
 					return;
 				}
 				bp->bio_cmd = BIO_READ;


More information about the svn-src-projects mailing list