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((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, 
  284                                       size, 1, 0, 0, 0);
  285 
  286                 if ( (error_ret = VNOP_PAGEOUT(vp, upl, upl_offset, (off_t)f_offset,
  287                                                (size_t)size, flags, ctx)) )
  288                         result = PAGER_ERROR;
  289 
  290                 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, 
  291                                       size, 1, 0, 0, 0);
  292 
  293                 goto out;
  294         }
  295         if (upl == NULL) {
  296                 int                     request_flags;
  297 
  298                 if (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_PAGEOUTV2) {
  299                         /*
  300                          * filesystem has requested the new form of VNOP_PAGEOUT for file
  301                          * backed objects... we will not grab the UPL befofe calling VNOP_PAGEOUT...
  302                          * it is the fileystem's responsibility to grab the range we're denoting
  303                          * via 'f_offset' and 'size' into a UPL... this allows the filesystem to first
  304                          * take any locks it needs, before effectively locking the pages into a UPL...
  305                          */
  306                         KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, 
  307                                               size, (int)f_offset, 0, 0, 0);
  308 
  309                         if ( (error_ret = VNOP_PAGEOUT(vp, NULL, upl_offset, (off_t)f_offset,
  310                                                        size, flags, ctx)) ) {
  311                                 result = PAGER_ERROR;
  312                         }
  313                         KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, 
  314                                               size, 0, 0, 0, 0);
  315 
  316                         goto out;
  317                 }
  318                 if (flags & UPL_MSYNC)
  319                         request_flags = UPL_UBC_MSYNC | UPL_RET_ONLY_DIRTY;
  320                 else
  321                         request_flags = UPL_UBC_PAGEOUT | UPL_RET_ONLY_DIRTY;
  322                 
  323                 if (ubc_create_upl(vp, f_offset, size, &upl, &pl, request_flags) != KERN_SUCCESS) {
  324                         result    = PAGER_ERROR;
  325                         error_ret = EINVAL;
  326                         goto out;
  327                 }
  328                 upl_offset = 0;
  329         } else 
  330                 pl = ubc_upl_pageinfo(upl);
  331 
  332         /*
  333          * we come here for pageouts to 'real' files and
  334          * for msyncs...  the upl may not contain any
  335          * dirty pages.. it's our responsibility to sort
  336          * through it and find the 'runs' of dirty pages
  337          * to call VNOP_PAGEOUT on...
  338          */
  339         if (ubc_getsize(vp) == 0) {
  340                 /*
  341                  * if the file has been effectively deleted, then
  342                  * we need to go through the UPL and invalidate any
  343                  * buffer headers we might have that reference any
  344                  * of it's pages
  345                  */
  346                 for (offset = upl_offset; isize; isize -= PAGE_SIZE, offset += PAGE_SIZE) {
  347 #if NFSCLIENT
  348                         if (vp->v_tag == VT_NFS)
  349                                 /* check with nfs if page is OK to drop */
  350                                 error = nfs_buf_page_inval(vp, (off_t)f_offset);
  351                         else
  352 #endif
  353                         {
  354                                 blkno = ubc_offtoblk(vp, (off_t)f_offset);
  355                                 error = buf_invalblkno(vp, blkno, 0);
  356                         }
  357                         if (error) {
  358                                 if ( !(flags & UPL_NOCOMMIT))
  359                                         ubc_upl_abort_range(upl, offset, PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY);
  360                                 if (error_ret == 0)
  361                                         error_ret = error;
  362                                 result = PAGER_ERROR;
  363 
  364                         } else if ( !(flags & UPL_NOCOMMIT)) {
  365                                 ubc_upl_commit_range(upl, offset, PAGE_SIZE, UPL_COMMIT_FREE_ON_EMPTY);
  366                         }
  367                         f_offset += PAGE_SIZE;
  368                 }
  369                 goto out;
  370         }
  371         /*
  372          * Ignore any non-present pages at the end of the
  373          * UPL so that we aren't looking at a upl that 
  374          * may already have been freed by the preceeding
  375          * aborts/completions.
  376          */
  377         base_index = upl_offset / PAGE_SIZE;
  378 
  379         for (pg_index = (upl_offset + isize) / PAGE_SIZE; pg_index > base_index;) {
  380                 if (upl_page_present(pl, --pg_index))
  381                         break;
  382                 if (pg_index == base_index) {
  383                         /*
  384                          * no pages were returned, so release
  385                          * our hold on the upl and leave
  386                          */
  387                         if ( !(flags & UPL_NOCOMMIT))
  388                                 ubc_upl_abort_range(upl, upl_offset, isize, UPL_ABORT_FREE_ON_EMPTY);
  389 
  390                         goto out;
  391                 }
  392         }
  393         isize = ((pg_index + 1) - base_index) * PAGE_SIZE;
  394 
  395         offset = upl_offset;
  396         pg_index = base_index;
  397 
  398         while (isize) {
  399                 int  xsize;
  400                 int  num_of_pages;
  401 
  402                 if ( !upl_page_present(pl, pg_index)) {
  403                         /*
  404                          * we asked for RET_ONLY_DIRTY, so it's possible
  405                          * to get back empty slots in the UPL
  406                          * just skip over them
  407                          */
  408                         f_offset += PAGE_SIZE;
  409                         offset   += PAGE_SIZE;
  410                         isize    -= PAGE_SIZE;
  411                         pg_index++;
  412 
  413                         continue;
  414                 }
  415                 if ( !upl_dirty_page(pl, pg_index)) {
  416                         /*
  417                          * if the page is not dirty and reached here it is
  418                          * marked precious or it is due to invalidation in
  419                          * memory_object_lock request as part of truncation
  420                          * We also get here from vm_object_terminate()
  421                          * So all you need to do in these
  422                          * cases is to invalidate incore buffer if it is there
  423                          * Note we must not sleep here if the buffer is busy - that is
  424                          * a lock inversion which causes deadlock.
  425                          */
  426 #if NFSCLIENT
  427                         if (vp->v_tag == VT_NFS)
  428                                 /* check with nfs if page is OK to drop */
  429                                 error = nfs_buf_page_inval(vp, (off_t)f_offset);
  430                         else
  431 #endif
  432                         {
  433                                 blkno = ubc_offtoblk(vp, (off_t)f_offset);
  434                                 error = buf_invalblkno(vp, blkno, 0);
  435                         }
  436                         if (error) {
  437                                 if ( !(flags & UPL_NOCOMMIT))
  438                                         ubc_upl_abort_range(upl, offset, PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY);
  439                                 if (error_ret == 0)
  440                                         error_ret = error;
  441                                 result = PAGER_ERROR;
  442 
  443                         } else if ( !(flags & UPL_NOCOMMIT)) {
  444                                 ubc_upl_commit_range(upl, offset, PAGE_SIZE, UPL_COMMIT_FREE_ON_EMPTY);
  445                         }
  446                         f_offset += PAGE_SIZE;
  447                         offset   += PAGE_SIZE;
  448                         isize    -= PAGE_SIZE;
  449                         pg_index++;
  450 
  451                         continue;
  452                 }
  453                 num_of_pages = 1;
  454                 xsize = isize - PAGE_SIZE;
  455 
  456                 while (xsize) {
  457                         if ( !upl_dirty_page(pl, pg_index + num_of_pages))
  458                                 break;
  459                         num_of_pages++;
  460                         xsize -= PAGE_SIZE;
  461                 }
  462                 xsize = num_of_pages * PAGE_SIZE;
  463 
  464                 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START, 
  465                                       xsize, (int)f_offset, 0, 0, 0);
  466 
  467                 if ( (error = VNOP_PAGEOUT(vp, upl, offset, (off_t)f_offset,
  468                                            xsize, flags, ctx)) ) {
  469                         if (error_ret == 0)
  470                                 error_ret = error;
  471                         result = PAGER_ERROR;
  472                 }
  473                 KERNEL_DEBUG_CONSTANT((MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END, 
  474                                       xsize, 0, 0, 0, 0);
  475 
  476                 f_offset += xsize;
  477                 offset   += xsize;
  478                 isize    -= xsize;
  479                 pg_index += num_of_pages;
  480         }
  481 out:
  482         if (errorp)
  483                 *errorp = error_ret;
  484 
  485         return (result);
  486 }
  487 
  488 
  489 pager_return_t
  490 vnode_pagein(
  491         struct vnode            *vp,
  492         upl_t                   upl,
  493         upl_offset_t            upl_offset,
  494         vm_object_offset_t      f_offset,
  495         upl_size_t              size,
  496         int                     flags,
  497         int                     *errorp)
  498 {
  499         struct uthread  *ut;
  500         upl_page_info_t *pl;
  501         int             result = PAGER_SUCCESS;
  502         int             error = 0;
  503         int             pages_in_upl;
  504         int             start_pg;
  505         int             last_pg;
  506         int             first_pg;
  507         int             xsize;
  508         int             must_commit = 1;
  509 
  510         if (flags & UPL_NOCOMMIT)
  511                 must_commit = 0;
  512 
  513         if (UBCINFOEXISTS(vp) == 0) {
  514                 result = PAGER_ERROR;
  515                 error  = PAGER_ERROR;
  516 
  517                 if (upl && must_commit)
  518                         ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
  519 
  520                 goto out;
  521         }
  522         if (upl == (upl_t)NULL) {
  523                 flags &= ~UPL_NOCOMMIT;
  524 
  525                 if (size > (MAX_UPL_SIZE * PAGE_SIZE)) {
  526                         result = PAGER_ERROR;
  527                         error  = PAGER_ERROR;
  528                         goto out;
  529                 }
  530                 if (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_PAGEINV2) {
  531                         /*
  532                          * filesystem has requested the new form of VNOP_PAGEIN for file
  533                          * backed objects... we will not grab the UPL befofe calling VNOP_PAGEIN...
  534                          * it is the fileystem's responsibility to grab the range we're denoting
  535                          * via 'f_offset' and 'size' into a UPL... this allows the filesystem to first
  536                          * take any locks it needs, before effectively locking the pages into a UPL...
  537                          * so we pass a NULL into the filesystem instead of a UPL pointer... the 'upl_offset'
  538                          * is used to identify the "must have" page in the extent... the filesystem is free
  539                          * to clip the extent to better fit the underlying FS blocksize if it desires as 
  540                          * long as it continues to include the "must have" page... 'f_offset' + 'upl_offset'
  541                          * identifies that page
  542                          */
  543                         if ( (error = VNOP_PAGEIN(vp, NULL, upl_offset, (off_t)f_offset,
  544                                                   size, flags, vfs_context_current())) ) {
  545                                 result = PAGER_ERROR;
  546                                 error  = PAGER_ERROR;
  547                         }
  548                         goto out;
  549                 }
  550                 ubc_create_upl(vp, f_offset, size, &upl, &pl, UPL_UBC_PAGEIN | UPL_RET_ONLY_ABSENT);
  551 
  552                 if (upl == (upl_t)NULL) {
  553                         result =  PAGER_ABSENT;
  554                         error = PAGER_ABSENT;
  555                         goto out;
  556                 }
  557                 upl_offset = 0;
  558                 first_pg = 0;
  559                 
  560                 /*
  561                  * if we get here, we've created the upl and
  562                  * are responsible for commiting/aborting it
  563                  * regardless of what the caller has passed in
  564                  */
  565                 must_commit = 1;
  566         } else {
  567                 pl = ubc_upl_pageinfo(upl);
  568                 first_pg = upl_offset / PAGE_SIZE;
  569         }
  570         pages_in_upl = size / PAGE_SIZE;
  571         DTRACE_VM2(pgpgin, int, pages_in_upl, (uint64_t *), NULL);
  572 
  573         /*
  574          * before we start marching forward, we must make sure we end on 
  575          * a present page, otherwise we will be working with a freed
  576          * upl
  577          */
  578         for (last_pg = pages_in_upl - 1; last_pg >= first_pg; last_pg--) {
  579                 if (upl_page_present(pl, last_pg))
  580                         break;
  581                 if (last_pg == first_pg) {
  582                         /*
  583                          * empty UPL, no pages are present
  584                          */
  585                         if (must_commit)
  586                                 ubc_upl_abort_range(upl, upl_offset, size, UPL_ABORT_FREE_ON_EMPTY);
  587                         goto out;
  588                 }
  589         }
  590         pages_in_upl = last_pg + 1;
  591         last_pg = first_pg;
  592 
  593         while (last_pg < pages_in_upl) {
  594                 /*
  595                  * skip over missing pages...
  596                  */
  597                 for ( ; last_pg < pages_in_upl; last_pg++) {
  598                         if (upl_page_present(pl, last_pg))
  599                                 break;
  600                 }
  601                 /*
  602                  * skip over 'valid' pages... we don't want to issue I/O for these
  603                  */
  604                 for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) {
  605                         if (!upl_valid_page(pl, last_pg))
  606                                 break;
  607                 }
  608                 if (last_pg > start_pg) {
  609                         /*
  610                          * we've found a range of valid pages
  611                          * if we've got COMMIT responsibility
  612                          * commit this range of pages back to the
  613                          * cache unchanged
  614                          */
  615                         xsize = (last_pg - start_pg) * PAGE_SIZE;
  616 
  617                         if (must_commit)
  618                                 ubc_upl_abort_range(upl, start_pg * PAGE_SIZE, xsize, UPL_ABORT_FREE_ON_EMPTY);
  619                 }
  620                 if (last_pg == pages_in_upl)
  621                         /*
  622                          * we're done... all pages that were present
  623                          * have either had I/O issued on them or 
  624                          * were aborted unchanged...
  625                          */
  626                         break;
  627 
  628                 if (!upl_page_present(pl, last_pg)) {
  629                         /*
  630                          * we found a range of valid pages 
  631                          * terminated by a missing page...
  632                          * bump index to the next page and continue on
  633                          */
  634                         last_pg++;
  635                         continue;
  636                 }
  637                 /*
  638                  * scan from the found invalid page looking for a valid
  639                  * or non-present page before the end of the upl is reached, if we
  640                  * find one, then it will be the last page of the request to
  641                  * 'cluster_io'
  642                  */
  643                 for (start_pg = last_pg; last_pg < pages_in_upl; last_pg++) {
  644                         if (upl_valid_page(pl, last_pg) || !upl_page_present(pl, last_pg))
  645                                 break;
  646                 }
  647                 if (last_pg > start_pg) {
  648                         int xoff;
  649                         xsize = (last_pg - start_pg) * PAGE_SIZE;
  650                         xoff  = start_pg * PAGE_SIZE;
  651 
  652                         if ( (error = VNOP_PAGEIN(vp, upl, (upl_offset_t) xoff,
  653                                                (off_t)f_offset + xoff,
  654                                                xsize, flags, vfs_context_current())) ) {
  655                                 /*
  656                                  * Usually this UPL will be aborted/committed by the lower cluster layer.
  657                                  *
  658                                  * a)   In the case of decmpfs, however, we may return an error (EAGAIN) to avoid
  659                                  *      a deadlock with another thread already inflating the file. 
  660                                  *
  661                                  * b)   In the case of content protection, EPERM is a valid error and we should respect it.
  662                                  *
  663                                  * In those cases, we must take care of our UPL at this layer itself.
  664                                  */
  665                                 if (must_commit) {
  666                                         if(error == EAGAIN) {
  667                                                 ubc_upl_abort_range(upl, (upl_offset_t) xoff, xsize, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_RESTART);
  668                                         }
  669 #if CONFIG_PROTECT
  670                                         if(error == EPERM) {
  671                                                 ubc_upl_abort_range(upl, (upl_offset_t) xoff, xsize, UPL_ABORT_FREE_ON_EMPTY | UPL_ABORT_ERROR);
  672                                         }
  673 #endif
  674                                 }
  675                                 result = PAGER_ERROR;
  676                                 error  = PAGER_ERROR;
  677 
  678                         }
  679                 }
  680         }
  681 out:
  682         if (errorp)
  683                 *errorp = result;
  684 
  685         ut = get_bsdthread_info(current_thread());
  686 
  687         if (ut->uu_lowpri_window) {
  688                 /*
  689                  * task is marked as a low priority I/O type
  690                  * and the I/O we issued while in this page fault
  691                  * collided with normal I/O operations... we'll
  692                  * delay in order to mitigate the impact of this
  693                  * task on the normal operation of the system
  694                  */
  695                 throttle_lowpri_io(TRUE);
  696         }
  697         return (error);
  698 }
  699 
  700 void
  701 vnode_pager_shutdown(void)
  702 {
  703         int i;
  704         vnode_t vp;
  705 
  706         for(i = 0; i < MAX_BACKING_STORE; i++) {
  707                 vp = (vnode_t)(bs_port_table[i]).vp;
  708                 if (vp) {
  709                         (bs_port_table[i]).vp = 0;
  710 
  711                         /* get rid of macx_swapon() reference */
  712                         vnode_rele(vp);
  713                 }
  714         }
  715 }
  716 
  717 
  718 void *
  719 upl_get_internal_page_list(upl_t upl)
  720 {
  721   return(UPL_GET_INTERNAL_PAGE_LIST(upl));
  722 
  723 }

Cache object: ebb0b17a7a4d794618390a9c419e5b5b


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