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$");
   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/devctl.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/selinfo.h>
   58 #include <sys/sysctl.h>
   59 #include <geom/geom.h>
   60 #include <geom/geom_int.h>
   61 #include <machine/stdarg.h>
   62 
   63 struct g_dev_softc {
   64         struct mtx       sc_mtx;
   65         struct cdev     *sc_dev;
   66         struct cdev     *sc_alias;
   67         int              sc_open;
   68         u_int            sc_active;
   69         struct selinfo   sc_selinfo;
   70 #define SC_A_DESTROY    (1 << 31)
   71 #define SC_A_OPEN       (1 << 30)
   72 #define SC_A_ACTIVE     (SC_A_OPEN - 1)
   73 };
   74 
   75 static d_open_t         g_dev_open;
   76 static d_close_t        g_dev_close;
   77 static d_strategy_t     g_dev_strategy;
   78 static d_ioctl_t        g_dev_ioctl;
   79 static d_kqfilter_t     g_dev_kqfilter;
   80 
   81 static void             gdev_filter_detach(struct knote *kn);
   82 static int              gdev_filter_vnode(struct knote *kn, long hint);
   83 
   84 static struct filterops gdev_filterops_vnode = {
   85         .f_isfd = 1,
   86         .f_detach = gdev_filter_detach,
   87         .f_event = gdev_filter_vnode,
   88 };
   89 
   90 static struct cdevsw g_dev_cdevsw = {
   91         .d_version =    D_VERSION,
   92         .d_open =       g_dev_open,
   93         .d_close =      g_dev_close,
   94         .d_read =       physread,
   95         .d_write =      physwrite,
   96         .d_ioctl =      g_dev_ioctl,
   97         .d_strategy =   g_dev_strategy,
   98         .d_name =       "g_dev",
   99         .d_flags =      D_DISK | D_TRACKCLOSE,
  100         .d_kqfilter =   g_dev_kqfilter,
  101 };
  102 
  103 static g_init_t g_dev_init;
  104 static g_fini_t g_dev_fini;
  105 static g_taste_t g_dev_taste;
  106 static g_orphan_t g_dev_orphan;
  107 static g_attrchanged_t g_dev_attrchanged;
  108 static g_resize_t g_dev_resize;
  109 
  110 static struct g_class g_dev_class       = {
  111         .name = "DEV",
  112         .version = G_VERSION,
  113         .init = g_dev_init,
  114         .fini = g_dev_fini,
  115         .taste = g_dev_taste,
  116         .orphan = g_dev_orphan,
  117         .attrchanged = g_dev_attrchanged,
  118         .resize = g_dev_resize
  119 };
  120 
  121 /*
  122  * We target 262144 (8 x 32768) sectors by default as this significantly
  123  * increases the throughput on commonly used SSD's with a marginal
  124  * increase in non-interruptible request latency.
  125  */
  126 static uint64_t g_dev_del_max_sectors = 262144;
  127 SYSCTL_DECL(_kern_geom);
  128 SYSCTL_NODE(_kern_geom, OID_AUTO, dev, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  129     "GEOM_DEV stuff");
  130 SYSCTL_QUAD(_kern_geom_dev, OID_AUTO, delete_max_sectors, CTLFLAG_RW,
  131     &g_dev_del_max_sectors, 0, "Maximum number of sectors in a single "
  132     "delete request sent to the provider. Larger requests are chunked "
  133     "so they can be interrupted. (0 = disable chunking)");
  134 
  135 static char *dumpdev = NULL;
  136 static void
  137 g_dev_init(struct g_class *mp)
  138 {
  139 
  140         dumpdev = kern_getenv("dumpdev");
  141 }
  142 
  143 static void
  144 g_dev_fini(struct g_class *mp)
  145 {
  146 
  147         freeenv(dumpdev);
  148         dumpdev = NULL;
  149 }
  150 
  151 static int
  152 g_dev_setdumpdev(struct cdev *dev, struct diocskerneldump_arg *kda)
  153 {
  154         struct g_kerneldump kd;
  155         struct g_consumer *cp;
  156         int error, len;
  157 
  158         MPASS(dev != NULL && kda != NULL);
  159         MPASS(kda->kda_index != KDA_REMOVE);
  160 
  161         cp = dev->si_drv2;
  162         len = sizeof(kd);
  163         memset(&kd, 0, len);
  164         kd.offset = 0;
  165         kd.length = OFF_MAX;
  166         error = g_io_getattr("GEOM::kerneldump", cp, &len, &kd);
  167         if (error != 0)
  168                 return (error);
  169 
  170         error = dumper_insert(&kd.di, devtoname(dev), kda);
  171         if (error == 0)
  172                 dev->si_flags |= SI_DUMPDEV;
  173 
  174         return (error);
  175 }
  176 
  177 static int
  178 init_dumpdev(struct cdev *dev)
  179 {
  180         struct diocskerneldump_arg kda;
  181         struct g_consumer *cp;
  182         const char *devprefix = _PATH_DEV, *devname;
  183         int error;
  184         size_t len;
  185 
  186         bzero(&kda, sizeof(kda));
  187         kda.kda_index = KDA_APPEND;
  188 
  189         if (dumpdev == NULL)
  190                 return (0);
  191 
  192         len = strlen(devprefix);
  193         devname = devtoname(dev);
  194         if (strcmp(devname, dumpdev) != 0 &&
  195            (strncmp(dumpdev, devprefix, len) != 0 ||
  196             strcmp(devname, dumpdev + len) != 0))
  197                 return (0);
  198 
  199         cp = (struct g_consumer *)dev->si_drv2;
  200         error = g_access(cp, 1, 0, 0);
  201         if (error != 0)
  202                 return (error);
  203 
  204         error = g_dev_setdumpdev(dev, &kda);
  205         if (error == 0) {
  206                 freeenv(dumpdev);
  207                 dumpdev = NULL;
  208         }
  209 
  210         (void)g_access(cp, -1, 0, 0);
  211 
  212         return (error);
  213 }
  214 
  215 static void
  216 g_dev_destroy(void *arg, int flags __unused)
  217 {
  218         struct g_consumer *cp;
  219         struct g_geom *gp;
  220         struct g_dev_softc *sc;
  221         char buf[SPECNAMELEN + 6];
  222 
  223         g_topology_assert();
  224         cp = arg;
  225         gp = cp->geom;
  226         sc = cp->private;
  227         g_trace(G_T_TOPOLOGY, "g_dev_destroy(%p(%s))", cp, gp->name);
  228         snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
  229         devctl_notify("GEOM", "DEV", "DESTROY", buf);
  230         knlist_clear(&sc->sc_selinfo.si_note, 0);
  231         knlist_destroy(&sc->sc_selinfo.si_note);
  232         if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
  233                 g_access(cp, -cp->acr, -cp->acw, -cp->ace);
  234         g_detach(cp);
  235         g_destroy_consumer(cp);
  236         g_destroy_geom(gp);
  237         mtx_destroy(&sc->sc_mtx);
  238         g_free(sc);
  239 }
  240 
  241 void
  242 g_dev_print(void)
  243 {
  244         struct g_geom *gp;
  245         char const *p = "";
  246 
  247         LIST_FOREACH(gp, &g_dev_class.geom, geom) {
  248                 printf("%s%s", p, gp->name);
  249                 p = " ";
  250         }
  251         printf("\n");
  252 }
  253 
  254 static void
  255 g_dev_set_physpath(struct g_consumer *cp)
  256 {
  257         struct g_dev_softc *sc;
  258         char *physpath;
  259         int error, physpath_len;
  260 
  261         if (g_access(cp, 1, 0, 0) != 0)
  262                 return;
  263 
  264         sc = cp->private;
  265         physpath_len = MAXPATHLEN;
  266         physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
  267         error = g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
  268         g_access(cp, -1, 0, 0);
  269         if (error == 0 && strlen(physpath) != 0) {
  270                 struct cdev *dev, *old_alias_dev;
  271                 struct cdev **alias_devp;
  272 
  273                 dev = sc->sc_dev;
  274                 old_alias_dev = sc->sc_alias;
  275                 alias_devp = (struct cdev **)&sc->sc_alias;
  276                 make_dev_physpath_alias(MAKEDEV_WAITOK | MAKEDEV_CHECKNAME,
  277                     alias_devp, dev, old_alias_dev, physpath);
  278         } else if (sc->sc_alias) {
  279                 destroy_dev((struct cdev *)sc->sc_alias);
  280                 sc->sc_alias = NULL;
  281         }
  282         g_free(physpath);
  283 }
  284 
  285 static void
  286 g_dev_set_media(struct g_consumer *cp)
  287 {
  288         struct g_dev_softc *sc;
  289         struct cdev *dev;
  290         char buf[SPECNAMELEN + 6];
  291 
  292         sc = cp->private;
  293         dev = sc->sc_dev;
  294         snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
  295         devctl_notify("DEVFS", "CDEV", "MEDIACHANGE", buf);
  296         devctl_notify("GEOM", "DEV", "MEDIACHANGE", buf);
  297         dev = sc->sc_alias;
  298         if (dev != NULL) {
  299                 snprintf(buf, sizeof(buf), "cdev=%s", dev->si_name);
  300                 devctl_notify("DEVFS", "CDEV", "MEDIACHANGE", buf);
  301                 devctl_notify("GEOM", "DEV", "MEDIACHANGE", buf);
  302         }
  303 }
  304 
  305 static void
  306 g_dev_attrchanged(struct g_consumer *cp, const char *attr)
  307 {
  308 
  309         if (strcmp(attr, "GEOM::media") == 0) {
  310                 g_dev_set_media(cp);
  311                 return;
  312         }
  313 
  314         if (strcmp(attr, "GEOM::physpath") == 0) {
  315                 g_dev_set_physpath(cp);
  316                 return;
  317         }
  318 }
  319 
  320 static void
  321 g_dev_resize(struct g_consumer *cp)
  322 {
  323         struct g_dev_softc *sc;
  324         char buf[SPECNAMELEN + 6];
  325 
  326         sc = cp->private;
  327         KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, NOTE_ATTRIB);
  328 
  329         snprintf(buf, sizeof(buf), "cdev=%s", cp->provider->name);
  330         devctl_notify("GEOM", "DEV", "SIZECHANGE", buf);
  331 }
  332 
  333 struct g_provider *
  334 g_dev_getprovider(struct cdev *dev)
  335 {
  336         struct g_consumer *cp;
  337 
  338         g_topology_assert();
  339         if (dev == NULL)
  340                 return (NULL);
  341         if (dev->si_devsw != &g_dev_cdevsw)
  342                 return (NULL);
  343         cp = dev->si_drv2;
  344         return (cp->provider);
  345 }
  346 
  347 static struct g_geom *
  348 g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
  349 {
  350         struct g_geom *gp;
  351         struct g_geom_alias *gap;
  352         struct g_consumer *cp;
  353         struct g_dev_softc *sc;
  354         int error;
  355         struct cdev *dev, *adev;
  356         char buf[SPECNAMELEN + 6];
  357         struct make_dev_args args;
  358 
  359         g_trace(G_T_TOPOLOGY, "dev_taste(%s,%s)", mp->name, pp->name);
  360         g_topology_assert();
  361         gp = g_new_geomf(mp, "%s", pp->name);
  362         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
  363         mtx_init(&sc->sc_mtx, "g_dev", NULL, MTX_DEF);
  364         cp = g_new_consumer(gp);
  365         cp->private = sc;
  366         cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
  367         error = g_attach(cp, pp);
  368         if (error != 0) {
  369                 printf("%s: g_dev_taste(%s) failed to g_attach, error=%d\n",
  370                     __func__, pp->name, error);
  371                 g_destroy_consumer(cp);
  372                 g_destroy_geom(gp);
  373                 mtx_destroy(&sc->sc_mtx);
  374                 g_free(sc);
  375                 return (NULL);
  376         }
  377         make_dev_args_init(&args);
  378         args.mda_flags = MAKEDEV_CHECKNAME | MAKEDEV_WAITOK;
  379         args.mda_devsw = &g_dev_cdevsw;
  380         args.mda_cr = NULL;
  381         args.mda_uid = UID_ROOT;
  382         args.mda_gid = GID_OPERATOR;
  383         args.mda_mode = 0640;
  384         args.mda_si_drv1 = sc;
  385         args.mda_si_drv2 = cp;
  386         error = make_dev_s(&args, &sc->sc_dev, "%s", gp->name);
  387         if (error != 0) {
  388                 printf("%s: make_dev_p() failed (gp->name=%s, error=%d)\n",
  389                     __func__, gp->name, error);
  390                 g_detach(cp);
  391                 g_destroy_consumer(cp);
  392                 g_destroy_geom(gp);
  393                 mtx_destroy(&sc->sc_mtx);
  394                 g_free(sc);
  395                 return (NULL);
  396         }
  397         dev = sc->sc_dev;
  398         dev->si_flags |= SI_UNMAPPED;
  399         dev->si_iosize_max = maxphys;
  400         knlist_init_mtx(&sc->sc_selinfo.si_note, &sc->sc_mtx);
  401         error = init_dumpdev(dev);
  402         if (error != 0)
  403                 printf("%s: init_dumpdev() failed (gp->name=%s, error=%d)\n",
  404                     __func__, gp->name, error);
  405 
  406         g_dev_attrchanged(cp, "GEOM::physpath");
  407         snprintf(buf, sizeof(buf), "cdev=%s", gp->name);
  408         devctl_notify("GEOM", "DEV", "CREATE", buf);
  409         /*
  410          * Now add all the aliases for this drive
  411          */
  412         LIST_FOREACH(gap, &pp->aliases, ga_next) {
  413                 error = make_dev_alias_p(MAKEDEV_CHECKNAME | MAKEDEV_WAITOK, &adev, dev,
  414                     "%s", gap->ga_alias);
  415                 if (error) {
  416                         printf("%s: make_dev_alias_p() failed (name=%s, error=%d)\n",
  417                             __func__, gap->ga_alias, error);
  418                         continue;
  419                 }
  420                 snprintf(buf, sizeof(buf), "cdev=%s", gap->ga_alias);
  421                 devctl_notify("GEOM", "DEV", "CREATE", buf);
  422         }
  423 
  424         return (gp);
  425 }
  426 
  427 static int
  428 g_dev_open(struct cdev *dev, int flags, int fmt, struct thread *td)
  429 {
  430         struct g_consumer *cp;
  431         struct g_dev_softc *sc;
  432         int error, r, w, e;
  433 
  434         cp = dev->si_drv2;
  435         g_trace(G_T_ACCESS, "g_dev_open(%s, %d, %d, %p)",
  436             cp->geom->name, flags, fmt, td);
  437 
  438         r = flags & FREAD ? 1 : 0;
  439         w = flags & FWRITE ? 1 : 0;
  440 #ifdef notyet
  441         e = flags & O_EXCL ? 1 : 0;
  442 #else
  443         e = 0;
  444 #endif
  445 
  446         /*
  447          * This happens on attempt to open a device node with O_EXEC.
  448          */
  449         if (r + w + e == 0)
  450                 return (EINVAL);
  451 
  452         if (w) {
  453                 /*
  454                  * When running in very secure mode, do not allow
  455                  * opens for writing of any disks.
  456                  */
  457                 error = securelevel_ge(td->td_ucred, 2);
  458                 if (error)
  459                         return (error);
  460         }
  461         g_topology_lock();
  462         error = g_access(cp, r, w, e);
  463         g_topology_unlock();
  464         if (error == 0) {
  465                 sc = dev->si_drv1;
  466                 mtx_lock(&sc->sc_mtx);
  467                 if (sc->sc_open == 0 && (sc->sc_active & SC_A_ACTIVE) != 0)
  468                         wakeup(&sc->sc_active);
  469                 sc->sc_open += r + w + e;
  470                 if (sc->sc_open == 0)
  471                         atomic_clear_int(&sc->sc_active, SC_A_OPEN);
  472                 else
  473                         atomic_set_int(&sc->sc_active, SC_A_OPEN);
  474                 KNOTE_LOCKED(&sc->sc_selinfo.si_note, NOTE_OPEN);
  475                 mtx_unlock(&sc->sc_mtx);
  476         }
  477         return (error);
  478 }
  479 
  480 static int
  481 g_dev_close(struct cdev *dev, int flags, int fmt, struct thread *td)
  482 {
  483         struct g_consumer *cp;
  484         struct g_dev_softc *sc;
  485         int error, r, w, e;
  486 
  487         cp = dev->si_drv2;
  488         g_trace(G_T_ACCESS, "g_dev_close(%s, %d, %d, %p)",
  489             cp->geom->name, flags, fmt, td);
  490 
  491         r = flags & FREAD ? -1 : 0;
  492         w = flags & FWRITE ? -1 : 0;
  493 #ifdef notyet
  494         e = flags & O_EXCL ? -1 : 0;
  495 #else
  496         e = 0;
  497 #endif
  498 
  499         /*
  500          * The vgonel(9) - caused by eg. forced unmount of devfs - calls
  501          * VOP_CLOSE(9) on devfs vnode without any FREAD or FWRITE flags,
  502          * which would result in zero deltas, which in turn would cause
  503          * panic in g_access(9).
  504          *
  505          * Note that we cannot zero the counters (ie. do "r = cp->acr"
  506          * etc) instead, because the consumer might be opened in another
  507          * devfs instance.
  508          */
  509         if (r + w + e == 0)
  510                 return (EINVAL);
  511 
  512         sc = dev->si_drv1;
  513         mtx_lock(&sc->sc_mtx);
  514         sc->sc_open += r + w + e;
  515         if (sc->sc_open == 0)
  516                 atomic_clear_int(&sc->sc_active, SC_A_OPEN);
  517         else
  518                 atomic_set_int(&sc->sc_active, SC_A_OPEN);
  519         while (sc->sc_open == 0 && (sc->sc_active & SC_A_ACTIVE) != 0)
  520                 msleep(&sc->sc_active, &sc->sc_mtx, 0, "g_dev_close", hz / 10);
  521         KNOTE_LOCKED(&sc->sc_selinfo.si_note, NOTE_CLOSE | (w ? NOTE_CLOSE_WRITE : 0));
  522         mtx_unlock(&sc->sc_mtx);
  523         g_topology_lock();
  524         error = g_access(cp, r, w, e);
  525         g_topology_unlock();
  526         return (error);
  527 }
  528 
  529 static int
  530 g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
  531 {
  532         struct g_consumer *cp;
  533         struct g_provider *pp;
  534         off_t offset, length, chunk, odd;
  535         int i, error;
  536 
  537         cp = dev->si_drv2;
  538         pp = cp->provider;
  539 
  540         /* If consumer or provider is dying, don't disturb. */
  541         if (cp->flags & G_CF_ORPHAN)
  542                 return (ENXIO);
  543         if (pp->error)
  544                 return (pp->error);
  545 
  546         error = 0;
  547         KASSERT(cp->acr || cp->acw,
  548             ("Consumer with zero access count in g_dev_ioctl"));
  549 
  550         i = IOCPARM_LEN(cmd);
  551         switch (cmd) {
  552         case DIOCGSECTORSIZE:
  553                 *(u_int *)data = pp->sectorsize;
  554                 if (*(u_int *)data == 0)
  555                         error = ENOENT;
  556                 break;
  557         case DIOCGMEDIASIZE:
  558                 *(off_t *)data = pp->mediasize;
  559                 if (*(off_t *)data == 0)
  560                         error = ENOENT;
  561                 break;
  562         case DIOCGFWSECTORS:
  563                 error = g_io_getattr("GEOM::fwsectors", cp, &i, data);
  564                 if (error == 0 && *(u_int *)data == 0)
  565                         error = ENOENT;
  566                 break;
  567         case DIOCGFWHEADS:
  568                 error = g_io_getattr("GEOM::fwheads", cp, &i, data);
  569                 if (error == 0 && *(u_int *)data == 0)
  570                         error = ENOENT;
  571                 break;
  572         case DIOCSKERNELDUMP:
  573             {
  574                 struct diocskerneldump_arg *kda;
  575                 uint8_t *encryptedkey;
  576 
  577                 kda = (struct diocskerneldump_arg *)data;
  578                 if (kda->kda_index == KDA_REMOVE_ALL ||
  579                     kda->kda_index == KDA_REMOVE_DEV ||
  580                     kda->kda_index == KDA_REMOVE) {
  581                         error = dumper_remove(devtoname(dev), kda);
  582                         explicit_bzero(kda, sizeof(*kda));
  583                         break;
  584                 }
  585 
  586                 if (kda->kda_encryption != KERNELDUMP_ENC_NONE) {
  587                         if (kda->kda_encryptedkeysize == 0 ||
  588                             kda->kda_encryptedkeysize >
  589                             KERNELDUMP_ENCKEY_MAX_SIZE) {
  590                                 explicit_bzero(kda, sizeof(*kda));
  591                                 return (EINVAL);
  592                         }
  593                         encryptedkey = malloc(kda->kda_encryptedkeysize, M_TEMP,
  594                             M_WAITOK);
  595                         error = copyin(kda->kda_encryptedkey, encryptedkey,
  596                             kda->kda_encryptedkeysize);
  597                 } else {
  598                         encryptedkey = NULL;
  599                 }
  600                 if (error == 0) {
  601                         kda->kda_encryptedkey = encryptedkey;
  602                         error = g_dev_setdumpdev(dev, kda);
  603                 }
  604                 zfree(encryptedkey, M_TEMP);
  605                 explicit_bzero(kda, sizeof(*kda));
  606                 break;
  607             }
  608         case DIOCGFLUSH:
  609                 error = g_io_flush(cp);
  610                 break;
  611         case DIOCGDELETE:
  612                 offset = ((off_t *)data)[0];
  613                 length = ((off_t *)data)[1];
  614                 if ((offset % pp->sectorsize) != 0 ||
  615                     (length % pp->sectorsize) != 0 || length <= 0) {
  616                         printf("%s: offset=%jd length=%jd\n", __func__, offset,
  617                             length);
  618                         error = EINVAL;
  619                         break;
  620                 }
  621                 while (length > 0) {
  622                         chunk = length;
  623                         if (g_dev_del_max_sectors != 0 &&
  624                             chunk > g_dev_del_max_sectors * pp->sectorsize) {
  625                                 chunk = g_dev_del_max_sectors * pp->sectorsize;
  626                                 if (pp->stripesize > 0) {
  627                                         odd = (offset + chunk +
  628                                             pp->stripeoffset) % pp->stripesize;
  629                                         if (chunk > odd)
  630                                                 chunk -= odd;
  631                                 }
  632                         }
  633                         error = g_delete_data(cp, offset, chunk);
  634                         length -= chunk;
  635                         offset += chunk;
  636                         if (error)
  637                                 break;
  638                         /*
  639                          * Since the request size can be large, the service
  640                          * time can be is likewise.  We make this ioctl
  641                          * interruptible by checking for signals for each bio.
  642                          */
  643                         if (SIGPENDING(td))
  644                                 break;
  645                 }
  646                 break;
  647         case DIOCGIDENT:
  648                 error = g_io_getattr("GEOM::ident", cp, &i, data);
  649                 break;
  650         case DIOCGPROVIDERNAME:
  651                 strlcpy(data, pp->name, i);
  652                 break;
  653         case DIOCGSTRIPESIZE:
  654                 *(off_t *)data = pp->stripesize;
  655                 break;
  656         case DIOCGSTRIPEOFFSET:
  657                 *(off_t *)data = pp->stripeoffset;
  658                 break;
  659         case DIOCGPHYSPATH:
  660                 error = g_io_getattr("GEOM::physpath", cp, &i, data);
  661                 if (error == 0 && *(char *)data == '\0')
  662                         error = ENOENT;
  663                 break;
  664         case DIOCGATTR: {
  665                 struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
  666 
  667                 if (arg->len > sizeof(arg->value)) {
  668                         error = EINVAL;
  669                         break;
  670                 }
  671                 error = g_io_getattr(arg->name, cp, &arg->len, &arg->value);
  672                 break;
  673         }
  674         case DIOCZONECMD: {
  675                 struct disk_zone_args *zone_args =(struct disk_zone_args *)data;
  676                 struct disk_zone_rep_entry *new_entries, *old_entries;
  677                 struct disk_zone_report *rep;
  678                 size_t alloc_size;
  679 
  680                 old_entries = NULL;
  681                 new_entries = NULL;
  682                 rep = NULL;
  683                 alloc_size = 0;
  684 
  685                 if (zone_args->zone_cmd == DISK_ZONE_REPORT_ZONES) {
  686                         rep = &zone_args->zone_params.report;
  687 #define MAXENTRIES      (maxphys / sizeof(struct disk_zone_rep_entry))
  688                         if (rep->entries_allocated > MAXENTRIES)
  689                                 rep->entries_allocated = MAXENTRIES;
  690                         alloc_size = rep->entries_allocated *
  691                             sizeof(struct disk_zone_rep_entry);
  692                         if (alloc_size != 0)
  693                                 new_entries = g_malloc(alloc_size,
  694                                     M_WAITOK | M_ZERO);
  695                         old_entries = rep->entries;
  696                         rep->entries = new_entries;
  697                 }
  698                 error = g_io_zonecmd(zone_args, cp);
  699                 if (zone_args->zone_cmd == DISK_ZONE_REPORT_ZONES &&
  700                     alloc_size != 0 && error == 0)
  701                         error = copyout(new_entries, old_entries, alloc_size);
  702                 if (old_entries != NULL && rep != NULL)
  703                         rep->entries = old_entries;
  704                 g_free(new_entries);
  705                 break;
  706         }
  707         default:
  708                 if (pp->geom->ioctl != NULL) {
  709                         error = pp->geom->ioctl(pp, cmd, data, fflag, td);
  710                 } else {
  711                         error = ENOIOCTL;
  712                 }
  713         }
  714 
  715         return (error);
  716 }
  717 
  718 static void
  719 g_dev_done(struct bio *bp2)
  720 {
  721         struct g_consumer *cp;
  722         struct g_dev_softc *sc;
  723         struct bio *bp;
  724         int active;
  725 
  726         cp = bp2->bio_from;
  727         sc = cp->private;
  728         bp = bp2->bio_parent;
  729         bp->bio_error = bp2->bio_error;
  730         bp->bio_completed = bp2->bio_completed;
  731         bp->bio_resid = bp->bio_length - bp2->bio_completed;
  732         if (bp2->bio_cmd == BIO_ZONE)
  733                 bcopy(&bp2->bio_zone, &bp->bio_zone, sizeof(bp->bio_zone));
  734 
  735         if (bp2->bio_error != 0) {
  736                 g_trace(G_T_BIO, "g_dev_done(%p) had error %d",
  737                     bp2, bp2->bio_error);
  738                 bp->bio_flags |= BIO_ERROR;
  739         } else {
  740                 if (bp->bio_cmd == BIO_READ)
  741                         KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, NOTE_READ);
  742                 if (bp->bio_cmd == BIO_WRITE)
  743                         KNOTE_UNLOCKED(&sc->sc_selinfo.si_note, NOTE_WRITE);
  744                 g_trace(G_T_BIO, "g_dev_done(%p/%p) resid %ld completed %jd",
  745                     bp2, bp, bp2->bio_resid, (intmax_t)bp2->bio_completed);
  746         }
  747         g_destroy_bio(bp2);
  748         active = atomic_fetchadd_int(&sc->sc_active, -1) - 1;
  749         if ((active & SC_A_ACTIVE) == 0) {
  750                 if ((active & SC_A_OPEN) == 0)
  751                         wakeup(&sc->sc_active);
  752                 if (active & SC_A_DESTROY)
  753                         g_post_event(g_dev_destroy, cp, M_NOWAIT, NULL);
  754         }
  755         biodone(bp);
  756 }
  757 
  758 static void
  759 g_dev_strategy(struct bio *bp)
  760 {
  761         struct g_consumer *cp;
  762         struct bio *bp2;
  763         struct cdev *dev;
  764         struct g_dev_softc *sc;
  765 
  766         KASSERT(bp->bio_cmd == BIO_READ ||
  767                 bp->bio_cmd == BIO_WRITE ||
  768                 bp->bio_cmd == BIO_DELETE ||
  769                 bp->bio_cmd == BIO_FLUSH ||
  770                 bp->bio_cmd == BIO_ZONE,
  771                 ("Wrong bio_cmd bio=%p cmd=%d", bp, bp->bio_cmd));
  772         dev = bp->bio_dev;
  773         cp = dev->si_drv2;
  774         KASSERT(cp->acr || cp->acw,
  775             ("Consumer with zero access count in g_dev_strategy"));
  776         biotrack(bp, __func__);
  777 #ifdef INVARIANTS
  778         if ((bp->bio_offset % cp->provider->sectorsize) != 0 ||
  779             (bp->bio_bcount % cp->provider->sectorsize) != 0) {
  780                 bp->bio_resid = bp->bio_bcount;
  781                 biofinish(bp, NULL, EINVAL);
  782                 return;
  783         }
  784 #endif
  785         sc = dev->si_drv1;
  786         KASSERT(sc->sc_open > 0, ("Closed device in g_dev_strategy"));
  787         atomic_add_int(&sc->sc_active, 1);
  788 
  789         for (;;) {
  790                 /*
  791                  * XXX: This is not an ideal solution, but I believe it to
  792                  * XXX: deadlock safely, all things considered.
  793                  */
  794                 bp2 = g_clone_bio(bp);
  795                 if (bp2 != NULL)
  796                         break;
  797                 pause("gdstrat", hz / 10);
  798         }
  799         KASSERT(bp2 != NULL, ("XXX: ENOMEM in a bad place"));
  800         bp2->bio_done = g_dev_done;
  801         g_trace(G_T_BIO,
  802             "g_dev_strategy(%p/%p) offset %jd length %jd data %p cmd %d",
  803             bp, bp2, (intmax_t)bp->bio_offset, (intmax_t)bp2->bio_length,
  804             bp2->bio_data, bp2->bio_cmd);
  805         g_io_request(bp2, cp);
  806         KASSERT(cp->acr || cp->acw,
  807             ("g_dev_strategy raced with g_dev_close and lost"));
  808 
  809 }
  810 
  811 /*
  812  * g_dev_callback()
  813  *
  814  * Called by devfs when asynchronous device destruction is completed.
  815  * - Mark that we have no attached device any more.
  816  * - If there are no outstanding requests, schedule geom destruction.
  817  *   Otherwise destruction will be scheduled later by g_dev_done().
  818  */
  819 
  820 static void
  821 g_dev_callback(void *arg)
  822 {
  823         struct g_consumer *cp;
  824         struct g_dev_softc *sc;
  825         int active;
  826 
  827         cp = arg;
  828         sc = cp->private;
  829         g_trace(G_T_TOPOLOGY, "g_dev_callback(%p(%s))", cp, cp->geom->name);
  830 
  831         sc->sc_dev = NULL;
  832         sc->sc_alias = NULL;
  833         active = atomic_fetchadd_int(&sc->sc_active, SC_A_DESTROY);
  834         if ((active & SC_A_ACTIVE) == 0)
  835                 g_post_event(g_dev_destroy, cp, M_WAITOK, NULL);
  836 }
  837 
  838 /*
  839  * g_dev_orphan()
  840  *
  841  * Called from below when the provider orphaned us.
  842  * - Clear any dump settings.
  843  * - Request asynchronous device destruction to prevent any more requests
  844  *   from coming in.  The provider is already marked with an error, so
  845  *   anything which comes in the interim will be returned immediately.
  846  */
  847 
  848 static void
  849 g_dev_orphan(struct g_consumer *cp)
  850 {
  851         struct cdev *dev;
  852         struct g_dev_softc *sc;
  853 
  854         g_topology_assert();
  855         sc = cp->private;
  856         dev = sc->sc_dev;
  857         g_trace(G_T_TOPOLOGY, "g_dev_orphan(%p(%s))", cp, cp->geom->name);
  858 
  859         /* Reset any dump-area set on this device */
  860         if (dev->si_flags & SI_DUMPDEV) {
  861                 struct diocskerneldump_arg kda;
  862 
  863                 bzero(&kda, sizeof(kda));
  864                 kda.kda_index = KDA_REMOVE_DEV;
  865                 (void)dumper_remove(devtoname(dev), &kda);
  866         }
  867 
  868         /* Destroy the struct cdev *so we get no more requests */
  869         delist_dev(dev);
  870         destroy_dev_sched_cb(dev, g_dev_callback, cp);
  871 }
  872 
  873 static void
  874 gdev_filter_detach(struct knote *kn)
  875 {
  876         struct g_dev_softc *sc;
  877 
  878         sc = kn->kn_hook;
  879 
  880         knlist_remove(&sc->sc_selinfo.si_note, kn, 0);
  881 }
  882 
  883 static int
  884 gdev_filter_vnode(struct knote *kn, long hint)
  885 {
  886         kn->kn_fflags |= kn->kn_sfflags & hint;
  887 
  888         return (kn->kn_fflags != 0);
  889 }
  890 
  891 static int
  892 g_dev_kqfilter(struct cdev *dev, struct knote *kn)
  893 {
  894         struct g_dev_softc *sc;
  895 
  896         sc = dev->si_drv1;
  897 
  898         if (kn->kn_filter != EVFILT_VNODE)
  899                 return (EINVAL);
  900 
  901 #define SUPPORTED_EVENTS (NOTE_ATTRIB | NOTE_OPEN | NOTE_CLOSE | \
  902     NOTE_CLOSE_WRITE | NOTE_READ | NOTE_WRITE)
  903         if (kn->kn_sfflags & ~SUPPORTED_EVENTS)
  904                 return (EOPNOTSUPP);
  905 
  906         kn->kn_fop = &gdev_filterops_vnode;
  907         kn->kn_hook = sc;
  908         knlist_add(&sc->sc_selinfo.si_note, kn, 0);
  909 
  910         return (0);
  911 }
  912 
  913 DECLARE_GEOM_CLASS(g_dev_class, g_dev);

Cache object: d40885f5db000d0401ece9fc6bd7eb03


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