diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2009-06-02 19:15:59 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2009-06-02 19:15:59 +0000 |
commit | 7ef4ec9ea365fa984b9efbb9f1075a61687690f0 (patch) | |
tree | 56b0e9f75bea0a5bfeadc65b10e8c1d7f7a4ff79 /sys | |
parent | 161ff1c02dac5a7dd1f2f07d13f194a87e7cbd6b (diff) |
Make rebuilds restartable over reboots.
Abort rebuild and drain IO when shutting down.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/softraid.c | 55 | ||||
-rw-r--r-- | sys/dev/softraidvar.h | 4 |
2 files changed, 49 insertions, 10 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c index 474b672cc5a..8c4496ac7af 100644 --- a/sys/dev/softraid.c +++ b/sys/dev/softraid.c @@ -1,4 +1,4 @@ -/* $OpenBSD: softraid.c,v 1.137 2009/06/02 12:32:08 deraadt Exp $ */ +/* $OpenBSD: softraid.c,v 1.138 2009/06/02 19:15:58 marco Exp $ */ /* * Copyright (c) 2007 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> @@ -1152,6 +1152,10 @@ sr_meta_native_attach(struct sr_discipline *sd, int force) ch_next = SLIST_NEXT(ch_entry, src_link); /* XXX do we want to read this again? */ + printf("ch %p %p\n", ch_entry, md); + printf("mm %x\n", ch_entry->src_dev_mm); + if (ch_entry->src_dev_mm == NODEV) + panic("src_dev_mm == NODEV"); if (sr_meta_native_read(sd, ch_entry->src_dev_mm, md, NULL)) printf("%s: could not read native metadata\n", @@ -2234,11 +2238,8 @@ sr_ioctl_createraid(struct sr_softc *sc, struct bioc_createraid *bc, int user) rv = sr_meta_save(sd, SR_META_DIRTY); sd->sd_shutdownhook = shutdownhook_establish(sr_shutdown, sd); - if (sd->sd_vol_status == BIOC_SVREBUILD) { - printf("%s: resuming rebuild on %s\n", DEVNAME(sc), - sd->sd_meta->ssd_devname); + if (sd->sd_vol_status == BIOC_SVREBUILD) kthread_create_deferred(sr_rebuild, sd); - } return (rv); unwind: @@ -2699,6 +2700,11 @@ sr_shutdown(void *arg) DNPRINTF(SR_D_DIS, "%s: sr_shutdown %s\n", DEVNAME(sc), sd->sd_meta->ssd_devname); + /* abort rebuild and drain io */ + sd->sd_going_down = 1; + while (sd->sd_reb_active) + tsleep(sd, PWAIT, "sr_shutdown", 1); + sr_meta_save(sd, 0); sr_discipline_shutdown(sd); @@ -2811,18 +2817,35 @@ sr_rebuild_thread(void *arg) struct sr_discipline *sd = arg; struct sr_softc *sc = sd->sd_sc; daddr64_t whole_blk, partial_blk, blk, sz, lba; + daddr64_t psz, rb, restart; uint64_t mysize = 0; struct sr_workunit *wu_r, *wu_w; struct scsi_xfer xs_r, xs_w; struct scsi_rw_16 cr, cw; - int c, s, slept; + int c, s, slept, percent = 0, old_percent = -1; u_int8_t *buf; whole_blk = sd->sd_meta->ssdi.ssd_size / SR_REBUILD_IO_SIZE; partial_blk = sd->sd_meta->ssdi.ssd_size % SR_REBUILD_IO_SIZE; + restart = sd->sd_meta->ssd_rebuild / SR_REBUILD_IO_SIZE; + if (restart > whole_blk) { + printf("%s: bogus rebuild restart offset, starting from 0\n", + DEVNAME(sc)); + restart = 0; + } + if (restart) { + psz = sd->sd_meta->ssdi.ssd_size; + rb = sd->sd_meta->ssd_rebuild; + percent = 100 - ((psz * 100 - rb * 100) / psz); + printf("%s: resuming rebuild on %s at %llu%%\n", + DEVNAME(sc), sd->sd_meta->ssd_devname, percent); + } + + sd->sd_reb_active = 1; + buf = malloc(SR_REBUILD_IO_SIZE << DEV_BSHIFT, M_DEVBUF, M_WAITOK); - for (blk = 0; blk <= whole_blk; blk++) { + for (blk = restart; blk <= whole_blk; blk++) { if (blk == whole_blk) sz = partial_blk; else @@ -2905,12 +2928,24 @@ queued: sr_wu_put(wu_w); sd->sd_meta->ssd_rebuild = lba; - /* XXX save metadata periodically */ + + /* save metadata every percent */ + psz = sd->sd_meta->ssdi.ssd_size; + rb = sd->sd_meta->ssd_rebuild; + percent = 100 - ((psz * 100 - rb * 100) / psz); + if (percent != old_percent && blk != whole_blk) { + if (sr_meta_save(sd, SR_META_DIRTY)) + printf("%s: could not save metadata to %s\n", + DEVNAME(sc), sd->sd_meta->ssd_devname); + old_percent = percent; + } + + if (sd->sd_going_down) + goto abort; } /* all done */ sd->sd_meta->ssd_rebuild = 0; - for (c = 0; c < sd->sd_meta->ssdi.ssd_chunk_no; c++) if (sd->sd_vol.sv_chunks[c]->src_meta.scm_status == BIOC_SDREBUILD) { @@ -2918,11 +2953,13 @@ queued: break; } +abort: if (sr_meta_save(sd, SR_META_DIRTY)) printf("%s: could not save metadata to %s\n", DEVNAME(sc), sd->sd_meta->ssd_devname); free(buf, M_DEVBUF); + sd->sd_reb_active = 0; kthread_exit(0); } diff --git a/sys/dev/softraidvar.h b/sys/dev/softraidvar.h index aed9c9eae1e..f25e95a3d74 100644 --- a/sys/dev/softraidvar.h +++ b/sys/dev/softraidvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: softraidvar.h,v 1.69 2009/06/02 05:49:35 marco Exp $ */ +/* $OpenBSD: softraidvar.h,v 1.70 2009/06/02 19:15:58 marco Exp $ */ /* * Copyright (c) 2006 Marco Peereboom <marco@peereboom.us> * Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org> @@ -405,6 +405,8 @@ struct sr_discipline { struct sr_workunit *sd_wu; /* all workunits */ u_int32_t sd_max_wu; int sd_rebuild; /* can we rebuild? */ + int sd_reb_active; /* rebuild in progress */ + int sd_going_down; /* dive dive dive */ struct sr_wu_list sd_wu_freeq; /* free wu queue */ struct sr_wu_list sd_wu_pendq; /* pending wu queue */ |