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/dev/ld.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 /*      $NetBSD: ld.c,v 1.35.2.1 2005/04/06 11:56:55 tron Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Doran and Charles M. Hannum.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Disk driver for use by RAID controllers.
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.35.2.1 2005/04/06 11:56:55 tron Exp $");
   45 
   46 #include "rnd.h"
   47 
   48 #include <sys/param.h>
   49 #include <sys/systm.h>
   50 #include <sys/kernel.h>
   51 #include <sys/device.h>
   52 #include <sys/queue.h>
   53 #include <sys/proc.h>
   54 #include <sys/buf.h>
   55 #include <sys/bufq.h>
   56 #include <sys/endian.h>
   57 #include <sys/disklabel.h>
   58 #include <sys/disk.h>
   59 #include <sys/dkio.h>
   60 #include <sys/stat.h>
   61 #include <sys/lock.h>
   62 #include <sys/conf.h>
   63 #include <sys/fcntl.h>
   64 #include <sys/vnode.h>
   65 #include <sys/syslog.h>
   66 #if NRND > 0
   67 #include <sys/rnd.h>
   68 #endif
   69 
   70 #include <dev/ldvar.h>
   71 
   72 static void     ldgetdefaultlabel(struct ld_softc *, struct disklabel *);
   73 static void     ldgetdisklabel(struct ld_softc *);
   74 static void     ldminphys(struct buf *bp);
   75 static void     ldshutdown(void *);
   76 static void     ldstart(struct ld_softc *);
   77 
   78 extern struct   cfdriver ld_cd;
   79 
   80 static dev_type_open(ldopen);
   81 static dev_type_close(ldclose);
   82 static dev_type_read(ldread);
   83 static dev_type_write(ldwrite);
   84 static dev_type_ioctl(ldioctl);
   85 static dev_type_strategy(ldstrategy);
   86 static dev_type_dump(lddump);
   87 static dev_type_size(ldsize);
   88 
   89 const struct bdevsw ld_bdevsw = {
   90         ldopen, ldclose, ldstrategy, ldioctl, lddump, ldsize, D_DISK
   91 };
   92 
   93 const struct cdevsw ld_cdevsw = {
   94         ldopen, ldclose, ldread, ldwrite, ldioctl,
   95         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
   96 };
   97 
   98 static struct   dkdriver lddkdriver = { ldstrategy, ldminphys };
   99 static void     *ld_sdh;
  100 
  101 void
  102 ldattach(struct ld_softc *sc)
  103 {
  104         char buf[9];
  105 
  106         if ((sc->sc_flags & LDF_ENABLED) == 0) {
  107                 aprint_normal("%s: disabled\n", sc->sc_dv.dv_xname);
  108                 return;
  109         }
  110 
  111         /* Initialise and attach the disk structure. */
  112         sc->sc_dk.dk_driver = &lddkdriver;
  113         sc->sc_dk.dk_name = sc->sc_dv.dv_xname;
  114         disk_attach(&sc->sc_dk);
  115 
  116         if (sc->sc_maxxfer > MAXPHYS)
  117                 sc->sc_maxxfer = MAXPHYS;
  118 
  119         /* Build synthetic geometry if necessary. */
  120         if (sc->sc_nheads == 0 || sc->sc_nsectors == 0 ||
  121             sc->sc_ncylinders == 0) {
  122                 uint64_t ncyl;
  123 
  124                 if (sc->sc_secperunit <= 528 * 2048)            /* 528MB */
  125                         sc->sc_nheads = 16;
  126                 else if (sc->sc_secperunit <= 1024 * 2048)      /* 1GB */
  127                         sc->sc_nheads = 32;
  128                 else if (sc->sc_secperunit <= 21504 * 2048)     /* 21GB */
  129                         sc->sc_nheads = 64;
  130                 else if (sc->sc_secperunit <= 43008 * 2048)     /* 42GB */
  131                         sc->sc_nheads = 128;
  132                 else
  133                         sc->sc_nheads = 255;
  134 
  135                 sc->sc_nsectors = 63;
  136                 sc->sc_ncylinders = INT_MAX;
  137                 ncyl = sc->sc_secperunit /
  138                     (sc->sc_nheads * sc->sc_nsectors);
  139                 if (ncyl < INT_MAX)
  140                         sc->sc_ncylinders = (int)ncyl;
  141         }
  142 
  143         format_bytes(buf, sizeof(buf), sc->sc_secperunit *
  144             sc->sc_secsize);
  145         aprint_normal("%s: %s, %d cyl, %d head, %d sec, %d bytes/sect x %"PRIu64" sectors\n",
  146             sc->sc_dv.dv_xname, buf, sc->sc_ncylinders, sc->sc_nheads,
  147             sc->sc_nsectors, sc->sc_secsize, sc->sc_secperunit);
  148 
  149 #if NRND > 0
  150         /* Attach the device into the rnd source list. */
  151         rnd_attach_source(&sc->sc_rnd_source, sc->sc_dv.dv_xname,
  152             RND_TYPE_DISK, 0);
  153 #endif
  154 
  155         /* Set the `shutdownhook'. */
  156         if (ld_sdh == NULL)
  157                 ld_sdh = shutdownhook_establish(ldshutdown, NULL);
  158         bufq_alloc(&sc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT()|BUFQ_SORT_RAWBLOCK);
  159 
  160         /* Discover wedges on this disk. */
  161         dkwedge_discover(&sc->sc_dk);
  162 }
  163 
  164 int
  165 ldadjqparam(struct ld_softc *sc, int max)
  166 {
  167         int s;
  168 
  169         s = splbio();
  170         sc->sc_maxqueuecnt = max;
  171         splx(s);
  172 
  173         return (0);
  174 }
  175 
  176 int
  177 ldbegindetach(struct ld_softc *sc, int flags)
  178 {
  179         int s, rv = 0;
  180 
  181         if ((sc->sc_flags & LDF_ENABLED) == 0)
  182                 return (0);
  183 
  184         if ((flags & DETACH_FORCE) == 0 && sc->sc_dk.dk_openmask != 0)
  185                 return (EBUSY);
  186 
  187         s = splbio();
  188         sc->sc_maxqueuecnt = 0;
  189         sc->sc_flags |= LDF_DETACH;
  190         while (sc->sc_queuecnt > 0) {
  191                 sc->sc_flags |= LDF_DRAIN;
  192                 rv = tsleep(&sc->sc_queuecnt, PRIBIO, "lddrn", 0);
  193                 if (rv)
  194                         break;
  195         }
  196         splx(s);
  197 
  198         return (rv);
  199 }
  200 
  201 void
  202 ldenddetach(struct ld_softc *sc)
  203 {
  204         int s, bmaj, cmaj, i, mn;
  205 
  206         if ((sc->sc_flags & LDF_ENABLED) == 0)
  207                 return;
  208 
  209         /* Wait for commands queued with the hardware to complete. */
  210         if (sc->sc_queuecnt != 0)
  211                 if (tsleep(&sc->sc_queuecnt, PRIBIO, "lddtch", 30 * hz))
  212                         printf("%s: not drained\n", sc->sc_dv.dv_xname);
  213 
  214         /* Locate the major numbers. */
  215         bmaj = bdevsw_lookup_major(&ld_bdevsw);
  216         cmaj = cdevsw_lookup_major(&ld_cdevsw);
  217 
  218         /* Kill off any queued buffers. */
  219         s = splbio();
  220         bufq_drain(&sc->sc_bufq);
  221         splx(s);
  222 
  223         bufq_free(&sc->sc_bufq);
  224 
  225         /* Nuke the vnodes for any open instances. */
  226         for (i = 0; i < MAXPARTITIONS; i++) {
  227                 mn = DISKMINOR(sc->sc_dv.dv_unit, i);
  228                 vdevgone(bmaj, mn, mn, VBLK);
  229                 vdevgone(cmaj, mn, mn, VCHR);
  230         }
  231 
  232         /* Delete all of our wedges. */
  233         dkwedge_delall(&sc->sc_dk);
  234 
  235         /* Detach from the disk list. */
  236         disk_detach(&sc->sc_dk);
  237 
  238 #if NRND > 0
  239         /* Unhook the entropy source. */
  240         rnd_detach_source(&sc->sc_rnd_source);
  241 #endif
  242 
  243         /*
  244          * XXX We can't really flush the cache here, beceause the
  245          * XXX device may already be non-existent from the controller's
  246          * XXX perspective.
  247          */
  248 #if 0
  249         /* Flush the device's cache. */
  250         if (sc->sc_flush != NULL)
  251                 if ((*sc->sc_flush)(sc) != 0)
  252                         printf("%s: unable to flush cache\n",
  253                             sc->sc_dv.dv_xname);
  254 #endif
  255 }
  256 
  257 /* ARGSUSED */
  258 static void
  259 ldshutdown(void *cookie)
  260 {
  261         struct ld_softc *sc;
  262         int i;
  263 
  264         for (i = 0; i < ld_cd.cd_ndevs; i++) {
  265                 if ((sc = device_lookup(&ld_cd, i)) == NULL)
  266                         continue;
  267                 if (sc->sc_flush != NULL && (*sc->sc_flush)(sc) != 0)
  268                         printf("%s: unable to flush cache\n",
  269                             sc->sc_dv.dv_xname);
  270         }
  271 }
  272 
  273 /* ARGSUSED */
  274 static int
  275 ldopen(dev_t dev, int flags, int fmt, struct proc *p)
  276 {
  277         struct ld_softc *sc;
  278         int error, unit, part;
  279 
  280         unit = DISKUNIT(dev);
  281         if ((sc = device_lookup(&ld_cd, unit)) == NULL)
  282                 return (ENXIO);
  283         if ((sc->sc_flags & LDF_ENABLED) == 0)
  284                 return (ENODEV);
  285         part = DISKPART(dev);
  286 
  287         if ((error = lockmgr(&sc->sc_dk.dk_openlock, LK_EXCLUSIVE, NULL)) != 0)
  288                 return (error);
  289 
  290         if (sc->sc_dk.dk_openmask == 0) {
  291                 /* Load the partition info if not already loaded. */
  292                 if ((sc->sc_flags & LDF_VLABEL) == 0)
  293                         ldgetdisklabel(sc);
  294         }
  295 
  296         /* Check that the partition exists. */
  297         if (part != RAW_PART && (part >= sc->sc_dk.dk_label->d_npartitions ||
  298             sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
  299                 error = ENXIO;
  300                 goto bad1;
  301         }
  302 
  303         /* Ensure only one open at a time. */
  304         switch (fmt) {
  305         case S_IFCHR:
  306                 sc->sc_dk.dk_copenmask |= (1 << part);
  307                 break;
  308         case S_IFBLK:
  309                 sc->sc_dk.dk_bopenmask |= (1 << part);
  310                 break;
  311         }
  312         sc->sc_dk.dk_openmask =
  313             sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
  314 
  315         (void) lockmgr(&sc->sc_dk.dk_openlock, LK_RELEASE, NULL);
  316         return (0);
  317 
  318  bad1:
  319         (void) lockmgr(&sc->sc_dk.dk_openlock, LK_RELEASE, NULL);
  320         return (error);
  321 }
  322 
  323 /* ARGSUSED */
  324 static int
  325 ldclose(dev_t dev, int flags, int fmt, struct proc *p)
  326 {
  327         struct ld_softc *sc;
  328         int error, part, unit;
  329 
  330         unit = DISKUNIT(dev);
  331         part = DISKPART(dev);
  332         sc = device_lookup(&ld_cd, unit);
  333 
  334         if ((error = lockmgr(&sc->sc_dk.dk_openlock, LK_EXCLUSIVE, NULL)) != 0)
  335                 return (error);
  336 
  337         switch (fmt) {
  338         case S_IFCHR:
  339                 sc->sc_dk.dk_copenmask &= ~(1 << part);
  340                 break;
  341         case S_IFBLK:
  342                 sc->sc_dk.dk_bopenmask &= ~(1 << part);
  343                 break;
  344         }
  345         sc->sc_dk.dk_openmask =
  346             sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
  347 
  348         if (sc->sc_dk.dk_openmask == 0) {
  349                 if (sc->sc_flush != NULL && (*sc->sc_flush)(sc) != 0)
  350                         printf("%s: unable to flush cache\n",
  351                             sc->sc_dv.dv_xname);
  352                 if ((sc->sc_flags & LDF_KLABEL) == 0)
  353                         sc->sc_flags &= ~LDF_VLABEL;
  354         }
  355 
  356         (void) lockmgr(&sc->sc_dk.dk_openlock, LK_RELEASE, NULL);
  357         return (0);
  358 }
  359 
  360 /* ARGSUSED */
  361 static int
  362 ldread(dev_t dev, struct uio *uio, int ioflag)
  363 {
  364 
  365         return (physio(ldstrategy, NULL, dev, B_READ, ldminphys, uio));
  366 }
  367 
  368 /* ARGSUSED */
  369 static int
  370 ldwrite(dev_t dev, struct uio *uio, int ioflag)
  371 {
  372 
  373         return (physio(ldstrategy, NULL, dev, B_WRITE, ldminphys, uio));
  374 }
  375 
  376 /* ARGSUSED */
  377 static int
  378 ldioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct proc *p)
  379 {
  380         struct ld_softc *sc;
  381         int part, unit, error;
  382 #ifdef __HAVE_OLD_DISKLABEL
  383         struct disklabel newlabel;
  384 #endif
  385         struct disklabel *lp;
  386 
  387         unit = DISKUNIT(dev);
  388         part = DISKPART(dev);
  389         sc = device_lookup(&ld_cd, unit);
  390         error = 0;
  391 
  392         switch (cmd) {
  393         case DIOCGDINFO:
  394                 memcpy(addr, sc->sc_dk.dk_label, sizeof(struct disklabel));
  395                 return (0);
  396 
  397 #ifdef __HAVE_OLD_DISKLABEL
  398         case ODIOCGDINFO:
  399                 newlabel = *(sc->sc_dk.dk_label);
  400                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  401                         return ENOTTY;
  402                 memcpy(addr, &newlabel, sizeof(struct olddisklabel));
  403                 return (0);
  404 #endif
  405 
  406         case DIOCGPART:
  407                 ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label;
  408                 ((struct partinfo *)addr)->part =
  409                     &sc->sc_dk.dk_label->d_partitions[part];
  410                 break;
  411 
  412         case DIOCWDINFO:
  413         case DIOCSDINFO:
  414 #ifdef __HAVE_OLD_DISKLABEL
  415         case ODIOCWDINFO:
  416         case ODIOCSDINFO:
  417 
  418                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
  419                         memset(&newlabel, 0, sizeof newlabel);
  420                         memcpy(&newlabel, addr, sizeof (struct olddisklabel));
  421                         lp = &newlabel;
  422                 } else
  423 #endif
  424                 lp = (struct disklabel *)addr;
  425 
  426                 if ((flag & FWRITE) == 0)
  427                         return (EBADF);
  428 
  429                 if ((error = lockmgr(&sc->sc_dk.dk_openlock, LK_EXCLUSIVE,
  430                                      NULL)) != 0)
  431                         return (error);
  432                 sc->sc_flags |= LDF_LABELLING;
  433 
  434                 error = setdisklabel(sc->sc_dk.dk_label,
  435                     lp, /*sc->sc_dk.dk_openmask : */0,
  436                     sc->sc_dk.dk_cpulabel);
  437                 if (error == 0 && (cmd == DIOCWDINFO
  438 #ifdef __HAVE_OLD_DISKLABEL
  439                     || cmd == ODIOCWDINFO
  440 #endif
  441                     ))
  442                         error = writedisklabel(
  443                             MAKEDISKDEV(major(dev), DISKUNIT(dev), RAW_PART),
  444                             ldstrategy, sc->sc_dk.dk_label,
  445                             sc->sc_dk.dk_cpulabel);
  446 
  447                 sc->sc_flags &= ~LDF_LABELLING;
  448                 (void) lockmgr(&sc->sc_dk.dk_openlock, LK_RELEASE, NULL);
  449                 break;
  450 
  451         case DIOCKLABEL:
  452                 if ((flag & FWRITE) == 0)
  453                         return (EBADF);
  454                 if (*(int *)addr)
  455                         sc->sc_flags |= LDF_KLABEL;
  456                 else
  457                         sc->sc_flags &= ~LDF_KLABEL;
  458                 break;
  459 
  460         case DIOCWLABEL:
  461                 if ((flag & FWRITE) == 0)
  462                         return (EBADF);
  463                 if (*(int *)addr)
  464                         sc->sc_flags |= LDF_WLABEL;
  465                 else
  466                         sc->sc_flags &= ~LDF_WLABEL;
  467                 break;
  468 
  469         case DIOCGDEFLABEL:
  470                 ldgetdefaultlabel(sc, (struct disklabel *)addr);
  471                 break;
  472 
  473 #ifdef __HAVE_OLD_DISKLABEL
  474         case ODIOCGDEFLABEL:
  475                 ldgetdefaultlabel(sc, &newlabel);
  476                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
  477                         return ENOTTY;
  478                 memcpy(addr, &newlabel, sizeof (struct olddisklabel));
  479                 break;
  480 #endif
  481 
  482         case DIOCCACHESYNC:
  483                 /*
  484                  * XXX Do we really need to care about having a writable
  485                  * file descriptor here?
  486                  */
  487                 if ((flag & FWRITE) == 0)
  488                         error = EBADF;
  489                 else if (sc->sc_flush)
  490                         error = (*sc->sc_flush)(sc);
  491                 else
  492                         error = 0;      /* XXX Error out instead? */
  493                 break;
  494 
  495         case DIOCAWEDGE:
  496             {
  497                 struct dkwedge_info *dkw = (void *) addr;
  498 
  499                 if ((flag & FWRITE) == 0)
  500                         return (EBADF);
  501 
  502                 /* If the ioctl happens here, the parent is us. */
  503                 strcpy(dkw->dkw_parent, sc->sc_dv.dv_xname);
  504                 return (dkwedge_add(dkw));
  505             }
  506 
  507         case DIOCDWEDGE:
  508             {
  509                 struct dkwedge_info *dkw = (void *) addr;
  510 
  511                 if ((flag & FWRITE) == 0)
  512                         return (EBADF);
  513 
  514                 /* If the ioctl happens here, the parent is us. */
  515                 strcpy(dkw->dkw_parent, sc->sc_dv.dv_xname);
  516                 return (dkwedge_del(dkw));
  517             }
  518 
  519         case DIOCLWEDGES:
  520             {
  521                 struct dkwedge_list *dkwl = (void *) addr;
  522 
  523                 return (dkwedge_list(&sc->sc_dk, dkwl, p));
  524             }
  525 
  526         default:
  527                 error = ENOTTY;
  528                 break;
  529         }
  530 
  531         return (error);
  532 }
  533 
  534 static void
  535 ldstrategy(struct buf *bp)
  536 {
  537         struct ld_softc *sc;
  538         struct disklabel *lp;
  539         daddr_t blkno;
  540         int s, part;
  541 
  542         sc = device_lookup(&ld_cd, DISKUNIT(bp->b_dev));
  543         part = DISKPART(bp->b_dev);
  544 
  545         if ((sc->sc_flags & LDF_DETACH) != 0) {
  546                 bp->b_error = EIO;
  547                 goto bad;
  548         }
  549 
  550         lp = sc->sc_dk.dk_label;
  551 
  552         /*
  553          * The transfer must be a whole number of blocks and the offset must
  554          * not be negative.
  555          */
  556         if ((bp->b_bcount % lp->d_secsize) != 0 || bp->b_blkno < 0) {
  557                 bp->b_error = EINVAL;
  558                 goto bad;
  559         }
  560 
  561         /* If it's a null transfer, return immediately. */
  562         if (bp->b_bcount == 0)
  563                 goto done;
  564 
  565         /*
  566          * Do bounds checking and adjust the transfer.  If error, process.
  567          * If past the end of partition, just return.
  568          */
  569         if (part != RAW_PART &&
  570             bounds_check_with_label(&sc->sc_dk, bp,
  571             (sc->sc_flags & (LDF_WLABEL | LDF_LABELLING)) != 0) <= 0) {
  572                 goto done;
  573         }
  574 
  575         /*
  576          * Convert the block number to absolute and put it in terms
  577          * of the device's logical block size.
  578          */
  579         if (lp->d_secsize == DEV_BSIZE)
  580                 blkno = bp->b_blkno;
  581         else if (lp->d_secsize > DEV_BSIZE)
  582                 blkno = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
  583         else
  584                 blkno = bp->b_blkno * (DEV_BSIZE / lp->d_secsize);
  585 
  586         if (part != RAW_PART)
  587                 blkno += lp->d_partitions[part].p_offset;
  588 
  589         bp->b_rawblkno = blkno;
  590 
  591         s = splbio();
  592         BUFQ_PUT(&sc->sc_bufq, bp);
  593         ldstart(sc);
  594         splx(s);
  595         return;
  596 
  597  bad:
  598         bp->b_flags |= B_ERROR;
  599  done:
  600         bp->b_resid = bp->b_bcount;
  601         biodone(bp);
  602 }
  603 
  604 static void
  605 ldstart(struct ld_softc *sc)
  606 {
  607         struct buf *bp;
  608         int error;
  609 
  610         while (sc->sc_queuecnt < sc->sc_maxqueuecnt) {
  611                 /* See if there is work to do. */
  612                 if ((bp = BUFQ_PEEK(&sc->sc_bufq)) == NULL)
  613                         break;
  614 
  615                 disk_busy(&sc->sc_dk);
  616                 sc->sc_queuecnt++;
  617 
  618                 if (__predict_true((error = (*sc->sc_start)(sc, bp)) == 0)) {
  619                         /*
  620                          * The back-end is running the job; remove it from
  621                          * the queue.
  622                          */
  623                         (void) BUFQ_GET(&sc->sc_bufq);
  624                 } else  {
  625                         disk_unbusy(&sc->sc_dk, 0, (bp->b_flags & B_READ));
  626                         sc->sc_queuecnt--;
  627                         if (error == EAGAIN) {
  628                                 /*
  629                                  * Temporary resource shortage in the
  630                                  * back-end; just defer the job until
  631                                  * later.
  632                                  *
  633                                  * XXX We might consider a watchdog timer
  634                                  * XXX to make sure we are kicked into action.
  635                                  */
  636                                 break;
  637                         } else {
  638                                 (void) BUFQ_GET(&sc->sc_bufq);
  639                                 bp->b_error = error;
  640                                 bp->b_flags |= B_ERROR;
  641                                 bp->b_resid = bp->b_bcount;
  642                                 biodone(bp);
  643                         }
  644                 }
  645         }
  646 }
  647 
  648 void
  649 lddone(struct ld_softc *sc, struct buf *bp)
  650 {
  651 
  652         if ((bp->b_flags & B_ERROR) != 0) {
  653                 diskerr(bp, "ld", "error", LOG_PRINTF, 0, sc->sc_dk.dk_label);
  654                 printf("\n");
  655         }
  656 
  657         disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid,
  658             (bp->b_flags & B_READ));
  659 #if NRND > 0
  660         rnd_add_uint32(&sc->sc_rnd_source, bp->b_rawblkno);
  661 #endif
  662         biodone(bp);
  663 
  664         if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) {
  665                 if ((sc->sc_flags & LDF_DRAIN) != 0) {
  666                         sc->sc_flags &= ~LDF_DRAIN;
  667                         wakeup(&sc->sc_queuecnt);
  668                 }
  669                 ldstart(sc);
  670         }
  671 }
  672 
  673 static int
  674 ldsize(dev_t dev)
  675 {
  676         struct ld_softc *sc;
  677         int part, unit, omask, size;
  678 
  679         unit = DISKUNIT(dev);
  680         if ((sc = device_lookup(&ld_cd, unit)) == NULL)
  681                 return (ENODEV);
  682         if ((sc->sc_flags & LDF_ENABLED) == 0)
  683                 return (ENODEV);
  684         part = DISKPART(dev);
  685 
  686         omask = sc->sc_dk.dk_openmask & (1 << part);
  687 
  688         if (omask == 0 && ldopen(dev, 0, S_IFBLK, NULL) != 0)
  689                 return (-1);
  690         else if (sc->sc_dk.dk_label->d_partitions[part].p_fstype != FS_SWAP)
  691                 size = -1;
  692         else
  693                 size = sc->sc_dk.dk_label->d_partitions[part].p_size *
  694                     (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE);
  695         if (omask == 0 && ldclose(dev, 0, S_IFBLK, NULL) != 0)
  696                 return (-1);
  697 
  698         return (size);
  699 }
  700 
  701 /*
  702  * Load the label information from the specified device.
  703  */
  704 static void
  705 ldgetdisklabel(struct ld_softc *sc)
  706 {
  707         const char *errstring;
  708 
  709         ldgetdefaultlabel(sc, sc->sc_dk.dk_label);
  710 
  711         /* Call the generic disklabel extraction routine. */
  712         errstring = readdisklabel(MAKEDISKDEV(0, sc->sc_dv.dv_unit, RAW_PART),
  713             ldstrategy, sc->sc_dk.dk_label, sc->sc_dk.dk_cpulabel);
  714         if (errstring != NULL)
  715                 printf("%s: %s\n", sc->sc_dv.dv_xname, errstring);
  716 
  717         /* In-core label now valid. */
  718         sc->sc_flags |= LDF_VLABEL;
  719 }
  720 
  721 /*
  722  * Construct a ficticious label.
  723  */
  724 static void
  725 ldgetdefaultlabel(struct ld_softc *sc, struct disklabel *lp)
  726 {
  727 
  728         memset(lp, 0, sizeof(struct disklabel));
  729 
  730         lp->d_secsize = sc->sc_secsize;
  731         lp->d_ntracks = sc->sc_nheads;
  732         lp->d_nsectors = sc->sc_nsectors;
  733         lp->d_ncylinders = sc->sc_ncylinders;
  734         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
  735         lp->d_type = DTYPE_LD;
  736         strlcpy(lp->d_typename, "unknown", sizeof(lp->d_typename));
  737         strlcpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
  738         lp->d_secperunit = sc->sc_secperunit;
  739         lp->d_rpm = 7200;
  740         lp->d_interleave = 1;
  741         lp->d_flags = 0;
  742 
  743         lp->d_partitions[RAW_PART].p_offset = 0;
  744         lp->d_partitions[RAW_PART].p_size =
  745             lp->d_secperunit * (lp->d_secsize / DEV_BSIZE);
  746         lp->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
  747         lp->d_npartitions = RAW_PART + 1;
  748 
  749         lp->d_magic = DISKMAGIC;
  750         lp->d_magic2 = DISKMAGIC;
  751         lp->d_checksum = dkcksum(lp);
  752 }
  753 
  754 /*
  755  * Take a dump.
  756  */
  757 static int
  758 lddump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  759 {
  760         struct ld_softc *sc;
  761         struct disklabel *lp;
  762         int unit, part, nsects, sectoff, towrt, nblk, maxblkcnt, rv;
  763         static int dumping;
  764 
  765         unit = DISKUNIT(dev);
  766         if ((sc = device_lookup(&ld_cd, unit)) == NULL)
  767                 return (ENXIO);
  768         if ((sc->sc_flags & LDF_ENABLED) == 0)
  769                 return (ENODEV);
  770         if (sc->sc_dump == NULL)
  771                 return (ENXIO);
  772 
  773         /* Check if recursive dump; if so, punt. */
  774         if (dumping)
  775                 return (EFAULT);
  776         dumping = 1;
  777 
  778         /* Convert to disk sectors.  Request must be a multiple of size. */
  779         part = DISKPART(dev);
  780         lp = sc->sc_dk.dk_label;
  781         if ((size % lp->d_secsize) != 0)
  782                 return (EFAULT);
  783         towrt = size / lp->d_secsize;
  784         blkno = dbtob(blkno) / lp->d_secsize;   /* blkno in DEV_BSIZE units */
  785 
  786         nsects = lp->d_partitions[part].p_size;
  787         sectoff = lp->d_partitions[part].p_offset;
  788 
  789         /* Check transfer bounds against partition size. */
  790         if ((blkno < 0) || ((blkno + towrt) > nsects))
  791                 return (EINVAL);
  792 
  793         /* Offset block number to start of partition. */
  794         blkno += sectoff;
  795 
  796         /* Start dumping and return when done. */
  797         maxblkcnt = sc->sc_maxxfer / sc->sc_secsize - 1;
  798         while (towrt > 0) {
  799                 nblk = min(maxblkcnt, towrt);
  800 
  801                 if ((rv = (*sc->sc_dump)(sc, va, blkno, nblk)) != 0)
  802                         return (rv);
  803 
  804                 towrt -= nblk;
  805                 blkno += nblk;
  806                 va += nblk * sc->sc_secsize;
  807         }
  808 
  809         dumping = 0;
  810         return (0);
  811 }
  812 
  813 /*
  814  * Adjust the size of a transfer.
  815  */
  816 static void
  817 ldminphys(struct buf *bp)
  818 {
  819         struct ld_softc *sc;
  820 
  821         sc = device_lookup(&ld_cd, DISKUNIT(bp->b_dev));
  822 
  823         if (bp->b_bcount > sc->sc_maxxfer)
  824                 bp->b_bcount = sc->sc_maxxfer;
  825         minphys(bp);
  826 }

Cache object: 88488fa4c16b4778a8e01bea28efcf09


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