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/vnd.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: vnd.c,v 1.106 2004/01/25 18:06:48 hannken Exp $        */
    2 
    3 /*-
    4  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Jason R. Thorpe.
    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  * Copyright (c) 1990, 1993
   41  *      The Regents of the University of California.  All rights reserved.
   42  *
   43  * This code is derived from software contributed to Berkeley by
   44  * the Systems Programming Group of the University of Utah Computer
   45  * Science Department.
   46  *
   47  * Redistribution and use in source and binary forms, with or without
   48  * modification, are permitted provided that the following conditions
   49  * are met:
   50  * 1. Redistributions of source code must retain the above copyright
   51  *    notice, this list of conditions and the following disclaimer.
   52  * 2. Redistributions in binary form must reproduce the above copyright
   53  *    notice, this list of conditions and the following disclaimer in the
   54  *    documentation and/or other materials provided with the distribution.
   55  * 3. Neither the name of the University nor the names of its contributors
   56  *    may be used to endorse or promote products derived from this software
   57  *    without specific prior written permission.
   58  *
   59  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   60  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   61  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   62  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   63  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   64  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   65  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   66  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   67  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   68  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   69  * SUCH DAMAGE.
   70  *
   71  * from: Utah $Hdr: vn.c 1.13 94/04/02$
   72  *
   73  *      @(#)vn.c        8.9 (Berkeley) 5/14/95
   74  */
   75 
   76 /*
   77  * Copyright (c) 1988 University of Utah.
   78  *
   79  * This code is derived from software contributed to Berkeley by
   80  * the Systems Programming Group of the University of Utah Computer
   81  * Science Department.
   82  *
   83  * Redistribution and use in source and binary forms, with or without
   84  * modification, are permitted provided that the following conditions
   85  * are met:
   86  * 1. Redistributions of source code must retain the above copyright
   87  *    notice, this list of conditions and the following disclaimer.
   88  * 2. Redistributions in binary form must reproduce the above copyright
   89  *    notice, this list of conditions and the following disclaimer in the
   90  *    documentation and/or other materials provided with the distribution.
   91  * 3. All advertising materials mentioning features or use of this software
   92  *    must display the following acknowledgement:
   93  *      This product includes software developed by the University of
   94  *      California, Berkeley and its contributors.
   95  * 4. Neither the name of the University nor the names of its contributors
   96  *    may be used to endorse or promote products derived from this software
   97  *    without specific prior written permission.
   98  *
   99  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  100  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  101  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  102  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  103  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  104  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  105  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  106  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  107  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  108  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  109  * SUCH DAMAGE.
  110  *
  111  * from: Utah $Hdr: vn.c 1.13 94/04/02$
  112  *
  113  *      @(#)vn.c        8.9 (Berkeley) 5/14/95
  114  */
  115 
  116 /*
  117  * Vnode disk driver.
  118  *
  119  * Block/character interface to a vnode.  Allows one to treat a file
  120  * as a disk (e.g. build a filesystem in it, mount it, etc.).
  121  *
  122  * NOTE 1: This uses the VOP_BMAP/VOP_STRATEGY interface to the vnode
  123  * instead of a simple VOP_RDWR.  We do this to avoid distorting the
  124  * local buffer cache.
  125  *
  126  * NOTE 2: There is a security issue involved with this driver.
  127  * Once mounted all access to the contents of the "mapped" file via
  128  * the special file is controlled by the permissions on the special
  129  * file, the protection of the mapped file is ignored (effectively,
  130  * by using root credentials in all transactions).
  131  *
  132  * NOTE 3: Doesn't interact with leases, should it?
  133  */
  134 
  135 #include <sys/cdefs.h>
  136 __KERNEL_RCSID(0, "$NetBSD: vnd.c,v 1.106 2004/01/25 18:06:48 hannken Exp $");
  137 
  138 #if defined(_KERNEL_OPT)
  139 #include "fs_nfs.h"
  140 #endif
  141 
  142 #include <sys/param.h>
  143 #include <sys/systm.h>
  144 #include <sys/namei.h>
  145 #include <sys/proc.h>
  146 #include <sys/errno.h>
  147 #include <sys/buf.h>
  148 #include <sys/malloc.h>
  149 #include <sys/ioctl.h>
  150 #include <sys/disklabel.h>
  151 #include <sys/device.h>
  152 #include <sys/disk.h>
  153 #include <sys/stat.h>
  154 #include <sys/mount.h>
  155 #include <sys/vnode.h>
  156 #include <sys/file.h>
  157 #include <sys/uio.h>
  158 #include <sys/conf.h>
  159 
  160 #include <miscfs/specfs/specdev.h>
  161 
  162 #include <dev/vndvar.h>
  163 
  164 #if defined(VNDDEBUG) && !defined(DEBUG)
  165 #define DEBUG
  166 #endif
  167 
  168 #ifdef DEBUG
  169 int dovndcluster = 1;
  170 #define VDB_FOLLOW      0x01
  171 #define VDB_INIT        0x02
  172 #define VDB_IO          0x04
  173 #define VDB_LABEL       0x08
  174 int vnddebug = 0x00;
  175 #endif
  176 
  177 #define vndunit(x)      DISKUNIT(x)
  178 
  179 struct vndxfer {
  180         struct buf      *vx_bp;         /* Pointer to parent buffer */
  181         int             vx_error;
  182         int             vx_pending;     /* # of pending aux buffers */
  183         int             vx_flags;
  184 #define VX_BUSY         1
  185 };
  186 
  187 struct vndbuf {
  188         struct buf      vb_buf;
  189         struct vndxfer  *vb_xfer;
  190 };
  191 
  192 #define VND_GETXFER(vnd)        pool_get(&(vnd)->sc_vxpool, PR_NOWAIT)
  193 #define VND_PUTXFER(vnd, vx)    pool_put(&(vnd)->sc_vxpool, (vx))
  194 
  195 #define VND_GETBUF(vnd)         pool_get(&(vnd)->sc_vbpool, PR_NOWAIT)
  196 #define VND_PUTBUF(vnd, vb)     pool_put(&(vnd)->sc_vbpool, (vb))
  197 
  198 struct vnd_softc *vnd_softc;
  199 int numvnd = 0;
  200 
  201 #define VNDLABELDEV(dev) \
  202         (MAKEDISKDEV(major((dev)), vndunit((dev)), RAW_PART))
  203 
  204 /* called by main() at boot time (XXX: and the LKM driver) */
  205 void    vndattach __P((int));
  206 int     vnddetach __P((void));
  207 
  208 void    vndclear __P((struct vnd_softc *, int));
  209 void    vndstart __P((struct vnd_softc *));
  210 int     vndsetcred __P((struct vnd_softc *, struct ucred *));
  211 void    vndthrottle __P((struct vnd_softc *, struct vnode *));
  212 void    vndiodone __P((struct buf *));
  213 #if 0
  214 void    vndshutdown __P((void));
  215 #endif
  216 
  217 void    vndgetdefaultlabel __P((struct vnd_softc *, struct disklabel *));
  218 void    vndgetdisklabel __P((dev_t));
  219 
  220 static  int vndlock __P((struct vnd_softc *));
  221 static  void vndunlock __P((struct vnd_softc *));
  222 
  223 dev_type_open(vndopen);
  224 dev_type_close(vndclose);
  225 dev_type_read(vndread);
  226 dev_type_write(vndwrite);
  227 dev_type_ioctl(vndioctl);
  228 dev_type_strategy(vndstrategy);
  229 dev_type_dump(vnddump);
  230 dev_type_size(vndsize);
  231 
  232 const struct bdevsw vnd_bdevsw = {
  233         vndopen, vndclose, vndstrategy, vndioctl, vnddump, vndsize, D_DISK
  234 };
  235 
  236 const struct cdevsw vnd_cdevsw = {
  237         vndopen, vndclose, vndread, vndwrite, vndioctl,
  238         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
  239 };
  240 
  241 int vndattached = 0;
  242 
  243 void
  244 vndattach(num)
  245         int num;
  246 {
  247         int i;
  248         char *mem;
  249 
  250         if (vndattached)
  251                 return;
  252         vndattached = 1;
  253         if (num <= 0)
  254                 return;
  255         i = num * sizeof(struct vnd_softc);
  256         mem = malloc(i, M_DEVBUF, M_NOWAIT|M_ZERO);
  257         if (mem == NULL) {
  258                 printf("WARNING: no memory for vnode disks\n");
  259                 return;
  260         }
  261         vnd_softc = (struct vnd_softc *)mem;
  262         numvnd = num;
  263 
  264         for (i = 0; i < numvnd; i++) {
  265                 vnd_softc[i].sc_unit = i;
  266                 bufq_alloc(&vnd_softc[i].sc_tab,
  267                     BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
  268         }
  269 }
  270 
  271 int
  272 vnddetach()
  273 {
  274         int i;
  275 
  276         /* First check we aren't in use. */
  277         for (i = 0; i < numvnd; i++)
  278                 if (vnd_softc[i].sc_flags & VNF_INITED)
  279                         return (EBUSY);
  280 
  281         for (i = 0; i < numvnd; i++)
  282                 bufq_free(&vnd_softc[i].sc_tab);
  283 
  284         free(vnd_softc, M_DEVBUF);
  285         vndattached = 0;
  286 
  287         return (0);
  288 }
  289 
  290 int
  291 vndopen(dev, flags, mode, p)
  292         dev_t dev;
  293         int flags, mode;
  294         struct proc *p;
  295 {
  296         int unit = vndunit(dev);
  297         struct vnd_softc *sc;
  298         int error = 0, part, pmask;
  299         struct disklabel *lp;
  300 
  301 #ifdef DEBUG
  302         if (vnddebug & VDB_FOLLOW)
  303                 printf("vndopen(0x%x, 0x%x, 0x%x, %p)\n", dev, flags, mode, p);
  304 #endif
  305         if (unit >= numvnd)
  306                 return (ENXIO);
  307         sc = &vnd_softc[unit];
  308 
  309         if ((error = vndlock(sc)) != 0)
  310                 return (error);
  311 
  312         lp = sc->sc_dkdev.dk_label;
  313 
  314         part = DISKPART(dev);
  315         pmask = (1 << part);
  316 
  317         /*
  318          * If we're initialized, check to see if there are any other
  319          * open partitions.  If not, then it's safe to update the
  320          * in-core disklabel.  Only read the disklabel if it is
  321          * not realdy valid.
  322          */
  323         if ((sc->sc_flags & (VNF_INITED|VNF_VLABEL)) == VNF_INITED &&
  324             sc->sc_dkdev.dk_openmask == 0)
  325                 vndgetdisklabel(dev);
  326 
  327         /* Check that the partitions exists. */
  328         if (part != RAW_PART) {
  329                 if (((sc->sc_flags & VNF_INITED) == 0) ||
  330                     ((part >= lp->d_npartitions) ||
  331                      (lp->d_partitions[part].p_fstype == FS_UNUSED))) {
  332                         error = ENXIO;
  333                         goto done;
  334                 }
  335         }
  336 
  337         /* Prevent our unit from being unconfigured while open. */
  338         switch (mode) {
  339         case S_IFCHR:
  340                 sc->sc_dkdev.dk_copenmask |= pmask;
  341                 break;
  342 
  343         case S_IFBLK:
  344                 sc->sc_dkdev.dk_bopenmask |= pmask;
  345                 break;
  346         }
  347         sc->sc_dkdev.dk_openmask =
  348             sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
  349 
  350  done:
  351         vndunlock(sc);
  352         return (error);
  353 }
  354 
  355 int
  356 vndclose(dev, flags, mode, p)
  357         dev_t dev;
  358         int flags, mode;
  359         struct proc *p;
  360 {
  361         int unit = vndunit(dev);
  362         struct vnd_softc *sc;
  363         int error = 0, part;
  364 
  365 #ifdef DEBUG
  366         if (vnddebug & VDB_FOLLOW)
  367                 printf("vndclose(0x%x, 0x%x, 0x%x, %p)\n", dev, flags, mode, p);
  368 #endif
  369 
  370         if (unit >= numvnd)
  371                 return (ENXIO);
  372         sc = &vnd_softc[unit];
  373 
  374         if ((error = vndlock(sc)) != 0)
  375                 return (error);
  376 
  377         part = DISKPART(dev);
  378 
  379         /* ...that much closer to allowing unconfiguration... */
  380         switch (mode) {
  381         case S_IFCHR:
  382                 sc->sc_dkdev.dk_copenmask &= ~(1 << part);
  383                 break;
  384 
  385         case S_IFBLK:
  386                 sc->sc_dkdev.dk_bopenmask &= ~(1 << part);
  387                 break;
  388         }
  389         sc->sc_dkdev.dk_openmask =
  390             sc->sc_dkdev.dk_copenmask | sc->sc_dkdev.dk_bopenmask;
  391 
  392         if (sc->sc_dkdev.dk_openmask == 0) {
  393                 if ((sc->sc_flags & VNF_KLABEL) == 0)
  394                         sc->sc_flags &= ~VNF_VLABEL;
  395         }
  396 
  397         vndunlock(sc);
  398         return (0);
  399 }
  400 
  401 /*
  402  * Break the request into bsize pieces and submit using VOP_BMAP/VOP_STRATEGY.
  403  */
  404 void
  405 vndstrategy(bp)
  406         struct buf *bp;
  407 {
  408         int unit = vndunit(bp->b_dev);
  409         struct vnd_softc *vnd = &vnd_softc[unit];
  410         struct vndxfer *vnx;
  411         struct mount *mp;
  412         int s, bsize, resid;
  413         off_t bn;
  414         caddr_t addr;
  415         int sz, flags, error, wlabel;
  416         struct disklabel *lp;
  417         struct partition *pp;
  418 
  419 #ifdef DEBUG
  420         if (vnddebug & VDB_FOLLOW)
  421                 printf("vndstrategy(%p): unit %d\n", bp, unit);
  422 #endif
  423         if ((vnd->sc_flags & VNF_INITED) == 0) {
  424                 bp->b_error = ENXIO;
  425                 bp->b_flags |= B_ERROR;
  426                 goto done;
  427         }
  428 
  429         /* If it's a nil transfer, wake up the top half now. */
  430         if (bp->b_bcount == 0)
  431                 goto done;
  432 
  433         lp = vnd->sc_dkdev.dk_label;
  434 
  435         /*
  436          * The transfer must be a whole number of blocks.
  437          */
  438         if ((bp->b_bcount % lp->d_secsize) != 0) {
  439                 bp->b_error = EINVAL;
  440                 bp->b_flags |= B_ERROR;
  441                 goto done;
  442         }
  443 
  444         /*
  445          * Do bounds checking and adjust transfer.  If there's an error,
  446          * the bounds check will flag that for us.
  447          */
  448         wlabel = vnd->sc_flags & (VNF_WLABEL|VNF_LABELLING);
  449         if (DISKPART(bp->b_dev) != RAW_PART)
  450                 if (bounds_check_with_label(&vnd->sc_dkdev, bp, wlabel) <= 0)
  451                         goto done;
  452 
  453         /*
  454          * check if we're read-only.
  455          */
  456         if ((vnd->sc_flags & VNF_READONLY) && !(bp->b_flags & B_READ)) {
  457                 bp->b_error = EACCES;
  458                 bp->b_flags |= B_ERROR;
  459                 goto done;
  460         }
  461 
  462         bp->b_resid = bp->b_bcount;
  463 
  464         /*
  465          * Put the block number in terms of the logical blocksize
  466          * of the "device".
  467          */
  468         bn = bp->b_blkno / (lp->d_secsize / DEV_BSIZE);
  469 
  470         /*
  471          * Translate the partition-relative block number to an absolute.
  472          */
  473         if (DISKPART(bp->b_dev) != RAW_PART) {
  474                 pp = &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(bp->b_dev)];
  475                 bn += pp->p_offset;
  476         }
  477 
  478         /* ...and convert to a byte offset within the file. */
  479         bn *= lp->d_secsize;
  480 
  481         if (vnd->sc_vp->v_mount == NULL) {
  482                 bp->b_error = ENXIO;
  483                 bp->b_flags |= B_ERROR;
  484                 goto done;
  485         }
  486         bsize = vnd->sc_vp->v_mount->mnt_stat.f_iosize;
  487         addr = bp->b_data;
  488         flags = (bp->b_flags & (B_READ|B_ASYNC)) | B_CALL;
  489 
  490         /* Allocate a header for this transfer and link it to the buffer */
  491         s = splbio();
  492         vnx = VND_GETXFER(vnd);
  493         splx(s);
  494         vnx->vx_flags = VX_BUSY;
  495         vnx->vx_error = 0;
  496         vnx->vx_pending = 0;
  497         vnx->vx_bp = bp;
  498 
  499         if ((flags & B_READ) == 0)
  500                 vn_start_write(vnd->sc_vp, &mp, V_WAIT);
  501 
  502         for (resid = bp->b_resid; resid; resid -= sz) {
  503                 struct vndbuf *nbp;
  504                 struct vnode *vp;
  505                 daddr_t nbn;
  506                 int off, nra;
  507 
  508                 nra = 0;
  509                 vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE);
  510                 error = VOP_BMAP(vnd->sc_vp, bn / bsize, &vp, &nbn, &nra);
  511                 VOP_UNLOCK(vnd->sc_vp, 0);
  512 
  513                 if (error == 0 && (long)nbn == -1)
  514                         error = EIO;
  515 
  516                 /*
  517                  * If there was an error or a hole in the file...punt.
  518                  * Note that we may have to wait for any operations
  519                  * that we have already fired off before releasing
  520                  * the buffer.
  521                  *
  522                  * XXX we could deal with holes here but it would be
  523                  * a hassle (in the write case).
  524                  */
  525                 if (error) {
  526                         s = splbio();
  527                         vnx->vx_error = error;
  528                         goto out;
  529                 }
  530 
  531 #ifdef DEBUG
  532                 if (!dovndcluster)
  533                         nra = 0;
  534 #endif
  535 
  536                 if ((off = bn % bsize) != 0)
  537                         sz = bsize - off;
  538                 else
  539                         sz = (1 + nra) * bsize;
  540                 if (resid < sz)
  541                         sz = resid;
  542 #ifdef DEBUG
  543                 if (vnddebug & VDB_IO)
  544                         printf("vndstrategy: vp %p/%p bn 0x%qx/0x%" PRIx64
  545                                " sz 0x%x\n",
  546                             vnd->sc_vp, vp, (long long)bn, nbn, sz);
  547 #endif
  548 
  549                 s = splbio();
  550                 nbp = VND_GETBUF(vnd);
  551                 splx(s);
  552                 BUF_INIT(&nbp->vb_buf);
  553                 nbp->vb_buf.b_flags = flags;
  554                 nbp->vb_buf.b_bcount = sz;
  555                 nbp->vb_buf.b_bufsize = round_page((ulong)addr + sz)
  556                     - trunc_page((ulong) addr);
  557                 nbp->vb_buf.b_error = 0;
  558                 nbp->vb_buf.b_data = addr;
  559                 nbp->vb_buf.b_blkno = nbp->vb_buf.b_rawblkno = nbn + btodb(off);
  560                 nbp->vb_buf.b_proc = bp->b_proc;
  561                 nbp->vb_buf.b_iodone = vndiodone;
  562                 nbp->vb_buf.b_vp = NULLVP;
  563 
  564                 nbp->vb_xfer = vnx;
  565 
  566                 BIO_COPYPRIO(&nbp->vb_buf, bp);
  567 
  568                 /*
  569                  * Just sort by block number
  570                  */
  571                 s = splbio();
  572                 if (vnx->vx_error != 0) {
  573                         VND_PUTBUF(vnd, nbp);
  574                         goto out;
  575                 }
  576                 vnx->vx_pending++;
  577                 bgetvp(vp, &nbp->vb_buf);
  578                 BUFQ_PUT(&vnd->sc_tab, &nbp->vb_buf);
  579                 vndstart(vnd);
  580                 splx(s);
  581                 bn += sz;
  582                 addr += sz;
  583         }
  584 
  585         s = splbio();
  586 
  587 out: /* Arrive here at splbio */
  588         if ((flags & B_READ) == 0)
  589                 vn_finished_write(mp, 0);
  590         vnx->vx_flags &= ~VX_BUSY;
  591         if (vnx->vx_pending == 0) {
  592                 if (vnx->vx_error != 0) {
  593                         bp->b_error = vnx->vx_error;
  594                         bp->b_flags |= B_ERROR;
  595                 }
  596                 VND_PUTXFER(vnd, vnx);
  597                 biodone(bp);
  598         }
  599         splx(s);
  600         return;
  601 
  602  done:
  603         biodone(bp);
  604 }
  605 
  606 /*
  607  * Feed requests sequentially.
  608  * We do it this way to keep from flooding NFS servers if we are connected
  609  * to an NFS file.  This places the burden on the client rather than the
  610  * server.
  611  */
  612 void
  613 vndstart(vnd)
  614         struct vnd_softc *vnd;
  615 {
  616         struct buf      *bp;
  617 
  618         /*
  619          * Dequeue now since lower level strategy routine might
  620          * queue using same links
  621          */
  622 
  623         if ((vnd->sc_flags & VNF_BUSY) != 0)
  624                 return;
  625 
  626         vnd->sc_flags |= VNF_BUSY;
  627 
  628         while (vnd->sc_active < vnd->sc_maxactive) {
  629                 bp = BUFQ_GET(&vnd->sc_tab);
  630                 if (bp == NULL)
  631                         break;
  632                 vnd->sc_active++;
  633 #ifdef DEBUG
  634                 if (vnddebug & VDB_IO)
  635                         printf("vndstart(%ld): bp %p vp %p blkno 0x%" PRIx64
  636                                 " flags %lx addr %p cnt 0x%lx\n",
  637                             (long) (vnd-vnd_softc), bp, bp->b_vp, bp->b_blkno,
  638                             bp->b_flags, bp->b_data, bp->b_bcount);
  639 #endif
  640 
  641                 /* Instrumentation. */
  642                 disk_busy(&vnd->sc_dkdev);
  643 
  644                 if ((bp->b_flags & B_READ) == 0)
  645                         bp->b_vp->v_numoutput++;
  646                 VOP_STRATEGY(bp->b_vp, bp);
  647         }
  648         vnd->sc_flags &= ~VNF_BUSY;
  649 }
  650 
  651 void
  652 vndiodone(bp)
  653         struct buf *bp;
  654 {
  655         struct vndbuf *vbp = (struct vndbuf *) bp;
  656         struct vndxfer *vnx = (struct vndxfer *)vbp->vb_xfer;
  657         struct buf *pbp = vnx->vx_bp;
  658         struct vnd_softc *vnd = &vnd_softc[vndunit(pbp->b_dev)];
  659         int s, resid;
  660 
  661         s = splbio();
  662 #ifdef DEBUG
  663         if (vnddebug & VDB_IO)
  664                 printf("vndiodone(%ld): vbp %p vp %p blkno 0x%" PRIx64
  665                        " addr %p cnt 0x%lx\n",
  666                     (long) (vnd-vnd_softc), vbp, vbp->vb_buf.b_vp,
  667                     vbp->vb_buf.b_blkno, vbp->vb_buf.b_data,
  668                     vbp->vb_buf.b_bcount);
  669 #endif
  670 
  671         resid = vbp->vb_buf.b_bcount - vbp->vb_buf.b_resid;
  672         pbp->b_resid -= resid;
  673         disk_unbusy(&vnd->sc_dkdev, resid, (pbp->b_flags & B_READ));
  674         vnx->vx_pending--;
  675 
  676         if (vbp->vb_buf.b_error) {
  677 #ifdef DEBUG
  678                 if (vnddebug & VDB_IO)
  679                         printf("vndiodone: vbp %p error %d\n", vbp,
  680                             vbp->vb_buf.b_error);
  681 #endif
  682                 vnx->vx_error = vbp->vb_buf.b_error;
  683         }
  684 
  685         if (vbp->vb_buf.b_vp != NULLVP)
  686                 brelvp(&vbp->vb_buf);
  687 
  688         VND_PUTBUF(vnd, vbp);
  689 
  690         /*
  691          * Wrap up this transaction if it has run to completion or, in
  692          * case of an error, when all auxiliary buffers have returned.
  693          */
  694         if (vnx->vx_error != 0) {
  695                 pbp->b_flags |= B_ERROR;
  696                 pbp->b_error = vnx->vx_error;
  697                 if ((vnx->vx_flags & VX_BUSY) == 0 && vnx->vx_pending == 0) {
  698 
  699 #ifdef DEBUG
  700                         if (vnddebug & VDB_IO)
  701                                 printf("vndiodone: pbp %p iodone: error %d\n",
  702                                         pbp, vnx->vx_error);
  703 #endif
  704                         VND_PUTXFER(vnd, vnx);
  705                         biodone(pbp);
  706                 }
  707         } else if (pbp->b_resid == 0) {
  708 
  709 #ifdef DIAGNOSTIC
  710                 if (vnx->vx_pending != 0)
  711                         panic("vndiodone: vnx pending: %d", vnx->vx_pending);
  712 #endif
  713 
  714                 if ((vnx->vx_flags & VX_BUSY) == 0) {
  715 #ifdef DEBUG
  716                         if (vnddebug & VDB_IO)
  717                                 printf("vndiodone: pbp %p iodone\n", pbp);
  718 #endif
  719                         VND_PUTXFER(vnd, vnx);
  720                         biodone(pbp);
  721                 }
  722         }
  723 
  724         vnd->sc_active--;
  725         vndstart(vnd);
  726         splx(s);
  727 }
  728 
  729 /* ARGSUSED */
  730 int
  731 vndread(dev, uio, flags)
  732         dev_t dev;
  733         struct uio *uio;
  734         int flags;
  735 {
  736         int unit = vndunit(dev);
  737         struct vnd_softc *sc;
  738 
  739 #ifdef DEBUG
  740         if (vnddebug & VDB_FOLLOW)
  741                 printf("vndread(0x%x, %p)\n", dev, uio);
  742 #endif
  743 
  744         if (unit >= numvnd)
  745                 return (ENXIO);
  746         sc = &vnd_softc[unit];
  747 
  748         if ((sc->sc_flags & VNF_INITED) == 0)
  749                 return (ENXIO);
  750 
  751         return (physio(vndstrategy, NULL, dev, B_READ, minphys, uio));
  752 }
  753 
  754 /* ARGSUSED */
  755 int
  756 vndwrite(dev, uio, flags)
  757         dev_t dev;
  758         struct uio *uio;
  759         int flags;
  760 {
  761         int unit = vndunit(dev);
  762         struct vnd_softc *sc;
  763 
  764 #ifdef DEBUG
  765         if (vnddebug & VDB_FOLLOW)
  766                 printf("vndwrite(0x%x, %p)\n", dev, uio);
  767 #endif
  768 
  769         if (unit >= numvnd)
  770                 return (ENXIO);
  771         sc = &vnd_softc[unit];
  772 
  773         if ((sc->sc_flags & VNF_INITED) == 0)
  774                 return (ENXIO);
  775 
  776         return (physio(vndstrategy, NULL, dev, B_WRITE, minphys, uio));
  777 }
  778 
  779 /* ARGSUSED */
  780 int
  781 vndioctl(dev, cmd, data, flag, p)
  782         dev_t dev;
  783         u_long cmd;
  784         caddr_t data;
  785         int flag;
  786         struct proc *p;
  787 {
  788         int unit = vndunit(dev);
  789         struct vnd_softc *vnd;
  790         struct vnd_ioctl *vio;
  791         struct vattr vattr;
  792         struct nameidata nd;
  793         int error, part, pmask;
  794         size_t geomsize;
  795         int fflags;
  796 #ifdef __HAVE_OLD_DISKLABEL
  797         struct disklabel newlabel;
  798 #endif
  799 
  800 #ifdef DEBUG
  801         if (vnddebug & VDB_FOLLOW)
  802                 printf("vndioctl(0x%x, 0x%lx, %p, 0x%x, %p): unit %d\n",
  803                     dev, cmd, data, flag, p, unit);
  804 #endif
  805         if (unit >= numvnd)
  806                 return (ENXIO);
  807 
  808         vnd = &vnd_softc[unit];
  809         vio = (struct vnd_ioctl *)data;
  810 
  811         /* Must be open for writes for these commands... */
  812         switch (cmd) {
  813         case VNDIOCSET:
  814         case VNDIOCCLR:
  815         case DIOCSDINFO:
  816         case DIOCWDINFO:
  817 #ifdef __HAVE_OLD_DISKLABEL
  818         case ODIOCSDINFO:
  819         case ODIOCWDINFO:
  820 #endif
  821         case DIOCKLABEL:
  822         case DIOCWLABEL:
  823                 if ((flag & FWRITE) == 0)
  824                         return (EBADF);
  825         }
  826 
  827         /* Must be initialized for these... */
  828         switch (cmd) {
  829         case VNDIOCCLR:
  830         case DIOCGDINFO:
  831         case DIOCSDINFO:
  832         case DIOCWDINFO:
  833         case DIOCGPART:
  834         case DIOCKLABEL:
  835         case DIOCWLABEL:
  836         case DIOCGDEFLABEL:
  837 #ifdef __HAVE_OLD_DISKLABEL
  838         case ODIOCGDINFO:
  839         case ODIOCSDINFO:
  840         case ODIOCWDINFO:
  841         case ODIOCGDEFLABEL:
  842 #endif
  843                 if ((vnd->sc_flags & VNF_INITED) == 0)
  844                         return (ENXIO);
  845         }
  846 
  847         switch (cmd) {
  848         case VNDIOCSET:
  849                 if (vnd->sc_flags & VNF_INITED)
  850                         return (EBUSY);
  851 
  852                 if ((error = vndlock(vnd)) != 0)
  853                         return (error);
  854 
  855                 fflags = FREAD;
  856                 if ((vio->vnd_flags & VNDIOF_READONLY) == 0)
  857                         fflags |= FWRITE;
  858                 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, vio->vnd_file, p);
  859                 if ((error = vn_open(&nd, fflags, 0)) != 0)
  860                         goto unlock_and_exit;
  861                 error = VOP_GETATTR(nd.ni_vp, &vattr, p->p_ucred, p);
  862                 VOP_UNLOCK(nd.ni_vp, 0);
  863                 if (!error && nd.ni_vp->v_type != VREG)
  864                         error = EOPNOTSUPP;
  865                 if (error)
  866                         goto close_and_exit;
  867                 vnd->sc_vp = nd.ni_vp;
  868                 vnd->sc_size = btodb(vattr.va_size);    /* note truncation */
  869 
  870                 /*
  871                  * Use pseudo-geometry specified.  If none was provided,
  872                  * use "standard" Adaptec fictitious geometry.
  873                  */
  874                 if (vio->vnd_flags & VNDIOF_HASGEOM) {
  875 
  876                         memcpy(&vnd->sc_geom, &vio->vnd_geom,
  877                             sizeof(vio->vnd_geom));
  878 
  879                         /*
  880                          * Sanity-check the sector size.
  881                          * XXX Don't allow secsize < DEV_BSIZE.  Should
  882                          * XXX we?
  883                          */
  884                         if (vnd->sc_geom.vng_secsize < DEV_BSIZE ||
  885                             (vnd->sc_geom.vng_secsize % DEV_BSIZE) != 0 ||
  886                             vnd->sc_geom.vng_ncylinders == 0 ||
  887                             (vnd->sc_geom.vng_ntracks *
  888                              vnd->sc_geom.vng_nsectors) == 0) {
  889                                 error = EINVAL;
  890                                 goto close_and_exit;
  891                         }
  892 
  893                         /*
  894                          * Compute the size (in DEV_BSIZE blocks) specified
  895                          * by the geometry.
  896                          */
  897                         geomsize = (vnd->sc_geom.vng_nsectors *
  898                             vnd->sc_geom.vng_ntracks *
  899                             vnd->sc_geom.vng_ncylinders) *
  900                             (vnd->sc_geom.vng_secsize / DEV_BSIZE);
  901 
  902                         /*
  903                          * Sanity-check the size against the specified
  904                          * geometry.
  905                          */
  906                         if (vnd->sc_size < geomsize) {
  907                                 error = EINVAL;
  908                                 goto close_and_exit;
  909                         }
  910                 } else {
  911                         /*
  912                          * Size must be at least 2048 DEV_BSIZE blocks
  913                          * (1M) in order to use this geometry.
  914                          */
  915                         if (vnd->sc_size < (32 * 64)) {
  916                                 error = EINVAL;
  917                                 goto close_and_exit;
  918                         }
  919 
  920                         vnd->sc_geom.vng_secsize = DEV_BSIZE;
  921                         vnd->sc_geom.vng_nsectors = 32;
  922                         vnd->sc_geom.vng_ntracks = 64;
  923                         vnd->sc_geom.vng_ncylinders = vnd->sc_size / (64 * 32);
  924                 }
  925 
  926                 if (vio->vnd_flags & VNDIOF_READONLY) {
  927                         vnd->sc_flags |= VNF_READONLY;
  928                 }
  929 
  930                 if ((error = vndsetcred(vnd, p->p_ucred)) != 0)
  931                         goto close_and_exit;
  932                 vndthrottle(vnd, vnd->sc_vp);
  933                 vio->vnd_size = dbtob(vnd->sc_size);
  934                 vnd->sc_flags |= VNF_INITED;
  935 #ifdef DEBUG
  936                 if (vnddebug & VDB_INIT)
  937                         printf("vndioctl: SET vp %p size 0x%lx %d/%d/%d/%d\n",
  938                             vnd->sc_vp, (unsigned long) vnd->sc_size,
  939                             vnd->sc_geom.vng_secsize,
  940                             vnd->sc_geom.vng_nsectors,
  941                             vnd->sc_geom.vng_ntracks,
  942                             vnd->sc_geom.vng_ncylinders);
  943 #endif
  944 
  945                 /* Attach the disk. */
  946                 memset(vnd->sc_xname, 0, sizeof(vnd->sc_xname)); /* XXX */
  947                 sprintf(vnd->sc_xname, "vnd%d", unit);          /* XXX */
  948                 vnd->sc_dkdev.dk_name = vnd->sc_xname;
  949                 disk_attach(&vnd->sc_dkdev);
  950 
  951                 /* Initialize the xfer and buffer pools. */
  952                 pool_init(&vnd->sc_vxpool, sizeof(struct vndxfer), 0,
  953                     0, 0, "vndxpl", NULL);
  954                 pool_init(&vnd->sc_vbpool, sizeof(struct vndbuf), 0,
  955                     0, 0, "vndbpl", NULL);
  956 
  957                 /* Try and read the disklabel. */
  958                 vndgetdisklabel(dev);
  959 
  960                 vndunlock(vnd);
  961 
  962                 break;
  963 
  964 close_and_exit:
  965                 (void) vn_close(nd.ni_vp, fflags, p->p_ucred, p);
  966 unlock_and_exit:
  967                 vndunlock(vnd);
  968                 return (error);
  969 
  970         case VNDIOCCLR:
  971                 if ((error = vndlock(vnd)) != 0)
  972                         return (error);
  973 
  974                 /*
  975                  * Don't unconfigure if any other partitions are open
  976                  * or if both the character and block flavors of this
  977                  * partition are open.
  978                  */
  979                 part = DISKPART(dev);
  980                 pmask = (1 << part);
  981                 if (((vnd->sc_dkdev.dk_openmask & ~pmask) ||
  982                     ((vnd->sc_dkdev.dk_bopenmask & pmask) &&
  983                     (vnd->sc_dkdev.dk_copenmask & pmask))) &&
  984                         !(vio->vnd_flags & VNDIOF_FORCE)) {
  985                         vndunlock(vnd);
  986                         return (EBUSY);
  987                 }
  988 
  989                 /*
  990                  * XXX vndclear() might call vndclose() implicitely;
  991                  * release lock to avoid recursion
  992                  */
  993                 vndunlock(vnd);
  994                 vndclear(vnd, minor(dev));
  995 #ifdef DEBUG
  996                 if (vnddebug & VDB_INIT)
  997                         printf("vndioctl: CLRed\n");
  998 #endif
  999 
 1000                 /* Destroy the xfer and buffer pools. */
 1001                 pool_destroy(&vnd->sc_vxpool);
 1002                 pool_destroy(&vnd->sc_vbpool);
 1003 
 1004                 /* Detatch the disk. */
 1005                 disk_detach(&vnd->sc_dkdev);
 1006 
 1007                 break;
 1008 
 1009         case VNDIOCGET: {
 1010                 struct vnd_user *vnu;
 1011                 struct vattr va;
 1012 
 1013                 vnu = (struct vnd_user *)data;
 1014 
 1015                 if (vnu->vnu_unit == -1)
 1016                         vnu->vnu_unit = unit;
 1017                 if (vnu->vnu_unit >= numvnd)
 1018                         return (ENXIO);
 1019                 if (vnu->vnu_unit < 0)
 1020                         return (EINVAL);
 1021 
 1022                 vnd = &vnd_softc[vnu->vnu_unit];
 1023 
 1024                 if (vnd->sc_flags & VNF_INITED) {
 1025                         error = VOP_GETATTR(vnd->sc_vp, &va, p->p_ucred, p);
 1026                         if (error)
 1027                                 return (error);
 1028                         vnu->vnu_dev = va.va_fsid;
 1029                         vnu->vnu_ino = va.va_fileid;
 1030                 }
 1031                 else {
 1032                         /* unused is not an error */
 1033                         vnu->vnu_dev = 0;
 1034                         vnu->vnu_ino = 0;
 1035                 }
 1036 
 1037                 break;
 1038         }
 1039 
 1040         case DIOCGDINFO:
 1041                 *(struct disklabel *)data = *(vnd->sc_dkdev.dk_label);
 1042                 break;
 1043 
 1044 #ifdef __HAVE_OLD_DISKLABEL
 1045         case ODIOCGDINFO:
 1046                 newlabel = *(vnd->sc_dkdev.dk_label);
 1047                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
 1048                         return ENOTTY;
 1049                 memcpy(data, &newlabel, sizeof (struct olddisklabel));
 1050                 break;
 1051 #endif
 1052 
 1053         case DIOCGPART:
 1054                 ((struct partinfo *)data)->disklab = vnd->sc_dkdev.dk_label;
 1055                 ((struct partinfo *)data)->part =
 1056                     &vnd->sc_dkdev.dk_label->d_partitions[DISKPART(dev)];
 1057                 break;
 1058 
 1059         case DIOCWDINFO:
 1060         case DIOCSDINFO:
 1061 #ifdef __HAVE_OLD_DISKLABEL
 1062         case ODIOCWDINFO:
 1063         case ODIOCSDINFO:
 1064 #endif
 1065         {
 1066                 struct disklabel *lp;
 1067 
 1068                 if ((error = vndlock(vnd)) != 0)
 1069                         return (error);
 1070 
 1071                 vnd->sc_flags |= VNF_LABELLING;
 1072 
 1073 #ifdef __HAVE_OLD_DISKLABEL
 1074                 if (cmd == ODIOCSDINFO || cmd == ODIOCWDINFO) {
 1075                         memset(&newlabel, 0, sizeof newlabel);
 1076                         memcpy(&newlabel, data, sizeof (struct olddisklabel));
 1077                         lp = &newlabel;
 1078                 } else
 1079 #endif
 1080                 lp = (struct disklabel *)data;
 1081 
 1082                 error = setdisklabel(vnd->sc_dkdev.dk_label,
 1083                     lp, 0, vnd->sc_dkdev.dk_cpulabel);
 1084                 if (error == 0) {
 1085                         if (cmd == DIOCWDINFO
 1086 #ifdef __HAVE_OLD_DISKLABEL
 1087                             || cmd == ODIOCWDINFO
 1088 #endif
 1089                            )
 1090                                 error = writedisklabel(VNDLABELDEV(dev),
 1091                                     vndstrategy, vnd->sc_dkdev.dk_label,
 1092                                     vnd->sc_dkdev.dk_cpulabel);
 1093                 }
 1094 
 1095                 vnd->sc_flags &= ~VNF_LABELLING;
 1096 
 1097                 vndunlock(vnd);
 1098 
 1099                 if (error)
 1100                         return (error);
 1101                 break;
 1102         }
 1103 
 1104         case DIOCKLABEL:
 1105                 if (*(int *)data != 0)
 1106                         vnd->sc_flags |= VNF_KLABEL;
 1107                 else
 1108                         vnd->sc_flags &= ~VNF_KLABEL;
 1109                 break;
 1110 
 1111         case DIOCWLABEL:
 1112                 if (*(int *)data != 0)
 1113                         vnd->sc_flags |= VNF_WLABEL;
 1114                 else
 1115                         vnd->sc_flags &= ~VNF_WLABEL;
 1116                 break;
 1117 
 1118         case DIOCGDEFLABEL:
 1119                 vndgetdefaultlabel(vnd, (struct disklabel *)data);
 1120                 break;
 1121 
 1122 #ifdef __HAVE_OLD_DISKLABEL
 1123         case ODIOCGDEFLABEL:
 1124                 vndgetdefaultlabel(vnd, &newlabel);
 1125                 if (newlabel.d_npartitions > OLDMAXPARTITIONS)
 1126                         return ENOTTY;
 1127                 memcpy(data, &newlabel, sizeof (struct olddisklabel));
 1128                 break;
 1129 #endif
 1130 
 1131         default:
 1132                 return (ENOTTY);
 1133         }
 1134 
 1135         return (0);
 1136 }
 1137 
 1138 /*
 1139  * Duplicate the current processes' credentials.  Since we are called only
 1140  * as the result of a SET ioctl and only root can do that, any future access
 1141  * to this "disk" is essentially as root.  Note that credentials may change
 1142  * if some other uid can write directly to the mapped file (NFS).
 1143  */
 1144 int
 1145 vndsetcred(vnd, cred)
 1146         struct vnd_softc *vnd;
 1147         struct ucred *cred;
 1148 {
 1149         struct uio auio;
 1150         struct iovec aiov;
 1151         char *tmpbuf;
 1152         int error;
 1153 
 1154         vnd->sc_cred = crdup(cred);
 1155         tmpbuf = malloc(DEV_BSIZE, M_TEMP, M_WAITOK);
 1156 
 1157         /* XXX: Horrible kludge to establish credentials for NFS */
 1158         aiov.iov_base = tmpbuf;
 1159         aiov.iov_len = min(DEV_BSIZE, dbtob(vnd->sc_size));
 1160         auio.uio_iov = &aiov;
 1161         auio.uio_iovcnt = 1;
 1162         auio.uio_offset = 0;
 1163         auio.uio_rw = UIO_READ;
 1164         auio.uio_segflg = UIO_SYSSPACE;
 1165         auio.uio_resid = aiov.iov_len;
 1166         vn_lock(vnd->sc_vp, LK_EXCLUSIVE | LK_RETRY);
 1167         error = VOP_READ(vnd->sc_vp, &auio, 0, vnd->sc_cred);
 1168         if (error == 0) {
 1169                 /*
 1170                  * Because vnd does all IO directly through the vnode
 1171                  * we need to flush (at least) the buffer from the above
 1172                  * VOP_READ from the buffer cache to prevent cache
 1173                  * incoherencies.  Also, be careful to write dirty
 1174                  * buffers back to stable storage.
 1175                  */
 1176                 error = vinvalbuf(vnd->sc_vp, V_SAVE, vnd->sc_cred,
 1177                             curproc, 0, 0);
 1178         }
 1179         VOP_UNLOCK(vnd->sc_vp, 0);
 1180 
 1181         free(tmpbuf, M_TEMP);
 1182         return (error);
 1183 }
 1184 
 1185 /*
 1186  * Set maxactive based on FS type
 1187  */
 1188 void
 1189 vndthrottle(vnd, vp)
 1190         struct vnd_softc *vnd;
 1191         struct vnode *vp;
 1192 {
 1193 #ifdef NFS
 1194         extern int (**nfsv2_vnodeop_p) __P((void *));
 1195 
 1196         if (vp->v_op == nfsv2_vnodeop_p)
 1197                 vnd->sc_maxactive = 2;
 1198         else
 1199 #endif
 1200                 vnd->sc_maxactive = 8;
 1201 
 1202         if (vnd->sc_maxactive < 1)
 1203                 vnd->sc_maxactive = 1;
 1204 }
 1205 
 1206 #if 0
 1207 void
 1208 vndshutdown()
 1209 {
 1210         struct vnd_softc *vnd;
 1211 
 1212         for (vnd = &vnd_softc[0]; vnd < &vnd_softc[numvnd]; vnd++)
 1213                 if (vnd->sc_flags & VNF_INITED)
 1214                         vndclear(vnd);
 1215 }
 1216 #endif
 1217 
 1218 void
 1219 vndclear(vnd, myminor)
 1220         struct vnd_softc *vnd;
 1221         int myminor;
 1222 {
 1223         struct vnode *vp = vnd->sc_vp;
 1224         struct proc *p = curproc;               /* XXX */
 1225         int fflags = FREAD;
 1226         int bmaj, cmaj, i, mn;
 1227 
 1228 #ifdef DEBUG
 1229         if (vnddebug & VDB_FOLLOW)
 1230                 printf("vndclear(%p): vp %p\n", vnd, vp);
 1231 #endif
 1232         /* locate the major number */
 1233         bmaj = bdevsw_lookup_major(&vnd_bdevsw);
 1234         cmaj = cdevsw_lookup_major(&vnd_cdevsw);
 1235 
 1236         /* Nuke the vnodes for any open instances */
 1237         for (i = 0; i < MAXPARTITIONS; i++) {
 1238                 mn = DISKMINOR(vnd->sc_unit, i);
 1239                 vdevgone(bmaj, mn, mn, VBLK);
 1240                 if (mn != myminor) /* XXX avoid to kill own vnode */
 1241                         vdevgone(cmaj, mn, mn, VCHR);
 1242         }
 1243 
 1244         if ((vnd->sc_flags & VNF_READONLY) == 0)
 1245                 fflags |= FWRITE;
 1246         vnd->sc_flags &= ~(VNF_INITED | VNF_READONLY | VNF_VLABEL);
 1247         if (vp == (struct vnode *)0)
 1248                 panic("vndioctl: null vp");
 1249         (void) vn_close(vp, fflags, vnd->sc_cred, p);
 1250         crfree(vnd->sc_cred);
 1251         vnd->sc_vp = (struct vnode *)0;
 1252         vnd->sc_cred = (struct ucred *)0;
 1253         vnd->sc_size = 0;
 1254 }
 1255 
 1256 int
 1257 vndsize(dev)
 1258         dev_t dev;
 1259 {
 1260         struct vnd_softc *sc;
 1261         struct disklabel *lp;
 1262         int part, unit, omask;
 1263         int size;
 1264 
 1265         unit = vndunit(dev);
 1266         if (unit >= numvnd)
 1267                 return (-1);
 1268         sc = &vnd_softc[unit];
 1269 
 1270         if ((sc->sc_flags & VNF_INITED) == 0)
 1271                 return (-1);
 1272 
 1273         part = DISKPART(dev);
 1274         omask = sc->sc_dkdev.dk_openmask & (1 << part);
 1275         lp = sc->sc_dkdev.dk_label;
 1276 
 1277         if (omask == 0 && vndopen(dev, 0, S_IFBLK, curproc))
 1278                 return (-1);
 1279 
 1280         if (lp->d_partitions[part].p_fstype != FS_SWAP)
 1281                 size = -1;
 1282         else
 1283                 size = lp->d_partitions[part].p_size *
 1284                     (lp->d_secsize / DEV_BSIZE);
 1285 
 1286         if (omask == 0 && vndclose(dev, 0, S_IFBLK, curproc))
 1287                 return (-1);
 1288 
 1289         return (size);
 1290 }
 1291 
 1292 int
 1293 vnddump(dev, blkno, va, size)
 1294         dev_t dev;
 1295         daddr_t blkno;
 1296         caddr_t va;
 1297         size_t size;
 1298 {
 1299 
 1300         /* Not implemented. */
 1301         return ENXIO;
 1302 }
 1303 
 1304 void
 1305 vndgetdefaultlabel(sc, lp)
 1306         struct vnd_softc *sc;
 1307         struct disklabel *lp;
 1308 {
 1309         struct vndgeom *vng = &sc->sc_geom;
 1310         struct partition *pp;
 1311 
 1312         memset(lp, 0, sizeof(*lp));
 1313 
 1314         lp->d_secperunit = sc->sc_size / (vng->vng_secsize / DEV_BSIZE);
 1315         lp->d_secsize = vng->vng_secsize;
 1316         lp->d_nsectors = vng->vng_nsectors;
 1317         lp->d_ntracks = vng->vng_ntracks;
 1318         lp->d_ncylinders = vng->vng_ncylinders;
 1319         lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
 1320 
 1321         strncpy(lp->d_typename, "vnd", sizeof(lp->d_typename));
 1322         lp->d_type = DTYPE_VND;
 1323         strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
 1324         lp->d_rpm = 3600;
 1325         lp->d_interleave = 1;
 1326         lp->d_flags = 0;
 1327 
 1328         pp = &lp->d_partitions[RAW_PART];
 1329         pp->p_offset = 0;
 1330         pp->p_size = lp->d_secperunit;
 1331         pp->p_fstype = FS_UNUSED;
 1332         lp->d_npartitions = RAW_PART + 1;
 1333 
 1334         lp->d_magic = DISKMAGIC;
 1335         lp->d_magic2 = DISKMAGIC;
 1336         lp->d_checksum = dkcksum(lp);
 1337 }
 1338 
 1339 /*
 1340  * Read the disklabel from a vnd.  If one is not present, create a fake one.
 1341  */
 1342 void
 1343 vndgetdisklabel(dev)
 1344         dev_t dev;
 1345 {
 1346         struct vnd_softc *sc = &vnd_softc[vndunit(dev)];
 1347         const char *errstring;
 1348         struct disklabel *lp = sc->sc_dkdev.dk_label;
 1349         struct cpu_disklabel *clp = sc->sc_dkdev.dk_cpulabel;
 1350         int i;
 1351 
 1352         memset(clp, 0, sizeof(*clp));
 1353 
 1354         vndgetdefaultlabel(sc, lp);
 1355 
 1356         /*
 1357          * Call the generic disklabel extraction routine.
 1358          */
 1359         errstring = readdisklabel(VNDLABELDEV(dev), vndstrategy, lp, clp);
 1360         if (errstring) {
 1361                 /*
 1362                  * Lack of disklabel is common, but we print the warning
 1363                  * anyway, since it might contain other useful information.
 1364                  */
 1365                 printf("%s: %s\n", sc->sc_xname, errstring);
 1366 
 1367                 /*
 1368                  * For historical reasons, if there's no disklabel
 1369                  * present, all partitions must be FS_BSDFFS and
 1370                  * occupy the entire disk.
 1371                  */
 1372                 for (i = 0; i < MAXPARTITIONS; i++) {
 1373                         /*
 1374                          * Don't wipe out port specific hack (such as
 1375                          * dos partition hack of i386 port).
 1376                          */
 1377                         if (lp->d_partitions[i].p_size != 0)
 1378                                 continue;
 1379 
 1380                         lp->d_partitions[i].p_size = lp->d_secperunit;
 1381                         lp->d_partitions[i].p_offset = 0;
 1382                         lp->d_partitions[i].p_fstype = FS_BSDFFS;
 1383                 }
 1384 
 1385                 strncpy(lp->d_packname, "default label",
 1386                     sizeof(lp->d_packname));
 1387 
 1388                 lp->d_npartitions = MAXPARTITIONS;
 1389                 lp->d_checksum = dkcksum(lp);
 1390         }
 1391 
 1392         /* In-core label now valid. */
 1393         sc->sc_flags |= VNF_VLABEL;
 1394 }
 1395 
 1396 /*
 1397  * Wait interruptibly for an exclusive lock.
 1398  *
 1399  * XXX
 1400  * Several drivers do this; it should be abstracted and made MP-safe.
 1401  */
 1402 static int
 1403 vndlock(sc)
 1404         struct vnd_softc *sc;
 1405 {
 1406         int error;
 1407 
 1408         while ((sc->sc_flags & VNF_LOCKED) != 0) {
 1409                 sc->sc_flags |= VNF_WANTED;
 1410                 if ((error = tsleep(sc, PRIBIO | PCATCH, "vndlck", 0)) != 0)
 1411                         return (error);
 1412         }
 1413         sc->sc_flags |= VNF_LOCKED;
 1414         return (0);
 1415 }
 1416 
 1417 /*
 1418  * Unlock and wake up any waiters.
 1419  */
 1420 static void
 1421 vndunlock(sc)
 1422         struct vnd_softc *sc;
 1423 {
 1424 
 1425         sc->sc_flags &= ~VNF_LOCKED;
 1426         if ((sc->sc_flags & VNF_WANTED) != 0) {
 1427                 sc->sc_flags &= ~VNF_WANTED;
 1428                 wakeup(sc);
 1429         }
 1430 }

Cache object: 996595fef6eaf4cb4c033d15224a4a9c


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