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/bsd/vm/vnode_pager.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) 2000-2006 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /* 
   29  * Mach Operating System
   30  * Copyright (c) 1987 Carnegie-Mellon University
   31  * All rights reserved.  The CMU software License Agreement specifies
   32  * the terms and conditions for use and redistribution.
   33  */
   34 /*
   35  *      File:   vnode_pager.c
   36  *
   37  *      "Swap" pager that pages to/from vnodes.  Also
   38  *      handles demand paging from files.
   39  *
   40  */
   41 
   42 #include <mach/boolean.h>
   43 #include <sys/param.h>
   44 #include <sys/systm.h>
   45 #include <sys/user.h>
   46 #include <sys/proc.h>
   47 #include <sys/kauth.h>
   48 #include <sys/buf.h>
   49 #include <sys/uio.h>
   50 #include <sys/vnode_internal.h>
   51 #include <sys/namei.h>
   52 #include <sys/mount_internal.h> /* needs internal due to fhandle_t */
   53 #include <sys/ubc_internal.h>
   54 #include <sys/lock.h>
   55 #include <sys/disk.h>           /* For DKIOC calls */
   56 
   57 #include <mach/mach_types.h>
   58 #include <mach/memory_object_types.h>
   59 #include <mach/memory_object_control.h>
   60 #include <mach/vm_map.h>
   61 #include <mach/mach_vm.h>
   62 #include <mach/upl.h>
   63 #include <mach/sdt.h>
   64 
   65 #include <vm/vm_map.h>
   66 #include <vm/vm_kern.h>
   67 #include <kern/zalloc.h>
   68 #include <kern/kalloc.h>
   69 #include <libkern/libkern.h>
   70 
   71 #include <vm/vnode_pager.h>
   72 #include <vm/vm_pageout.h>
   73 
   74 #include <kern/assert.h>
   75 #include <sys/kdebug.h>
   76 #include <machine/spl.h>
   77 
   78 #include <nfs/rpcv2.h>
   79 #include <nfs/nfsproto.h>
   80 #include <nfs/nfs.h>
   81 
   82 #include <vm/vm_protos.h>
   83 
   84 
   85 void
   86 vnode_pager_throttle()
   87 {
   88         struct uthread *ut;
   89 
   90         ut = get_bsdthread_info(current_thread());
   91 
   92         if (ut->uu_lowpri_window)
   93                 throttle_lowpri_io(TRUE);
   94 }
   95 
   96 
   97 boolean_t
   98 vnode_pager_isSSD(vnode_t vp)
   99 {
  100         if (vp->v_mount->mnt_kern_flag & MNTK_SSD)
  101                 return (TRUE);
  102         return (FALSE);
  103 }
  104 
  105 
  106 uint32_t
  107 vnode_pager_isinuse(struct vnode *vp)
  108 {
  109         if (vp->v_usecount > vp->v_kusecount)
  110                 return (1);
  111         return (0);
  112 }
  113 
  114 uint32_t
  115 vnode_pager_return_hard_throttle_limit(struct vnode *vp, uint32_t *limit, uint32_t hard_throttle)
  116 {
  117         return(cluster_hard_throttle_limit(vp, limit, hard_throttle));
  118 }
  119 
  120 vm_object_offset_t
  121 vnode_pager_get_filesize(struct vnode *vp)
  122 {
  123 
  124         return (vm_object_offset_t) ubc_getsize(vp);
  125 }
  126 
  127 kern_return_t
  128 vnode_pager_get_pathname(
  129         struct vnode    *vp,
  130         char            *pathname,
  131         vm_size_t       *length_p)
  132 {
  133         int     error, len;
  134 
  135         len = (int) *length_p;
  136         error = vn_getpath(vp, pathname, &len);
  137         if (error != 0) {
  138                 return KERN_FAILURE;
  139         }
  140         *length_p = (vm_size_t) len;
  141         return KERN_SUCCESS;
  142 }
  143 
  144 kern_return_t
  145 vnode_pager_get_filename(
  146         struct vnode    *vp,
  147         const char      **filename)
  148 {
  149         *filename = vp->v_name;
  150         return KERN_SUCCESS;
  151 }
  152 
  153 kern_return_t
  154 vnode_pager_get_cs_blobs(
  155         struct vnode    *vp,
  156         void            **blobs)
  157 {
  158         *blobs = ubc_get_cs_blobs(vp);
  159         return KERN_SUCCESS;
  160 }
  161 
  162 /* 
  163  * vnode_trim:
  164  * Used to call the DKIOCUNMAP ioctl on the underlying disk device for the specified vnode.
  165  * Trims the region at offset bytes into the file, for length bytes.
  166  *
  167  * Care must be taken to ensure that the vnode is sufficiently reference counted at the time this
  168  * function is called; no iocounts or usecounts are taken on the vnode.
  169  * This function is non-idempotent in error cases;  We cannot un-discard the blocks if only some of them
  170  * are successfully discarded.
  171  */
  172 u_int32_t vnode_trim (
  173                 struct vnode *vp,
  174                 off_t offset,
  175                 size_t length)
  176 {
  177         daddr64_t io_blockno;    /* Block number corresponding to the start of the extent */
  178         size_t io_bytecount;    /* Number of bytes in current extent for the specified range */
  179         size_t trimmed = 0;
  180         off_t current_offset = offset; 
  181         size_t remaining_length = length;
  182         int error = 0;
  183         u_int32_t blocksize = 0;
  184         struct vnode *devvp;
  185         dk_extent_t extent;
  186         dk_unmap_t unmap;
  187 
  188 
  189         /* Get the underlying device vnode */
  190         devvp = vp->v_mount->mnt_devvp;
  191 
  192         /* Figure out the underlying device block size */
  193         error  = VNOP_IOCTL(devvp, DKIOCGETBLOCKSIZE, (caddr_t)&blocksize, 0, vfs_context_kernel());
  194         if (error) {
  195                 goto trim_exit;
  196         }
  197 
  198         /* 
  199          * We may not get the entire range from offset -> offset+length in a single
  200          * extent from the blockmap call.  Keep looping/going until we are sure we've hit
  201          * the whole range or if we encounter an error.
  202          */
  203         while (trimmed < length) {
  204                 /*
  205                  * VNOP_BLOCKMAP will tell us the logical to physical block number mapping for the
  206                  * specified offset.  It returns blocks in contiguous chunks, so if the logical range is 
  207                  * broken into multiple extents, it must be called multiple times, increasing the offset
  208                  * in each call to ensure that the entire range is covered.
  209                  */
  210                 error = VNOP_BLOCKMAP (vp, current_offset, remaining_length, 
  211                                 &io_blockno, &io_bytecount, NULL, VNODE_READ, NULL);
  212 
  213                 if (error) {
  214                         goto trim_exit;
  215                 }
  216                 /* 
  217                  * We have a contiguous run.  Prepare & issue the ioctl for the device.
  218                  * the DKIOCUNMAP ioctl takes offset in bytes from the start of the device.
  219                  */
  220                 memset (&extent, 0, sizeof(dk_extent_t));
  221                 memset (&unmap, 0, sizeof(dk_unmap_t));
  222                 extent.offset = (uint64_t) io_blockno * (u_int64_t) blocksize;
  223                 extent.length = io_bytecount;
  224                 unmap.extents = &extent;
  225                 unmap.extentsCount = 1;
  226                 error = VNOP_IOCTL(devvp, DKIOCUNMAP, (caddr_t)&unmap, 0, vfs_context_kernel());
  227 
  228                 if (error) {
  229                         goto trim_exit;
  230                 }
  231                 remaining_length = remaining_length - io_bytecount;
  232                 trimmed = trimmed + io_bytecount;
  233                 current_offset = current_offset + io_bytecount;
  234         }
  235 trim_exit:
  236 
  237         return error;
  238 
  239 }
  240 
  241 pager_return_t
  242 vnode_pageout(struct vnode *vp,
  243         upl_t                   upl,
  244         upl_offset_t            upl_offset,
  245         vm_object_offset_t      f_offset,
  246         upl_size_t              size,
  247         int                     flags,
  248         int                     *errorp)
  249 {
  250         int             result = PAGER_SUCCESS;
  251         int             error = 0;
  252         int             error_ret = 0;
  253         daddr64_t blkno;
  254         int isize;
  255         int pg_index;
  256         int base_index;
  257         upl_offset_t offset;
  258         upl_page_info_t *pl;
  259         vfs_context_t ctx = vfs_context_current();      /* pager context */
  260 
  261         isize = (int)size;
  262 
  263         if (isize <= 0) {
  264                 result    = PAGER_ERROR;
  265                 error_ret = EINVAL;
  266                 goto out;
  267         }
  268 
  269         if (UBCINFOEXISTS(vp) == 0) {
  270                 result    = PAGER_ERROR;
  271                 error_ret = EINVAL;
  272 
  273                 if (upl && !(flags & UPL_NOCOMMIT))
  274                         ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY);
  275                 goto out;
  276         }
  277         if ( !(flags & UPL_VNODE_PAGER)) {
  278                 /*
  279                  * This is a pageout from the default pager,
  280                  * just go ahead and call vnop_pageout since
  281                  * it has already sorted out the dirty ranges
  282                  */
  283                 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
  284                         (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, 
  285                         size, 1, 0, 0, 0);
  286 
  287                 if ( (error_ret = VNOP_PAGEOUT(vp, upl, upl_offset, (off_t)f_offset,
  288                                                (size_t)size, flags, ctx)) )
  289                         result = PAGER_ERROR;
  290 
  291                 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
  292                         (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, 
  293                         size, 1, 0, 0, 0);
  294 
  295                 goto out;
  296         }
  297         if (upl == NULL) {
  298                 int                     request_flags;
  299 
  300                 if (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_PAGEOUTV2) {
  301                         /*
  302                          * filesystem has requested the new form of VNOP_PAGEOUT for file
  303                          * backed objects... we will not grab the UPL befofe calling VNOP_PAGEOUT...
  304                          * it is the fileystem's responsibility to grab the range we're denoting
  305                          * via 'f_offset' and 'size' into a UPL... this allows the filesystem to first
  306                          * take any locks it needs, before effectively locking the pages into a UPL...
  307                          */
  308                         KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, 
  309                                 (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, 
  310                                 size, (int)f_offset, 0, 0, 0);
  311 
  312                         if ( (error_ret = VNOP_PAGEOUT(vp, NULL, upl_offset, (off_t)f_offset,
  313                                                        size, flags, ctx)) ) {
  314                                 result = PAGER_ERROR;
  315                         }
  316                         KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
  317                                 (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, 
  318                                 size, 0, 0, 0, 0);
  319 
  320                         goto out;
  321                 }
  322                 if (flags & UPL_MSYNC)
  323                         request_flags = UPL_UBC_MSYNC | UPL_RET_ONLY_DIRTY;
  324                 else
  325                         request_flags = UPL_UBC_PAGEOUT | UPL_RET_ONLY_DIRTY;
  326                 
  327                 if (ubc_create_upl(vp, f_offset, size, &upl, &pl, request_flags) != KERN_SUCCESS) {
  328                         result    = PAGER_ERROR;
  329                         error_ret = EINVAL;
  330                         goto out;
  331                 }
  332                 upl_offset = 0;
  333         } else 
  334                 pl = ubc_upl_pageinfo(upl);
  335 
  336         /*
  337          * we come here for pageouts to 'real' files and
  338          * for msyncs...  the upl may not contain any
  339          * dirty pages.. it's our responsibility to sort
  340          * through it and find the 'runs' of dirty pages
  341          * to call VNOP_PAGEOUT on...
  342          */
  343         if (ubc_getsize(vp) == 0) {
  344                 /*
  345                  * if the file has been effectively deleted, then
  346                  * we need to go through the UPL and invalidate any
  347                  * buffer headers we might have that reference any
  348                  * of it's pages
  349                  */
  350                 for (offset = upl_offset; isize; isize -= PAGE_SIZE, offset += PAGE_SIZE) {
  351 #if NFSCLIENT
  352                         if (vp->v_tag == VT_NFS)
  353                                 /* check with nfs if page is OK to drop */
  354                                 error = nfs_buf_page_inval(vp, (off_t)f_offset);
  355                         else
  356 #endif
  357                         {
  358                                 blkno = ubc_offtoblk(vp, (off_t)f_offset);
  359                                 error = buf_invalblkno(vp, blkno, 0);
  360                         }
  361                         if (error) {
  362                                 if ( !(flags & UPL_NOCOMMIT))
  363                                         ubc_upl_abort_range(upl, offset, PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY);
  364                                 if (error_ret == 0)
  365                                         error_ret = error;
  366                                 result = PAGER_ERROR;
  367 
  368                         } else if ( !(flags & UPL_NOCOMMIT)) {
  369                                 ubc_upl_commit_range(upl, offset, PAGE_SIZE, UPL_COMMIT_FREE_ON_EMPTY);
  370                         }
  371                         f_offset += PAGE_SIZE;
  372                 }
  373                 goto out;
  374         }
  375         /*
  376          * Ignore any non-present pages at the end of the
  377          * UPL so that we aren't looking at a upl that 
  378          * may already have been freed by the preceeding
  379          * aborts/completions.
  380          */
  381         base_index = upl_offset / PAGE_SIZE;
  382 
  383         for (pg_index = (upl_offset + isize) / PAGE_SIZE; pg_index > base_index;) {
  384                 if (upl_page_present(pl, --pg_index))
  385                         break;
  386                 if (pg_index == base_index) {
  387                         /*
  388                          * no pages were returned, so release
  389                          * our hold on the upl and leave
  390                          */
  391                         if ( !(flags & UPL_NOCOMMIT))
  392                                 ubc_upl_abort_range(upl, upl_offset, isize, UPL_ABORT_FREE_ON_EMPTY);
  393 
  394                         goto out;
  395                 }
  396         }
  397         isize = ((pg_index + 1) - base_index) * PAGE_SIZE;
  398 
  399         offset = upl_offset;
  400         pg_index = base_index;
  401 
  402         while (isize) {
  403                 int  xsize;
  404                 int  num_of_pages;
  405 
  406                 if ( !upl_page_present(pl, pg_index)) {
  407                         /*
  408                          * we asked for RET_ONLY_DIRTY, so it's possible
  409                          * to get back empty slots in the UPL
  410                          * just skip over them
  411                          */
  412                         f_offset += PAGE_SIZE;
  413                         offset   += PAGE_SIZE;
  414                         isize    -= PAGE_SIZE;
  415                         pg_index++;
  416 
  417                         continue;
  418                 }
  419                 if ( !upl_dirty_page(pl, pg_index)) {
  420                         /*
  421                          * if the page is not dirty and reached here it is
  422                          * marked precious or it is due to invalidation in
  423                          * memory_object_lock request as part of truncation
  424                          * We also get here from vm_object_terminate()
  425                          * So all you need to do in these
  426                          * cases is to invalidate incore buffer if it is there
  427                          * Note we must not sleep here if the buffer is busy - that is
  428                          * a lock inversion which causes deadlock.
  429                          */
  430 #if NFSCLIENT
  431                         if (vp->v_tag == VT_NFS)
  432                                 /* check with nfs if page is OK to drop */
  433                                 error = nfs_buf_page_inval(vp, (off_t)f_offset);
  434                         else
  435 #endif
  436                         {
  437                                 blkno = ubc_offtoblk(vp, (off_t)f_offset);
  438                                 error = buf_invalblkno(vp, blkno, 0);
  439                         }
  440                         if (error) {
  441                                 if ( !(flags & UPL_NOCOMMIT))
  442                                         ubc_upl_abort_range(upl, offset, PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY);
  443                                 if (error_ret == 0)
  444                                         error_ret = error;
  445                                 result = PAGER_ERROR;
  446 
  447                         } else if ( !(flags & UPL_NOCOMMIT)) {
  448                                 ubc_upl_commit_range(upl, offset, PAGE_SIZE, UPL_COMMIT_FREE_ON_EMPTY);
  449                         }
  450                         f_offset += PAGE_SIZE;
  451                         offset   += PAGE_SIZE;
  452                         isize    -= PAGE_SIZE;
  453                         pg_index++;
  454 
  455                         continue;
  456                 }
  457                 num_of_pages = 1;
  458                 xsize = isize - PAGE_SIZE;
  459 
  460                 while (xsize) {
  461                         if ( !upl_dirty_page(pl, pg_index + num_of_pages))
  462                                 break;
  463                         num_of_pages++;
  464                         xsize -= PAGE_SIZE;
  465                 }
  466                 xsize = num_of_pages * PAGE_SIZE;
  467 
  468                 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
  469                         (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, 
  470                         xsize, (int)f_offset, 0, 0, 0);
  471 
  472                 if ( (error = VNOP_PAGEOUT(vp, upl, offset, (off_t)f_offset,
  473                                            xsize, flags, ctx)) ) {
  474                         if (error_ret == 0)
  475                                 error_ret = error;
  476                         result = PAGER_ERROR;
  477                 }
  478                 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
  479                         (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, 
  480                         xsize, 0, 0, 0, 0);
  481 
  482                 f_offset += xsize;
  483                 offset   += xsize;
  484                 isize    -= xsize;
  485                 pg_index += num_of_pages;
  486         }
  487 out:
  488         if (errorp)
  489                 *errorp = error_ret;
  490 
  491         return (result);
  492 }
  493 
  494 
  495 pager_return_t
  496 vnode_pagein(
  497         struct vnode            *vp,
  498         upl_t                   upl,
  499         upl_offset_t            upl_offset,
  500         vm_object_offset_t      f_offset,
  501         upl_size_t              size,
  502         int                     flags,
  503         int                     *errorp)
  504 {
  505         upl_page_info_t *pl;
  506         int             result = PAGER_SUCCESS;
  507         int             error = 0;
  508         int             pages_in_upl;
  509         int             start_pg;
  510         int             last_pg;
  511         int             first_pg;
  512         int             xsize;
  513         int             must_commit = 1;
  514 
  515         if (flags & UPL_NOCOMMIT)
  516                 must_commit = 0;
  517 
  518         if (UBCINFOEXISTS(vp) == 0) {
  519                 result = PAGER_ERROR;
  520                 error  = PAGER_ERROR;
  521 
  522                 if (upl && must_commit)
  523                         ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
  524 
  525                 goto out;
  526         }
  527         if (upl == (upl_t)NULL) {
  528                 flags &= ~UPL_NOCOMMIT;
  529 
  530                 if (size > (MAX_UPL_SIZE * PAGE_SIZE)) {
  531                         result = PAGER_ERROR;
  532                         error  = PAGER_ERROR;
  533                         goto out;
  534                 }
  535                 if (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_PAGEINV2) {
  536                         /*
  537                          * filesystem has requested the new form of VNOP_PAGEIN for file
  538                          * backed objects... we will not grab the UPL befofe calling VNOP_PAGEIN...
  539                          * it is the fileystem's responsibility to grab the range we're denoting
  540                          * via 'f_offset' and 'size' into a UPL... this allows the filesystem to first
  541                          * take any locks it needs, before effectively locking the pages into a UPL...
  542                          * so we pass a NULL into the filesystem instead of a UPL pointer... the 'upl_offset'
  543                          * is used to identify the "must have" page in the extent... the filesystem is free
  544                          * to clip the extent to better fit the underlying FS blocksize if it desires as 
  545                          * long as it continues to include the "must have" page... 'f_offset' + 'upl_offset'
  546                          * identifies that page
  547                          */
  548                         if ( (error = VNOP_PAGEIN(vp, NULL, upl_offset, (off_t)f_offset,
  549                                                   size, flags, vfs_context_current())) ) {
  550                                 result = PAGER_ERROR;
  551                                 error  = PAGER_ERROR;
  552                         }
  553                         goto out;
  554                 }
  555                 ubc_create_upl(vp, f_offset, size, &upl, &pl, UPL_UBC_PAGEIN | UPL_RET_ONLY_ABSENT);
  556 
  557                 if (upl == (upl_t)NULL) {
  558                         result =  PAGER_ABSENT;
  559                         error = PAGER_ABSENT;
  560                         goto out;
  561                 }
  562                 ubc_upl_range_needed(upl, upl_offset / PAGE_SIZE, 1);
  563 
  564                 upl_offset = 0;
  565                 first_pg = 0;
  566                 
  567                 /*
  568                  * if we get here, we've created the upl and
  569                  * are responsible for commiting/aborting it
  570                  * regardless of what the caller has passed in
  571                  */
  572                 must_commit = 1;
  573         } else {
  574                 pl = ubc_upl_pageinfo(upl);
  575                 first_pg = upl_offset / PAGE_SIZE;
  576         }
  577         pages_in_upl = size / PAGE_SIZE;
  578         DTRACE_VM2(pgpgin, int, pages_in_upl, (uint64_t *), NULL);
  579 
  580         /*
  581          * before we start marching forward, we must make sure we end on 
  582          * a present page, otherwise we will be working with a freed
  583          * upl
  584          */
  585         for (last_pg = pages_in_upl - 1; last_pg >= first_pg; last_pg--) {
  586                 if (upl_page_present(pl, last_pg))
  587                         break;
  588                 if (last_pg == first_pg) {
  589                         /*
  590                          * empty UPL, no pages are present
  591                          */
  592                         if (must_commit)
  593                                 ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY);
  594                         goto out;
  595                 }
  596         }
  597         pages_in_upl = last_pg + 1;
  598         last_pg = first_pg;
  599 
  600         while (last_pg < pages_in_upl) {
  601                 /*
  602                  * skip over missing pages...
  603                  */
  604                 for ( ; last_pg < pages_in_upl; last_pg++) {
  605                         if (upl_page_present(pl, last_pg))
  606                                 break;
  607                 }
  608                 /*
  609                  * skip over 'valid' pages... we don't want to issue I/O for these
  610                  */
  611                 for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) {
  612                         if (!upl_valid_page(pl, last_pg))
  613                                 break;
  614                 }
  615                 if (last_pg > start_pg) {
  616                         /*
  617                          * we've found a range of valid pages
  618                          * if we've got COMMIT responsibility
  619                          * commit this range of pages back to the
  620                          * cache unchanged
  621                          */
  622                         xsize = (last_pg - start_pg) * PAGE_SIZE;
  623 
  624                         if (must_commit)
  625                                 ubc_upl_abort_range(upl, start_pg * PAGE_SIZE, xsize, UPL_ABORT_FREE_ON_EMPTY);
  626                 }
  627                 if (last_pg == pages_in_upl)
  628                         /*
  629                          * we're done... all pages that were present
  630                          * have either had I/O issued on them or 
  631                          * were aborted unchanged...
  632                          */
  633                         break;
  634 
  635                 if (!upl_page_present(pl, last_pg)) {
  636                         /*
  637                          * we found a range of valid pages 
  638                          * terminated by a missing page...
  639                          * bump index to the next page and continue on
  640                          */
  641                         last_pg++;
  642                         continue;
  643                 }
  644                 /*
  645                  * scan from the found invalid page looking for a valid
  646                  * or non-present page before the end of the upl is reached, if we
  647                  * find one, then it will be the last page of the request to
  648                  * 'cluster_io'
  649                  */
  650                 for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) {
  651                         if (upl_valid_page(pl, last_pg) || !upl_page_present(pl, last_pg))
  652                                 break;
  653                 }
  654                 if (last_pg > start_pg) {
  655                         int xoff;
  656                         xsize = (last_pg - start_pg) * PAGE_SIZE;
  657                         xoff  = start_pg * PAGE_SIZE;
  658 
  659                         if ( (error = VNOP_PAGEIN(vp, upl, (upl_offset_t) xoff,
  660                                                (off_t)f_offset + xoff,
  661                                                xsize, flags, vfs_context_current())) ) {
  662                                 /*
  663                                  * Usually this UPL will be aborted/committed by the lower cluster layer.
  664                                  *
  665                                  * a)   In the case of decmpfs, however, we may return an error (EAGAIN) to avoid
  666                                  *      a deadlock with another thread already inflating the file. 
  667                                  *
  668                                  * b)   In the case of content protection, EPERM is a valid error and we should respect it.
  669                                  *
  670                                  * In those cases, we must take care of our UPL at this layer itself.
  671                                  */
  672                                 if (must_commit) {
  673                                         if(error == EAGAIN) {
  674                                                 ubc_upl_abort_range(upl, (upl_offset_t) xoff, xsize, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_RESTART);
  675                                         }
  676 #if CONFIG_PROTECT
  677                                         if(error == EPERM) {
  678                                                 ubc_upl_abort_range(upl, (upl_offset_t) xoff, xsize, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
  679                                         }
  680 #endif
  681                                 }
  682                                 result = PAGER_ERROR;
  683                                 error  = PAGER_ERROR;
  684 
  685                         }
  686                 }
  687         }
  688 out:
  689         if (errorp)
  690                 *errorp = result;
  691 
  692         return (error);
  693 }
  694 
  695 void
  696 vnode_pager_shutdown(void)
  697 {
  698         int i;
  699         vnode_t vp;
  700 
  701         for(i = 0; i < MAX_BACKING_STORE; i++) {
  702                 vp = (vnode_t)(bs_port_table[i]).vp;
  703                 if (vp) {
  704                         (bs_port_table[i]).vp = 0;
  705 
  706                         /* get rid of macx_swapon() reference */
  707                         vnode_rele(vp);
  708                 }
  709         }
  710 }
  711 
  712 
  713 void *
  714 upl_get_internal_page_list(upl_t upl)
  715 {
  716   return(UPL_GET_INTERNAL_PAGE_LIST(upl));
  717 
  718 }

Cache object: 9e624680315864ff9f95a0559be340f7


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