summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_bsd.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-05-03 08:01:34 +0000
committerphk <phk@FreeBSD.org>2003-05-03 08:01:34 +0000
commitbbc021cef5bf2653bc66f885455851f31ccb3479 (patch)
tree45ec5c4bc695d816fbe5b392d48341a4e89f9ea4 /sys/geom/geom_bsd.c
parent53c33bd230087a300fe957b1f37af59d3aa11b94 (diff)
downloadFreeBSD-src-bbc021cef5bf2653bc66f885455851f31ccb3479.zip
FreeBSD-src-bbc021cef5bf2653bc66f885455851f31ccb3479.tar.gz
Add a OAM interface for changing the label and writing the boot code.
Diffstat (limited to 'sys/geom/geom_bsd.c')
-rw-r--r--sys/geom/geom_bsd.c152
1 files changed, 126 insertions, 26 deletions
diff --git a/sys/geom/geom_bsd.c b/sys/geom/geom_bsd.c
index 7fa11a2..c3579ab 100644
--- a/sys/geom/geom_bsd.c
+++ b/sys/geom/geom_bsd.c
@@ -231,6 +231,54 @@ g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int se
}
/*
+ * This function writes the current label to disk, possibly updating
+ * the alpha SRM checksum.
+ */
+
+static int
+g_bsd_writelabel(struct g_geom *gp, u_char *bootcode)
+{
+ off_t secoff;
+ u_int secsize;
+ struct g_consumer *cp;
+ struct g_slicer *gsp;
+ struct g_bsd_softc *ms;
+ u_char *buf;
+ uint64_t sum;
+ int error, i;
+
+ gsp = gp->softc;
+ ms = gsp->softc;
+ cp = LIST_FIRST(&gp->consumer);
+ /* Get sector size, we need it to read data. */
+ secsize = cp->provider->sectorsize;
+ secoff = ms->labeloffset % secsize;
+ if (bootcode == NULL) {
+ buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
+ if (buf == NULL || error != 0)
+ return (error);
+ bcopy(ms->label, buf + secoff, sizeof(ms->label));
+ } else {
+ buf = bootcode;
+ bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label));
+ }
+ if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
+ sum = 0;
+ for (i = 0; i < 63; i++)
+ sum += le64dec(buf + i * 8);
+ le64enc(buf + 504, sum);
+ }
+ if (bootcode == NULL) {
+ error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
+ g_free(buf);
+ } else {
+ error = g_write_data(cp, 0, bootcode, BBSIZE);
+ }
+ return(error);
+}
+
+
+/*
* Implement certain ioctls to modify disklabels with. This function
* is called by the event handler thread with topology locked as result
* of the g_post_event() in g_bsd_start(). It is not necessary to keep
@@ -246,12 +294,8 @@ g_bsd_ioctl(void *arg, int flag)
struct g_slicer *gsp;
struct g_bsd_softc *ms;
struct g_ioctl *gio;
- struct g_consumer *cp;
- u_char *buf, *label;
- off_t secoff;
- u_int secsize;
- int error, i;
- uint64_t sum;
+ u_char *label;
+ int error;
g_topology_assert();
bp = arg;
@@ -279,26 +323,7 @@ g_bsd_ioctl(void *arg, int flag)
}
KASSERT(gio->cmd == DIOCWDINFO, ("Unknown ioctl in g_bsd_ioctl"));
-
- cp = LIST_FIRST(&gp->consumer);
- /* Get sector size, we need it to read data. */
- secsize = cp->provider->sectorsize;
- secoff = ms->labeloffset % secsize;
- buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
- if (buf == NULL || error != 0) {
- g_io_deliver(bp, error);
- return;
- }
- bcopy(ms->label, buf + secoff, sizeof(ms->label));
- if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
- sum = 0;
- for (i = 0; i < 63; i++)
- sum += le64dec(buf + i * 8);
- le64enc(buf + 504, sum);
- }
- error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
- g_free(buf);
- g_io_deliver(bp, error);
+ g_io_deliver(bp, g_bsd_writelabel(gp, NULL));
}
/*
@@ -641,10 +666,85 @@ g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
return (NULL);
}
+struct h0h0 {
+ struct g_geom *gp;
+ struct g_bsd_softc *ms;
+ u_char *label;
+ int error;
+};
+
+static void
+g_bsd_callconfig(void *arg, int flag)
+{
+ struct h0h0 *hp;
+
+ hp = arg;
+ hp->error = g_bsd_modify(hp->gp, hp->label);
+ if (!hp->error)
+ hp->error = g_bsd_writelabel(hp->gp, NULL);
+}
+
+/*
+ * NB! curthread is user process which GCTL'ed.
+ */
+static int
+g_bsd_config(struct gctl_req *req, struct g_geom *gp, const char *verb)
+{
+ u_char *label;
+ int error, i;
+ struct h0h0 h0h0;
+ struct g_slicer *gsp;
+ struct g_consumer *cp;
+
+ i = 0;
+ g_topology_assert();
+ cp = LIST_FIRST(&gp->consumer);
+ gsp = gp->softc;
+ if (!strcmp(verb, "write label")) {
+ label = gctl_get_paraml(req, "label", LABELSIZE);
+ if (label == NULL)
+ return (EINVAL);
+ h0h0.gp = gp;
+ h0h0.ms = gsp->softc;
+ h0h0.label = label;
+ h0h0.error = -1;
+ /* XXX: Does this reference register with our selfdestruct code ? */
+ error = g_access_rel(cp, 1, 1, 1);
+ if (error) {
+ g_free(label);
+ return (error);
+ }
+ g_topology_unlock();
+ g_waitfor_event(g_bsd_callconfig, &h0h0, M_WAITOK, gp, NULL);
+ g_topology_lock();
+ error = h0h0.error;
+ g_access_rel(cp, -1, -1, -1);
+ g_free(label);
+ } else if (!strcmp(verb, "write bootcode")) {
+ label = gctl_get_paraml(req, "bootcode", BBSIZE);
+ if (label == NULL)
+ return (EINVAL);
+ /* XXX: Does this reference register with our selfdestruct code ? */
+ error = g_access_rel(cp, 1, 1, 1);
+ if (error) {
+ g_free(label);
+ return (error);
+ }
+ error = g_bsd_writelabel(gp, label);
+ g_access_rel(cp, -1, -1, -1);
+ g_free(label);
+ } else {
+ return (gctl_error(req, "Unknown verb parameter"));
+ }
+
+ return (error);
+}
+
/* Finally, register with GEOM infrastructure. */
static struct g_class g_bsd_class = {
.name = BSD_CLASS_NAME,
.taste = g_bsd_taste,
+ .config_geom = g_bsd_config,
G_CLASS_INITIALIZER
};
OpenPOWER on IntegriCloud