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/ufs/ufs/ufs_readwrite.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) 1993
    3  *      The Regents of the University of California.  All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. All advertising materials mentioning features or use of this software
   14  *    must display the following acknowledgement:
   15  *      This product includes software developed by the University of
   16  *      California, Berkeley and its contributors.
   17  * 4. Neither the name of the University nor the names of its contributors
   18  *    may be used to endorse or promote products derived from this software
   19  *    without specific prior written permission.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  *
   33  *      @(#)ufs_readwrite.c     8.11 (Berkeley) 5/8/95
   34  * $FreeBSD$
   35  */
   36 
   37 #define BLKSIZE(a, b, c)        blksize(a, b, c)
   38 #define FS                      struct fs
   39 #define I_FS                    i_fs
   40 #define READ                    ffs_read
   41 #define READ_S                  "ffs_read"
   42 #define WRITE                   ffs_write
   43 #define WRITE_S                 "ffs_write"
   44 
   45 #include <vm/vm.h>
   46 #include <vm/vm_object.h>
   47 #include <vm/vm_pager.h>
   48 #include <vm/vm_map.h>
   49 #include <vm/vnode_pager.h>
   50 #include <sys/poll.h>
   51 
   52 /*
   53  * Vnode op for reading.
   54  */
   55 /* ARGSUSED */
   56 int
   57 READ(ap)
   58         struct vop_read_args /* {
   59                 struct vnode *a_vp;
   60                 struct uio *a_uio;
   61                 int a_ioflag;
   62                 struct ucred *a_cred;
   63         } */ *ap;
   64 {
   65         register struct vnode *vp;
   66         register struct inode *ip;
   67         register struct uio *uio;
   68         register FS *fs;
   69         struct buf *bp;
   70         ufs_daddr_t lbn, nextlbn;
   71         off_t bytesinfile;
   72         long size, xfersize, blkoffset;
   73         int error, orig_resid;
   74         u_short mode;
   75         int seqcount;
   76         int ioflag;
   77         vm_object_t object;
   78 
   79         vp = ap->a_vp;
   80         seqcount = ap->a_ioflag >> 16;
   81         ip = VTOI(vp);
   82         mode = ip->i_mode;
   83         uio = ap->a_uio;
   84         ioflag = ap->a_ioflag;
   85 
   86 #ifdef DIAGNOSTIC
   87         if (uio->uio_rw != UIO_READ)
   88                 panic("%s: mode", READ_S);
   89 
   90         if (vp->v_type == VLNK) {
   91                 if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
   92                         panic("%s: short symlink", READ_S);
   93         } else if (vp->v_type != VREG && vp->v_type != VDIR)
   94                 panic("%s: type %d", READ_S, vp->v_type);
   95 #endif
   96         fs = ip->I_FS;
   97         if ((u_int64_t)uio->uio_offset > fs->fs_maxfilesize)
   98                 return (EFBIG);
   99 
  100         orig_resid = uio->uio_resid;
  101         if (orig_resid <= 0)
  102                 return (0);
  103 
  104         object = vp->v_object;
  105 
  106         bytesinfile = ip->i_size - uio->uio_offset;
  107         if (bytesinfile <= 0) {
  108                 if ((vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
  109                         ip->i_flag |= IN_ACCESS;
  110                 return 0;
  111         }
  112 
  113         if (object)
  114                 vm_object_reference(object);
  115 #if 1
  116         /*
  117          * If IO optimisation is turned on,
  118          * and we are NOT a VM based IO request, 
  119          * (i.e. not headed for the buffer cache)
  120          * but there IS a vm object associated with it.
  121          */
  122         if ((ioflag & IO_VMIO) == 0 && (vfs_ioopt > 1) && object) {
  123                 int nread, toread;
  124 
  125                 toread = uio->uio_resid;
  126                 if (toread > bytesinfile)
  127                         toread = bytesinfile;
  128                 if (toread >= PAGE_SIZE) {
  129                         /*
  130                          * Then if it's at least a page in size, try 
  131                          * get the data from the object using vm tricks
  132                          */
  133                         error = uioread(toread, uio, object, &nread);
  134                         if ((uio->uio_resid == 0) || (error != 0)) {
  135                                 /*
  136                                  * If we finished or there was an error
  137                                  * then finish up.
  138                                  */
  139                                 if ((error == 0 ||
  140                                     uio->uio_resid != orig_resid) &&
  141                                     (vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
  142                                         ip->i_flag |= IN_ACCESS;
  143                                 if (object)
  144                                         /*
  145                                          * This I don't understand
  146                                          */
  147                                         vm_object_vndeallocate(object);
  148                                 return error;
  149                         }
  150                 }
  151         }
  152 #endif
  153 
  154         /*
  155          * Ok so we couldn't do it all in one vm trick...
  156          * so cycle around trying smaller bites..
  157          */
  158         for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) {
  159                 if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
  160                         break;
  161 #if 1
  162                 if ((ioflag & IO_VMIO) == 0 && (vfs_ioopt > 1) && object) {
  163                         /*
  164                          * Obviously we didn't finish above, but we
  165                          * didn't get an error either. Try the same trick again.
  166                          * but this time we are looping.
  167                          */
  168                         int nread, toread;
  169                         toread = uio->uio_resid;
  170                         if (toread > bytesinfile)
  171                                 toread = bytesinfile;
  172 
  173                         /*
  174                          * Once again, if there isn't enough for a
  175                          * whole page, don't try optimising.
  176                          */
  177                         if (toread >= PAGE_SIZE) {
  178                                 error = uioread(toread, uio, object, &nread);
  179                                 if ((uio->uio_resid == 0) || (error != 0)) {
  180                                         if ((error == 0 ||
  181                                             uio->uio_resid != orig_resid) &&
  182                                             (vp->v_mount->mnt_flag &
  183                                             MNT_NOATIME) == 0)
  184                                                 ip->i_flag |= IN_ACCESS;
  185                                         if (object)
  186                                                 vm_object_vndeallocate(object);
  187                                         return error;
  188                                 }
  189                                 /*
  190                                  * To get here we didnt't finish or err.
  191                                  * If we did get some data,
  192                                  * loop to try another bite.
  193                                  */
  194                                 if (nread > 0) {
  195                                         continue;
  196                                 }
  197                         }
  198                 }
  199 #endif
  200 
  201                 lbn = lblkno(fs, uio->uio_offset);
  202                 nextlbn = lbn + 1;
  203                 size = BLKSIZE(fs, ip, lbn);
  204                 blkoffset = blkoff(fs, uio->uio_offset);
  205                 
  206                 /*
  207                  * The amount we want to transfer in this iteration is
  208                  * one FS block less the amount of the data before
  209                  * our startpoint (duh!)
  210                  */
  211                 xfersize = fs->fs_bsize - blkoffset;
  212 
  213                 /*
  214                  * But if we actually want less than the block,
  215                  * or the file doesn't have a whole block more of data,
  216                  * then use the lesser number.
  217                  */
  218                 if (uio->uio_resid < xfersize)
  219                         xfersize = uio->uio_resid;
  220                 if (bytesinfile < xfersize)
  221                         xfersize = bytesinfile;
  222 
  223                 if (lblktosize(fs, nextlbn) >= ip->i_size)
  224                         /*
  225                          * Don't do readahead if this is the end of the file.
  226                          */
  227                         error = bread(vp, lbn, size, NOCRED, &bp);
  228                 else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0)
  229                         /* 
  230                          * Otherwise if we are allowed to cluster,
  231                          * grab as much as we can.
  232                          *
  233                          * XXX  This may not be a win if we are not
  234                          * doing sequential access.
  235                          */
  236                         error = cluster_read(vp, ip->i_size, lbn,
  237                                 size, NOCRED, uio->uio_resid, seqcount, &bp);
  238                 else if (lbn - 1 == vp->v_lastr) {
  239                         /*
  240                          * If we are NOT allowed to cluster, then
  241                          * if we appear to be acting sequentially,
  242                          * fire off a request for a readahead
  243                          * as well as a read. Note that the 4th and 5th
  244                          * arguments point to arrays of the size specified in
  245                          * the 6th argument.
  246                          */
  247                         int nextsize = BLKSIZE(fs, ip, nextlbn);
  248                         error = breadn(vp, lbn,
  249                             size, &nextlbn, &nextsize, 1, NOCRED, &bp);
  250                 } else
  251                         /*
  252                          * Failing all of the above, just read what the 
  253                          * user asked for. Interestingly, the same as
  254                          * the first option above.
  255                          */
  256                         error = bread(vp, lbn, size, NOCRED, &bp);
  257                 if (error) {
  258                         brelse(bp);
  259                         bp = NULL;
  260                         break;
  261                 }
  262 
  263                 /*
  264                  * Remember where we read so we can see latter if we start
  265                  * acting sequential.
  266                  */
  267                 vp->v_lastr = lbn;
  268 
  269                 /*
  270                  * We should only get non-zero b_resid when an I/O error
  271                  * has occurred, which should cause us to break above.
  272                  * However, if the short read did not cause an error,
  273                  * then we want to ensure that we do not uiomove bad
  274                  * or uninitialized data.
  275                  */
  276                 size -= bp->b_resid;
  277                 if (size < xfersize) {
  278                         if (size == 0)
  279                                 break;
  280                         xfersize = size;
  281                 }
  282 
  283                 if (vfs_ioopt && object &&
  284                     (bp->b_flags & B_VMIO) &&
  285                     ((blkoffset & PAGE_MASK) == 0) &&
  286                     ((xfersize & PAGE_MASK) == 0)) {
  287                         /*
  288                          * If VFS IO  optimisation is turned on,
  289                          * and it's an exact page multiple
  290                          * And a normal VM based op,
  291                          * then use uiomiveco()
  292                          */
  293                         error =
  294                                 uiomoveco((char *)bp->b_data + blkoffset,
  295                                         (int)xfersize, uio, object);
  296                 } else {
  297                         /*
  298                          * otherwise use the general form
  299                          */
  300                         error =
  301                                 uiomove((char *)bp->b_data + blkoffset,
  302                                         (int)xfersize, uio);
  303                 }
  304 
  305                 if (error)
  306                         break;
  307 
  308                 if ((ioflag & IO_VMIO) &&
  309                    (LIST_FIRST(&bp->b_dep) == NULL)) {
  310                         /*
  311                          * If there are no dependencies, and
  312                          * it's VMIO, then we don't need the buf,
  313                          * mark it available for freeing. The VM has the data.
  314                          */
  315                         bp->b_flags |= B_RELBUF;
  316                         brelse(bp);
  317                 } else {
  318                         /*
  319                          * Otherwise let whoever
  320                          * made the request take care of
  321                          * freeing it. We just queue
  322                          * it onto another list.
  323                          */
  324                         bqrelse(bp);
  325                 }
  326         }
  327 
  328         /* 
  329          * This can only happen in the case of an error
  330          * because the loop above resets bp to NULL on each iteration
  331          * and on normal completion has not set a new value into it.
  332          * so it must have come from a 'break' statement
  333          */
  334         if (bp != NULL) {
  335                 if ((ioflag & IO_VMIO) &&
  336                    (LIST_FIRST(&bp->b_dep) == NULL)) {
  337                         bp->b_flags |= B_RELBUF;
  338                         brelse(bp);
  339                 } else {
  340                         bqrelse(bp);
  341                 }
  342         }
  343 
  344         if (object)
  345                 vm_object_vndeallocate(object);
  346         if ((error == 0 || uio->uio_resid != orig_resid) &&
  347             (vp->v_mount->mnt_flag & MNT_NOATIME) == 0)
  348                 ip->i_flag |= IN_ACCESS;
  349         return (error);
  350 }
  351 
  352 /*
  353  * Vnode op for writing.
  354  */
  355 int
  356 WRITE(ap)
  357         struct vop_write_args /* {
  358                 struct vnode *a_vp;
  359                 struct uio *a_uio;
  360                 int a_ioflag;
  361                 struct ucred *a_cred;
  362         } */ *ap;
  363 {
  364         register struct vnode *vp;
  365         register struct uio *uio;
  366         register struct inode *ip;
  367         register FS *fs;
  368         struct buf *bp;
  369         struct proc *p;
  370         ufs_daddr_t lbn;
  371         off_t osize;
  372         int blkoffset, error, extended, flags, ioflag, resid, size, xfersize;
  373         vm_object_t object;
  374 
  375         extended = 0;
  376         ioflag = ap->a_ioflag;
  377         uio = ap->a_uio;
  378         vp = ap->a_vp;
  379         ip = VTOI(vp);
  380 
  381         object = vp->v_object;
  382         if (object)
  383                 vm_object_reference(object);
  384 
  385 #ifdef DIAGNOSTIC
  386         if (uio->uio_rw != UIO_WRITE)
  387                 panic("%s: mode", WRITE_S);
  388 #endif
  389 
  390         switch (vp->v_type) {
  391         case VREG:
  392                 if (ioflag & IO_APPEND)
  393                         uio->uio_offset = ip->i_size;
  394                 if ((ip->i_flags & APPEND) && uio->uio_offset != ip->i_size) {
  395                         if (object)
  396                                 vm_object_vndeallocate(object);
  397                         return (EPERM);
  398                 }
  399                 /* FALLTHROUGH */
  400         case VLNK:
  401                 break;
  402         case VDIR:
  403                 if ((ioflag & IO_SYNC) == 0)
  404                         panic("%s: nonsync dir write", WRITE_S);
  405                 break;
  406         default:
  407                 panic("%s: type", WRITE_S);
  408         }
  409 
  410         fs = ip->I_FS;
  411         if (uio->uio_offset < 0 ||
  412             (u_int64_t)uio->uio_offset + uio->uio_resid > fs->fs_maxfilesize) {
  413                 if (object)
  414                         vm_object_vndeallocate(object);
  415                 return (EFBIG);
  416         }
  417         /*
  418          * Maybe this should be above the vnode op call, but so long as
  419          * file servers have no limits, I don't think it matters.
  420          */
  421         p = uio->uio_procp;
  422         if (vp->v_type == VREG && p &&
  423             uio->uio_offset + uio->uio_resid >
  424             p->p_rlimit[RLIMIT_FSIZE].rlim_cur) {
  425                 psignal(p, SIGXFSZ);
  426                 if (object)
  427                         vm_object_vndeallocate(object);
  428                 return (EFBIG);
  429         }
  430 
  431         resid = uio->uio_resid;
  432         osize = ip->i_size;
  433         flags = ioflag & IO_SYNC ? B_SYNC : 0;
  434 
  435         if (object && (object->flags & OBJ_OPT)) {
  436                 vm_freeze_copyopts(object,
  437                         OFF_TO_IDX(uio->uio_offset),
  438                         OFF_TO_IDX(uio->uio_offset + uio->uio_resid + PAGE_MASK));
  439         }
  440 
  441         for (error = 0; uio->uio_resid > 0;) {
  442                 lbn = lblkno(fs, uio->uio_offset);
  443                 blkoffset = blkoff(fs, uio->uio_offset);
  444                 xfersize = fs->fs_bsize - blkoffset;
  445                 if (uio->uio_resid < xfersize)
  446                         xfersize = uio->uio_resid;
  447 
  448                 if (uio->uio_offset + xfersize > ip->i_size)
  449                         vnode_pager_setsize(vp, uio->uio_offset + xfersize);
  450 
  451                 /*      
  452                  * Avoid a data-consistency race between write() and mmap()
  453                  * by ensuring that newly allocated blocks are zerod.  The
  454                  * race can occur even in the case where the write covers
  455                  * the entire block.
  456                  */
  457                 flags |= B_CLRBUF;
  458 #if 0
  459                 if (fs->fs_bsize > xfersize)
  460                         flags |= B_CLRBUF;
  461                 else
  462                         flags &= ~B_CLRBUF;
  463 #endif
  464 /* XXX is uio->uio_offset the right thing here? */
  465                 error = VOP_BALLOC(vp, uio->uio_offset, xfersize,
  466                     ap->a_cred, flags, &bp);
  467                 if (error != 0)
  468                         break;
  469 
  470                 if (uio->uio_offset + xfersize > ip->i_size) {
  471                         ip->i_size = uio->uio_offset + xfersize;
  472                         extended = 1;
  473                 }
  474 
  475                 size = BLKSIZE(fs, ip, lbn) - bp->b_resid;
  476                 if (size < xfersize)
  477                         xfersize = size;
  478 
  479                 error =
  480                     uiomove((char *)bp->b_data + blkoffset, (int)xfersize, uio);
  481                 if ((ioflag & IO_VMIO) &&
  482                    (LIST_FIRST(&bp->b_dep) == NULL))
  483                         bp->b_flags |= B_RELBUF;
  484 
  485                 if (ioflag & IO_SYNC) {
  486                         (void)bwrite(bp);
  487                 } else if (xfersize + blkoffset == fs->fs_bsize) {
  488                         if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0) {
  489                                 bp->b_flags |= B_CLUSTEROK;
  490                                 cluster_write(bp, ip->i_size);
  491                         } else {
  492                                 bawrite(bp);
  493                         }
  494                 } else {
  495                         bp->b_flags |= B_CLUSTEROK;
  496                         bdwrite(bp);
  497                 }
  498                 if (error || xfersize == 0)
  499                         break;
  500                 ip->i_flag |= IN_CHANGE | IN_UPDATE;
  501         }
  502         /*
  503          * If we successfully wrote any data, and we are not the superuser
  504          * we clear the setuid and setgid bits as a precaution against
  505          * tampering.
  506          */
  507         if (resid > uio->uio_resid && ap->a_cred && ap->a_cred->cr_uid != 0)
  508                 ip->i_mode &= ~(ISUID | ISGID);
  509         if (error) {
  510                 if (ioflag & IO_UNIT) {
  511                         (void)UFS_TRUNCATE(vp, osize,
  512                             ioflag & IO_SYNC, ap->a_cred, uio->uio_procp);
  513                         uio->uio_offset -= resid - uio->uio_resid;
  514                         uio->uio_resid = resid;
  515                 }
  516         } else if (resid > uio->uio_resid && (ioflag & IO_SYNC))
  517                 error = UFS_UPDATE(vp, 1);
  518         if (!error)
  519                 VN_POLLEVENT(vp, POLLWRITE | (extended ? POLLEXTEND : 0));
  520 
  521         if (object)
  522                 vm_object_vndeallocate(object);
  523 
  524         return (error);
  525 }
  526 
  527 
  528 /*
  529  * get page routine
  530  */
  531 int
  532 ffs_getpages(ap)
  533         struct vop_getpages_args *ap;
  534 {
  535         off_t foff, physoffset;
  536         int i, size, bsize;
  537         struct vnode *dp, *vp;
  538         vm_object_t obj;
  539         vm_pindex_t pindex, firstindex;
  540         vm_page_t m, mreq;
  541         int bbackwards, bforwards;
  542         int pbackwards, pforwards;
  543         int firstpage;
  544         int reqlblkno;
  545         daddr_t reqblkno;
  546         int poff;
  547         int pcount;
  548         int rtval;
  549         int pagesperblock;
  550 
  551 
  552         pcount = round_page(ap->a_count) / PAGE_SIZE;
  553         mreq = ap->a_m[ap->a_reqpage];
  554         firstindex = ap->a_m[0]->pindex;
  555 
  556         /*
  557          * if ANY DEV_BSIZE blocks are valid on a large filesystem block
  558          * then, the entire page is valid --
  559          */
  560         if (mreq->valid) {
  561                 mreq->valid = VM_PAGE_BITS_ALL;
  562                 for (i = 0; i < pcount; i++) {
  563                         if (i != ap->a_reqpage) {
  564                                 vm_page_free(ap->a_m[i]);
  565                         }
  566                 }
  567                 return VM_PAGER_OK;
  568         }
  569 
  570         vp = ap->a_vp;
  571         obj = vp->v_object;
  572         bsize = vp->v_mount->mnt_stat.f_iosize;
  573         pindex = mreq->pindex;
  574         foff = IDX_TO_OFF(pindex) /* + ap->a_offset should be zero */;
  575 
  576         if (bsize < PAGE_SIZE)
  577                 return vnode_pager_generic_getpages(ap->a_vp, ap->a_m,
  578                                                     ap->a_count,
  579                                                     ap->a_reqpage);
  580             
  581 
  582         if (firstindex == 0)
  583                 vp->v_lastr = 0;
  584 
  585         if ((obj->behavior != OBJ_RANDOM) &&
  586                 ((firstindex != 0) && (firstindex <= vp->v_lastr) &&
  587                  ((firstindex + pcount) > vp->v_lastr)) ||
  588                 (obj->behavior == OBJ_SEQUENTIAL)) {
  589                 struct uio auio;
  590                 struct iovec aiov;
  591                 int error;
  592 
  593                 for (i = 0; i < pcount; i++) {
  594                         m = ap->a_m[i];
  595                         vm_page_activate(m);
  596                         vm_page_io_start(m);
  597                         vm_page_wakeup(m);
  598                 }
  599 
  600                 auio.uio_iov = &aiov;
  601                 auio.uio_iovcnt = 1;
  602                 aiov.iov_base = 0;
  603                 aiov.iov_len = MAXBSIZE;
  604                 auio.uio_resid = MAXBSIZE;
  605                 auio.uio_offset = foff;
  606                 auio.uio_segflg = UIO_NOCOPY;
  607                 auio.uio_rw = UIO_READ;
  608                 auio.uio_procp = curproc;
  609                 error = VOP_READ(vp, &auio,
  610                         IO_VMIO | ((MAXBSIZE / bsize) << 16), curproc->p_ucred);
  611 
  612                 for (i = 0; i < pcount; i++) {
  613                         m = ap->a_m[i];
  614                         vm_page_io_finish(m);
  615 
  616                         if ((m != mreq) && (m->wire_count == 0) && (m->hold_count == 0) &&
  617                                 (m->valid == 0) && (m->busy == 0) &&
  618                                 (m->flags & PG_BUSY) == 0) {
  619                                 vm_page_busy(m);
  620                                 vm_page_free(m);
  621                         } else if (m == mreq) {
  622                                 while (m->flags & PG_BUSY) {
  623                                         vm_page_sleep(m, "ffspwt", NULL);
  624                                 }
  625                                 vm_page_busy(m);
  626                                 vp->v_lastr = m->pindex + 1;
  627                         } else {
  628                                 if (m->wire_count == 0) {
  629                                         if (m->busy || (m->flags & PG_MAPPED) ||
  630                                                 (m->flags & (PG_WANTED | PG_BUSY)) == PG_WANTED) {
  631                                                 vm_page_activate(m);
  632                                         } else {
  633                                                 vm_page_deactivate(m);
  634                                         }
  635                                 }
  636                                 vp->v_lastr = m->pindex + 1;
  637                         }
  638                 }
  639 
  640                 if (mreq->valid == 0) 
  641                         return VM_PAGER_ERROR;
  642 
  643                 mreq->valid = VM_PAGE_BITS_ALL;
  644                 return VM_PAGER_OK;
  645         }
  646 
  647         /*
  648          * foff is the file offset of the required page
  649          * reqlblkno is the logical block that contains the page
  650          * poff is the index of the page into the logical block
  651          */
  652         reqlblkno = foff / bsize;
  653         poff = (foff % bsize) / PAGE_SIZE;
  654 
  655         if ( VOP_BMAP( vp, reqlblkno, &dp, &reqblkno,
  656                 &bforwards, &bbackwards) || (reqblkno == -1)) {
  657                 for(i = 0; i < pcount; i++) {
  658                         if (i != ap->a_reqpage)
  659                                 vm_page_free(ap->a_m[i]);
  660                 }
  661                 if (reqblkno == -1) {
  662                         if ((mreq->flags & PG_ZERO) == 0)
  663                                 vm_page_zero_fill(mreq);
  664                         mreq->dirty = 0;
  665                         mreq->valid = VM_PAGE_BITS_ALL;
  666                         return VM_PAGER_OK;
  667                 } else {
  668                         return VM_PAGER_ERROR;
  669                 }
  670         }
  671 
  672         physoffset = (off_t)reqblkno * DEV_BSIZE + poff * PAGE_SIZE;
  673         pagesperblock = bsize / PAGE_SIZE;
  674         /*
  675          * find the first page that is contiguous...
  676          * note that pbackwards is the number of pages that are contiguous
  677          * backwards.
  678          */
  679         firstpage = 0;
  680         if (ap->a_count) {
  681                 pbackwards = poff + bbackwards * pagesperblock;
  682                 if (ap->a_reqpage > pbackwards) {
  683                         firstpage = ap->a_reqpage - pbackwards;
  684                         for(i=0;i<firstpage;i++)
  685                                 vm_page_free(ap->a_m[i]);
  686                 }
  687 
  688         /*
  689          * pforwards is the number of pages that are contiguous
  690          * after the current page.
  691          */
  692                 pforwards = (pagesperblock - (poff + 1)) +
  693                         bforwards * pagesperblock;
  694                 if (pforwards < (pcount - (ap->a_reqpage + 1))) {
  695                         for( i = ap->a_reqpage + pforwards + 1; i < pcount; i++)
  696                                 vm_page_free(ap->a_m[i]);
  697                         pcount = ap->a_reqpage + pforwards + 1;
  698                 }
  699 
  700         /*
  701          * number of pages for I/O corrected for the non-contig pages at
  702          * the beginning of the array.
  703          */
  704                 pcount -= firstpage;
  705         }
  706 
  707         /*
  708          * calculate the size of the transfer
  709          */
  710 
  711         size = pcount * PAGE_SIZE;
  712         vp->v_lastr = mreq->pindex + pcount;
  713 
  714         if ((IDX_TO_OFF(ap->a_m[firstpage]->pindex) + size) >
  715                 obj->un_pager.vnp.vnp_size)
  716                 size = obj->un_pager.vnp.vnp_size -
  717                         IDX_TO_OFF(ap->a_m[firstpage]->pindex);
  718 
  719         physoffset -= foff;
  720         rtval = VOP_GETPAGES(dp, &ap->a_m[firstpage], size,
  721                 (ap->a_reqpage - firstpage), physoffset);
  722 
  723         return (rtval);
  724 }
  725 
  726 /*
  727  * put page routine
  728  *
  729  * XXX By default, wimp out... note that a_offset is ignored (and always
  730  * XXX has been).
  731  */
  732 int
  733 ffs_putpages(ap)
  734         struct vop_putpages_args *ap;
  735 {
  736         return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
  737                 ap->a_sync, ap->a_rtvals);
  738 }

Cache object: 193849919c04458e4f743d949aed0354


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