summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarco Peereboom <marco@cvs.openbsd.org>2009-06-02 19:15:59 +0000
committerMarco Peereboom <marco@cvs.openbsd.org>2009-06-02 19:15:59 +0000
commit7ef4ec9ea365fa984b9efbb9f1075a61687690f0 (patch)
tree56b0e9f75bea0a5bfeadc65b10e8c1d7f7a4ff79 /sys
parent161ff1c02dac5a7dd1f2f07d13f194a87e7cbd6b (diff)
Make rebuilds restartable over reboots.
Abort rebuild and drain IO when shutting down.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/softraid.c55
-rw-r--r--sys/dev/softraidvar.h4
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 */