summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-03-23 10:16:14 +0000
committerphk <phk@FreeBSD.org>2003-03-23 10:16:14 +0000
commit35c6fd6e4d230bf1784a3b34fe9f8e016159d614 (patch)
tree44d6b0e7213b172d67bc6c90c9530944d49fe314
parentdaa779779c50fac88bb9b400c4841a2559f0ce3e (diff)
downloadFreeBSD-src-35c6fd6e4d230bf1784a3b34fe9f8e016159d614.zip
FreeBSD-src-35c6fd6e4d230bf1784a3b34fe9f8e016159d614.tar.gz
Marshalling stuff for OAM API.
-rw-r--r--sys/geom/geom_ctl.c185
-rw-r--r--sys/geom/geom_ext.h2
2 files changed, 187 insertions, 0 deletions
diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c
index 1cb502c..a206305 100644
--- a/sys/geom/geom_ctl.c
+++ b/sys/geom/geom_ctl.c
@@ -49,8 +49,16 @@
#include <sys/lock.h>
#include <sys/mutex.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+
#include <geom/geom.h>
#include <geom/geom_int.h>
+#define GEOM_CTL_TABLE 1
+#include <geom/geom_ctl.h>
+#include <geom/geom_ext.h>
+
static g_access_t g_ctl_access;
static g_start_t g_ctl_start;
@@ -193,6 +201,180 @@ g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct th
return(error);
}
+/*
+ * Report an error back to the user in ascii format. Return whatever copyout
+ * returned, or EINVAL if it succeeded.
+ * XXX: should not be static.
+ * XXX: should take printf like args.
+ */
+static int
+g_ctl_seterror(struct geom_ctl_req *req, const char *errtxt)
+{
+ int error;
+
+ error = copyout(errtxt, req->error,
+ imin(req->lerror, strlen(errtxt) + 1));
+ if (!error)
+ error = EINVAL;
+ return (error);
+}
+
+/*
+ * Allocate space and copyin() something.
+ * XXX: this should really be a standard function in the kernel.
+ */
+static void *
+geom_alloc_copyin(void *uaddr, size_t len, int *errp)
+{
+ int error;
+ void *ptr;
+
+ ptr = g_malloc(len, M_WAITOK);
+ if (ptr == NULL)
+ error = ENOMEM;
+ else
+ error = copyin(uaddr, ptr, len);
+ if (!error)
+ return (ptr);
+ *errp = error;
+ if (ptr != NULL)
+ g_free(ptr);
+ return (NULL);
+}
+
+
+/*
+ * XXX: This function is a nightmare. It walks through the request and
+ * XXX: makes sure that the various bits and pieces are there and copies
+ * XXX: some of them into kernel memory to make things easier.
+ * XXX: I really wish we had a standard marshalling layer somewhere.
+ */
+
+static int
+geom_ctl_copyin(struct geom_ctl_req *req)
+{
+ int error, i, j;
+ struct geom_ctl_req_arg *ap;
+ char *p;
+
+ error = 0;
+ if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
+ return (g_ctl_seterror(req, "No access to error field"));
+ ap = geom_alloc_copyin(req->arg, req->narg * sizeof(*ap), &error);
+ if (ap == NULL)
+ return (error);
+ for (i = 0; !error && i < req->narg; i++) {
+ if (ap[i].len < 0 &&
+ !useracc(ap[i].value, 1 + -ap[i].len, VM_PROT_READ))
+ error = g_ctl_seterror(req, "No access to param data");
+ else if (ap[i].len > 0 &&
+ !useracc(ap[i].value, ap[i].len,
+ VM_PROT_READ | VM_PROT_WRITE))
+ error = g_ctl_seterror(req, "No access to param data");
+ if (ap[i].name == NULL)
+ continue;
+ p = NULL;
+ if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN)
+ error = EINVAL;
+ if (error)
+ break;
+ p = geom_alloc_copyin(ap[i].name, ap[i].nlen + 1, &error);
+ if (error)
+ break;
+ if (p[ap[i].nlen] != '\0')
+ error = EINVAL;
+ if (!error) {
+ ap[i].name = p;
+ ap[i].nlen = 0;
+ } else {
+ g_free(p);
+ break;
+ }
+ }
+ if (!error) {
+ req->arg = ap;
+ return (0);
+ }
+ for (j = 0; j < i; j++)
+ if (ap[j].nlen == 0 && ap[j].name != NULL)
+ g_free(ap[j].name);
+ g_free(ap);
+ return (error);
+}
+
+static void
+geom_ctl_dump(struct geom_ctl_req *req)
+{
+ u_int i;
+ int j, error;
+ struct geom_ctl_req_arg *ap;
+ void *p;
+
+
+ printf("Dump of geom_ctl %s request at %p:\n", req->reqt->name, req);
+ if (req->lerror > 0) {
+ p = geom_alloc_copyin(req->error, req->lerror, &error);
+ if (p != NULL) {
+ ((char *)p)[req->lerror - 1] = '\0';
+ printf(" error:\t\"%s\"\n", (char *)p);
+ g_free(p);
+ }
+ }
+ for (i = 0; i < req->narg; i++) {
+ ap = &req->arg[i];
+ if (ap->name != NULL)
+ printf(" param:\t\"%s\"", ap->name);
+ else
+ printf(" meta:\t@%jd", (intmax_t)ap->offset);
+ printf(" [%d] = ", ap->len);
+ if (ap->len < 0) {
+ p = geom_alloc_copyin(ap->value, 1 + -ap->len, &error);
+ ((char *)p)[-ap->len] = '\0';
+ if (p != NULL)
+ printf("\"%s\"", (char *)p);
+ g_free(p);
+ } else if (ap->len > 0) {
+ p = geom_alloc_copyin(ap->value, ap->len, &error);
+ for (j = 0; j < ap->len; j++)
+ printf(" %02x", ((u_char *)p)[j]);
+ g_free(p);
+ } else {
+ printf(" = %p", ap->value);
+ }
+ printf("\n");
+ }
+}
+
+/*
+ * Handle ioctl from libgeom::geom_ctl.c
+ */
+static int
+g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
+{
+ int error;
+ int i;
+ struct geom_ctl_req *req;
+
+ req = (void *)data;
+ if (req->lerror < 1)
+ return (EINVAL);
+ if (req->version != GEOM_CTL_VERSION)
+ return (g_ctl_seterror(req,
+ "Kernel and libgeom version skew."));
+ for (i = 0; gcrt[i].request != GEOM_INVALID_REQUEST; i++)
+ if (gcrt[i].request == req->request) {
+ req->reqt = &gcrt[i];
+ break;
+ }
+ if (gcrt[i].request == GEOM_INVALID_REQUEST)
+ return (g_ctl_seterror(req, "Invalid request"));
+ error = geom_ctl_copyin(req);
+ if (error)
+ return (error);
+ geom_ctl_dump(req);
+ return (0);
+}
+
static int
g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
{
@@ -204,6 +386,9 @@ g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
case GEOMCONFIGGEOM:
error = g_ctl_ioctl_configgeom(dev, cmd, data, fflag, td);
break;
+ case GEOM_CTL:
+ error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td);
+ break;
default:
error = ENOTTY;
break;
diff --git a/sys/geom/geom_ext.h b/sys/geom/geom_ext.h
index 15c0d17..b247dae 100644
--- a/sys/geom/geom_ext.h
+++ b/sys/geom/geom_ext.h
@@ -60,4 +60,6 @@ struct geom_ctl_req {
#define GEOM_CTL _IOW('G', GEOM_CTL_VERSION, struct geom_ctl_req)
+#define PATH_GEOM_CTL "geom.ctl"
+
#endif /* _GEOM_GEOM_EXT_H_ */
OpenPOWER on IntegriCloud