summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Peereboom <marco@cvs.openbsd.org>2009-06-03 02:55:05 +0000
committerMarco Peereboom <marco@cvs.openbsd.org>2009-06-03 02:55:05 +0000
commitff63910995f11bd60cf093a0e8a96107be508007 (patch)
treeb9116cdb98c565de167d528e451d20d18dbd399f
parent83ace60d7843daf6381f0971113d6400429f0f94 (diff)
Make sure we don't stomp on a RAID partition that is already in use.
Code is now enabled and ready for general testing.
-rw-r--r--sys/dev/softraid.c201
1 files changed, 108 insertions, 93 deletions
diff --git a/sys/dev/softraid.c b/sys/dev/softraid.c
index afb2c71a91f..a9ec2bf9893 100644
--- a/sys/dev/softraid.c
+++ b/sys/dev/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.140 2009/06/02 21:23:11 marco Exp $ */
+/* $OpenBSD: softraid.c,v 1.141 2009/06/03 02:55:04 marco Exp $ */
/*
* Copyright (c) 2007 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
@@ -1781,7 +1781,7 @@ sr_ioctl_setstate(struct sr_softc *sc, struct bioc_setstate *bs)
{
int rv = EINVAL, part;
int i, c, found, vol, open = 0;
- struct sr_discipline *sd;
+ struct sr_discipline *sd = NULL, *sw = NULL;
char devname[32];
struct bdevsw *bdsw;
dev_t dev;
@@ -1790,7 +1790,7 @@ sr_ioctl_setstate(struct sr_softc *sc, struct bioc_setstate *bs)
struct sr_meta_chunk *old, *new;
/* XXX disabled for now */
- goto done;
+ //goto done;
if (bs->bs_other_id_type == BIOC_SSOTHER_UNUSED)
goto done;
@@ -1802,109 +1802,124 @@ sr_ioctl_setstate(struct sr_softc *sc, struct bioc_setstate *bs)
if (vol != bs->bs_volid)
continue;
sd = sc->sc_dis[i];
+ break;
+ }
+ if (sd == NULL)
+ goto done;
- if (!sd->sd_rebuild) {
- printf("%s: discipline does not support rebuild\n",
- DEVNAME(sc));
- goto done;
- }
+ if (!sd->sd_rebuild) {
+ printf("%s: discipline does not support rebuild\n",
+ DEVNAME(sc));
+ goto done;
+ }
- /* make sure volume is in the right state */
- if (sd->sd_vol_status == BIOC_SVREBUILD) {
- printf("%s: rebuild already in progress\n", DEVNAME(sc));
- goto done;
- }
- if (sd->sd_vol_status != BIOC_SVDEGRADED) {
- printf("%s: %s not degraded\n", DEVNAME(sc),
- sd->sd_meta->ssd_devname);
- goto done;
- }
+ /* make sure volume is in the right state */
+ if (sd->sd_vol_status == BIOC_SVREBUILD) {
+ printf("%s: rebuild already in progress\n", DEVNAME(sc));
+ goto done;
+ }
+ if (sd->sd_vol_status != BIOC_SVDEGRADED) {
+ printf("%s: %s not degraded\n", DEVNAME(sc),
+ sd->sd_meta->ssd_devname);
+ goto done;
+ }
- /* find offline chunk */
- for (c = 0, found = -1; c < sd->sd_meta->ssdi.ssd_chunk_no; c++)
- if (sd->sd_vol.sv_chunks[c]->src_meta.scm_status ==
- BIOC_SDOFFLINE) {
- found = c;
- new = &sd->sd_vol.sv_chunks[c]->src_meta;
+ /* find offline chunk */
+ for (c = 0, found = -1; c < sd->sd_meta->ssdi.ssd_chunk_no; c++)
+ if (sd->sd_vol.sv_chunks[c]->src_meta.scm_status ==
+ BIOC_SDOFFLINE) {
+ found = c;
+ new = &sd->sd_vol.sv_chunks[c]->src_meta;
+ if (c > 0)
+ break; /* roll at least once over the for */
+ } else {
+ csize = sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_size;
+ old = &sd->sd_vol.sv_chunks[c]->src_meta;
+ if (found != -1)
break;
- } else {
- csize = sd->sd_vol.sv_chunks[c]->src_meta.scmi.scm_size;
- old = &sd->sd_vol.sv_chunks[c]->src_meta;
- }
- if (found == -1) {
- printf("%s: no offline chunks available for rebuild\n",
- DEVNAME(sc));
- goto done;
}
+ if (found == -1) {
+ printf("%s: no offline chunks available for rebuild\n",
+ DEVNAME(sc));
+ goto done;
+ }
- /* populate meta entry */
- dev = (dev_t)bs->bs_other_id;
- sr_meta_getdevname(sc, dev, devname, sizeof(devname));
- bdsw = bdevsw_lookup(dev);
+ /* populate meta entry */
+ dev = (dev_t)bs->bs_other_id;
+ sr_meta_getdevname(sc, dev, devname, sizeof(devname));
+ bdsw = bdevsw_lookup(dev);
- if (bdsw->d_open(dev, FREAD | FWRITE, S_IFBLK, curproc)) {
- DNPRINTF(SR_D_META,"%s: sr_ioctl_setstate can't "
- "open %s\n", DEVNAME(sc), devname);
- goto done;
- }
- open = 1; /* close dev on error */
-
- /* get partition */
- part = DISKPART(dev);
- if ((*bdsw->d_ioctl)(dev, DIOCGDINFO, (void *)&label, FREAD,
- curproc)) {
- DNPRINTF(SR_D_META, "%s: sr_ioctl_setstate ioctl "
- "failed\n", DEVNAME(sc));
- goto done;
- }
- if (label.d_partitions[part].p_fstype != FS_RAID) {
- printf("%s: %s partition not of type RAID (%d)\n",
- DEVNAME(sc) , devname,
- label.d_partitions[part].p_fstype);
- goto done;
- }
+ if (bdsw->d_open(dev, FREAD | FWRITE, S_IFBLK, curproc)) {
+ DNPRINTF(SR_D_META,"%s: sr_ioctl_setstate can't "
+ "open %s\n", DEVNAME(sc), devname);
+ goto done;
+ }
+ open = 1; /* close dev on error */
- /* is partition large enough? */
- size = DL_GETPSIZE(&label.d_partitions[part]) -
- SR_META_SIZE - SR_META_OFFSET;
- if (size < csize) {
- printf("%s: partition too small, at least %llu B "
- "required\n", DEVNAME(sc), csize << DEV_BSHIFT);
- goto done;
- } else if (size > csize)
- printf("%s: partition too large, wasting %llu B\n",
- DEVNAME(sc), (size - csize) << DEV_BSHIFT);
-
- /* XXX make sure we are not stomping on some other partition */
-
- /* recreate metadata */
- open = 0; /* leave dev open from here on out */
- sd->sd_vol.sv_chunks[found]->src_dev_mm = dev;
- new->scmi.scm_volid = old->scmi.scm_volid;
- new->scmi.scm_chunk_id = found;
- strlcpy(new->scmi.scm_devname, devname,
- sizeof new->scmi.scm_devname);
- new->scmi.scm_size = size;
- new->scmi.scm_coerced_size = old->scmi.scm_coerced_size;
- bcopy(&old->scmi.scm_uuid, &new->scmi.scm_uuid,
- sizeof new->scmi.scm_uuid);
- sr_checksum(sc, new, &new->scm_checksum,
- sizeof(struct sr_meta_chunk_invariant));
- sd->sd_set_chunk_state(sd, found, BIOC_SDREBUILD);
- if (sr_meta_save(sd, SR_META_DIRTY)) {
- printf("%s: could not save metadata to %s\n",
- DEVNAME(sc), devname);
- goto done;
- }
+ /* get partition */
+ part = DISKPART(dev);
+ if ((*bdsw->d_ioctl)(dev, DIOCGDINFO, (void *)&label, FREAD,
+ curproc)) {
+ DNPRINTF(SR_D_META, "%s: sr_ioctl_setstate ioctl failed\n",
+ DEVNAME(sc));
+ goto done;
+ }
+ if (label.d_partitions[part].p_fstype != FS_RAID) {
+ printf("%s: %s partition not of type RAID (%d)\n",
+ DEVNAME(sc) , devname,
+ label.d_partitions[part].p_fstype);
+ goto done;
+ }
- printf("%s: trying rebuild %s from %s\n", DEVNAME(sc),
- sd->sd_meta->ssd_devname, devname);
+ /* is partition large enough? */
+ size = DL_GETPSIZE(&label.d_partitions[part]) -
+ SR_META_SIZE - SR_META_OFFSET;
+ if (size < csize) {
+ printf("%s: partition too small, at least %llu B required\n",
+ DEVNAME(sc), csize << DEV_BSHIFT);
+ goto done;
+ } else if (size > csize)
+ printf("%s: partition too large, wasting %llu B\n",
+ DEVNAME(sc), (size - csize) << DEV_BSHIFT);
- kthread_create_deferred(sr_rebuild, sd);
+ /* make sure we are not stomping on some other partition */
+ for (i = 0, vol = -1; i < SR_MAXSCSIBUS; i++) {
+ if (!sc->sc_dis[i])
+ continue;
+ sw = sc->sc_dis[i];
+ for (c = 0; c < sw->sd_meta->ssdi.ssd_chunk_no; c++)
+ if (sw->sd_vol.sv_chunks[c]->src_dev_mm == dev) {
+ printf("%s: %s chunk already in use\n",
+ DEVNAME(sc), devname);
+ goto done;
+ }
+ }
- break; /* all done */
+ /* recreate metadata */
+ open = 0; /* leave dev open from here on out */
+ sd->sd_vol.sv_chunks[found]->src_dev_mm = dev;
+ new->scmi.scm_volid = old->scmi.scm_volid;
+ new->scmi.scm_chunk_id = found;
+ strlcpy(new->scmi.scm_devname, devname,
+ sizeof new->scmi.scm_devname);
+ new->scmi.scm_size = size;
+ new->scmi.scm_coerced_size = old->scmi.scm_coerced_size;
+ bcopy(&old->scmi.scm_uuid, &new->scmi.scm_uuid,
+ sizeof new->scmi.scm_uuid);
+ sr_checksum(sc, new, &new->scm_checksum,
+ sizeof(struct sr_meta_chunk_invariant));
+ sd->sd_set_chunk_state(sd, found, BIOC_SDREBUILD);
+ if (sr_meta_save(sd, SR_META_DIRTY)) {
+ printf("%s: could not save metadata to %s\n",
+ DEVNAME(sc), devname);
+ goto done;
}
+ printf("%s: trying rebuild %s from %s\n", DEVNAME(sc),
+ sd->sd_meta->ssd_devname, devname);
+
+ kthread_create_deferred(sr_rebuild, sd);
+
rv = 0;
done:
if (open)