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_dev.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 2002 Poul-Henning Kamp
    5  * Copyright (c) 2002 Networks Associates Technology, Inc.
    6  * All rights reserved.
    7  *
    8  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
    9  * and NAI Labs, the Security Research Division of Network Associates, Inc.
   10  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
   11  * DARPA CHATS research program.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. The names of the authors may not be used to endorse or promote
   22  *    products derived from this software without specific prior written
   23  *    permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD: releng/12.0/sys/geom/geom_dev.c 333282 2018-05-06 00:22:38Z markj $");
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/malloc.h>
   44 #include <sys/kernel.h>
   45 #include <sys/conf.h>
   46 #include <sys/ctype.h>
   47 #include <sys/bio.h>
   48 #include <sys/bus.h>
   49 #include <sys/lock.h>
   50 #include <sys/mutex.h>
   51 #include <sys/proc.h>
   52 #include <sys/errno.h>
   53 #include <sys/time.h>
   54 #include <sys/disk.h>
   55 #include <sys/fcntl.h>
   56 #include <sys/limits.h>
   57 #include <sys/sysctl.h>
   58 #include <geom/geom.h>
   59 #include <geom/geom_int.h>
   60 #include <machine/stdarg.h>
   61 
   62 struct g_dev_softc {
   63         struct mtx       sc_mtx;
   64         struct cdev     *sc_dev;
   65         struct cdev     *sc_alias;
   66         int              sc_open;
   67         int              sc_active;
   68 };
   69 
   70 static d_open_t         g_dev_open;
   71 static d_close_t        g_dev_close;
   72 static d_strategy_t     g_dev_strategy;
   73 static d_ioctl_t        g_dev_ioctl;
   74 
   75 static struct cdevsw g_dev_cdevsw = {
   76         .d_version =    D_VERSION,
   77         .d_open =       g_dev_open,
   78         .d_close =      g_dev_close,
   79         .d_read =       physread,
   80         .d_write =      physwrite,
   81         .d_ioctl =      g_dev_ioctl,
   82         .d_strategy =   g_dev_strategy,
   83         .d_name =       "g_dev",
   84         .d_flags =      D_DISK | D_TRACKCLOSE,
   85 };
   86 
   87 static g_init_t g_dev_init;
   88 static g_fini_t g_dev_fini;
   89 static g_taste_t g_dev_taste;
   90 static g_orphan_t g_dev_orphan;
   91 static g_attrchanged_t g_dev_attrchanged;
   92 
   93 static struct g_class g_dev_class       = {
   94         .name = "DEV",
   95         .version = G_VERSION,
   96         .init = g_dev_init,
   97         .fini = g_dev_fini,
   98         .taste = g_dev_taste,
   99         .orphan = g_dev_orphan,
  100         .attrchanged = g_dev_attrchanged
  101 };
  102 
  103 /*
  104  * We target 262144 (8 x 32768) sectors by default as this significantly
  105  * increases the throughput on commonly used SSD's with a marginal
  106  * increase in non-interruptible request latency.
  107  */
  108 static uint64_t g_dev_del_max_sectors = 262144;
  109 SYSCTL_DECL(_kern_geom);
  110 SYSCTL_NODE(_kern_geom, OID_AUTO, dev, CTLFLAG_RW, 0, "GEOM_DEV stuff");
  111 SYSCTL_QUAD(_kern_geom_dev, OID_AUTO, delete_max_sectors, CTLFLAG_RW,
  112     &g_dev_del_max_sectors, 0, "Maximum number of sectors in a single "
  113     "delete request sent to the provider. Larger requests are chunked "
  114     "so they can be interrupted. (0 = disable chunking)");
  115 
  116 static char *dumpdev = NULL;
  117 static void
  118 g_dev_init(struct g_class *mp)
  119 {
  120 
  121         dumpdev = kern_getenv("dumpdev");
  122 }
  123 
  124 static void
  125 g_dev_fini(struct g_class *mp)
  126 {
  127 
  128         freeenv(dumpdev);
  129         dumpdev = NULL;
  130 }
  131 
  132 static int
  133 g_dev_setdumpdev(struct cdev *dev, struct diocskerneldump_arg *kda,
  134     struct thread *td)
  135 {
  136         struct g_kerneldump kd;
  137         struct g_consumer *cp;
  138         int error, len;
  139 
  140         if (dev == NULL || kda == NULL)
  141                 return (clear_dumper(td));
  142 
  143         cp = dev->si_drv2;
  144         len = sizeof(kd);
  145         memset(&kd, 0, len);
  146         kd.offset = 0;
  147         kd.length = OFF_MAX;
  148         error = g_io_getattr("GEOM::kerneldump", cp, &len, &kd);
  149         if (error != 0)
  150                 return (error);
  151 
  152         error = set_dumper(&kd.di, devtoname(dev), td, kda->kda_compression,
  153             kda->kda_encryption, kda->kda_key, kda->kda_encryptedkeysize,
  154             kda->kda_encryptedkey);
  155         if (error == 0)
  156                 dev->si_flags |= SI_DUMPDEV;
  157 
  158         return (error);
  159 }
  160 
  161 static int
  162 init_dumpdev(struct cdev *dev)
  163 {
  164         struct diocskerneldump_arg kda;
  165         struct g_consumer *cp;
  166         const char *devprefix = "/dev/", *devname;
  167         int error;
  168         size_t len;
  169 
  170         bzero(&kda, sizeof(kda));
  171         kda.kda_enable = 1;
  172 
  173         if (dumpdev == NULL)
  174                 return (0);
  175 
  176         len = strlen(devprefix);
  177         devname = devtoname(dev);
  178         if (strcmp(devname, dumpdev) != 0 &&
  179            (strncmp(dumpdev, devprefix, len) != 0 ||
  180             strcmp(devname, dumpdev + len) != 0))
  181                 return (0);
  182 
  183         cp = (struct g_consumer *)dev->si_drv2;
  184         error = g_access(cp, 1, 0, 0);
  185         if (error != 0)
  186                 return (error);
  187 
  188         error = g_dev_setdumpdev(dev, &kda, curthread);
  189         if (error == 0) {
  190                 freeenv(dumpdev);
  191                 dumpdev = NULL;
  192         }
  193 
  194         (void)g_access(cp, -1, 0, 0);
  195 
  196         return (error);
  197 }
  198 
  199 static void
  200 g_dev_destroy(void *arg, int flags __unused)
  201 {
  202         struct g_consumer *cp;
  203         struct g_geom *gp;
  204         struct g_dev_softc *sc;
  205         char buf[SPECNAMELEN + 6];
  206 
  207         g_topology_assert();
  208         cp = arg;
  209         gp = cp->geom;
  210         sc = cp->private;
  211         g_trace(G_T_TOPOLOGY, "g_dev_destroy(%p(%s))", cp, gp->name);
  212         snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
  213         devctl_notify_f("GEOM", "DEV", "DESTROY", buf, M_WAITOK);
  214         if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
  215                 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
  216         g_detach(cp);
  217         g_destroy_consumer(cp);
  218         g_destroy_geom(gp);
  219         mtx_destroy(&sc->sc_mtx);
  220         g_free(sc);
  221 }
  222 
  223 void
  224 g_dev_print(void)
  225 {
  226         struct g_geom *gp;
  227         char const *p = "";
  228 
  229         LIST_FOREACH(gp, &g_dev_class.geom, geom) {
  230                 printf("%s%s", p, gp->name);
  231                 p = " ";
  232         }
  233         printf("\n");
  234 }
  235 
  236 static void
  237 g_dev_set_physpath(struct g_consumer *cp)
  238 {
  239         struct g_dev_softc *sc;
  240         char *physpath;
  241         int error, physpath_len;
  242 
  243         if (g_access(cp, 1, 0, 0) != 0)
  244                 return;
  245 
  246         sc = cp->private;
  247         physpath_len = MAXPATHLEN;
  248         physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
  249         error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
  250         g_access(cp, -1, 0, 0);
  251         if (error == 0 && strlen(physpath) != 0) {
  252                 struct cdev *dev, *old_alias_dev;
  253                 struct cdev **alias_devp;
  254 
  255                 dev = sc->sc_dev;
  256                 old_alias_dev = sc->sc_alias;
  257                 alias_devp = (struct cdev **)&sc->sc_alias;
  258                 make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp, dev,
  259                     old_alias_dev, physpath);
  260         } else if (sc->sc_alias) {
  261                 destroy_dev((struct cdev *)sc->sc_alias);
  262                 sc->sc_alias = NULL;
  263         }
  264         g_free(physpath);
  265 }
  266 
  267 static void
  268 g_dev_set_media(struct g_consumer *cp)
  269 {
  270         struct g_dev_softc *sc;
  271         struct cdev *dev;
  272         char buf[SPECNAMELEN + 6];
  273 
  274         sc = cp->private;
  275         dev = sc->sc_dev;
  276         snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
  277         devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
  278         devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf, M_WAITOK);
  279         dev = sc->sc_alias;
  280         if (dev != NULL) {
  281                 snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
  282                 devctl_notify_f("DEVFS", "CDEV", "MEDIACHANGE", buf, M_WAITOK);
  283                 devctl_notify_f("GEOM", "DEV", "MEDIACHANGE", buf, M_WAITOK);
  284         }
  285 }
  286 
  287 static void
  288 g_dev_attrchanged(struct g_consumer *cp, const char *attr)
  289 {
  290 
  291         if (strcmp(attr, "GEOM::media") == 0) {
  292                 g_dev_set_media(cp);
  293                 return;
  294         }
  295 
  296         if (strcmp(attr, "GEOM::physpath") == 0) {
  297                 g_dev_set_physpath(cp);
  298                 return;
  299         }
  300 }
  301 
  302 struct g_provider *
  303 g_dev_getprovider(struct cdev *dev)
  304 {
  305         struct g_consumer *cp;
  306 
  307         g_topology_assert();
  308         if (dev == NULL)
  309                 return (NULL);
  310         if (dev->si_devsw != &g_dev_cdevsw)
  311                 return (NULL);
  312         cp = dev->si_drv2;
  313         return (cp->provider);
  314 }
  315 
  316 static struct g_geom *
  317 g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
  318 {
  319         struct g_geom *gp;
  320         struct g_geom_alias *gap;
  321         struct g_consumer *cp;
  322         struct g_dev_softc *sc;
  323         int error;
  324         struct cdev *dev, *adev;
  325         char buf[SPECNAMELEN + 6];
  326 
  327         g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
  328         g_topology_assert();
  329         gp = g_new_geomf(mp, "%s", pp->name);
  330         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
  331         mtx_init(&sc->sc_mtx, "g_dev", NULL, MTX_DEF);
  332         cp = g_new_consumer(gp);
  333         cp->private = sc;
  334         cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
  335         error = g_attach(cp, pp);
  336         KASSERT(error == 0,
  337             ("g_dev_taste(%s) failed to g_attach, err=%d", pp->name, error));
  338         error = make_dev_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &dev,
  339             &g_dev_cdevsw, NULL, UID_ROOT, GID_OPERATOR, 0640, "%s", gp->name);
  340         if (error != 0) {
  341                 printf("%s: make_dev_p() failed (gp->name=%s, error=%d)\n",
  342                     __func__, gp->name, error);
  343                 g_detach(cp);
  344                 g_destroy_consumer(cp);
  345                 g_destroy_geom(gp);
  346                 mtx_destroy(&sc->sc_mtx);
  347                 g_free(sc);
  348                 return (NULL);
  349         }
  350         dev->si_flags |= SI_UNMAPPED;
  351         sc->sc_dev = dev;
  352 
  353         dev->si_iosize_max = MAXPHYS;
  354         dev->si_drv2 = cp;
  355         error = init_dumpdev(dev);
  356         if (error != 0)
  357                 printf("%s: init_dumpdev() failed (gp->name=%s, error=%d)\n",
  358                     __func__, gp->name, error);
  359 
  360         g_dev_attrchanged(cp, "GEOM::physpath");
  361         snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
  362         devctl_notify_f("GEOM", "DEV", "CREATE", buf, M_WAITOK);
  363         /*
  364          * Now add all the aliases for this drive
  365          */
  366         LIST_FOREACH(gap, &pp->geom->aliases, ga_next) {
  367                 error = make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &adev, dev,
  368                     "%s", gap->ga_alias);
  369                 if (error) {
  370                         printf("%s: make_dev_alias_p() failed (name=%s, error=%d)\n",
  371                             __func__, gap->ga_alias, error);
  372                         continue;
  373                 }
  374                 snprintf(buf, sizeof(buf), "cdev=%s", gap->ga_alias);
  375                 devctl_notify_f("GEOM", "DEV", "CREATE", buf, M_WAITOK);
  376         }
  377 
  378         return (gp);
  379 }
  380 
  381 static int
  382 g_dev_open(struct cdev *dev, int flags, int fmt, struct thread *td)
  383 {
  384         struct g_consumer *cp;
  385         struct g_dev_softc *sc;
  386         int error, r, w, e;
  387 
  388         cp = dev->si_drv2;
  389         if (cp == NULL)
  390                 return (ENXIO);         /* g_dev_taste() not done yet */
  391         g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
  392             cp->geom->name, flags, fmt, td);
  393 
  394         r = flags & FREAD ? 1 : 0;
  395         w = flags & FWRITE ? 1 : 0;
  396 #ifdef notyet
  397         e = flags & O_EXCL ? 1 : 0;
  398 #else
  399         e = 0;
  400 #endif
  401 
  402         /*
  403          * This happens on attempt to open a device node with O_EXEC.
  404          */
  405         if (r + w + e == 0)
  406                 return (EINVAL);
  407 
  408         if (w) {
  409                 /*
  410                  * When running in very secure mode, do not allow
  411                  * opens for writing of any disks.
  412                  */
  413                 error = securelevel_ge(td->td_ucred, 2);
  414                 if (error)
  415                         return (error);
  416         }
  417         g_topology_lock();
  418         error = g_access(cp, r, w, e);
  419         g_topology_unlock();
  420         if (error == 0) {
  421                 sc = cp->private;
  422                 mtx_lock(&sc->sc_mtx);
  423                 if (sc->sc_open == 0 && sc->sc_active != 0)
  424                         wakeup(&sc->sc_active);
  425                 sc->sc_open += r + w + e;
  426                 mtx_unlock(&sc->sc_mtx);
  427         }
  428         return (error);
  429 }
  430 
  431 static int
  432 g_dev_close(struct cdev *dev, int flags, int fmt, struct thread *td)
  433 {
  434         struct g_consumer *cp;
  435         struct g_dev_softc *sc;
  436         int error, r, w, e;
  437 
  438         cp = dev->si_drv2;
  439         if (cp == NULL)
  440                 return (ENXIO);
  441         g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
  442             cp->geom->name, flags, fmt, td);
  443 
  444         r = flags & FREAD ? -1 : 0;
  445         w = flags & FWRITE ? -1 : 0;
  446 #ifdef notyet
  447         e = flags & O_EXCL ? -1 : 0;
  448 #else
  449         e = 0;
  450 #endif
  451 
  452         /*
  453          * The vgonel(9) - caused by eg. forced unmount of devfs - calls
  454          * VOP_CLOSE(9) on devfs vnode without any FREAD or FWRITE flags,
  455          * which would result in zero deltas, which in turn would cause
  456          * panic in g_access(9).
  457          *
  458          * Note that we cannot zero the counters (ie. do "r = cp->acr"
  459          * etc) instead, because the consumer might be opened in another
  460          * devfs instance.
  461          */
  462         if (r + w + e == 0)
  463                 return (EINVAL);
  464 
  465         sc = cp->private;
  466         mtx_lock(&sc->sc_mtx);
  467         sc->sc_open += r + w + e;
  468         while (sc->sc_open == 0 && sc->sc_active != 0)
  469                 msleep(&sc->sc_active, &sc->sc_mtx, 0, "PRIBIO", 0);
  470         mtx_unlock(&sc->sc_mtx);
  471         g_topology_lock();
  472         error = g_access(cp, r, w, e);
  473         g_topology_unlock();
  474         return (error);
  475 }
  476 
  477 /*
  478  * XXX: Until we have unmessed the ioctl situation, there is a race against
  479  * XXX: a concurrent orphanization.  We cannot close it by holding topology
  480  * XXX: since that would prevent us from doing our job, and stalling events
  481  * XXX: will break (actually: stall) the BSD disklabel hacks.
  482  */
  483 static int
  484 g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  485 {
  486         struct g_consumer *cp;
  487         struct g_provider *pp;
  488         off_t offset, length, chunk, odd;
  489         int i, error;
  490 
  491         cp = dev->si_drv2;
  492         pp = cp->provider;
  493 
  494         error = 0;
  495         KASSERT(cp->acr || cp->acw,
  496             ("Consumer with zero access count in g_dev_ioctl"));
  497 
  498         i = IOCPARM_LEN(cmd);
  499         switch (cmd) {
  500         case DIOCGSECTORSIZE:
  501                 *(u_int *)data = cp->provider->sectorsize;
  502                 if (*(u_int *)data == 0)
  503                         error = ENOENT;
  504                 break;
  505         case DIOCGMEDIASIZE:
  506                 *(off_t *)data = cp->provider->mediasize;
  507                 if (*(off_t *)data == 0)
  508                         error = ENOENT;
  509                 break;
  510         case DIOCGFWSECTORS:
  511                 error = g_io_getattr("GEOM::fwsectors", cp, &i, data);
  512                 if (error == 0 && *(u_int *)data == 0)
  513                         error = ENOENT;
  514                 break;
  515         case DIOCGFWHEADS:
  516                 error = g_io_getattr("GEOM::fwheads", cp, &i, data);
  517                 if (error == 0 && *(u_int *)data == 0)
  518                         error = ENOENT;
  519                 break;
  520         case DIOCGFRONTSTUFF:
  521                 error = g_io_getattr("GEOM::frontstuff", cp, &i, data);
  522                 break;
  523 #ifdef COMPAT_FREEBSD11
  524         case DIOCSKERNELDUMP_FREEBSD11:
  525             {
  526                 struct diocskerneldump_arg kda;
  527 
  528                 bzero(&kda, sizeof(kda));
  529                 kda.kda_encryption = KERNELDUMP_ENC_NONE;
  530                 kda.kda_enable = (uint8_t)*(u_int *)data;
  531                 if (kda.kda_enable == 0)
  532                         error = g_dev_setdumpdev(NULL, NULL, td);
  533                 else
  534                         error = g_dev_setdumpdev(dev, &kda, td);
  535                 break;
  536             }
  537 #endif
  538         case DIOCSKERNELDUMP:
  539             {
  540                 struct diocskerneldump_arg *kda;
  541                 uint8_t *encryptedkey;
  542 
  543                 kda = (struct diocskerneldump_arg *)data;
  544                 if (kda->kda_enable == 0) {
  545                         error = g_dev_setdumpdev(NULL, NULL, td);
  546                         break;
  547                 }
  548 
  549                 if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
  550                         if (kda->kda_encryptedkeysize <= 0 ||
  551                             kda->kda_encryptedkeysize >
  552                             KERNELDUMP_ENCKEY_MAX_SIZE) {
  553                                 return (EINVAL);
  554                         }
  555                         encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP,
  556                             M_WAITOK);
  557                         error = copyin(kda->kda_encryptedkey, encryptedkey,
  558                             kda->kda_encryptedkeysize);
  559                 } else {
  560                         encryptedkey = NULL;
  561                 }
  562                 if (error == 0) {
  563                         kda->kda_encryptedkey = encryptedkey;
  564                         error = g_dev_setdumpdev(dev, kda, td);
  565                 }
  566                 if (encryptedkey != NULL) {
  567                         explicit_bzero(encryptedkey, kda->kda_encryptedkeysize);
  568                         free(encryptedkey, M_TEMP);
  569                 }
  570                 explicit_bzero(kda, sizeof(*kda));
  571                 break;
  572             }
  573         case DIOCGFLUSH:
  574                 error = g_io_flush(cp);
  575                 break;
  576         case DIOCGDELETE:
  577                 offset = ((off_t *)data)[0];
  578                 length = ((off_t *)data)[1];
  579                 if ((offset % cp->provider->sectorsize) != 0 ||
  580                     (length % cp->provider->sectorsize) != 0 || length <= 0) {
  581                         printf("%s: offset=%jd length=%jd\n", __func__, offset,
  582                             length);
  583                         error = EINVAL;
  584                         break;
  585                 }
  586                 while (length > 0) {
  587                         chunk = length;
  588                         if (g_dev_del_max_sectors != 0 && chunk >
  589                             g_dev_del_max_sectors * cp->provider->sectorsize) {
  590                                 chunk = g_dev_del_max_sectors *
  591                                     cp->provider->sectorsize;
  592                                 if (cp->provider->stripesize > 0) {
  593                                         odd = (offset + chunk +
  594                                             cp->provider->stripeoffset) %
  595                                             cp->provider->stripesize;
  596                                         if (chunk > odd)
  597                                                 chunk -= odd;
  598                                 }
  599                         }
  600                         error = g_delete_data(cp, offset, chunk);
  601                         length -= chunk;
  602                         offset += chunk;
  603                         if (error)
  604                                 break;
  605                         /*
  606                          * Since the request size can be large, the service
  607                          * time can be is likewise.  We make this ioctl
  608                          * interruptible by checking for signals for each bio.
  609                          */
  610                         if (SIGPENDING(td))
  611                                 break;
  612                 }
  613                 break;
  614         case DIOCGIDENT:
  615                 error = g_io_getattr("GEOM::ident", cp, &i, data);
  616                 break;
  617         case DIOCGPROVIDERNAME:
  618                 if (pp == NULL)
  619                         return (ENOENT);
  620                 strlcpy(data, pp->name, i);
  621                 break;
  622         case DIOCGSTRIPESIZE:
  623                 *(off_t *)data = cp->provider->stripesize;
  624                 break;
  625         case DIOCGSTRIPEOFFSET:
  626                 *(off_t *)data = cp->provider->stripeoffset;
  627                 break;
  628         case DIOCGPHYSPATH:
  629                 error = g_io_getattr("GEOM::physpath", cp, &i, data);
  630                 if (error == 0 && *(char *)data == '\0')
  631                         error = ENOENT;
  632                 break;
  633         case DIOCGATTR: {
  634                 struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
  635 
  636                 if (arg->len > sizeof(arg->value)) {
  637                         error = EINVAL;
  638                         break;
  639                 }
  640                 error = g_io_getattr(arg->name, cp, &arg->len, &arg->value);
  641                 break;
  642         }
  643         case DIOCZONECMD: {
  644                 struct disk_zone_args *zone_args =(struct disk_zone_args *)data;
  645                 struct disk_zone_rep_entry *new_entries, *old_entries;
  646                 struct disk_zone_report *rep;
  647                 size_t alloc_size;
  648 
  649                 old_entries = NULL;
  650                 new_entries = NULL;
  651                 rep = NULL;
  652                 alloc_size = 0;
  653 
  654                 if (zone_args->zone_cmd == DISK_ZONE_REPORT_ZONES) {
  655 
  656                         rep = &zone_args->zone_params.report;
  657                         alloc_size = rep->entries_allocated *
  658                             sizeof(struct disk_zone_rep_entry);
  659                         if (alloc_size != 0)
  660                                 new_entries = g_malloc(alloc_size,
  661                                     M_WAITOK| M_ZERO);
  662                         old_entries = rep->entries;
  663                         rep->entries = new_entries;
  664                 }
  665                 error = g_io_zonecmd(zone_args, cp);
  666                 if ((zone_args->zone_cmd == DISK_ZONE_REPORT_ZONES)
  667                  && (alloc_size != 0)
  668                  && (error == 0)) {
  669                         error = copyout(new_entries, old_entries, alloc_size);
  670                 }
  671                 if ((old_entries != NULL)
  672                  && (rep != NULL))
  673                         rep->entries = old_entries;
  674 
  675                 if (new_entries != NULL)
  676                         g_free(new_entries);
  677                 break;
  678         }
  679         default:
  680                 if (cp->provider->geom->ioctl != NULL) {
  681                         error = cp->provider->geom->ioctl(cp->provider, cmd, data, fflag, td);
  682                 } else {
  683                         error = ENOIOCTL;
  684                 }
  685         }
  686 
  687         return (error);
  688 }
  689 
  690 static void
  691 g_dev_done(struct bio *bp2)
  692 {
  693         struct g_consumer *cp;
  694         struct g_dev_softc *sc;
  695         struct bio *bp;
  696         int destroy;
  697 
  698         cp = bp2->bio_from;
  699         sc = cp->private;
  700         bp = bp2->bio_parent;
  701         bp->bio_error = bp2->bio_error;
  702         bp->bio_completed = bp2->bio_completed;
  703         bp->bio_resid = bp->bio_length - bp2->bio_completed;
  704         if (bp2->bio_cmd == BIO_ZONE)
  705                 bcopy(&bp2->bio_zone, &bp->bio_zone, sizeof(bp->bio_zone));
  706 
  707         if (bp2->bio_error != 0) {
  708                 g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
  709                     bp2, bp2->bio_error);
  710                 bp->bio_flags |= BIO_ERROR;
  711         } else {
  712                 g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %jd",
  713                     bp2, bp, bp2->bio_resid, (intmax_t)bp2->bio_completed);
  714         }
  715         g_destroy_bio(bp2);
  716         destroy = 0;
  717         mtx_lock(&sc->sc_mtx);
  718         if ((--sc->sc_active) == 0) {
  719                 if (sc->sc_open == 0)
  720                         wakeup(&sc->sc_active);
  721                 if (sc->sc_dev == NULL)
  722                         destroy = 1;
  723         }
  724         mtx_unlock(&sc->sc_mtx);
  725         if (destroy)
  726                 g_post_event(g_dev_destroy, cp, M_NOWAIT, NULL);
  727         biodone(bp);
  728 }
  729 
  730 static void
  731 g_dev_strategy(struct bio *bp)
  732 {
  733         struct g_consumer *cp;
  734         struct bio *bp2;
  735         struct cdev *dev;
  736         struct g_dev_softc *sc;
  737 
  738         KASSERT(bp->bio_cmd == BIO_READ ||
  739                 bp->bio_cmd == BIO_WRITE ||
  740                 bp->bio_cmd == BIO_DELETE ||
  741                 bp->bio_cmd == BIO_FLUSH ||
  742                 bp->bio_cmd == BIO_ZONE,
  743                 ("Wrong bio_cmd bio=%p cmd=%d", bp, bp->bio_cmd));
  744         dev = bp->bio_dev;
  745         cp = dev->si_drv2;
  746         sc = cp->private;
  747         KASSERT(cp->acr || cp->acw,
  748             ("Consumer with zero access count in g_dev_strategy"));
  749         biotrack(bp, __func__);
  750 #ifdef INVARIANTS
  751         if ((bp->bio_offset % cp->provider->sectorsize) != 0 ||
  752             (bp->bio_bcount % cp->provider->sectorsize) != 0) {
  753                 bp->bio_resid = bp->bio_bcount;
  754                 biofinish(bp, NULL, EINVAL);
  755                 return;
  756         }
  757 #endif
  758         mtx_lock(&sc->sc_mtx);
  759         KASSERT(sc->sc_open > 0, ("Closed device in g_dev_strategy"));
  760         sc->sc_active++;
  761         mtx_unlock(&sc->sc_mtx);
  762 
  763         for (;;) {
  764                 /*
  765                  * XXX: This is not an ideal solution, but I believe it to
  766                  * XXX: deadlock safely, all things considered.
  767                  */
  768                 bp2 = g_clone_bio(bp);
  769                 if (bp2 != NULL)
  770                         break;
  771                 pause("gdstrat", hz / 10);
  772         }
  773         KASSERT(bp2 != NULL, ("XXX: ENOMEM in a bad place"));
  774         bp2->bio_done = g_dev_done;
  775         g_trace(G_T_BIO,
  776             "g_dev_strategy(%p/%p) offset %jd length %jd data %p cmd %d",
  777             bp, bp2, (intmax_t)bp->bio_offset, (intmax_t)bp2->bio_length,
  778             bp2->bio_data, bp2->bio_cmd);
  779         g_io_request(bp2, cp);
  780         KASSERT(cp->acr || cp->acw,
  781             ("g_dev_strategy raced with g_dev_close and lost"));
  782 
  783 }
  784 
  785 /*
  786  * g_dev_callback()
  787  *
  788  * Called by devfs when asynchronous device destruction is completed.
  789  * - Mark that we have no attached device any more.
  790  * - If there are no outstanding requests, schedule geom destruction.
  791  *   Otherwise destruction will be scheduled later by g_dev_done().
  792  */
  793 
  794 static void
  795 g_dev_callback(void *arg)
  796 {
  797         struct g_consumer *cp;
  798         struct g_dev_softc *sc;
  799         int destroy;
  800 
  801         cp = arg;
  802         sc = cp->private;
  803         g_trace(G_T_TOPOLOGY, "g_dev_callback(%p(%s))", cp, cp->geom->name);
  804 
  805         mtx_lock(&sc->sc_mtx);
  806         sc->sc_dev = NULL;
  807         sc->sc_alias = NULL;
  808         destroy = (sc->sc_active == 0);
  809         mtx_unlock(&sc->sc_mtx);
  810         if (destroy)
  811                 g_post_event(g_dev_destroy, cp, M_WAITOK, NULL);
  812 }
  813 
  814 /*
  815  * g_dev_orphan()
  816  *
  817  * Called from below when the provider orphaned us.
  818  * - Clear any dump settings.
  819  * - Request asynchronous device destruction to prevent any more requests
  820  *   from coming in.  The provider is already marked with an error, so
  821  *   anything which comes in the interim will be returned immediately.
  822  */
  823 
  824 static void
  825 g_dev_orphan(struct g_consumer *cp)
  826 {
  827         struct cdev *dev;
  828         struct g_dev_softc *sc;
  829 
  830         g_topology_assert();
  831         sc = cp->private;
  832         dev = sc->sc_dev;
  833         g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, cp->geom->name);
  834 
  835         /* Reset any dump-area set on this device */
  836         if (dev->si_flags & SI_DUMPDEV)
  837                 (void)clear_dumper(curthread);
  838 
  839         /* Destroy the struct cdev *so we get no more requests */
  840         destroy_dev_sched_cb(dev, g_dev_callback, cp);
  841 }
  842 
  843 DECLARE_GEOM_CLASS(g_dev_class, g_dev);

Cache object: 9267c71a5dccbb58f8debfe637180539


[ 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.