Date: Mon, 7 Feb 2011 10:02:48 +0000 (UTC) From: Alexander Motin <mav@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r218394 - projects/graid/head/sys/geom/raid Message-ID: <201102071002.p17A2mrH004823@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201102071002.p17A2mrH004823>