geom_ctl.c revision 112534
1105068Sphk/*- 2105068Sphk * Copyright (c) 2002 Poul-Henning Kamp 3105068Sphk * Copyright (c) 2002 Networks Associates Technology, Inc. 4105068Sphk * All rights reserved. 5105068Sphk * 6105068Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7105068Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc. 8105068Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9105068Sphk * DARPA CHATS research program. 10105068Sphk * 11105068Sphk * Redistribution and use in source and binary forms, with or without 12105068Sphk * modification, are permitted provided that the following conditions 13105068Sphk * are met: 14105068Sphk * 1. Redistributions of source code must retain the above copyright 15105068Sphk * notice, this list of conditions and the following disclaimer. 16105068Sphk * 2. Redistributions in binary form must reproduce the above copyright 17105068Sphk * notice, this list of conditions and the following disclaimer in the 18105068Sphk * documentation and/or other materials provided with the distribution. 19105068Sphk * 3. The names of the authors may not be used to endorse or promote 20105068Sphk * products derived from this software without specific prior written 21105068Sphk * permission. 22105068Sphk * 23105068Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24105068Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25105068Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26105068Sphk * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27105068Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28105068Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29105068Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30105068Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31105068Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32105068Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33105068Sphk * SUCH DAMAGE. 34105068Sphk * 35105068Sphk * $FreeBSD: head/sys/geom/geom_ctl.c 112534 2003-03-24 13:37:15Z phk $ 36105068Sphk */ 37105068Sphk 38105068Sphk#include "opt_geom.h" 39105068Sphk 40105068Sphk#include <sys/param.h> 41105068Sphk#include <sys/systm.h> 42105068Sphk#include <sys/kernel.h> 43105068Sphk#include <sys/sysctl.h> 44105068Sphk#include <sys/bio.h> 45105068Sphk#include <sys/conf.h> 46105068Sphk#include <sys/disk.h> 47105068Sphk#include <sys/malloc.h> 48105068Sphk#include <sys/sysctl.h> 49105068Sphk 50105068Sphk#include <sys/lock.h> 51105068Sphk#include <sys/mutex.h> 52112511Sphk 53112511Sphk#include <vm/vm.h> 54112511Sphk#include <vm/vm_extern.h> 55112511Sphk 56105068Sphk#include <geom/geom.h> 57105068Sphk#include <geom/geom_int.h> 58112511Sphk#define GEOM_CTL_TABLE 1 59112511Sphk#include <geom/geom_ctl.h> 60112511Sphk#include <geom/geom_ext.h> 61105068Sphk 62105068Sphkstatic d_ioctl_t g_ctl_ioctl; 63105068Sphk 64112534Sphkstatic struct cdevsw g_ctl_cdevsw = { 65112534Sphk .d_open = nullopen, 66112534Sphk .d_close = nullclose, 67112534Sphk .d_ioctl = g_ctl_ioctl, 68112534Sphk .d_name = "g_ctl", 69105068Sphk}; 70105068Sphk 71112534Sphkvoid 72105068Sphkg_ctl_init(void) 73105068Sphk{ 74105068Sphk 75112534Sphk make_dev(&g_ctl_cdevsw, 0, 76112534Sphk UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL); 77105068Sphk} 78105068Sphk 79105068Sphkstatic int 80105092Sphkg_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 81105092Sphk{ 82105092Sphk struct geomconfiggeom *gcp; 83106518Sphk struct g_configargs ga; 84105092Sphk int error; 85105092Sphk 86105092Sphk error = 0; 87105504Sphk bzero(&ga, sizeof ga); 88105092Sphk gcp = (struct geomconfiggeom *)data; 89105092Sphk ga.class = g_idclass(&gcp->class); 90105092Sphk if (ga.class == NULL) 91105092Sphk return (EINVAL); 92106518Sphk if (ga.class->config == NULL) 93105092Sphk return (EOPNOTSUPP); 94105504Sphk ga.geom = g_idgeom(&gcp->geom); 95105092Sphk ga.provider = g_idprovider(&gcp->provider); 96105092Sphk ga.len = gcp->len; 97105092Sphk if (gcp->len > 64 * 1024) 98105092Sphk return (EINVAL); 99105092Sphk else if (gcp->len == 0) { 100105092Sphk ga.ptr = NULL; 101105092Sphk } else { 102111119Simp ga.ptr = g_malloc(gcp->len, M_WAITOK); 103106518Sphk error = copyin(gcp->ptr, ga.ptr, gcp->len); 104106518Sphk if (error) { 105106518Sphk g_free(ga.ptr); 106106518Sphk return (error); 107106518Sphk } 108105092Sphk } 109105504Sphk ga.flag = gcp->flag; 110106518Sphk error = ga.class->config(&ga); 111106518Sphk if (gcp->len != 0) 112106518Sphk copyout(ga.ptr, gcp->ptr, gcp->len); /* Ignore error */ 113105504Sphk gcp->class.u.id = (uintptr_t)ga.class; 114105504Sphk gcp->class.len = 0; 115105504Sphk gcp->geom.u.id = (uintptr_t)ga.geom; 116105504Sphk gcp->geom.len = 0; 117105504Sphk gcp->provider.u.id = (uintptr_t)ga.provider; 118105504Sphk gcp->provider.len = 0; 119105092Sphk return(error); 120105092Sphk} 121105092Sphk 122112511Sphk/* 123112511Sphk * Report an error back to the user in ascii format. Return whatever copyout 124112511Sphk * returned, or EINVAL if it succeeded. 125112511Sphk * XXX: should not be static. 126112511Sphk * XXX: should take printf like args. 127112511Sphk */ 128105092Sphkstatic int 129112511Sphkg_ctl_seterror(struct geom_ctl_req *req, const char *errtxt) 130112511Sphk{ 131112511Sphk int error; 132112511Sphk 133112511Sphk error = copyout(errtxt, req->error, 134112511Sphk imin(req->lerror, strlen(errtxt) + 1)); 135112511Sphk if (!error) 136112511Sphk error = EINVAL; 137112511Sphk return (error); 138112511Sphk} 139112511Sphk 140112511Sphk/* 141112511Sphk * Allocate space and copyin() something. 142112511Sphk * XXX: this should really be a standard function in the kernel. 143112511Sphk */ 144112511Sphkstatic void * 145112511Sphkgeom_alloc_copyin(void *uaddr, size_t len, int *errp) 146112511Sphk{ 147112511Sphk int error; 148112511Sphk void *ptr; 149112511Sphk 150112511Sphk ptr = g_malloc(len, M_WAITOK); 151112511Sphk if (ptr == NULL) 152112511Sphk error = ENOMEM; 153112511Sphk else 154112511Sphk error = copyin(uaddr, ptr, len); 155112511Sphk if (!error) 156112511Sphk return (ptr); 157112511Sphk *errp = error; 158112511Sphk if (ptr != NULL) 159112511Sphk g_free(ptr); 160112511Sphk return (NULL); 161112511Sphk} 162112511Sphk 163112511Sphk 164112511Sphk/* 165112511Sphk * XXX: This function is a nightmare. It walks through the request and 166112511Sphk * XXX: makes sure that the various bits and pieces are there and copies 167112511Sphk * XXX: some of them into kernel memory to make things easier. 168112511Sphk * XXX: I really wish we had a standard marshalling layer somewhere. 169112511Sphk */ 170112511Sphk 171112511Sphkstatic int 172112511Sphkgeom_ctl_copyin(struct geom_ctl_req *req) 173112511Sphk{ 174112511Sphk int error, i, j; 175112511Sphk struct geom_ctl_req_arg *ap; 176112511Sphk char *p; 177112511Sphk 178112511Sphk error = 0; 179112511Sphk if (!useracc(req->error, req->lerror, VM_PROT_WRITE)) 180112511Sphk return (g_ctl_seterror(req, "No access to error field")); 181112511Sphk ap = geom_alloc_copyin(req->arg, req->narg * sizeof(*ap), &error); 182112511Sphk if (ap == NULL) 183112511Sphk return (error); 184112511Sphk for (i = 0; !error && i < req->narg; i++) { 185112511Sphk if (ap[i].len < 0 && 186112511Sphk !useracc(ap[i].value, 1 + -ap[i].len, VM_PROT_READ)) 187112511Sphk error = g_ctl_seterror(req, "No access to param data"); 188112511Sphk else if (ap[i].len > 0 && 189112511Sphk !useracc(ap[i].value, ap[i].len, 190112511Sphk VM_PROT_READ | VM_PROT_WRITE)) 191112511Sphk error = g_ctl_seterror(req, "No access to param data"); 192112511Sphk if (ap[i].name == NULL) 193112511Sphk continue; 194112511Sphk p = NULL; 195112511Sphk if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) 196112511Sphk error = EINVAL; 197112511Sphk if (error) 198112511Sphk break; 199112511Sphk p = geom_alloc_copyin(ap[i].name, ap[i].nlen + 1, &error); 200112511Sphk if (error) 201112511Sphk break; 202112511Sphk if (p[ap[i].nlen] != '\0') 203112511Sphk error = EINVAL; 204112511Sphk if (!error) { 205112511Sphk ap[i].name = p; 206112511Sphk ap[i].nlen = 0; 207112511Sphk } else { 208112511Sphk g_free(p); 209112511Sphk break; 210112511Sphk } 211112511Sphk } 212112511Sphk if (!error) { 213112511Sphk req->arg = ap; 214112511Sphk return (0); 215112511Sphk } 216112511Sphk for (j = 0; j < i; j++) 217112511Sphk if (ap[j].nlen == 0 && ap[j].name != NULL) 218112511Sphk g_free(ap[j].name); 219112511Sphk g_free(ap); 220112511Sphk return (error); 221112511Sphk} 222112511Sphk 223112511Sphkstatic void 224112511Sphkgeom_ctl_dump(struct geom_ctl_req *req) 225112511Sphk{ 226112511Sphk u_int i; 227112511Sphk int j, error; 228112511Sphk struct geom_ctl_req_arg *ap; 229112511Sphk void *p; 230112511Sphk 231112511Sphk 232112511Sphk printf("Dump of geom_ctl %s request at %p:\n", req->reqt->name, req); 233112511Sphk if (req->lerror > 0) { 234112511Sphk p = geom_alloc_copyin(req->error, req->lerror, &error); 235112511Sphk if (p != NULL) { 236112511Sphk ((char *)p)[req->lerror - 1] = '\0'; 237112511Sphk printf(" error:\t\"%s\"\n", (char *)p); 238112511Sphk g_free(p); 239112511Sphk } 240112511Sphk } 241112511Sphk for (i = 0; i < req->narg; i++) { 242112511Sphk ap = &req->arg[i]; 243112511Sphk if (ap->name != NULL) 244112511Sphk printf(" param:\t\"%s\"", ap->name); 245112511Sphk else 246112511Sphk printf(" meta:\t@%jd", (intmax_t)ap->offset); 247112511Sphk printf(" [%d] = ", ap->len); 248112511Sphk if (ap->len < 0) { 249112511Sphk p = geom_alloc_copyin(ap->value, 1 + -ap->len, &error); 250112511Sphk ((char *)p)[-ap->len] = '\0'; 251112511Sphk if (p != NULL) 252112511Sphk printf("\"%s\"", (char *)p); 253112511Sphk g_free(p); 254112511Sphk } else if (ap->len > 0) { 255112511Sphk p = geom_alloc_copyin(ap->value, ap->len, &error); 256112511Sphk for (j = 0; j < ap->len; j++) 257112511Sphk printf(" %02x", ((u_char *)p)[j]); 258112511Sphk g_free(p); 259112511Sphk } else { 260112511Sphk printf(" = %p", ap->value); 261112511Sphk } 262112511Sphk printf("\n"); 263112511Sphk } 264112511Sphk} 265112511Sphk 266112511Sphk/* 267112511Sphk * Handle ioctl from libgeom::geom_ctl.c 268112511Sphk */ 269112511Sphkstatic int 270112511Sphkg_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 271112511Sphk{ 272112511Sphk int error; 273112511Sphk int i; 274112511Sphk struct geom_ctl_req *req; 275112511Sphk 276112511Sphk req = (void *)data; 277112511Sphk if (req->lerror < 1) 278112511Sphk return (EINVAL); 279112511Sphk if (req->version != GEOM_CTL_VERSION) 280112511Sphk return (g_ctl_seterror(req, 281112511Sphk "Kernel and libgeom version skew.")); 282112511Sphk for (i = 0; gcrt[i].request != GEOM_INVALID_REQUEST; i++) 283112511Sphk if (gcrt[i].request == req->request) { 284112511Sphk req->reqt = &gcrt[i]; 285112511Sphk break; 286112511Sphk } 287112511Sphk if (gcrt[i].request == GEOM_INVALID_REQUEST) 288112511Sphk return (g_ctl_seterror(req, "Invalid request")); 289112511Sphk error = geom_ctl_copyin(req); 290112511Sphk if (error) 291112511Sphk return (error); 292112534Sphk req->reqt = &gcrt[i]; 293112534Sphk g_stall_events(); 294112511Sphk geom_ctl_dump(req); 295112534Sphk g_release_events(); 296112511Sphk return (0); 297112511Sphk} 298112511Sphk 299112511Sphkstatic int 300105068Sphkg_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 301105068Sphk{ 302105068Sphk int error; 303105068Sphk 304105068Sphk switch(cmd) { 305105092Sphk case GEOMCONFIGGEOM: 306112534Sphk DROP_GIANT(); 307112534Sphk g_topology_lock(); 308105092Sphk error = g_ctl_ioctl_configgeom(dev, cmd, data, fflag, td); 309112534Sphk g_topology_unlock(); 310112534Sphk PICKUP_GIANT(); 311105092Sphk break; 312112511Sphk case GEOM_CTL: 313112511Sphk error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td); 314112511Sphk break; 315105068Sphk default: 316105068Sphk error = ENOTTY; 317105068Sphk break; 318105068Sphk } 319105068Sphk return (error); 320105068Sphk 321105068Sphk} 322