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_disk.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  * 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 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: releng/11.2/sys/geom/geom_disk.c 329316 2018-02-15 15:33:17Z avg $");
   38 
   39 #include "opt_geom.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/systm.h>
   43 #include <sys/kernel.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/bio.h>
   46 #include <sys/bus.h>
   47 #include <sys/ctype.h>
   48 #include <sys/fcntl.h>
   49 #include <sys/malloc.h>
   50 #include <sys/sbuf.h>
   51 #include <sys/devicestat.h>
   52 #include <machine/md_var.h>
   53 
   54 #include <sys/lock.h>
   55 #include <sys/mutex.h>
   56 #include <geom/geom.h>
   57 #include <geom/geom_disk.h>
   58 #include <geom/geom_int.h>
   59 
   60 #include <dev/led/led.h>
   61 
   62 #include <machine/bus.h>
   63 
   64 struct g_disk_softc {
   65         struct mtx               done_mtx;
   66         struct disk             *dp;
   67         struct sysctl_ctx_list  sysctl_ctx;
   68         struct sysctl_oid       *sysctl_tree;
   69         char                    led[64];
   70         uint32_t                state;
   71         struct mtx               start_mtx;
   72 };
   73 
   74 static g_access_t g_disk_access;
   75 static g_start_t g_disk_start;
   76 static g_ioctl_t g_disk_ioctl;
   77 static g_dumpconf_t g_disk_dumpconf;
   78 static g_provgone_t g_disk_providergone;
   79 
   80 static struct g_class g_disk_class = {
   81         .name = G_DISK_CLASS_NAME,
   82         .version = G_VERSION,
   83         .start = g_disk_start,
   84         .access = g_disk_access,
   85         .ioctl = g_disk_ioctl,
   86         .providergone = g_disk_providergone,
   87         .dumpconf = g_disk_dumpconf,
   88 };
   89 
   90 SYSCTL_DECL(_kern_geom);
   91 static SYSCTL_NODE(_kern_geom, OID_AUTO, disk, CTLFLAG_RW, 0,
   92     "GEOM_DISK stuff");
   93 
   94 DECLARE_GEOM_CLASS(g_disk_class, g_disk);
   95 
   96 static int
   97 g_disk_access(struct g_provider *pp, int r, int w, int e)
   98 {
   99         struct disk *dp;
  100         struct g_disk_softc *sc;
  101         int error;
  102 
  103         g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
  104             pp->name, r, w, e);
  105         g_topology_assert();
  106         sc = pp->private;
  107         if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
  108                 /*
  109                  * Allow decreasing access count even if disk is not
  110                  * available anymore.
  111                  */
  112                 if (r <= 0 && w <= 0 && e <= 0)
  113                         return (0);
  114                 return (ENXIO);
  115         }
  116         r += pp->acr;
  117         w += pp->acw;
  118         e += pp->ace;
  119         error = 0;
  120         if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
  121                 /*
  122                  * It would be better to defer this decision to d_open if
  123                  * it was able to take flags.
  124                  */
  125                 if (w > 0 && (dp->d_flags & DISKFLAG_WRITE_PROTECT) != 0)
  126                         error = EROFS;
  127                 if (error == 0 && dp->d_open != NULL)
  128                         error = dp->d_open(dp);
  129                 if (bootverbose && error != 0)
  130                         printf("Opened disk %s -> %d\n", pp->name, error);
  131                 if (error != 0)
  132                         return (error);
  133                 pp->sectorsize = dp->d_sectorsize;
  134                 if (dp->d_maxsize == 0) {
  135                         printf("WARNING: Disk drive %s%d has no d_maxsize\n",
  136                             dp->d_name, dp->d_unit);
  137                         dp->d_maxsize = DFLTPHYS;
  138                 }
  139                 if (dp->d_delmaxsize == 0) {
  140                         if (bootverbose && dp->d_flags & DISKFLAG_CANDELETE) {
  141                                 printf("WARNING: Disk drive %s%d has no "
  142                                     "d_delmaxsize\n", dp->d_name, dp->d_unit);
  143                         }
  144                         dp->d_delmaxsize = dp->d_maxsize;
  145                 }
  146                 pp->stripeoffset = dp->d_stripeoffset;
  147                 pp->stripesize = dp->d_stripesize;
  148                 dp->d_flags |= DISKFLAG_OPEN;
  149                 /*
  150                  * Do not invoke resize event when initial size was zero.
  151                  * Some disks report its size only after first opening.
  152                  */
  153                 if (pp->mediasize == 0)
  154                         pp->mediasize = dp->d_mediasize;
  155                 else
  156                         g_resize_provider(pp, dp->d_mediasize);
  157         } else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) {
  158                 if (dp->d_close != NULL) {
  159                         error = dp->d_close(dp);
  160                         if (error != 0)
  161                                 printf("Closed disk %s -> %d\n",
  162                                     pp->name, error);
  163                 }
  164                 sc->state = G_STATE_ACTIVE;
  165                 if (sc->led[0] != 0)
  166                         led_set(sc->led, "");
  167                 dp->d_flags &= ~DISKFLAG_OPEN;
  168         }
  169         return (error);
  170 }
  171 
  172 static void
  173 g_disk_kerneldump(struct bio *bp, struct disk *dp)
  174 {
  175         struct g_kerneldump *gkd;
  176         struct g_geom *gp;
  177 
  178         gkd = (struct g_kerneldump*)bp->bio_data;
  179         gp = bp->bio_to->geom;
  180         g_trace(G_T_TOPOLOGY, "g_disk_kerneldump(%s, %jd, %jd)",
  181                 gp->name, (intmax_t)gkd->offset, (intmax_t)gkd->length);
  182         if (dp->d_dump == NULL) {
  183                 g_io_deliver(bp, ENODEV);
  184                 return;
  185         }
  186         gkd->di.dumper = dp->d_dump;
  187         gkd->di.priv = dp;
  188         gkd->di.blocksize = dp->d_sectorsize;
  189         gkd->di.maxiosize = dp->d_maxsize;
  190         gkd->di.mediaoffset = gkd->offset;
  191         if ((gkd->offset + gkd->length) > dp->d_mediasize)
  192                 gkd->length = dp->d_mediasize - gkd->offset;
  193         gkd->di.mediasize = gkd->length;
  194         g_io_deliver(bp, 0);
  195 }
  196 
  197 static void
  198 g_disk_setstate(struct bio *bp, struct g_disk_softc *sc)
  199 {
  200         const char *cmd;
  201 
  202         memcpy(&sc->state, bp->bio_data, sizeof(sc->state));
  203         if (sc->led[0] != 0) {
  204                 switch (sc->state) {
  205                 case G_STATE_FAILED:
  206                         cmd = "1";
  207                         break;
  208                 case G_STATE_REBUILD:
  209                         cmd = "f5";
  210                         break;
  211                 case G_STATE_RESYNC:
  212                         cmd = "f1";
  213                         break;
  214                 default:
  215                         cmd = "";
  216                         break;
  217                 }
  218                 led_set(sc->led, cmd);
  219         }
  220         g_io_deliver(bp, 0);
  221 }
  222 
  223 static void
  224 g_disk_done(struct bio *bp)
  225 {
  226         struct bintime now;
  227         struct bio *bp2;
  228         struct g_disk_softc *sc;
  229 
  230         /* See "notes" for why we need a mutex here */
  231         /* XXX: will witness accept a mix of Giant/unGiant drivers here ? */
  232         bp2 = bp->bio_parent;
  233         sc = bp2->bio_to->private;
  234         bp->bio_completed = bp->bio_length - bp->bio_resid;
  235         binuptime(&now);
  236         mtx_lock(&sc->done_mtx);
  237         if (bp2->bio_error == 0)
  238                 bp2->bio_error = bp->bio_error;
  239         bp2->bio_completed += bp->bio_completed;
  240 
  241         switch (bp->bio_cmd) {
  242         case BIO_ZONE:
  243                 bcopy(&bp->bio_zone, &bp2->bio_zone, sizeof(bp->bio_zone));
  244                 /*FALLTHROUGH*/
  245         case BIO_READ:
  246         case BIO_WRITE:
  247         case BIO_DELETE:
  248         case BIO_FLUSH:
  249                 devstat_end_transaction_bio_bt(sc->dp->d_devstat, bp, &now);
  250                 break;
  251         default:
  252                 break;
  253         }
  254         bp2->bio_inbed++;
  255         if (bp2->bio_children == bp2->bio_inbed) {
  256                 mtx_unlock(&sc->done_mtx);
  257                 bp2->bio_resid = bp2->bio_bcount - bp2->bio_completed;
  258                 g_io_deliver(bp2, bp2->bio_error);
  259         } else
  260                 mtx_unlock(&sc->done_mtx);
  261         g_destroy_bio(bp);
  262 }
  263 
  264 static int
  265 g_disk_ioctl(struct g_provider *pp, u_long cmd, void * data, int fflag, struct thread *td)
  266 {
  267         struct disk *dp;
  268         struct g_disk_softc *sc;
  269         int error;
  270 
  271         sc = pp->private;
  272         dp = sc->dp;
  273 
  274         if (dp->d_ioctl == NULL)
  275                 return (ENOIOCTL);
  276         error = dp->d_ioctl(dp, cmd, data, fflag, td);
  277         return (error);
  278 }
  279 
  280 static off_t
  281 g_disk_maxsize(struct disk *dp, struct bio *bp)
  282 {
  283         if (bp->bio_cmd == BIO_DELETE)
  284                 return (dp->d_delmaxsize);
  285         return (dp->d_maxsize);
  286 }
  287 
  288 static int
  289 g_disk_maxsegs(struct disk *dp, struct bio *bp)
  290 {
  291         return ((g_disk_maxsize(dp, bp) / PAGE_SIZE) + 1);
  292 }
  293 
  294 static void
  295 g_disk_advance(struct disk *dp, struct bio *bp, off_t off)
  296 {
  297 
  298         bp->bio_offset += off;
  299         bp->bio_length -= off;
  300 
  301         if ((bp->bio_flags & BIO_VLIST) != 0) {
  302                 bus_dma_segment_t *seg, *end;
  303 
  304                 seg = (bus_dma_segment_t *)bp->bio_data;
  305                 end = (bus_dma_segment_t *)bp->bio_data + bp->bio_ma_n;
  306                 off += bp->bio_ma_offset;
  307                 while (off >= seg->ds_len) {
  308                         KASSERT((seg != end),
  309                             ("vlist request runs off the end"));
  310                         off -= seg->ds_len;
  311                         seg++;
  312                 }
  313                 bp->bio_ma_offset = off;
  314                 bp->bio_ma_n = end - seg;
  315                 bp->bio_data = (void *)seg;
  316         } else if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
  317                 bp->bio_ma += off / PAGE_SIZE;
  318                 bp->bio_ma_offset += off;
  319                 bp->bio_ma_offset %= PAGE_SIZE;
  320                 bp->bio_ma_n -= off / PAGE_SIZE;
  321         } else {
  322                 bp->bio_data += off;
  323         }
  324 }
  325 
  326 static void
  327 g_disk_seg_limit(bus_dma_segment_t *seg, off_t *poffset,
  328     off_t *plength, int *ppages)
  329 {
  330         uintptr_t seg_page_base;
  331         uintptr_t seg_page_end;
  332         off_t offset;
  333         off_t length;
  334         int seg_pages;
  335 
  336         offset = *poffset;
  337         length = *plength;
  338 
  339         if (length > seg->ds_len - offset)
  340                 length = seg->ds_len - offset;
  341 
  342         seg_page_base = trunc_page(seg->ds_addr + offset);
  343         seg_page_end  = round_page(seg->ds_addr + offset + length);
  344         seg_pages = (seg_page_end - seg_page_base) >> PAGE_SHIFT;
  345 
  346         if (seg_pages > *ppages) {
  347                 seg_pages = *ppages;
  348                 length = (seg_page_base + (seg_pages << PAGE_SHIFT)) -
  349                     (seg->ds_addr + offset);
  350         }
  351 
  352         *poffset = 0;
  353         *plength -= length;
  354         *ppages -= seg_pages;
  355 }
  356 
  357 static off_t
  358 g_disk_vlist_limit(struct disk *dp, struct bio *bp, bus_dma_segment_t **pendseg)
  359 {
  360         bus_dma_segment_t *seg, *end;
  361         off_t residual;
  362         off_t offset;
  363         int pages;
  364 
  365         seg = (bus_dma_segment_t *)bp->bio_data;
  366         end = (bus_dma_segment_t *)bp->bio_data + bp->bio_ma_n;
  367         residual = bp->bio_length;
  368         offset = bp->bio_ma_offset;
  369         pages = g_disk_maxsegs(dp, bp);
  370         while (residual != 0 && pages != 0) {
  371                 KASSERT((seg != end),
  372                     ("vlist limit runs off the end"));
  373                 g_disk_seg_limit(seg, &offset, &residual, &pages);
  374                 seg++;
  375         }
  376         if (pendseg != NULL)
  377                 *pendseg = seg;
  378         return (residual);
  379 }
  380 
  381 static bool
  382 g_disk_limit(struct disk *dp, struct bio *bp)
  383 {
  384         bool limited = false;
  385         off_t maxsz;
  386 
  387         maxsz = g_disk_maxsize(dp, bp);
  388 
  389         /*
  390          * XXX: If we have a stripesize we should really use it here.
  391          *      Care should be taken in the delete case if this is done
  392          *      as deletes can be very sensitive to size given how they
  393          *      are processed.
  394          */
  395         if (bp->bio_length > maxsz) {
  396                 bp->bio_length = maxsz;
  397                 limited = true;
  398         }
  399 
  400         if ((bp->bio_flags & BIO_VLIST) != 0) {
  401                 bus_dma_segment_t *firstseg, *endseg;
  402                 off_t residual;
  403 
  404                 firstseg = (bus_dma_segment_t*)bp->bio_data;
  405                 residual = g_disk_vlist_limit(dp, bp, &endseg);
  406                 if (residual != 0) {
  407                         bp->bio_ma_n = endseg - firstseg;
  408                         bp->bio_length -= residual;
  409                         limited = true;
  410                 }
  411         } else if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
  412                 bp->bio_ma_n =
  413                     howmany(bp->bio_ma_offset + bp->bio_length, PAGE_SIZE);
  414         }
  415 
  416         return (limited);
  417 }
  418 
  419 static void
  420 g_disk_start(struct bio *bp)
  421 {
  422         struct bio *bp2, *bp3;
  423         struct disk *dp;
  424         struct g_disk_softc *sc;
  425         int error;
  426         off_t off;
  427 
  428         sc = bp->bio_to->private;
  429         if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
  430                 g_io_deliver(bp, ENXIO);
  431                 return;
  432         }
  433         error = EJUSTRETURN;
  434         switch(bp->bio_cmd) {
  435         case BIO_DELETE:
  436                 if (!(dp->d_flags & DISKFLAG_CANDELETE)) {
  437                         error = EOPNOTSUPP;
  438                         break;
  439                 }
  440                 /* fall-through */
  441         case BIO_READ:
  442         case BIO_WRITE:
  443                 KASSERT((dp->d_flags & DISKFLAG_UNMAPPED_BIO) != 0 ||
  444                     (bp->bio_flags & BIO_UNMAPPED) == 0,
  445                     ("unmapped bio not supported by disk %s", dp->d_name));
  446                 off = 0;
  447                 bp3 = NULL;
  448                 bp2 = g_clone_bio(bp);
  449                 if (bp2 == NULL) {
  450                         error = ENOMEM;
  451                         break;
  452                 }
  453                 for (;;) {
  454                         if (g_disk_limit(dp, bp2)) {
  455                                 off += bp2->bio_length;
  456 
  457                                 /*
  458                                  * To avoid a race, we need to grab the next bio
  459                                  * before we schedule this one.  See "notes".
  460                                  */
  461                                 bp3 = g_clone_bio(bp);
  462                                 if (bp3 == NULL)
  463                                         bp->bio_error = ENOMEM;
  464                         }
  465                         bp2->bio_done = g_disk_done;
  466                         bp2->bio_pblkno = bp2->bio_offset / dp->d_sectorsize;
  467                         bp2->bio_bcount = bp2->bio_length;
  468                         bp2->bio_disk = dp;
  469                         mtx_lock(&sc->start_mtx); 
  470                         devstat_start_transaction_bio(dp->d_devstat, bp2);
  471                         mtx_unlock(&sc->start_mtx); 
  472                         dp->d_strategy(bp2);
  473 
  474                         if (bp3 == NULL)
  475                                 break;
  476 
  477                         bp2 = bp3;
  478                         bp3 = NULL;
  479                         g_disk_advance(dp, bp2, off);
  480                 }
  481                 break;
  482         case BIO_GETATTR:
  483                 /* Give the driver a chance to override */
  484                 if (dp->d_getattr != NULL) {
  485                         if (bp->bio_disk == NULL)
  486                                 bp->bio_disk = dp;
  487                         error = dp->d_getattr(bp);
  488                         if (error != -1)
  489                                 break;
  490                         error = EJUSTRETURN;
  491                 }
  492                 if (g_handleattr_int(bp, "GEOM::candelete",
  493                     (dp->d_flags & DISKFLAG_CANDELETE) != 0))
  494                         break;
  495                 else if (g_handleattr_int(bp, "GEOM::fwsectors",
  496                     dp->d_fwsectors))
  497                         break;
  498                 else if (g_handleattr_int(bp, "GEOM::fwheads", dp->d_fwheads))
  499                         break;
  500                 else if (g_handleattr_off_t(bp, "GEOM::frontstuff", 0))
  501                         break;
  502                 else if (g_handleattr_str(bp, "GEOM::ident", dp->d_ident))
  503                         break;
  504                 else if (g_handleattr_str(bp, "GEOM::descr", dp->d_descr))
  505                         break;
  506                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_vendor",
  507                     dp->d_hba_vendor))
  508                         break;
  509                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_device",
  510                     dp->d_hba_device))
  511                         break;
  512                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_subvendor",
  513                     dp->d_hba_subvendor))
  514                         break;
  515                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_subdevice",
  516                     dp->d_hba_subdevice))
  517                         break;
  518                 else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump"))
  519                         g_disk_kerneldump(bp, dp);
  520                 else if (!strcmp(bp->bio_attribute, "GEOM::setstate"))
  521                         g_disk_setstate(bp, sc);
  522                 else if (g_handleattr_uint16_t(bp, "GEOM::rotation_rate",
  523                     dp->d_rotation_rate))
  524                         break;
  525                 else 
  526                         error = ENOIOCTL;
  527                 break;
  528         case BIO_FLUSH:
  529                 g_trace(G_T_BIO, "g_disk_flushcache(%s)",
  530                     bp->bio_to->name);
  531                 if (!(dp->d_flags & DISKFLAG_CANFLUSHCACHE)) {
  532                         error = EOPNOTSUPP;
  533                         break;
  534                 }
  535                 /*FALLTHROUGH*/
  536         case BIO_ZONE:
  537                 if (bp->bio_cmd == BIO_ZONE) {
  538                         if (!(dp->d_flags & DISKFLAG_CANZONE)) {
  539                                 error = EOPNOTSUPP;
  540                                 break;
  541                         }
  542                         g_trace(G_T_BIO, "g_disk_zone(%s)",
  543                             bp->bio_to->name);
  544                 }
  545                 bp2 = g_clone_bio(bp);
  546                 if (bp2 == NULL) {
  547                         g_io_deliver(bp, ENOMEM);
  548                         return;
  549                 }
  550                 bp2->bio_done = g_disk_done;
  551                 bp2->bio_disk = dp;
  552                 mtx_lock(&sc->start_mtx);
  553                 devstat_start_transaction_bio(dp->d_devstat, bp2);
  554                 mtx_unlock(&sc->start_mtx);
  555                 dp->d_strategy(bp2);
  556                 break;
  557         default:
  558                 error = EOPNOTSUPP;
  559                 break;
  560         }
  561         if (error != EJUSTRETURN)
  562                 g_io_deliver(bp, error);
  563         return;
  564 }
  565 
  566 static void
  567 g_disk_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
  568 {
  569         struct bio *bp;
  570         struct disk *dp;
  571         struct g_disk_softc *sc;
  572         char *buf;
  573         int res = 0;
  574 
  575         sc = gp->softc;
  576         if (sc == NULL || (dp = sc->dp) == NULL)
  577                 return;
  578         if (indent == NULL) {
  579                 sbuf_printf(sb, " hd %u", dp->d_fwheads);
  580                 sbuf_printf(sb, " sc %u", dp->d_fwsectors);
  581                 return;
  582         }
  583         if (pp != NULL) {
  584                 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n",
  585                     indent, dp->d_fwheads);
  586                 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n",
  587                     indent, dp->d_fwsectors);
  588 
  589                 /*
  590                  * "rotationrate" is a little complicated, because the value
  591                  * returned by the drive might not be the RPM; 0 and 1 are
  592                  * special cases, and there's also a valid range.
  593                  */
  594                 sbuf_printf(sb, "%s<rotationrate>", indent);
  595                 if (dp->d_rotation_rate == DISK_RR_UNKNOWN) /* Old drives */
  596                         sbuf_printf(sb, "unknown");     /* don't report RPM. */
  597                 else if (dp->d_rotation_rate == DISK_RR_NON_ROTATING)
  598                         sbuf_printf(sb, "");
  599                 else if ((dp->d_rotation_rate >= DISK_RR_MIN) &&
  600                     (dp->d_rotation_rate <= DISK_RR_MAX))
  601                         sbuf_printf(sb, "%u", dp->d_rotation_rate);
  602                 else
  603                         sbuf_printf(sb, "invalid");
  604                 sbuf_printf(sb, "</rotationrate>\n");
  605                 if (dp->d_getattr != NULL) {
  606                         buf = g_malloc(DISK_IDENT_SIZE, M_WAITOK);
  607                         bp = g_alloc_bio();
  608                         bp->bio_disk = dp;
  609                         bp->bio_attribute = "GEOM::ident";
  610                         bp->bio_length = DISK_IDENT_SIZE;
  611                         bp->bio_data = buf;
  612                         res = dp->d_getattr(bp);
  613                         sbuf_printf(sb, "%s<ident>", indent);
  614                         g_conf_printf_escaped(sb, "%s",
  615                             res == 0 ? buf: dp->d_ident);
  616                         sbuf_printf(sb, "</ident>\n");
  617                         bp->bio_attribute = "GEOM::lunid";
  618                         bp->bio_length = DISK_IDENT_SIZE;
  619                         bp->bio_data = buf;
  620                         if (dp->d_getattr(bp) == 0) {
  621                                 sbuf_printf(sb, "%s<lunid>", indent);
  622                                 g_conf_printf_escaped(sb, "%s", buf);
  623                                 sbuf_printf(sb, "</lunid>\n");
  624                         }
  625                         bp->bio_attribute = "GEOM::lunname";
  626                         bp->bio_length = DISK_IDENT_SIZE;
  627                         bp->bio_data = buf;
  628                         if (dp->d_getattr(bp) == 0) {
  629                                 sbuf_printf(sb, "%s<lunname>", indent);
  630                                 g_conf_printf_escaped(sb, "%s", buf);
  631                                 sbuf_printf(sb, "</lunname>\n");
  632                         }
  633                         g_destroy_bio(bp);
  634                         g_free(buf);
  635                 } else {
  636                         sbuf_printf(sb, "%s<ident>", indent);
  637                         g_conf_printf_escaped(sb, "%s", dp->d_ident);
  638                         sbuf_printf(sb, "</ident>\n");
  639                 }
  640                 sbuf_printf(sb, "%s<descr>", indent);
  641                 g_conf_printf_escaped(sb, "%s", dp->d_descr);
  642                 sbuf_printf(sb, "</descr>\n");
  643         }
  644 }
  645 
  646 static void
  647 g_disk_resize(void *ptr, int flag)
  648 {
  649         struct disk *dp;
  650         struct g_geom *gp;
  651         struct g_provider *pp;
  652 
  653         if (flag == EV_CANCEL)
  654                 return;
  655         g_topology_assert();
  656 
  657         dp = ptr;
  658         gp = dp->d_geom;
  659 
  660         if (dp->d_destroyed || gp == NULL)
  661                 return;
  662 
  663         LIST_FOREACH(pp, &gp->provider, provider) {
  664                 if (pp->sectorsize != 0 &&
  665                     pp->sectorsize != dp->d_sectorsize)
  666                         g_wither_provider(pp, ENXIO);
  667                 else
  668                         g_resize_provider(pp, dp->d_mediasize);
  669         }
  670 }
  671 
  672 static void
  673 g_disk_create(void *arg, int flag)
  674 {
  675         struct g_geom *gp;
  676         struct g_provider *pp;
  677         struct disk *dp;
  678         struct g_disk_softc *sc;
  679         char tmpstr[80];
  680 
  681         if (flag == EV_CANCEL)
  682                 return;
  683         g_topology_assert();
  684         dp = arg;
  685 
  686         mtx_pool_lock(mtxpool_sleep, dp);
  687         dp->d_init_level = DISK_INIT_START;
  688 
  689         /*
  690          * If the disk has already gone away, we can just stop here and
  691          * call the user's callback to tell him we've cleaned things up.
  692          */
  693         if (dp->d_goneflag != 0) {
  694                 mtx_pool_unlock(mtxpool_sleep, dp);
  695                 if (dp->d_gone != NULL)
  696                         dp->d_gone(dp);
  697                 return;
  698         }
  699         mtx_pool_unlock(mtxpool_sleep, dp);
  700 
  701         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
  702         mtx_init(&sc->start_mtx, "g_disk_start", NULL, MTX_DEF);
  703         mtx_init(&sc->done_mtx, "g_disk_done", NULL, MTX_DEF);
  704         sc->dp = dp;
  705         gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit);
  706         gp->softc = sc;
  707         pp = g_new_providerf(gp, "%s", gp->name);
  708         devstat_remove_entry(pp->stat);
  709         pp->stat = NULL;
  710         dp->d_devstat->id = pp;
  711         pp->mediasize = dp->d_mediasize;
  712         pp->sectorsize = dp->d_sectorsize;
  713         pp->stripeoffset = dp->d_stripeoffset;
  714         pp->stripesize = dp->d_stripesize;
  715         if ((dp->d_flags & DISKFLAG_UNMAPPED_BIO) != 0)
  716                 pp->flags |= G_PF_ACCEPT_UNMAPPED;
  717         if ((dp->d_flags & DISKFLAG_DIRECT_COMPLETION) != 0)
  718                 pp->flags |= G_PF_DIRECT_SEND;
  719         pp->flags |= G_PF_DIRECT_RECEIVE;
  720         if (bootverbose)
  721                 printf("GEOM: new disk %s\n", gp->name);
  722         sysctl_ctx_init(&sc->sysctl_ctx);
  723         snprintf(tmpstr, sizeof(tmpstr), "GEOM disk %s", gp->name);
  724         sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
  725                 SYSCTL_STATIC_CHILDREN(_kern_geom_disk), OID_AUTO, gp->name,
  726                 CTLFLAG_RD, 0, tmpstr);
  727         if (sc->sysctl_tree != NULL) {
  728                 SYSCTL_ADD_STRING(&sc->sysctl_ctx,
  729                     SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "led",
  730                     CTLFLAG_RWTUN, sc->led, sizeof(sc->led),
  731                     "LED name");
  732         }
  733         pp->private = sc;
  734         dp->d_geom = gp;
  735         g_error_provider(pp, 0);
  736 
  737         mtx_pool_lock(mtxpool_sleep, dp);
  738         dp->d_init_level = DISK_INIT_DONE;
  739 
  740         /*
  741          * If the disk has gone away at this stage, start the withering
  742          * process for it.
  743          */
  744         if (dp->d_goneflag != 0) {
  745                 mtx_pool_unlock(mtxpool_sleep, dp);
  746                 g_wither_provider(pp, ENXIO);
  747                 return;
  748         }
  749         mtx_pool_unlock(mtxpool_sleep, dp);
  750 
  751 }
  752 
  753 /*
  754  * We get this callback after all of the consumers have gone away, and just
  755  * before the provider is freed.  If the disk driver provided a d_gone
  756  * callback, let them know that it is okay to free resources -- they won't
  757  * be getting any more accesses from GEOM.
  758  */
  759 static void
  760 g_disk_providergone(struct g_provider *pp)
  761 {
  762         struct disk *dp;
  763         struct g_disk_softc *sc;
  764 
  765         sc = (struct g_disk_softc *)pp->private;
  766         dp = sc->dp;
  767         if (dp != NULL && dp->d_gone != NULL)
  768                 dp->d_gone(dp);
  769         if (sc->sysctl_tree != NULL) {
  770                 sysctl_ctx_free(&sc->sysctl_ctx);
  771                 sc->sysctl_tree = NULL;
  772         }
  773         if (sc->led[0] != 0) {
  774                 led_set(sc->led, "");
  775                 sc->led[0] = 0;
  776         }
  777         pp->private = NULL;
  778         pp->geom->softc = NULL;
  779         mtx_destroy(&sc->done_mtx);
  780         mtx_destroy(&sc->start_mtx);
  781         g_free(sc);
  782 }
  783 
  784 static void
  785 g_disk_destroy(void *ptr, int flag)
  786 {
  787         struct disk *dp;
  788         struct g_geom *gp;
  789         struct g_disk_softc *sc;
  790 
  791         g_topology_assert();
  792         dp = ptr;
  793         gp = dp->d_geom;
  794         if (gp != NULL) {
  795                 sc = gp->softc;
  796                 if (sc != NULL)
  797                         sc->dp = NULL;
  798                 dp->d_geom = NULL;
  799                 g_wither_geom(gp, ENXIO);
  800         }
  801 
  802         g_free(dp);
  803 }
  804 
  805 /*
  806  * We only allow printable characters in disk ident,
  807  * the rest is converted to 'x<HH>'.
  808  */
  809 static void
  810 g_disk_ident_adjust(char *ident, size_t size)
  811 {
  812         char *p, tmp[4], newid[DISK_IDENT_SIZE];
  813 
  814         newid[0] = '\0';
  815         for (p = ident; *p != '\0'; p++) {
  816                 if (isprint(*p)) {
  817                         tmp[0] = *p;
  818                         tmp[1] = '\0';
  819                 } else {
  820                         snprintf(tmp, sizeof(tmp), "x%02hhx",
  821                             *(unsigned char *)p);
  822                 }
  823                 if (strlcat(newid, tmp, sizeof(newid)) >= sizeof(newid))
  824                         break;
  825         }
  826         bzero(ident, size);
  827         strlcpy(ident, newid, size);
  828 }
  829 
  830 struct disk *
  831 disk_alloc(void)
  832 {
  833 
  834         return (g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO));
  835 }
  836 
  837 void
  838 disk_create(struct disk *dp, int version)
  839 {
  840 
  841         if (version != DISK_VERSION) {
  842                 printf("WARNING: Attempt to add disk %s%d %s",
  843                     dp->d_name, dp->d_unit,
  844                     " using incompatible ABI version of disk(9)\n");
  845                 printf("WARNING: Ignoring disk %s%d\n",
  846                     dp->d_name, dp->d_unit);
  847                 return;
  848         }
  849         if (dp->d_flags & DISKFLAG_RESERVED) {
  850                 printf("WARNING: Attempt to add non-MPSAFE disk %s%d\n",
  851                     dp->d_name, dp->d_unit);
  852                 printf("WARNING: Ignoring disk %s%d\n",
  853                     dp->d_name, dp->d_unit);
  854                 return;
  855         }
  856         KASSERT(dp->d_strategy != NULL, ("disk_create need d_strategy"));
  857         KASSERT(dp->d_name != NULL, ("disk_create need d_name"));
  858         KASSERT(*dp->d_name != 0, ("disk_create need d_name"));
  859         KASSERT(strlen(dp->d_name) < SPECNAMELEN - 4, ("disk name too long"));
  860         if (dp->d_devstat == NULL)
  861                 dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit,
  862                     dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED,
  863                     DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
  864         dp->d_geom = NULL;
  865 
  866         dp->d_init_level = DISK_INIT_NONE;
  867 
  868         g_disk_ident_adjust(dp->d_ident, sizeof(dp->d_ident));
  869         g_post_event(g_disk_create, dp, M_WAITOK, dp, NULL);
  870 }
  871 
  872 void
  873 disk_destroy(struct disk *dp)
  874 {
  875 
  876         g_cancel_event(dp);
  877         dp->d_destroyed = 1;
  878         if (dp->d_devstat != NULL)
  879                 devstat_remove_entry(dp->d_devstat);
  880         g_post_event(g_disk_destroy, dp, M_WAITOK, NULL);
  881 }
  882 
  883 void
  884 disk_gone(struct disk *dp)
  885 {
  886         struct g_geom *gp;
  887         struct g_provider *pp;
  888 
  889         mtx_pool_lock(mtxpool_sleep, dp);
  890         dp->d_goneflag = 1;
  891 
  892         /*
  893          * If we're still in the process of creating this disk (the
  894          * g_disk_create() function is still queued, or is in
  895          * progress), the init level will not yet be DISK_INIT_DONE.
  896          *
  897          * If that is the case, g_disk_create() will see d_goneflag
  898          * and take care of cleaning things up.
  899          *
  900          * If the disk has already been created, we default to
  901          * withering the provider as usual below.
  902          *
  903          * If the caller has not set a d_gone() callback, he will
  904          * not be any worse off by returning here, because the geom
  905          * has not been fully setup in any case.
  906          */
  907         if (dp->d_init_level < DISK_INIT_DONE) {
  908                 mtx_pool_unlock(mtxpool_sleep, dp);
  909                 return;
  910         }
  911         mtx_pool_unlock(mtxpool_sleep, dp);
  912 
  913         gp = dp->d_geom;
  914         if (gp != NULL) {
  915                 pp = LIST_FIRST(&gp->provider);
  916                 if (pp != NULL) {
  917                         KASSERT(LIST_NEXT(pp, provider) == NULL,
  918                             ("geom %p has more than one provider", gp));
  919                         g_wither_provider(pp, ENXIO);
  920                 }
  921         }
  922 }
  923 
  924 void
  925 disk_attr_changed(struct disk *dp, const char *attr, int flag)
  926 {
  927         struct g_geom *gp;
  928         struct g_provider *pp;
  929         char devnamebuf[128];
  930 
  931         gp = dp->d_geom;
  932         if (gp != NULL)
  933                 LIST_FOREACH(pp, &gp->provider, provider)
  934                         (void)g_attr_changed(pp, attr, flag);
  935         snprintf(devnamebuf, sizeof(devnamebuf), "devname=%s%d", dp->d_name,
  936             dp->d_unit);
  937         devctl_notify("GEOM", "disk", attr, devnamebuf);
  938 }
  939 
  940 void
  941 disk_media_changed(struct disk *dp, int flag)
  942 {
  943         struct g_geom *gp;
  944         struct g_provider *pp;
  945 
  946         gp = dp->d_geom;
  947         if (gp != NULL) {
  948                 pp = LIST_FIRST(&gp->provider);
  949                 if (pp != NULL) {
  950                         KASSERT(LIST_NEXT(pp, provider) == NULL,
  951                             ("geom %p has more than one provider", gp));
  952                         g_media_changed(pp, flag);
  953                 }
  954         }
  955 }
  956 
  957 void
  958 disk_media_gone(struct disk *dp, int flag)
  959 {
  960         struct g_geom *gp;
  961         struct g_provider *pp;
  962 
  963         gp = dp->d_geom;
  964         if (gp != NULL) {
  965                 pp = LIST_FIRST(&gp->provider);
  966                 if (pp != NULL) {
  967                         KASSERT(LIST_NEXT(pp, provider) == NULL,
  968                             ("geom %p has more than one provider", gp));
  969                         g_media_gone(pp, flag);
  970                 }
  971         }
  972 }
  973 
  974 int
  975 disk_resize(struct disk *dp, int flag)
  976 {
  977 
  978         if (dp->d_destroyed || dp->d_geom == NULL)
  979                 return (0);
  980 
  981         return (g_post_event(g_disk_resize, dp, flag, NULL));
  982 }
  983 
  984 static void
  985 g_kern_disks(void *p, int flag __unused)
  986 {
  987         struct sbuf *sb;
  988         struct g_geom *gp;
  989         char *sp;
  990 
  991         sb = p;
  992         sp = "";
  993         g_topology_assert();
  994         LIST_FOREACH(gp, &g_disk_class.geom, geom) {
  995                 sbuf_printf(sb, "%s%s", sp, gp->name);
  996                 sp = " ";
  997         }
  998         sbuf_finish(sb);
  999 }
 1000 
 1001 static int
 1002 sysctl_disks(SYSCTL_HANDLER_ARGS)
 1003 {
 1004         int error;
 1005         struct sbuf *sb;
 1006 
 1007         sb = sbuf_new_auto();
 1008         g_waitfor_event(g_kern_disks, sb, M_WAITOK, NULL);
 1009         error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
 1010         sbuf_delete(sb);
 1011         return error;
 1012 }
 1013  
 1014 SYSCTL_PROC(_kern, OID_AUTO, disks,
 1015     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
 1016     sysctl_disks, "A", "names of available disks");

Cache object: 6e2479e559d3fe553dc45597469b2d0f


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