xref: /onnv-gate/usr/src/uts/common/fs/swapfs/swap_vnops.c (revision 12173:9552c31d849c)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52414Saguzovsk  * Common Development and Distribution License (the "License").
62414Saguzovsk  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12173SMichael.Corcoran@Sun.COM  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <sys/param.h>
270Sstevel@tonic-gate #include <sys/systm.h>
280Sstevel@tonic-gate #include <sys/buf.h>
290Sstevel@tonic-gate #include <sys/cred.h>
300Sstevel@tonic-gate #include <sys/errno.h>
310Sstevel@tonic-gate #include <sys/vnode.h>
323898Srsb #include <sys/vfs_opreg.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/swap.h>
350Sstevel@tonic-gate #include <sys/mman.h>
360Sstevel@tonic-gate #include <sys/vmsystm.h>
370Sstevel@tonic-gate #include <sys/vtrace.h>
380Sstevel@tonic-gate #include <sys/debug.h>
390Sstevel@tonic-gate #include <sys/sysmacros.h>
400Sstevel@tonic-gate #include <sys/vm.h>
410Sstevel@tonic-gate 
420Sstevel@tonic-gate #include <sys/fs/swapnode.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate #include <vm/seg.h>
450Sstevel@tonic-gate #include <vm/page.h>
460Sstevel@tonic-gate #include <vm/pvn.h>
470Sstevel@tonic-gate #include <fs/fs_subr.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #include <vm/seg_kp.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * Define the routines within this file.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate static int	swap_getpage(struct vnode *vp, offset_t off, size_t len,
555331Samw     uint_t *protp, struct page **plarr, size_t plsz, struct seg *seg,
565331Samw     caddr_t addr, enum seg_rw rw, struct cred *cr, caller_context_t *ct);
570Sstevel@tonic-gate static int	swap_putpage(struct vnode *vp, offset_t off, size_t len,
585331Samw     int flags, struct cred *cr, caller_context_t *ct);
595331Samw static void	swap_inactive(struct vnode *vp, struct cred *cr,
605331Samw     caller_context_t *ct);
610Sstevel@tonic-gate static void	swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn,
625331Samw     cred_t *cr, caller_context_t *ct);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static int	swap_getapage(struct vnode *vp, u_offset_t off, size_t len,
650Sstevel@tonic-gate     uint_t *protp, page_t **plarr, size_t plsz,
660Sstevel@tonic-gate     struct seg *seg, caddr_t addr, enum seg_rw rw, struct cred *cr);
670Sstevel@tonic-gate 
680Sstevel@tonic-gate int	swap_getconpage(struct vnode *vp, u_offset_t off, size_t len,
692414Saguzovsk     uint_t *protp, page_t **plarr, size_t plsz, page_t *conpp,
702414Saguzovsk     uint_t *pszc, spgcnt_t *nreloc, struct seg *seg, caddr_t addr,
712414Saguzovsk     enum seg_rw rw, struct cred *cr);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static int 	swap_putapage(struct vnode *vp, page_t *pp, u_offset_t *off,
740Sstevel@tonic-gate     size_t *lenp, int flags, struct cred *cr);
750Sstevel@tonic-gate 
760Sstevel@tonic-gate const fs_operation_def_t swap_vnodeops_template[] = {
773898Srsb 	VOPNAME_INACTIVE,	{ .vop_inactive = swap_inactive },
783898Srsb 	VOPNAME_GETPAGE,	{ .vop_getpage = swap_getpage },
793898Srsb 	VOPNAME_PUTPAGE,	{ .vop_putpage = swap_putpage },
803898Srsb 	VOPNAME_DISPOSE,	{ .vop_dispose = swap_dispose },
813898Srsb 	VOPNAME_SETFL,		{ .error = fs_error },
823898Srsb 	VOPNAME_POLL,		{ .error = fs_error },
833898Srsb 	VOPNAME_PATHCONF,	{ .error = fs_error },
843898Srsb 	VOPNAME_GETSECATTR,	{ .error = fs_error },
853898Srsb 	VOPNAME_SHRLOCK,	{ .error = fs_error },
863898Srsb 	NULL,			NULL
870Sstevel@tonic-gate };
880Sstevel@tonic-gate 
890Sstevel@tonic-gate vnodeops_t *swap_vnodeops;
900Sstevel@tonic-gate 
910Sstevel@tonic-gate /* ARGSUSED */
920Sstevel@tonic-gate static void
swap_inactive(struct vnode * vp,struct cred * cr,caller_context_t * ct)930Sstevel@tonic-gate swap_inactive(
940Sstevel@tonic-gate 	struct vnode *vp,
955331Samw 	struct cred *cr,
965331Samw 	caller_context_t *ct)
970Sstevel@tonic-gate {
980Sstevel@tonic-gate 	SWAPFS_PRINT(SWAP_VOPS, "swap_inactive: vp %x\n", vp, 0, 0, 0, 0);
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /*
1020Sstevel@tonic-gate  * Return all the pages from [off..off+len] in given file
1030Sstevel@tonic-gate  */
1045331Samw /*ARGSUSED*/
1050Sstevel@tonic-gate static int
swap_getpage(struct vnode * vp,offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr,caller_context_t * ct)1060Sstevel@tonic-gate swap_getpage(
1070Sstevel@tonic-gate 	struct vnode *vp,
1080Sstevel@tonic-gate 	offset_t off,
1090Sstevel@tonic-gate 	size_t len,
1100Sstevel@tonic-gate 	uint_t *protp,
1110Sstevel@tonic-gate 	page_t *pl[],
1120Sstevel@tonic-gate 	size_t plsz,
1130Sstevel@tonic-gate 	struct seg *seg,
1140Sstevel@tonic-gate 	caddr_t addr,
1150Sstevel@tonic-gate 	enum seg_rw rw,
1165331Samw 	struct cred *cr,
1175331Samw 	caller_context_t *ct)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	int err;
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	SWAPFS_PRINT(SWAP_VOPS, "swap_getpage: vp %p, off %llx, len %lx\n",
1220Sstevel@tonic-gate 	    (void *)vp, off, len, 0, 0);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_GETPAGE,
1250Sstevel@tonic-gate 	    "swapfs getpage:vp %p off %llx len %ld",
1260Sstevel@tonic-gate 	    (void *)vp, off, len);
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	if (len <= PAGESIZE) {
1290Sstevel@tonic-gate 		err = swap_getapage(vp, (u_offset_t)off, len, protp, pl, plsz,
1300Sstevel@tonic-gate 		    seg, addr, rw, cr);
1310Sstevel@tonic-gate 	} else {
1320Sstevel@tonic-gate 		err = pvn_getpages(swap_getapage, vp, (u_offset_t)off, len,
1330Sstevel@tonic-gate 		    protp, pl, plsz, seg, addr, rw, cr);
1340Sstevel@tonic-gate 	}
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate 	return (err);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate  * Called from pvn_getpages or swap_getpage to get a particular page.
1410Sstevel@tonic-gate  */
1420Sstevel@tonic-gate /*ARGSUSED*/
1430Sstevel@tonic-gate static int
swap_getapage(struct vnode * vp,u_offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr)1440Sstevel@tonic-gate swap_getapage(
1450Sstevel@tonic-gate 	struct vnode *vp,
1460Sstevel@tonic-gate 	u_offset_t off,
1470Sstevel@tonic-gate 	size_t len,
1480Sstevel@tonic-gate 	uint_t *protp,
1490Sstevel@tonic-gate 	page_t *pl[],
1500Sstevel@tonic-gate 	size_t plsz,
1510Sstevel@tonic-gate 	struct seg *seg,
1520Sstevel@tonic-gate 	caddr_t addr,
1530Sstevel@tonic-gate 	enum seg_rw rw,
1540Sstevel@tonic-gate 	struct cred *cr)
1550Sstevel@tonic-gate {
1560Sstevel@tonic-gate 	struct page *pp, *rpp;
1570Sstevel@tonic-gate 	int flags;
1580Sstevel@tonic-gate 	int err = 0;
1590Sstevel@tonic-gate 	struct vnode *pvp = NULL;
1600Sstevel@tonic-gate 	u_offset_t poff;
1610Sstevel@tonic-gate 	int flag_noreloc;
1620Sstevel@tonic-gate 	se_t lock;
1630Sstevel@tonic-gate 	extern int kcage_on;
1640Sstevel@tonic-gate 	int upgrade = 0;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	SWAPFS_PRINT(SWAP_VOPS, "swap_getapage: vp %p, off %llx, len %lx\n",
1676695Saguzovsk 	    vp, off, len, 0, 0);
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	/*
1700Sstevel@tonic-gate 	 * Until there is a call-back mechanism to cause SEGKP
1710Sstevel@tonic-gate 	 * pages to be unlocked, make them non-relocatable.
1720Sstevel@tonic-gate 	 */
1730Sstevel@tonic-gate 	if (SEG_IS_SEGKP(seg))
1740Sstevel@tonic-gate 		flag_noreloc = PG_NORELOC;
1750Sstevel@tonic-gate 	else
1760Sstevel@tonic-gate 		flag_noreloc = 0;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (protp != NULL)
1790Sstevel@tonic-gate 		*protp = PROT_ALL;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	lock = (rw == S_CREATE ? SE_EXCL : SE_SHARED);
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate again:
1840Sstevel@tonic-gate 	if (pp = page_lookup(vp, off, lock)) {
1850Sstevel@tonic-gate 		/*
1860Sstevel@tonic-gate 		 * In very rare instances, a segkp page may have been
1870Sstevel@tonic-gate 		 * relocated outside of the kernel by the kernel cage
1880Sstevel@tonic-gate 		 * due to the window between page_unlock() and
1890Sstevel@tonic-gate 		 * VOP_PUTPAGE() in segkp_unlock().  Due to the
1900Sstevel@tonic-gate 		 * rareness of these occurances, the solution is to
1910Sstevel@tonic-gate 		 * relocate the page to a P_NORELOC page.
1920Sstevel@tonic-gate 		 */
1930Sstevel@tonic-gate 		if (flag_noreloc != 0) {
1940Sstevel@tonic-gate 			if (!PP_ISNORELOC(pp) && kcage_on) {
1950Sstevel@tonic-gate 				if (lock != SE_EXCL) {
1960Sstevel@tonic-gate 					upgrade = 1;
1970Sstevel@tonic-gate 					if (!page_tryupgrade(pp)) {
1980Sstevel@tonic-gate 						page_unlock(pp);
1990Sstevel@tonic-gate 						lock = SE_EXCL;
2000Sstevel@tonic-gate 						goto again;
2010Sstevel@tonic-gate 					}
2020Sstevel@tonic-gate 				}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 				if (page_relocate_cage(&pp, &rpp) != 0)
2050Sstevel@tonic-gate 					panic("swap_getapage: "
2060Sstevel@tonic-gate 					    "page_relocate_cage failed");
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 				pp = rpp;
2090Sstevel@tonic-gate 			}
2100Sstevel@tonic-gate 		}
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 		if (pl) {
2130Sstevel@tonic-gate 			if (upgrade)
2140Sstevel@tonic-gate 				page_downgrade(pp);
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 			pl[0] = pp;
2170Sstevel@tonic-gate 			pl[1] = NULL;
2180Sstevel@tonic-gate 		} else {
2190Sstevel@tonic-gate 			page_unlock(pp);
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 	} else {
2220Sstevel@tonic-gate 		pp = page_create_va(vp, off, PAGESIZE,
2230Sstevel@tonic-gate 		    PG_WAIT | PG_EXCL | flag_noreloc,
2240Sstevel@tonic-gate 		    seg, addr);
2250Sstevel@tonic-gate 		/*
2260Sstevel@tonic-gate 		 * Someone raced in and created the page after we did the
2270Sstevel@tonic-gate 		 * lookup but before we did the create, so go back and
2280Sstevel@tonic-gate 		 * try to look it up again.
2290Sstevel@tonic-gate 		 */
2300Sstevel@tonic-gate 		if (pp == NULL)
2310Sstevel@tonic-gate 			goto again;
2320Sstevel@tonic-gate 		if (rw != S_CREATE) {
2330Sstevel@tonic-gate 			err = swap_getphysname(vp, off, &pvp, &poff);
2340Sstevel@tonic-gate 			if (pvp) {
2350Sstevel@tonic-gate 				struct anon *ap;
2360Sstevel@tonic-gate 				kmutex_t *ahm;
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 				flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
2390Sstevel@tonic-gate 				err = VOP_PAGEIO(pvp, pp, poff,
2405331Samw 				    PAGESIZE, flags, cr, NULL);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 				if (!err) {
243*12173SMichael.Corcoran@Sun.COM 					ahm = AH_MUTEX(vp, off);
2440Sstevel@tonic-gate 					mutex_enter(ahm);
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 					ap = swap_anon(vp, off);
2476695Saguzovsk 					if (ap == NULL) {
2486695Saguzovsk 						panic("swap_getapage:"
2496695Saguzovsk 						    " null anon");
2506695Saguzovsk 					}
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 					if (ap->an_pvp == pvp &&
2530Sstevel@tonic-gate 					    ap->an_poff == poff) {
2540Sstevel@tonic-gate 						swap_phys_free(pvp, poff,
2550Sstevel@tonic-gate 						    PAGESIZE);
2560Sstevel@tonic-gate 						ap->an_pvp = NULL;
2570Sstevel@tonic-gate 						ap->an_poff = NULL;
2580Sstevel@tonic-gate 						hat_setmod(pp);
2590Sstevel@tonic-gate 					}
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 					mutex_exit(ahm);
2620Sstevel@tonic-gate 				}
2630Sstevel@tonic-gate 			} else {
2640Sstevel@tonic-gate 				if (!err)
2650Sstevel@tonic-gate 					pagezero(pp, 0, PAGESIZE);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 				/*
2680Sstevel@tonic-gate 				 * If it's a fault ahead, release page_io_lock
2690Sstevel@tonic-gate 				 * and SE_EXCL we grabbed in page_create_va
2700Sstevel@tonic-gate 				 *
2710Sstevel@tonic-gate 				 * If we are here, we haven't called VOP_PAGEIO
2720Sstevel@tonic-gate 				 * and thus calling pvn_read_done(pp, B_READ)
2730Sstevel@tonic-gate 				 * below may mislead that we tried i/o. Besides,
2740Sstevel@tonic-gate 				 * in case of async, pvn_read_done() should
2750Sstevel@tonic-gate 				 * not be called by *getpage()
2760Sstevel@tonic-gate 				 */
2770Sstevel@tonic-gate 				if (pl == NULL) {
2780Sstevel@tonic-gate 					/*
2790Sstevel@tonic-gate 					 * swap_getphysname can return error
2800Sstevel@tonic-gate 					 * only when we are getting called from
2810Sstevel@tonic-gate 					 * swapslot_free which passes non-NULL
2820Sstevel@tonic-gate 					 * pl to VOP_GETPAGE.
2830Sstevel@tonic-gate 					 */
2840Sstevel@tonic-gate 					ASSERT(err == 0);
2850Sstevel@tonic-gate 					page_io_unlock(pp);
2860Sstevel@tonic-gate 					page_unlock(pp);
2870Sstevel@tonic-gate 				}
2880Sstevel@tonic-gate 			}
2890Sstevel@tonic-gate 		}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		ASSERT(pp != NULL);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 		if (err && pl)
2940Sstevel@tonic-gate 			pvn_read_done(pp, B_ERROR);
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 		if (!err && pl)
2970Sstevel@tonic-gate 			pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_GETAPAGE,
3006695Saguzovsk 	    "swapfs getapage:pp %p vp %p off %llx", pp, vp, off);
3010Sstevel@tonic-gate 	return (err);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate  * Called from large page anon routines only! This is an ugly hack where
3060Sstevel@tonic-gate  * the anon layer directly calls into swapfs with a preallocated large page.
3070Sstevel@tonic-gate  * Another method would have been to change to VOP and add an extra arg for
3080Sstevel@tonic-gate  * the preallocated large page. This all could be cleaned up later when we
3090Sstevel@tonic-gate  * solve the anonymous naming problem and no longer need to loop across of
3100Sstevel@tonic-gate  * the VOP in PAGESIZE increments to fill in or initialize a large page as
3110Sstevel@tonic-gate  * is done today. I think the latter is better since it avoid a change to
3120Sstevel@tonic-gate  * the VOP interface that could later be avoided.
3130Sstevel@tonic-gate  */
3140Sstevel@tonic-gate int
swap_getconpage(struct vnode * vp,u_offset_t off,size_t len,uint_t * protp,page_t * pl[],size_t plsz,page_t * conpp,uint_t * pszc,spgcnt_t * nreloc,struct seg * seg,caddr_t addr,enum seg_rw rw,struct cred * cr)3150Sstevel@tonic-gate swap_getconpage(
3160Sstevel@tonic-gate 	struct vnode *vp,
3170Sstevel@tonic-gate 	u_offset_t off,
3180Sstevel@tonic-gate 	size_t len,
3190Sstevel@tonic-gate 	uint_t *protp,
3200Sstevel@tonic-gate 	page_t *pl[],
3210Sstevel@tonic-gate 	size_t plsz,
3220Sstevel@tonic-gate 	page_t	*conpp,
3232414Saguzovsk 	uint_t	*pszc,
3240Sstevel@tonic-gate 	spgcnt_t *nreloc,
3250Sstevel@tonic-gate 	struct seg *seg,
3260Sstevel@tonic-gate 	caddr_t addr,
3270Sstevel@tonic-gate 	enum seg_rw rw,
3280Sstevel@tonic-gate 	struct cred *cr)
3290Sstevel@tonic-gate {
3300Sstevel@tonic-gate 	struct page	*pp;
3310Sstevel@tonic-gate 	int 		err = 0;
3320Sstevel@tonic-gate 	struct vnode	*pvp = NULL;
3330Sstevel@tonic-gate 	u_offset_t	poff;
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	ASSERT(len == PAGESIZE);
3360Sstevel@tonic-gate 	ASSERT(pl != NULL);
3370Sstevel@tonic-gate 	ASSERT(plsz == PAGESIZE);
3380Sstevel@tonic-gate 	ASSERT(protp == NULL);
3390Sstevel@tonic-gate 	ASSERT(nreloc != NULL);
3400Sstevel@tonic-gate 	ASSERT(!SEG_IS_SEGKP(seg)); /* XXX for now not supported */
3410Sstevel@tonic-gate 	SWAPFS_PRINT(SWAP_VOPS, "swap_getconpage: vp %p, off %llx, len %lx\n",
3426695Saguzovsk 	    vp, off, len, 0, 0);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	/*
3450Sstevel@tonic-gate 	 * If we are not using a preallocated page then we know one already
3460Sstevel@tonic-gate 	 * exists. So just let the old code handle it.
3470Sstevel@tonic-gate 	 */
3480Sstevel@tonic-gate 	if (conpp == NULL) {
3490Sstevel@tonic-gate 		err = swap_getapage(vp, (u_offset_t)off, len, protp, pl, plsz,
3500Sstevel@tonic-gate 		    seg, addr, rw, cr);
3510Sstevel@tonic-gate 		return (err);
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 	ASSERT(conpp->p_szc != 0);
3540Sstevel@tonic-gate 	ASSERT(PAGE_EXCL(conpp));
3550Sstevel@tonic-gate 
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	ASSERT(conpp->p_next == conpp);
3580Sstevel@tonic-gate 	ASSERT(conpp->p_prev == conpp);
3590Sstevel@tonic-gate 	ASSERT(!PP_ISAGED(conpp));
3600Sstevel@tonic-gate 	ASSERT(!PP_ISFREE(conpp));
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	*nreloc = 0;
3630Sstevel@tonic-gate 	pp = page_lookup_create(vp, off, SE_SHARED, conpp, nreloc, 0);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * If existing page is found we may need to relocate.
3670Sstevel@tonic-gate 	 */
3680Sstevel@tonic-gate 	if (pp != conpp) {
3690Sstevel@tonic-gate 		ASSERT(rw != S_CREATE);
3702414Saguzovsk 		ASSERT(pszc != NULL);
3710Sstevel@tonic-gate 		ASSERT(PAGE_SHARED(pp));
3720Sstevel@tonic-gate 		if (pp->p_szc < conpp->p_szc) {
3732414Saguzovsk 			*pszc = pp->p_szc;
3740Sstevel@tonic-gate 			page_unlock(pp);
3750Sstevel@tonic-gate 			err = -1;
3762414Saguzovsk 		} else if (pp->p_szc > conpp->p_szc &&
3772414Saguzovsk 		    seg->s_szc > conpp->p_szc) {
3782414Saguzovsk 			*pszc = MIN(pp->p_szc, seg->s_szc);
3790Sstevel@tonic-gate 			page_unlock(pp);
3800Sstevel@tonic-gate 			err = -2;
3810Sstevel@tonic-gate 		} else {
3820Sstevel@tonic-gate 			pl[0] = pp;
3830Sstevel@tonic-gate 			pl[1] = NULL;
3840Sstevel@tonic-gate 			if (page_pptonum(pp) &
3852414Saguzovsk 			    (page_get_pagecnt(conpp->p_szc) - 1))
3866695Saguzovsk 				cmn_err(CE_PANIC, "swap_getconpage: no root");
3870Sstevel@tonic-gate 		}
3880Sstevel@tonic-gate 		return (err);
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	ASSERT(PAGE_EXCL(pp));
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	if (*nreloc != 0) {
3940Sstevel@tonic-gate 		ASSERT(rw != S_CREATE);
3950Sstevel@tonic-gate 		pl[0] = pp;
3960Sstevel@tonic-gate 		pl[1] = NULL;
3970Sstevel@tonic-gate 		return (0);
3980Sstevel@tonic-gate 	}
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 	*nreloc = 1;
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/*
4030Sstevel@tonic-gate 	 * If necessary do the page io.
4040Sstevel@tonic-gate 	 */
4050Sstevel@tonic-gate 	if (rw != S_CREATE) {
4060Sstevel@tonic-gate 		/*
4070Sstevel@tonic-gate 		 * Since we are only called now on behalf of an
4080Sstevel@tonic-gate 		 * address space operation it's impossible for
4090Sstevel@tonic-gate 		 * us to fail unlike swap_getapge() which
4100Sstevel@tonic-gate 		 * also gets called from swapslot_free().
4110Sstevel@tonic-gate 		 */
4120Sstevel@tonic-gate 		if (swap_getphysname(vp, off, &pvp, &poff)) {
4130Sstevel@tonic-gate 			cmn_err(CE_PANIC,
4140Sstevel@tonic-gate 			    "swap_getconpage: swap_getphysname failed!");
4150Sstevel@tonic-gate 		}
4160Sstevel@tonic-gate 
4176695Saguzovsk 		if (pvp != NULL) {
4186695Saguzovsk 			err = VOP_PAGEIO(pvp, pp, poff, PAGESIZE, B_READ,
4196695Saguzovsk 			    cr, NULL);
4206695Saguzovsk 			if (err == 0) {
4216695Saguzovsk 				struct anon *ap;
4226695Saguzovsk 				kmutex_t *ahm;
4236695Saguzovsk 
424*12173SMichael.Corcoran@Sun.COM 				ahm = AH_MUTEX(vp, off);
4256695Saguzovsk 				mutex_enter(ahm);
4266695Saguzovsk 				ap = swap_anon(vp, off);
4276695Saguzovsk 				if (ap == NULL)
4286695Saguzovsk 					panic("swap_getconpage: null anon");
4296695Saguzovsk 				if (ap->an_pvp != pvp || ap->an_poff != poff)
4306695Saguzovsk 					panic("swap_getconpage: bad anon");
4316695Saguzovsk 
4326695Saguzovsk 				swap_phys_free(pvp, poff, PAGESIZE);
4336695Saguzovsk 				ap->an_pvp = NULL;
4346695Saguzovsk 				ap->an_poff = NULL;
4356695Saguzovsk 				hat_setmod(pp);
4366695Saguzovsk 				mutex_exit(ahm);
4376695Saguzovsk 			}
4380Sstevel@tonic-gate 		} else {
4390Sstevel@tonic-gate 			pagezero(pp, 0, PAGESIZE);
4400Sstevel@tonic-gate 		}
4410Sstevel@tonic-gate 	}
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	/*
4440Sstevel@tonic-gate 	 * Normally we would let pvn_read_done() destroy
4450Sstevel@tonic-gate 	 * the page on IO error. But since this is a preallocated
4460Sstevel@tonic-gate 	 * page we'll let the anon layer handle it.
4470Sstevel@tonic-gate 	 */
4480Sstevel@tonic-gate 	page_io_unlock(pp);
4490Sstevel@tonic-gate 	if (err != 0)
4500Sstevel@tonic-gate 		page_hashout(pp, NULL);
4510Sstevel@tonic-gate 	ASSERT(pp->p_next == pp);
4520Sstevel@tonic-gate 	ASSERT(pp->p_prev == pp);
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_GETAPAGE,
4556695Saguzovsk 	    "swapfs getconpage:pp %p vp %p off %llx", pp, vp, off);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	pl[0] = pp;
4580Sstevel@tonic-gate 	pl[1] = NULL;
4590Sstevel@tonic-gate 	return (err);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate /* Async putpage klustering stuff */
4630Sstevel@tonic-gate int sw_pending_size;
4640Sstevel@tonic-gate extern int klustsize;
4650Sstevel@tonic-gate extern struct async_reqs *sw_getreq();
4660Sstevel@tonic-gate extern void sw_putreq(struct async_reqs *);
4670Sstevel@tonic-gate extern void sw_putbackreq(struct async_reqs *);
4680Sstevel@tonic-gate extern struct async_reqs *sw_getfree();
4690Sstevel@tonic-gate extern void sw_putfree(struct async_reqs *);
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate static size_t swap_putpagecnt, swap_pagespushed;
4720Sstevel@tonic-gate static size_t swap_otherfail, swap_otherpages;
4730Sstevel@tonic-gate static size_t swap_klustfail, swap_klustpages;
4740Sstevel@tonic-gate static size_t swap_getiofail, swap_getiopages;
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate  * Flags are composed of {B_INVAL, B_DIRTY B_FREE, B_DONTNEED}.
4780Sstevel@tonic-gate  * If len == 0, do from off to EOF.
4790Sstevel@tonic-gate  */
4800Sstevel@tonic-gate static int swap_nopage = 0;	/* Don't do swap_putpage's if set */
4810Sstevel@tonic-gate 
4820Sstevel@tonic-gate /* ARGSUSED */
4830Sstevel@tonic-gate static int
swap_putpage(struct vnode * vp,offset_t off,size_t len,int flags,struct cred * cr,caller_context_t * ct)4840Sstevel@tonic-gate swap_putpage(
4850Sstevel@tonic-gate 	struct vnode *vp,
4860Sstevel@tonic-gate 	offset_t off,
4870Sstevel@tonic-gate 	size_t len,
4880Sstevel@tonic-gate 	int flags,
4895331Samw 	struct cred *cr,
4905331Samw 	caller_context_t *ct)
4910Sstevel@tonic-gate {
4920Sstevel@tonic-gate 	page_t *pp;
4930Sstevel@tonic-gate 	u_offset_t io_off;
4940Sstevel@tonic-gate 	size_t io_len = 0;
4950Sstevel@tonic-gate 	int err = 0;
4967547SDonghai.Qiao@Sun.COM 	int nowait;
4970Sstevel@tonic-gate 	struct async_reqs *arg;
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	if (swap_nopage)
5000Sstevel@tonic-gate 		return (0);
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	ASSERT(vp->v_count != 0);
5030Sstevel@tonic-gate 
5047547SDonghai.Qiao@Sun.COM 	nowait = flags & B_PAGE_NOWAIT;
5057547SDonghai.Qiao@Sun.COM 
5062779Ssl108498 	/*
5072779Ssl108498 	 * Clear force flag so that p_lckcnt pages are not invalidated.
5082779Ssl108498 	 */
5097547SDonghai.Qiao@Sun.COM 	flags &= ~(B_FORCE | B_PAGE_NOWAIT);
5102779Ssl108498 
5110Sstevel@tonic-gate 	SWAPFS_PRINT(SWAP_VOPS,
5120Sstevel@tonic-gate 	    "swap_putpage: vp %p, off %llx len %lx, flags %x\n",
5130Sstevel@tonic-gate 	    (void *)vp, off, len, flags, 0);
5140Sstevel@tonic-gate 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_PUTPAGE,
5150Sstevel@tonic-gate 	    "swapfs putpage:vp %p off %llx len %ld", (void *)vp, off, len);
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	if (vp->v_flag & VNOMAP)
5180Sstevel@tonic-gate 		return (ENOSYS);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (!vn_has_cached_data(vp))
5210Sstevel@tonic-gate 		return (0);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (len == 0) {
5240Sstevel@tonic-gate 		if (curproc == proc_pageout)
5250Sstevel@tonic-gate 			cmn_err(CE_PANIC, "swapfs: pageout can't block");
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 		/* Search the entire vp list for pages >= off. */
5280Sstevel@tonic-gate 		err = pvn_vplist_dirty(vp, (u_offset_t)off, swap_putapage,
5290Sstevel@tonic-gate 		    flags, cr);
5300Sstevel@tonic-gate 	} else {
5310Sstevel@tonic-gate 		u_offset_t eoff;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 		/*
5340Sstevel@tonic-gate 		 * Loop over all offsets in the range [off...off + len]
5350Sstevel@tonic-gate 		 * looking for pages to deal with.
5360Sstevel@tonic-gate 		 */
5370Sstevel@tonic-gate 		eoff = off + len;
5380Sstevel@tonic-gate 		for (io_off = (u_offset_t)off; io_off < eoff;
5390Sstevel@tonic-gate 		    io_off += io_len) {
5400Sstevel@tonic-gate 			/*
5410Sstevel@tonic-gate 			 * If we run out of the async req slot, put the page
5420Sstevel@tonic-gate 			 * now instead of queuing.
5430Sstevel@tonic-gate 			 */
5440Sstevel@tonic-gate 			if (flags == (B_ASYNC | B_FREE) &&
5450Sstevel@tonic-gate 			    sw_pending_size < klustsize &&
5460Sstevel@tonic-gate 			    (arg = sw_getfree())) {
5470Sstevel@tonic-gate 				/*
5480Sstevel@tonic-gate 				 * If we are clustering, we should allow
5490Sstevel@tonic-gate 				 * pageout to feed us more pages because # of
5500Sstevel@tonic-gate 				 * pushes is limited by # of I/Os, and one
5510Sstevel@tonic-gate 				 * cluster is considered to be one I/O.
5520Sstevel@tonic-gate 				 */
5530Sstevel@tonic-gate 				if (pushes)
5540Sstevel@tonic-gate 					pushes--;
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 				arg->a_vp = vp;
5570Sstevel@tonic-gate 				arg->a_off = io_off;
5580Sstevel@tonic-gate 				arg->a_len = PAGESIZE;
5590Sstevel@tonic-gate 				arg->a_flags = B_ASYNC | B_FREE;
5600Sstevel@tonic-gate 				arg->a_cred = kcred;
5610Sstevel@tonic-gate 				sw_putreq(arg);
5620Sstevel@tonic-gate 				io_len = PAGESIZE;
5630Sstevel@tonic-gate 				continue;
5640Sstevel@tonic-gate 			}
5650Sstevel@tonic-gate 			/*
5660Sstevel@tonic-gate 			 * If we are not invalidating pages, use the
5670Sstevel@tonic-gate 			 * routine page_lookup_nowait() to prevent
5680Sstevel@tonic-gate 			 * reclaiming them from the free list.
5690Sstevel@tonic-gate 			 */
5707547SDonghai.Qiao@Sun.COM 			if (!nowait && ((flags & B_INVAL) ||
5717547SDonghai.Qiao@Sun.COM 			    (flags & (B_ASYNC | B_FREE)) == B_FREE))
5720Sstevel@tonic-gate 				pp = page_lookup(vp, io_off, SE_EXCL);
5730Sstevel@tonic-gate 			else
5740Sstevel@tonic-gate 				pp = page_lookup_nowait(vp, io_off,
5757547SDonghai.Qiao@Sun.COM 				    (flags & (B_FREE | B_INVAL)) ?
5767547SDonghai.Qiao@Sun.COM 				    SE_EXCL : SE_SHARED);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 			if (pp == NULL || pvn_getdirty(pp, flags) == 0)
5790Sstevel@tonic-gate 				io_len = PAGESIZE;
5800Sstevel@tonic-gate 			else {
5810Sstevel@tonic-gate 				err = swap_putapage(vp, pp, &io_off, &io_len,
5820Sstevel@tonic-gate 				    flags, cr);
5830Sstevel@tonic-gate 				if (err != 0)
5840Sstevel@tonic-gate 					break;
5850Sstevel@tonic-gate 			}
5860Sstevel@tonic-gate 		}
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 	/* If invalidating, verify all pages on vnode list are gone. */
5890Sstevel@tonic-gate 	if (err == 0 && off == 0 && len == 0 &&
5900Sstevel@tonic-gate 	    (flags & B_INVAL) && vn_has_cached_data(vp)) {
5910Sstevel@tonic-gate 		cmn_err(CE_WARN,
5920Sstevel@tonic-gate 		    "swap_putpage: B_INVAL, pages not gone");
5930Sstevel@tonic-gate 	}
5940Sstevel@tonic-gate 	return (err);
5950Sstevel@tonic-gate }
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate /*
5980Sstevel@tonic-gate  * Write out a single page.
5990Sstevel@tonic-gate  * For swapfs this means choose a physical swap slot and write the page
6000Sstevel@tonic-gate  * out using VOP_PAGEIO.
6010Sstevel@tonic-gate  * In the (B_ASYNC | B_FREE) case we try to find a bunch of other dirty
6020Sstevel@tonic-gate  * swapfs pages, a bunch of contiguous swap slots and then write them
6030Sstevel@tonic-gate  * all out in one clustered i/o.
6040Sstevel@tonic-gate  */
6050Sstevel@tonic-gate /*ARGSUSED*/
6060Sstevel@tonic-gate static int
swap_putapage(struct vnode * vp,page_t * pp,u_offset_t * offp,size_t * lenp,int flags,struct cred * cr)6070Sstevel@tonic-gate swap_putapage(
6080Sstevel@tonic-gate 	struct vnode *vp,
6090Sstevel@tonic-gate 	page_t *pp,
6100Sstevel@tonic-gate 	u_offset_t *offp,
6110Sstevel@tonic-gate 	size_t *lenp,
6120Sstevel@tonic-gate 	int flags,
6130Sstevel@tonic-gate 	struct cred *cr)
6140Sstevel@tonic-gate {
6150Sstevel@tonic-gate 	int err;
6160Sstevel@tonic-gate 	struct vnode *pvp;
6170Sstevel@tonic-gate 	u_offset_t poff, off;
6180Sstevel@tonic-gate 	u_offset_t doff;
6190Sstevel@tonic-gate 	size_t dlen;
6200Sstevel@tonic-gate 	size_t klsz = 0;
6210Sstevel@tonic-gate 	u_offset_t klstart = 0;
6220Sstevel@tonic-gate 	struct vnode *klvp = NULL;
6230Sstevel@tonic-gate 	page_t *pplist;
6240Sstevel@tonic-gate 	se_t se;
6250Sstevel@tonic-gate 	struct async_reqs *arg;
6260Sstevel@tonic-gate 	size_t swap_klustsize;
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/*
6290Sstevel@tonic-gate 	 * This check is added for callers who access swap_putpage with len = 0.
6300Sstevel@tonic-gate 	 * swap_putpage calls swap_putapage page-by-page via pvn_vplist_dirty.
6310Sstevel@tonic-gate 	 * And it's necessary to do the same queuing if users have the same
6320Sstevel@tonic-gate 	 * B_ASYNC|B_FREE flags on.
6330Sstevel@tonic-gate 	 */
6340Sstevel@tonic-gate 	if (flags == (B_ASYNC | B_FREE) &&
6350Sstevel@tonic-gate 	    sw_pending_size < klustsize && (arg = sw_getfree())) {
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 		hat_setmod(pp);
6380Sstevel@tonic-gate 		page_io_unlock(pp);
6390Sstevel@tonic-gate 		page_unlock(pp);
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 		arg->a_vp = vp;
6420Sstevel@tonic-gate 		arg->a_off = pp->p_offset;
6430Sstevel@tonic-gate 		arg->a_len = PAGESIZE;
6440Sstevel@tonic-gate 		arg->a_flags = B_ASYNC | B_FREE;
6450Sstevel@tonic-gate 		arg->a_cred = kcred;
6460Sstevel@tonic-gate 		sw_putreq(arg);
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		return (0);
6490Sstevel@tonic-gate 	}
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	SWAPFS_PRINT(SWAP_PUTP,
6526695Saguzovsk 	    "swap_putapage: pp %p, vp %p, off %llx, flags %x\n",
6536695Saguzovsk 	    pp, vp, pp->p_offset, flags, 0);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 	ASSERT(PAGE_LOCKED(pp));
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	off = pp->p_offset;
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	doff = off;
6600Sstevel@tonic-gate 	dlen = PAGESIZE;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (err = swap_newphysname(vp, off, &doff, &dlen, &pvp, &poff)) {
6630Sstevel@tonic-gate 		err = (flags == (B_ASYNC | B_FREE) ? ENOMEM : 0);
6640Sstevel@tonic-gate 		hat_setmod(pp);
6650Sstevel@tonic-gate 		page_io_unlock(pp);
6660Sstevel@tonic-gate 		page_unlock(pp);
6670Sstevel@tonic-gate 		goto out;
6680Sstevel@tonic-gate 	}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	klvp = pvp;
6710Sstevel@tonic-gate 	klstart = poff;
6720Sstevel@tonic-gate 	pplist = pp;
6730Sstevel@tonic-gate 	/*
6740Sstevel@tonic-gate 	 * If this is ASYNC | FREE and we've accumulated a bunch of such
6750Sstevel@tonic-gate 	 * pending requests, kluster.
6760Sstevel@tonic-gate 	 */
6770Sstevel@tonic-gate 	if (flags == (B_ASYNC | B_FREE))
6780Sstevel@tonic-gate 		swap_klustsize = klustsize;
6790Sstevel@tonic-gate 	else
6800Sstevel@tonic-gate 		swap_klustsize = PAGESIZE;
6810Sstevel@tonic-gate 	se = (flags & B_FREE ? SE_EXCL : SE_SHARED);
6820Sstevel@tonic-gate 	klsz = PAGESIZE;
6830Sstevel@tonic-gate 	while (klsz < swap_klustsize) {
6840Sstevel@tonic-gate 		if ((arg = sw_getreq()) == NULL) {
6850Sstevel@tonic-gate 			swap_getiofail++;
6860Sstevel@tonic-gate 			swap_getiopages += btop(klsz);
6870Sstevel@tonic-gate 			break;
6880Sstevel@tonic-gate 		}
6890Sstevel@tonic-gate 		ASSERT(vn_matchops(arg->a_vp, swap_vnodeops));
6900Sstevel@tonic-gate 		vp = arg->a_vp;
6910Sstevel@tonic-gate 		off = arg->a_off;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 		if ((pp = page_lookup_nowait(vp, off, se)) == NULL) {
6940Sstevel@tonic-gate 			swap_otherfail++;
6950Sstevel@tonic-gate 			swap_otherpages += btop(klsz);
6960Sstevel@tonic-gate 			sw_putfree(arg);
6970Sstevel@tonic-gate 			break;
6980Sstevel@tonic-gate 		}
6990Sstevel@tonic-gate 		if (pvn_getdirty(pp, flags | B_DELWRI) == 0) {
7000Sstevel@tonic-gate 			sw_putfree(arg);
7010Sstevel@tonic-gate 			continue;
7020Sstevel@tonic-gate 		}
7030Sstevel@tonic-gate 		/* Get new physical backing store for the page */
7040Sstevel@tonic-gate 		doff = off;
7050Sstevel@tonic-gate 		dlen = PAGESIZE;
7060Sstevel@tonic-gate 		if (err = swap_newphysname(vp, off, &doff, &dlen,
7076695Saguzovsk 		    &pvp, &poff)) {
7080Sstevel@tonic-gate 			swap_otherfail++;
7090Sstevel@tonic-gate 			swap_otherpages += btop(klsz);
7100Sstevel@tonic-gate 			hat_setmod(pp);
7110Sstevel@tonic-gate 			page_io_unlock(pp);
7120Sstevel@tonic-gate 			page_unlock(pp);
7130Sstevel@tonic-gate 			sw_putbackreq(arg);
7140Sstevel@tonic-gate 			break;
7150Sstevel@tonic-gate 		}
7160Sstevel@tonic-gate 		/* Try to cluster new physical name with previous ones */
7170Sstevel@tonic-gate 		if (klvp == pvp && poff == klstart + klsz) {
7180Sstevel@tonic-gate 			klsz += PAGESIZE;
7190Sstevel@tonic-gate 			page_add(&pplist, pp);
7200Sstevel@tonic-gate 			pplist = pplist->p_next;
7210Sstevel@tonic-gate 			sw_putfree(arg);
7220Sstevel@tonic-gate 		} else if (klvp == pvp && poff == klstart - PAGESIZE) {
7230Sstevel@tonic-gate 			klsz += PAGESIZE;
7240Sstevel@tonic-gate 			klstart -= PAGESIZE;
7250Sstevel@tonic-gate 			page_add(&pplist, pp);
7260Sstevel@tonic-gate 			sw_putfree(arg);
7270Sstevel@tonic-gate 		} else {
7280Sstevel@tonic-gate 			swap_klustfail++;
7290Sstevel@tonic-gate 			swap_klustpages += btop(klsz);
7300Sstevel@tonic-gate 			hat_setmod(pp);
7310Sstevel@tonic-gate 			page_io_unlock(pp);
7320Sstevel@tonic-gate 			page_unlock(pp);
7330Sstevel@tonic-gate 			sw_putbackreq(arg);
7340Sstevel@tonic-gate 			break;
7350Sstevel@tonic-gate 		}
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 
7380Sstevel@tonic-gate 	err = VOP_PAGEIO(klvp, pplist, klstart, klsz,
7396695Saguzovsk 	    B_WRITE | flags, cr, NULL);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	if ((flags & B_ASYNC) == 0)
7420Sstevel@tonic-gate 		pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	/* Statistics */
7450Sstevel@tonic-gate 	if (!err) {
7460Sstevel@tonic-gate 		swap_putpagecnt++;
7470Sstevel@tonic-gate 		swap_pagespushed += btop(klsz);
7480Sstevel@tonic-gate 	}
7490Sstevel@tonic-gate out:
7500Sstevel@tonic-gate 	TRACE_4(TR_FAC_SWAPFS, TR_SWAPFS_PUTAPAGE,
7516695Saguzovsk 	    "swapfs putapage:vp %p klvp %p, klstart %lx, klsz %lx",
7526695Saguzovsk 	    vp, klvp, klstart, klsz);
7530Sstevel@tonic-gate 	if (err && err != ENOMEM)
7540Sstevel@tonic-gate 		cmn_err(CE_WARN, "swapfs_putapage: err %d\n", err);
7550Sstevel@tonic-gate 	if (lenp)
7560Sstevel@tonic-gate 		*lenp = PAGESIZE;
7570Sstevel@tonic-gate 	return (err);
7580Sstevel@tonic-gate }
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate static void
swap_dispose(vnode_t * vp,page_t * pp,int fl,int dn,cred_t * cr,caller_context_t * ct)7615331Samw swap_dispose(
7625331Samw 	vnode_t *vp,
7635331Samw 	page_t *pp,
7645331Samw 	int fl,
7655331Samw 	int dn,
7665331Samw 	cred_t *cr,
7675331Samw 	caller_context_t *ct)
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	int err;
7700Sstevel@tonic-gate 	u_offset_t off = pp->p_offset;
7710Sstevel@tonic-gate 	vnode_t *pvp;
7720Sstevel@tonic-gate 	u_offset_t poff;
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	ASSERT(PAGE_EXCL(pp));
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * The caller will free/invalidate large page in one shot instead of
7780Sstevel@tonic-gate 	 * one small page at a time.
7790Sstevel@tonic-gate 	 */
7800Sstevel@tonic-gate 	if (pp->p_szc != 0) {
7810Sstevel@tonic-gate 		page_unlock(pp);
7820Sstevel@tonic-gate 		return;
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	err = swap_getphysname(vp, off, &pvp, &poff);
7860Sstevel@tonic-gate 	if (!err && pvp != NULL)
7875331Samw 		VOP_DISPOSE(pvp, pp, fl, dn, cr, ct);
7880Sstevel@tonic-gate 	else
7895331Samw 		fs_dispose(vp, pp, fl, dn, cr, ct);
7900Sstevel@tonic-gate }
791