- ubc_create_upl( vp,
- f_offset,
- isize,
- &vpupl,
- &pl,
- UPL_COPYOUT_FROM);
- if (vpupl == (upl_t) 0)
- return PAGER_ABSENT;
-
- vp_size = ubc_getsize(vp);
- if (vp_size == 0) {
-
- while (isize) {
- blkno = ubc_offtoblk(vp, (off_t)f_offset);
-start0:
- if (bp = incore(vp, blkno)) {
- if (ISSET(bp->b_flags, B_BUSY)) {
- SET(bp->b_flags, B_WANTED);
- error = tsleep(bp, (PRIBIO + 1), "vnpgout", 0);
- goto start0;
- } else {
- bremfree(bp);
- SET(bp->b_flags, (B_BUSY|B_INVAL));
+ if (upl == NULL) {
+ int request_flags;
+
+ if (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSVNOP_PAGEOUTV2) {
+ /*
+ * filesystem has requested the new form of VNOP_PAGEOUT for file
+ * backed objects... we will not grab the UPL befofe calling VNOP_PAGEOUT...
+ * it is the fileystem's responsibility to grab the range we're denoting
+ * via 'f_offset' and 'size' into a UPL... this allows the filesystem to first
+ * take any locks it needs, before effectively locking the pages into a UPL...
+ */
+ KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
+ (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_START,
+ size, (int)f_offset, 0, 0, 0);
+
+ if ((error_ret = VNOP_PAGEOUT(vp, NULL, upl_offset, (off_t)f_offset,
+ size, flags, ctx))) {
+ result = PAGER_ERROR;
+ }
+ KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
+ (MACHDBG_CODE(DBG_MACH_VM, 1)) | DBG_FUNC_END,
+ size, 0, 0, 0, 0);
+
+ goto out;
+ }
+ if (flags & UPL_MSYNC) {
+ request_flags = UPL_UBC_MSYNC | UPL_RET_ONLY_DIRTY;
+ } else {
+ request_flags = UPL_UBC_PAGEOUT | UPL_RET_ONLY_DIRTY;
+ }
+
+ if (ubc_create_upl_kernel(vp, f_offset, size, &upl, &pl, request_flags, VM_KERN_MEMORY_FILE) != KERN_SUCCESS) {
+ result = PAGER_ERROR;
+ error_ret = EINVAL;
+ goto out;
+ }
+ upl_offset = 0;
+ } else {
+ pl = ubc_upl_pageinfo(upl);
+ }
+
+ /*
+ * Ignore any non-present pages at the end of the
+ * UPL so that we aren't looking at a upl that
+ * may already have been freed by the preceeding
+ * aborts/completions.
+ */
+ base_index = upl_offset / PAGE_SIZE;
+
+ for (pg_index = (upl_offset + isize) / PAGE_SIZE; pg_index > base_index;) {
+ if (upl_page_present(pl, --pg_index)) {
+ break;
+ }
+ if (pg_index == base_index) {
+ /*
+ * no pages were returned, so release
+ * our hold on the upl and leave
+ */
+ if (!(flags & UPL_NOCOMMIT)) {
+ ubc_upl_abort_range(upl, upl_offset, isize, UPL_ABORT_FREE_ON_EMPTY);
+ }
+
+ goto out;
+ }
+ }
+ isize = ((pg_index + 1) - base_index) * PAGE_SIZE;
+
+ /*
+ * we come here for pageouts to 'real' files and
+ * for msyncs... the upl may not contain any
+ * dirty pages.. it's our responsibility to sort
+ * through it and find the 'runs' of dirty pages
+ * to call VNOP_PAGEOUT on...
+ */
+
+ if (ubc_getsize(vp) == 0) {
+ /*
+ * if the file has been effectively deleted, then
+ * we need to go through the UPL and invalidate any
+ * buffer headers we might have that reference any
+ * of it's pages
+ */
+ for (offset = upl_offset; isize; isize -= PAGE_SIZE, offset += PAGE_SIZE) {
+#if CONFIG_NFS_CLIENT
+ if (vp->v_tag == VT_NFS) {
+ /* check with nfs if page is OK to drop */
+ error = nfs_buf_page_inval(vp, (off_t)f_offset);
+ } else
+#endif /* CONFIG_NFS_CLIENT */
+ {
+ blkno = ubc_offtoblk(vp, (off_t)f_offset);
+ error = buf_invalblkno(vp, blkno, 0);
+ }
+ if (error) {
+ if (!(flags & UPL_NOCOMMIT)) {
+ ubc_upl_abort_range(upl, offset, PAGE_SIZE, UPL_ABORT_FREE_ON_EMPTY);
+ }
+ if (error_ret == 0) {
+ error_ret = error;