summaryrefslogtreecommitdiffstats
path: root/sys/geom
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2002-12-29 14:59:24 +0000
committerphk <phk@FreeBSD.org>2002-12-29 14:59:24 +0000
commit78a7deb4bb779eaaac181332869143e3fc21294b (patch)
treedbda3a3e9d00c9f670ffe3778efc36cbcde41af8 /sys/geom
parent590b9fdfdc9599c994f1e04d7304070dc530d107 (diff)
downloadFreeBSD-src-78a7deb4bb779eaaac181332869143e3fc21294b.zip
FreeBSD-src-78a7deb4bb779eaaac181332869143e3fc21294b.tar.gz
Implement ioctls for tampering with sector0.
Diffstat (limited to 'sys/geom')
-rw-r--r--sys/geom/geom_mbr.c111
1 files changed, 84 insertions, 27 deletions
diff --git a/sys/geom/geom_mbr.c b/sys/geom/geom_mbr.c
index d1a9720..457c7bb 100644
--- a/sys/geom/geom_mbr.c
+++ b/sys/geom/geom_mbr.c
@@ -106,17 +106,26 @@ g_enc_dos_partition(u_char *ptr, struct dos_partition *d)
struct g_mbr_softc {
int type [NDOSPART];
- struct dos_partition dospart[NDOSPART];
+ u_char sec0[512];
};
static int
-g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, struct dos_partition *dp)
+g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, u_char *sec0)
{
int i, error;
off_t l[NDOSPART];
+ struct dos_partition ndp[NDOSPART], *dp;
g_topology_assert();
+ if (sec0[0x1fe] != 0x55 && sec0[0x1ff] != 0xaa)
+ return (EBUSY);
+
+ dp = ndp;
+ for (i = 0; i < NDOSPART; i++)
+ g_dec_dos_partition(
+ sec0 + DOSPARTOFF + i * sizeof(struct dos_partition),
+ dp + i);
if ((!bcmp(dp, historical_bogus_partition_table,
sizeof historical_bogus_partition_table)) ||
(!bcmp(dp, historical_bogus_partition_table_fixed,
@@ -162,9 +171,43 @@ g_mbr_modify(struct g_geom *gp, struct g_mbr_softc *ms, struct dos_partition *dp
(off_t)dp[i].dp_start << 9ULL, l[i], 512,
"%ss%d", gp->name, 1 + i);
}
+ bcopy(sec0, ms->sec0, 512);
return (0);
}
+static void
+g_mbr_ioctl(void *arg)
+{
+ struct bio *bp;
+ struct g_geom *gp;
+ struct g_slicer *gsp;
+ struct g_mbr_softc *ms;
+ struct g_ioctl *gio;
+ struct g_consumer *cp;
+ u_char *sec0;
+ int error;
+
+ /* Get hold of the interesting bits from the bio. */
+ bp = arg;
+ gp = bp->bio_to->geom;
+ gsp = gp->softc;
+ ms = gsp->softc;
+ gio = (struct g_ioctl *)bp->bio_data;
+
+ /* The disklabel to set is the ioctl argument. */
+ sec0 = gio->data;
+
+ error = g_mbr_modify(gp, ms, sec0);
+ if (error) {
+ g_io_deliver(bp, error);
+ return;
+ }
+ cp = LIST_FIRST(&gp->consumer);
+ error = g_write_data(cp, 0, sec0, 512);
+ g_io_deliver(bp, error);
+}
+
+
static int
g_mbr_start(struct bio *bp)
{
@@ -172,7 +215,8 @@ g_mbr_start(struct bio *bp)
struct g_geom *gp;
struct g_mbr_softc *mp;
struct g_slicer *gsp;
- int idx;
+ struct g_ioctl *gio;
+ int idx, error;
pp = bp->bio_to;
idx = pp->index;
@@ -186,6 +230,40 @@ g_mbr_start(struct bio *bp)
gsp->slices[idx].offset))
return (1);
}
+
+ /* We only handle ioctl(2) requests of the right format. */
+ if (strcmp(bp->bio_attribute, "GEOM::ioctl"))
+ return (0);
+ else if (bp->bio_length != sizeof(*gio))
+ return (0);
+
+ /* Get hold of the ioctl parameters. */
+ gio = (struct g_ioctl *)bp->bio_data;
+
+ switch (gio->cmd) {
+ case DIOCGMBR:
+ /* Return a copy of the disklabel to userland. */
+ bcopy(mp->sec0, gio->data, 512);
+ g_io_deliver(bp, 0);
+ return (1);
+ case DIOCSMBR:
+ /*
+ * These we cannot do without the topology lock and some
+ * some I/O requests. Ask the event-handler to schedule
+ * us in a less restricted environment.
+ */
+ error = g_call_me(g_mbr_ioctl, bp);
+ if (error)
+ g_io_deliver(bp, error);
+ /*
+ * We must return non-zero to indicate that we will deal
+ * with this bio, even though we have not done so yet.
+ */
+ return (1);
+ default:
+ return (0);
+ }
+
return (0);
}
@@ -225,8 +303,7 @@ g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist)
{
struct g_geom *gp;
struct g_consumer *cp;
- int error, i;
- struct dos_partition dp[NDOSPART];
+ int error;
struct g_mbr_softc *ms;
struct g_slicer *gsp;
u_int fwsectors, sectorsize;
@@ -253,30 +330,10 @@ g_mbr_taste(struct g_class *mp, struct g_provider *pp, int insist)
buf = g_read_data(cp, 0, sectorsize, &error);
if (buf == NULL || error != 0)
break;
- if (buf[0x1fe] != 0x55 && buf[0x1ff] != 0xaa) {
- g_free(buf);
- break;
- }
- for (i = 0; i < NDOSPART; i++)
- g_dec_dos_partition(
- buf + DOSPARTOFF + i * sizeof(struct dos_partition),
- dp + i);
- g_free(buf);
- if (bcmp(dp, historical_bogus_partition_table,
- sizeof historical_bogus_partition_table) == 0) {
- if (bootverbose)
- printf("Ignoring known bogus MBR #0\n");
- break;
- }
- if (bcmp(dp, historical_bogus_partition_table_fixed,
- sizeof historical_bogus_partition_table_fixed) == 0) {
- if (bootverbose)
- printf("Ignoring known bogus MBR #1\n");
- break;
- }
g_topology_lock();
- g_mbr_modify(gp, ms, dp);
+ g_mbr_modify(gp, ms, buf);
g_topology_unlock();
+ g_free(buf);
break;
}
g_topology_lock();
OpenPOWER on IntegriCloud