The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/geom_ctl.c

Version: -  FREEBSD  -  FREEBSD11  -  FREEBSD10  -  FREEBSD9  -  FREEBSD92  -  FREEBSD91  -  FREEBSD90  -  FREEBSD8  -  FREEBSD82  -  FREEBSD81  -  FREEBSD80  -  FREEBSD7  -  FREEBSD74  -  FREEBSD73  -  FREEBSD72  -  FREEBSD71  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2002 Poul-Henning Kamp
    3  * Copyright (c) 2002 Networks Associates Technology, Inc.
    4  * All rights reserved.
    5  *
    6  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
    7  * and NAI Labs, the Security Research Division of Network Associates, Inc.
    8  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
    9  * DARPA CHATS research program.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. The names of the authors may not be used to endorse or promote
   20  *    products derived from this software without specific prior written
   21  *    permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  *
   35  * $FreeBSD: src/sys/geom/geom_ctl.c,v 1.22 2003/05/04 19:24:34 phk Exp $
   36  */
   37 
   38 #include "opt_geom.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/systm.h>
   42 #include <sys/kernel.h>
   43 #include <sys/sysctl.h>
   44 #include <sys/bio.h>
   45 #include <sys/conf.h>
   46 #include <sys/disk.h>
   47 #include <sys/malloc.h>
   48 #include <sys/sysctl.h>
   49 #include <sys/sbuf.h>
   50 
   51 #include <sys/lock.h>
   52 #include <sys/mutex.h>
   53 
   54 #include <vm/vm.h>
   55 #include <vm/vm_extern.h>
   56 
   57 #include <geom/geom.h>
   58 #include <geom/geom_int.h>
   59 #define GCTL_TABLE 1
   60 #include <geom/geom_ctl.h>
   61 #include <geom/geom_ext.h>
   62 
   63 #include <machine/stdarg.h>
   64 
   65 static d_ioctl_t g_ctl_ioctl;
   66 
   67 static struct cdevsw g_ctl_cdevsw = {
   68         .d_open =       nullopen,
   69         .d_close =      nullclose,
   70         .d_ioctl =      g_ctl_ioctl,
   71         .d_name =       "g_ctl",
   72 };
   73 
   74 void
   75 g_ctl_init(void)
   76 {
   77 
   78         make_dev(&g_ctl_cdevsw, 0,
   79             UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL);
   80         KASSERT(GCTL_PARAM_RD == VM_PROT_READ,
   81                 ("GCTL_PARAM_RD != VM_PROT_READ"));
   82         KASSERT(GCTL_PARAM_WR == VM_PROT_WRITE,
   83                 ("GCTL_PARAM_WR != VM_PROT_WRITE"));
   84 }
   85 
   86 /*
   87  * Report an error back to the user in ascii format.  Return whatever copyout
   88  * returned, or EINVAL if it succeeded.
   89  * XXX: should not be static.
   90  * XXX: should take printf like args.
   91  */
   92 int
   93 gctl_error(struct gctl_req *req, const char *fmt, ...)
   94 {
   95         int error;
   96         va_list ap;
   97         struct sbuf *sb;
   98 
   99         sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
  100         if (sb == NULL) {
  101                 error = copyout(fmt, req->error,
  102                             imin(req->lerror, strlen(fmt) + 1));
  103         } else {
  104                 va_start(ap, fmt);
  105                 sbuf_vprintf(sb, fmt, ap);
  106                 sbuf_finish(sb);
  107                 if (g_debugflags & G_F_CTLDUMP)
  108                         printf("gctl %p error \"%s\"\n", req, sbuf_data(sb));
  109                 error = copyout(sbuf_data(sb), req->error,
  110                     imin(req->lerror, sbuf_len(sb) + 1));
  111         }
  112         if (!error)
  113                 error = EINVAL;
  114         sbuf_delete(sb);
  115         return (error);
  116 }
  117 
  118 /*
  119  * Allocate space and copyin() something.
  120  * XXX: this should really be a standard function in the kernel.
  121  */
  122 static void *
  123 geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len, int *errp)
  124 {
  125         int error;
  126         void *ptr;
  127 
  128         ptr = g_malloc(len, M_WAITOK);
  129         if (ptr == NULL)
  130                 error = ENOMEM;
  131         else
  132                 error = copyin(uaddr, ptr, len);
  133         if (!error)
  134                 return (ptr);
  135         gctl_error(req, "no access to argument");
  136         *errp = error;
  137         if (ptr != NULL)
  138                 g_free(ptr);
  139         return (NULL);
  140 }
  141 
  142 
  143 /*
  144  * XXX: This function is a nightmare.  It walks through the request and
  145  * XXX: makes sure that the various bits and pieces are there and copies
  146  * XXX: some of them into kernel memory to make things easier.
  147  * XXX: I really wish we had a standard marshalling layer somewhere.
  148  */
  149 
  150 static int
  151 gctl_copyin(struct gctl_req *req)
  152 {
  153         int error, i, j;
  154         struct gctl_req_arg *ap;
  155         char *p;
  156 
  157         error = 0;
  158         ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap), &error);
  159         if (ap == NULL) {
  160                 gctl_error(req, "copyin() of arguments failed");
  161                 return (error);
  162         }
  163 
  164         for (i = 0; !error && i < req->narg; i++) {
  165                 if (ap[i].len > 0 &&
  166                     !useracc(ap[i].value, ap[i].len, 
  167                     ap[i].flag & GCTL_PARAM_RW))
  168                         error = gctl_error(req, "no access to param data");
  169                 if (error)
  170                         break;
  171                 p = NULL;
  172                 if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) {
  173                         error = gctl_error(req, "wrong param name length");
  174                         break;
  175                 }
  176                 p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen, &error);
  177                 if (p == NULL)
  178                         break;
  179                 if (p[ap[i].nlen - 1] != '\0') {
  180                         error = gctl_error(req, "unterminated param name");
  181                         g_free(p);
  182                         break;
  183                 }
  184                 ap[i].name = p;
  185                 ap[i].nlen = 0;
  186         }
  187         if (!error) {
  188                 req->arg = ap;
  189                 return (0);
  190         }
  191         for (j = 0; j < i; j++)
  192                 if (ap[j].nlen == 0 && ap[j].name != NULL)
  193                         g_free(ap[j].name);
  194         g_free(ap);
  195         return (error);
  196 }
  197 
  198 static void
  199 gctl_free(struct gctl_req *req)
  200 {
  201         int i;
  202 
  203         for (i = 0; i < req->narg; i++) {
  204                 if (req->arg[i].nlen == 0 && req->arg[i].name != NULL)
  205                         g_free(req->arg[i].name);
  206         }
  207         g_free(req->arg);
  208 }
  209 
  210 static void
  211 gctl_dump(struct gctl_req *req)
  212 {
  213         u_int i;
  214         int j, error;
  215         struct gctl_req_arg *ap;
  216         void *p;
  217         
  218 
  219         printf("Dump of gctl %s request at %p:\n", req->reqt->name, req);
  220         if (req->lerror > 0) {
  221                 p = geom_alloc_copyin(req, req->error, req->lerror, &error);
  222                 if (p != NULL) {
  223                         ((char *)p)[req->lerror - 1] = '\0';
  224                         printf("  error:\t\"%s\"\n", (char *)p);
  225                         g_free(p);
  226                 }
  227         }
  228         for (i = 0; i < req->narg; i++) {
  229                 ap = &req->arg[i];
  230                 printf("  param:\t\"%s\"", ap->name);
  231                 printf(" [%s%s%d] = ",
  232                     ap->flag & GCTL_PARAM_RD ? "R" : "",
  233                     ap->flag & GCTL_PARAM_WR ? "W" : "",
  234                     ap->len);
  235                 if (ap->flag & GCTL_PARAM_ASCII) {
  236                         p = geom_alloc_copyin(req, ap->value, ap->len, &error);
  237                         if (p != NULL) {
  238                                 ((char *)p)[ap->len - 1] = '\0';
  239                                 printf("\"%s\"", (char *)p);
  240                         }
  241                         g_free(p);
  242                 } else if (ap->len > 0) {
  243                         p = geom_alloc_copyin(req, ap->value, ap->len, &error);
  244                         for (j = 0; j < ap->len; j++)
  245                                 printf(" %02x", ((u_char *)p)[j]);
  246                         g_free(p);
  247                 } else {
  248                         printf(" = %p", ap->value);
  249                 }
  250                 printf("\n");
  251         }
  252 }
  253 
  254 int
  255 gctl_set_param(struct gctl_req *req, const char *param, void *ptr, int len)
  256 {
  257         int i, error;
  258         struct gctl_req_arg *ap;
  259 
  260         for (i = 0; i < req->narg; i++) {
  261                 ap = &req->arg[i];
  262                 if (strcmp(param, ap->name))
  263                         continue;
  264                 if (!(ap->flag & GCTL_PARAM_WR)) {
  265                         gctl_error(req, "No write access %s argument", param);
  266                         return (EINVAL);
  267                 }
  268                 if (ap->len != len) {
  269                         gctl_error(req, "Wrong length %s argument", param);
  270                         return (EINVAL);
  271                 }
  272                 error = copyout(ptr, ap->value, len);
  273                 return (error);
  274         }
  275         gctl_error(req, "Missing %s argument", param);
  276         return (EINVAL);
  277 }
  278 
  279 void *
  280 gctl_get_param(struct gctl_req *req, const char *param, int *len)
  281 {
  282         int i, error, j;
  283         void *p;
  284         struct gctl_req_arg *ap;
  285 
  286         for (i = 0; i < req->narg; i++) {
  287                 ap = &req->arg[i];
  288                 if (strcmp(param, ap->name))
  289                         continue;
  290                 if (!(ap->flag & GCTL_PARAM_RD))
  291                         continue;
  292                 if (ap->len > 0)
  293                         j = ap->len;
  294                 else
  295                         j = 0;
  296                 if (j != 0)
  297                         p = geom_alloc_copyin(req, ap->value, j, &error);
  298                         /* XXX: should not fail, tested prviously */
  299                 else
  300                         p = ap->value;
  301                 if (len != NULL)
  302                         *len = j;
  303                 return (p);
  304         }
  305         return (NULL);
  306 }
  307 
  308 void *
  309 gctl_get_paraml(struct gctl_req *req, const char *param, int len)
  310 {
  311         int i;
  312         void *p;
  313 
  314         p = gctl_get_param(req, param, &i);
  315         if (p == NULL)
  316                 gctl_error(req, "Missing %s argument", param);
  317         else if (i != len) {
  318                 g_free(p);
  319                 p = NULL;
  320                 gctl_error(req, "Wrong length %s argument", param);
  321         }
  322         return (p);
  323 }
  324 
  325 static struct g_class*
  326 gctl_get_class(struct gctl_req *req)
  327 {
  328         char *p;
  329         int len;
  330         struct g_class *cp;
  331 
  332         p = gctl_get_param(req, "class", &len);
  333         if (p == NULL)
  334                 return (NULL);
  335         if (p[len - 1] != '\0') {
  336                 gctl_error(req, "Unterminated class name");
  337                 g_free(p);
  338                 return (NULL);
  339         }
  340         LIST_FOREACH(cp, &g_classes, class) {
  341                 if (!strcmp(p, cp->name)) {
  342                         g_free(p);
  343                         return (cp);
  344                 }
  345         }
  346         g_free(p);
  347         gctl_error(req, "Class not found");
  348         return (NULL);
  349 }
  350 
  351 static struct g_geom*
  352 gctl_get_geom(struct gctl_req *req, struct g_class *mpr)
  353 {
  354         char *p;
  355         int len;
  356         struct g_class *mp;
  357         struct g_geom *gp;
  358 
  359         p = gctl_get_param(req, "geom", &len);
  360         if (p == NULL)
  361                 return (NULL);
  362         if (p[len - 1] != '\0') {
  363                 gctl_error(req, "Unterminated provider name");
  364                 g_free(p);
  365                 return (NULL);
  366         }
  367         LIST_FOREACH(mp, &g_classes, class) {
  368                 if (mpr != NULL && mpr != mp)
  369                         continue;
  370                 LIST_FOREACH(gp, &mp->geom, geom) {
  371                         if (!strcmp(p, gp->name)) {
  372                                 g_free(p);
  373                                 return (gp);
  374                         }
  375                 }
  376         }
  377         gctl_error(req, "Geom not found");
  378         g_free(p);
  379         return (NULL);
  380 }
  381 
  382 static struct g_provider*
  383 gctl_get_provider(struct gctl_req *req)
  384 {
  385         char *p;
  386         int len;
  387         struct g_class *cp;
  388         struct g_geom *gp;
  389         struct g_provider *pp;
  390 
  391         p = gctl_get_param(req, "provider", &len);
  392         if (p == NULL)
  393                 return (NULL);
  394         if (p[len - 1] != '\0') {
  395                 gctl_error(req, "Unterminated provider name");
  396                 g_free(p);
  397                 return (NULL);
  398         }
  399         LIST_FOREACH(cp, &g_classes, class) {
  400                 LIST_FOREACH(gp, &cp->geom, geom) {
  401                         LIST_FOREACH(pp, &gp->provider, provider) {
  402                                 if (!strcmp(p, pp->name)) {
  403                                         g_free(p);
  404                                         return (pp);
  405                                 }
  406                         }
  407                 }
  408         }
  409         gctl_error(req, "Provider not found");
  410         g_free(p);
  411         return (NULL);
  412 }
  413 
  414 static int
  415 gctl_create_geom(struct gctl_req *req)
  416 {
  417         struct g_class *mp;
  418         struct g_provider *pp;
  419         int error;
  420 
  421         g_topology_assert();
  422         mp = gctl_get_class(req);
  423         if (mp == NULL)
  424                 return (gctl_error(req, "Class not found"));
  425         if (mp->create_geom == NULL)
  426                 return (gctl_error(req, "Class has no create_geom method"));
  427         pp = gctl_get_provider(req);
  428         error = mp->create_geom(req, mp, pp);
  429         g_topology_assert();
  430         return (error);
  431 }
  432 
  433 static int
  434 gctl_destroy_geom(struct gctl_req *req)
  435 {
  436         struct g_class *mp;
  437         struct g_geom *gp;
  438         int error;
  439 
  440         g_topology_assert();
  441         mp = gctl_get_class(req);
  442         if (mp == NULL)
  443                 return (gctl_error(req, "Class not found"));
  444         if (mp->destroy_geom == NULL)
  445                 return (gctl_error(req, "Class has no destroy_geom method"));
  446         gp = gctl_get_geom(req, mp);
  447         if (gp == NULL)
  448                 return (gctl_error(req, "Geom not specified"));
  449         if (gp->class != mp)
  450                 return (gctl_error(req, "Geom not of specificed class"));
  451         error = mp->destroy_geom(req, mp, gp);
  452         g_topology_assert();
  453         return (error);
  454 }
  455 
  456 static int
  457 gctl_config_geom(struct gctl_req *req)
  458 {
  459         struct g_class *mp;
  460         struct g_geom *gp;
  461         char *verb;
  462         int error, vlen;
  463 
  464         g_topology_assert();
  465         mp = gctl_get_class(req);
  466         if (mp == NULL)
  467                 return (gctl_error(req, "Class not found"));
  468         if (mp->config_geom == NULL)
  469                 return (gctl_error(req, "Class has no config_geom method"));
  470         gp = gctl_get_geom(req, mp);
  471         if (gp == NULL)
  472                 return (gctl_error(req, "Geom not specified"));
  473         if (gp->class != mp)
  474                 return (gctl_error(req, "Geom not of specificed class"));
  475         verb = gctl_get_param(req, "verb", &vlen);
  476         if (verb == NULL)
  477                 return (gctl_error(req, "Missing verb parameter"));
  478         if (vlen < 2) {
  479                 g_free(verb);
  480                 return (gctl_error(req, "Too short verb parameter"));
  481         }
  482         if (verb[vlen - 1] != '\0') {
  483                 g_free(verb);
  484                 return (gctl_error(req, "Unterminated verb parameter"));
  485         }
  486         error = mp->config_geom(req, gp, verb);
  487         g_free(verb);
  488         g_topology_assert();
  489         return (error);
  490 }
  491 
  492 /*
  493  * Handle ioctl from libgeom::geom_ctl.c
  494  */
  495 static int
  496 g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  497 {
  498         int error;
  499         int i;
  500         struct gctl_req *req;
  501 
  502         req = (void *)data;
  503         /* It is an error if we cannot return an error text */
  504         if (req->lerror < 1)
  505                 return (EINVAL);
  506         if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
  507                 return (EINVAL);
  508 
  509         /* Check the version */
  510         if (req->version != GCTL_VERSION)
  511                 return (gctl_error(req,
  512                     "kernel and libgeom version mismatch."));
  513         
  514         /* Check the request type */
  515         for (i = 0; gcrt[i].request != GCTL_INVALID_REQUEST; i++)
  516                 if (gcrt[i].request == req->request)
  517                         break;
  518         if (gcrt[i].request == GCTL_INVALID_REQUEST)
  519                 return (gctl_error(req, "invalid request"));
  520         req->reqt = &gcrt[i];
  521 
  522         /* Get things on board */
  523         error = gctl_copyin(req);
  524         if (error)
  525                 return (error);
  526 
  527         if (g_debugflags & G_F_CTLDUMP)
  528                 gctl_dump(req);
  529         g_topology_lock();
  530         switch (req->request) {
  531         case GCTL_CREATE_GEOM:
  532                 error = gctl_create_geom(req);
  533                 break;
  534         case GCTL_DESTROY_GEOM:
  535                 error = gctl_destroy_geom(req);
  536                 break;
  537         case GCTL_CONFIG_GEOM:
  538                 error = gctl_config_geom(req);
  539                 break;
  540         default:
  541                 error = gctl_error(req, "XXX: TBD");
  542                 break;
  543         }
  544         gctl_free(req);
  545         g_topology_unlock();
  546         return (error);
  547 }
  548 
  549 static int
  550 g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  551 {
  552         int error;
  553 
  554         switch(cmd) {
  555         case GEOM_CTL:
  556                 DROP_GIANT();
  557                 error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td);
  558                 PICKUP_GIANT();
  559                 break;
  560         default:
  561                 error = ENOTTY;
  562                 break;
  563         }
  564         return (error);
  565 
  566 }

Cache object: 53993f5cd5d9ced87fed32b82550cc08


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.