summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_bsd.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-01-26 21:54:36 +0000
committerphk <phk@FreeBSD.org>2003-01-26 21:54:36 +0000
commitf71e2dab31370e0325052fc73b068e52032e831e (patch)
tree70afd612269d511d30366eccb8b10b03b5585207 /sys/geom/geom_bsd.c
parent0d45de23ba9e63ea3cdc543dd8676df4151503cd (diff)
downloadFreeBSD-src-f71e2dab31370e0325052fc73b068e52032e831e.zip
FreeBSD-src-f71e2dab31370e0325052fc73b068e52032e831e.tar.gz
Implement DIOCBSDBB ioctl which overwrites first BBSIZE bytes of BSD
labeled disk. This is complicated by the fact that BBSIZE is greater than the PAGE_SIZE limit ioctl inflicts on arguments which are automatically copied in. As long as we don't need access to userland memory (copyin/out) we can deal with the ioctl using g_callme() which executes it from the GEOM event thread. Once we need copyin/out, we need to return the bio with EDIRIOCTL in order to make geom_dev call us back in the original process context where copyin will work. Unfortunately, that results in us getting called with Giant, so we have to DROP_GIANT/PICKUP_GIANT around the code where we diddle GEOMs internals. Sometimes you just can't win... ... But it does make geom_bsd.c an almost complete example of the GEOM beastiarium.
Diffstat (limited to 'sys/geom/geom_bsd.c')
-rw-r--r--sys/geom/geom_bsd.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c
index 70c0758..2f93f32 100644
--- a/sys/geom/geom_bsd.c
+++ b/sys/geom/geom_bsd.c
@@ -547,6 +547,63 @@ g_bsd_ioctl(void *arg)
}
/*
+ * Rewrite the bootblock, which is BBSIZE bytes from the start of the disk.
+ * We punch down the disklabel where we expect it to be before writing.
+ */
+static int
+g_bsd_diocbsdbb(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ struct g_geom *gp;
+ struct g_slicer *gsp;
+ struct g_bsd_softc *ms;
+ struct disklabel *dl;
+ struct g_consumer *cp;
+ u_char *buf;
+ void *p;
+ u_int secsize;
+ int error, i;
+ uint64_t sum;
+
+ /* Get hold of the interesting bits from the bio. */
+ gp = (void *)dev;
+ gsp = gp->softc;
+ ms = gsp->softc;
+
+ /* The disklabel to set is the ioctl argument. */
+ buf = g_malloc(BBSIZE, 0);
+ p = *(void **)data;
+ error = copyin(p, buf, BBSIZE);
+ if (error) {
+ g_free(buf);
+ return (error);
+ }
+ /* The disklabel to set is the ioctl argument. */
+ dl = (void *)(buf + ms->labeloffset);
+
+ DROP_GIANT();
+
+ /* Validate and modify our slice instance to match. */
+ error = g_bsd_modify(gp, dl); /* Picks up topology lock on success. */
+ if (!error) {
+ cp = LIST_FIRST(&gp->consumer);
+ secsize = cp->provider->sectorsize;
+ dl = &ms->ondisk;
+ g_bsd_leenc_disklabel(buf + ms->labeloffset, dl);
+ if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
+ sum = 0;
+ for (i = 0; i < 63; i++)
+ sum += g_dec_le8(buf + i * 8);
+ g_enc_le8(buf + 504, sum);
+ }
+ error = g_write_data(cp, 0, buf, BBSIZE);
+ g_topology_unlock();
+ }
+ g_free(buf);
+ PICKUP_GIANT();
+ return (error);
+}
+
+/*
* If the user tries to overwrite our disklabel through an open partition
* or via a magicwrite config call, we end up here and try to prevent
* footshooting as best we can.
@@ -655,6 +712,11 @@ g_bsd_start(struct bio *bp)
bcopy(&ms->inram, gio->data, sizeof(ms->inram));
g_io_deliver(bp, 0);
return (1);
+ case DIOCBSDBB:
+ gio->func = g_bsd_diocbsdbb;
+ gio->dev = (void *)gp;
+ g_io_deliver(bp, EDIRIOCTL);
+ return (1);
case DIOCSDINFO:
case DIOCWDINFO:
/*
OpenPOWER on IntegriCloud