xref: /illumos-gate/usr/src/uts/common/fs/swapfs/swap_vnops.c (revision aeac2d873b68a43f6650e0d0f021c02f5a653a21)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/param.h>
28 #include <sys/systm.h>
29 #include <sys/buf.h>
30 #include <sys/cred.h>
31 #include <sys/errno.h>
32 #include <sys/vnode.h>
33 #include <sys/vfs_opreg.h>
34 #include <sys/cmn_err.h>
35 #include <sys/swap.h>
36 #include <sys/mman.h>
37 #include <sys/vmsystm.h>
38 #include <sys/vtrace.h>
39 #include <sys/debug.h>
40 #include <sys/sysmacros.h>
41 #include <sys/vm.h>
42 
43 #include <sys/fs/swapnode.h>
44 
45 #include <vm/seg.h>
46 #include <vm/page.h>
47 #include <vm/pvn.h>
48 #include <fs/fs_subr.h>
49 
50 #include <vm/seg_kp.h>
51 
52 /*
53  * Define the routines within this file.
54  */
55 static int	swap_getpage(struct vnode *vp, offset_t off, size_t len,
56     uint_t *protp, struct page **plarr, size_t plsz, struct seg *seg,
57     caddr_t addr, enum seg_rw rw, struct cred *cr, caller_context_t *ct);
58 static int	swap_putpage(struct vnode *vp, offset_t off, size_t len,
59     int flags, struct cred *cr, caller_context_t *ct);
60 static void	swap_inactive(struct vnode *vp, struct cred *cr,
61     caller_context_t *ct);
62 static void	swap_dispose(vnode_t *vp, page_t *pp, int fl, int dn,
63     cred_t *cr, caller_context_t *ct);
64 
65 static int	swap_getapage(struct vnode *vp, u_offset_t off, size_t len,
66     uint_t *protp, page_t **plarr, size_t plsz,
67     struct seg *seg, caddr_t addr, enum seg_rw rw, struct cred *cr);
68 
69 int	swap_getconpage(struct vnode *vp, u_offset_t off, size_t len,
70     uint_t *protp, page_t **plarr, size_t plsz, page_t *conpp,
71     uint_t *pszc, spgcnt_t *nreloc, struct seg *seg, caddr_t addr,
72     enum seg_rw rw, struct cred *cr);
73 
74 static int 	swap_putapage(struct vnode *vp, page_t *pp, u_offset_t *off,
75     size_t *lenp, int flags, struct cred *cr);
76 
77 const fs_operation_def_t swap_vnodeops_template[] = {
78 	VOPNAME_INACTIVE,	{ .vop_inactive = swap_inactive },
79 	VOPNAME_GETPAGE,	{ .vop_getpage = swap_getpage },
80 	VOPNAME_PUTPAGE,	{ .vop_putpage = swap_putpage },
81 	VOPNAME_DISPOSE,	{ .vop_dispose = swap_dispose },
82 	VOPNAME_SETFL,		{ .error = fs_error },
83 	VOPNAME_POLL,		{ .error = fs_error },
84 	VOPNAME_PATHCONF,	{ .error = fs_error },
85 	VOPNAME_GETSECATTR,	{ .error = fs_error },
86 	VOPNAME_SHRLOCK,	{ .error = fs_error },
87 	NULL,			NULL
88 };
89 
90 vnodeops_t *swap_vnodeops;
91 
92 /* ARGSUSED */
93 static void
94 swap_inactive(
95 	struct vnode *vp,
96 	struct cred *cr,
97 	caller_context_t *ct)
98 {
99 	SWAPFS_PRINT(SWAP_VOPS, "swap_inactive: vp %x\n", vp, 0, 0, 0, 0);
100 }
101 
102 /*
103  * Return all the pages from [off..off+len] in given file
104  */
105 /*ARGSUSED*/
106 static int
107 swap_getpage(
108 	struct vnode *vp,
109 	offset_t off,
110 	size_t len,
111 	uint_t *protp,
112 	page_t *pl[],
113 	size_t plsz,
114 	struct seg *seg,
115 	caddr_t addr,
116 	enum seg_rw rw,
117 	struct cred *cr,
118 	caller_context_t *ct)
119 {
120 	SWAPFS_PRINT(SWAP_VOPS, "swap_getpage: vp %p, off %llx, len %lx\n",
121 	    (void *)vp, off, len, 0, 0);
122 
123 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_GETPAGE,
124 	    "swapfs getpage:vp %p off %llx len %ld",
125 	    (void *)vp, off, len);
126 
127 	return (pvn_getpages(swap_getapage, vp, (u_offset_t)off, len, protp,
128 	    pl, plsz, seg, addr, rw, cr));
129 }
130 
131 /*
132  * Called from pvn_getpages to get a particular page.
133  */
134 /*ARGSUSED*/
135 static int
136 swap_getapage(
137 	struct vnode *vp,
138 	u_offset_t off,
139 	size_t len,
140 	uint_t *protp,
141 	page_t *pl[],
142 	size_t plsz,
143 	struct seg *seg,
144 	caddr_t addr,
145 	enum seg_rw rw,
146 	struct cred *cr)
147 {
148 	struct page *pp, *rpp;
149 	int flags;
150 	int err = 0;
151 	struct vnode *pvp = NULL;
152 	u_offset_t poff;
153 	int flag_noreloc;
154 	se_t lock;
155 	extern int kcage_on;
156 	int upgrade = 0;
157 
158 	SWAPFS_PRINT(SWAP_VOPS, "swap_getapage: vp %p, off %llx, len %lx\n",
159 	    vp, off, len, 0, 0);
160 
161 	/*
162 	 * Until there is a call-back mechanism to cause SEGKP
163 	 * pages to be unlocked, make them non-relocatable.
164 	 */
165 	if (SEG_IS_SEGKP(seg))
166 		flag_noreloc = PG_NORELOC;
167 	else
168 		flag_noreloc = 0;
169 
170 	if (protp != NULL)
171 		*protp = PROT_ALL;
172 
173 	lock = (rw == S_CREATE ? SE_EXCL : SE_SHARED);
174 
175 again:
176 	if (pp = page_lookup(vp, off, lock)) {
177 		/*
178 		 * In very rare instances, a segkp page may have been
179 		 * relocated outside of the kernel by the kernel cage
180 		 * due to the window between page_unlock() and
181 		 * VOP_PUTPAGE() in segkp_unlock().  Due to the
182 		 * rareness of these occurances, the solution is to
183 		 * relocate the page to a P_NORELOC page.
184 		 */
185 		if (flag_noreloc != 0) {
186 			if (!PP_ISNORELOC(pp) && kcage_on) {
187 				if (lock != SE_EXCL) {
188 					upgrade = 1;
189 					if (!page_tryupgrade(pp)) {
190 						page_unlock(pp);
191 						lock = SE_EXCL;
192 						goto again;
193 					}
194 				}
195 
196 				if (page_relocate_cage(&pp, &rpp) != 0)
197 					panic("swap_getapage: "
198 					    "page_relocate_cage failed");
199 
200 				pp = rpp;
201 			}
202 		}
203 
204 		if (pl) {
205 			if (upgrade)
206 				page_downgrade(pp);
207 
208 			pl[0] = pp;
209 			pl[1] = NULL;
210 		} else {
211 			page_unlock(pp);
212 		}
213 	} else {
214 		pp = page_create_va(vp, off, PAGESIZE,
215 		    PG_WAIT | PG_EXCL | flag_noreloc,
216 		    seg, addr);
217 		/*
218 		 * Someone raced in and created the page after we did the
219 		 * lookup but before we did the create, so go back and
220 		 * try to look it up again.
221 		 */
222 		if (pp == NULL)
223 			goto again;
224 		if (rw != S_CREATE) {
225 			err = swap_getphysname(vp, off, &pvp, &poff);
226 			if (pvp) {
227 				struct anon *ap;
228 				kmutex_t *ahm;
229 
230 				flags = (pl == NULL ? B_ASYNC|B_READ : B_READ);
231 				err = VOP_PAGEIO(pvp, pp, poff,
232 				    PAGESIZE, flags, cr, NULL);
233 
234 				if (!err) {
235 					ahm = AH_MUTEX(vp, off);
236 					mutex_enter(ahm);
237 
238 					ap = swap_anon(vp, off);
239 					if (ap == NULL) {
240 						panic("swap_getapage:"
241 						    " null anon");
242 					}
243 
244 					if (ap->an_pvp == pvp &&
245 					    ap->an_poff == poff) {
246 						swap_phys_free(pvp, poff,
247 						    PAGESIZE);
248 						ap->an_pvp = NULL;
249 						ap->an_poff = NULL;
250 						hat_setmod(pp);
251 					}
252 
253 					mutex_exit(ahm);
254 				}
255 			} else {
256 				if (!err)
257 					pagezero(pp, 0, PAGESIZE);
258 
259 				/*
260 				 * If it's a fault ahead, release page_io_lock
261 				 * and SE_EXCL we grabbed in page_create_va
262 				 *
263 				 * If we are here, we haven't called VOP_PAGEIO
264 				 * and thus calling pvn_read_done(pp, B_READ)
265 				 * below may mislead that we tried i/o. Besides,
266 				 * in case of async, pvn_read_done() should
267 				 * not be called by *getpage()
268 				 */
269 				if (pl == NULL) {
270 					/*
271 					 * swap_getphysname can return error
272 					 * only when we are getting called from
273 					 * swapslot_free which passes non-NULL
274 					 * pl to VOP_GETPAGE.
275 					 */
276 					ASSERT(err == 0);
277 					page_io_unlock(pp);
278 					page_unlock(pp);
279 				}
280 			}
281 		}
282 
283 		ASSERT(pp != NULL);
284 
285 		if (err && pl)
286 			pvn_read_done(pp, B_ERROR);
287 
288 		if (!err && pl)
289 			pvn_plist_init(pp, pl, plsz, off, PAGESIZE, rw);
290 	}
291 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_GETAPAGE,
292 	    "swapfs getapage:pp %p vp %p off %llx", pp, vp, off);
293 	return (err);
294 }
295 
296 /*
297  * Called from large page anon routines only! This is an ugly hack where
298  * the anon layer directly calls into swapfs with a preallocated large page.
299  * Another method would have been to change to VOP and add an extra arg for
300  * the preallocated large page. This all could be cleaned up later when we
301  * solve the anonymous naming problem and no longer need to loop across of
302  * the VOP in PAGESIZE increments to fill in or initialize a large page as
303  * is done today. I think the latter is better since it avoid a change to
304  * the VOP interface that could later be avoided.
305  */
306 int
307 swap_getconpage(
308 	struct vnode *vp,
309 	u_offset_t off,
310 	size_t len,
311 	uint_t *protp,
312 	page_t *pl[],
313 	size_t plsz,
314 	page_t	*conpp,
315 	uint_t	*pszc,
316 	spgcnt_t *nreloc,
317 	struct seg *seg,
318 	caddr_t addr,
319 	enum seg_rw rw,
320 	struct cred *cr)
321 {
322 	struct page	*pp;
323 	int 		err = 0;
324 	struct vnode	*pvp = NULL;
325 	u_offset_t	poff;
326 
327 	ASSERT(len == PAGESIZE);
328 	ASSERT(pl != NULL);
329 	ASSERT(plsz == PAGESIZE);
330 	ASSERT(protp == NULL);
331 	ASSERT(nreloc != NULL);
332 	ASSERT(!SEG_IS_SEGKP(seg)); /* XXX for now not supported */
333 	SWAPFS_PRINT(SWAP_VOPS, "swap_getconpage: vp %p, off %llx, len %lx\n",
334 	    vp, off, len, 0, 0);
335 
336 	/*
337 	 * If we are not using a preallocated page then we know one already
338 	 * exists. So just let the old code handle it.
339 	 */
340 	if (conpp == NULL) {
341 		err = swap_getapage(vp, (u_offset_t)off, len, protp, pl, plsz,
342 		    seg, addr, rw, cr);
343 		return (err);
344 	}
345 	ASSERT(conpp->p_szc != 0);
346 	ASSERT(PAGE_EXCL(conpp));
347 
348 
349 	ASSERT(conpp->p_next == conpp);
350 	ASSERT(conpp->p_prev == conpp);
351 	ASSERT(!PP_ISAGED(conpp));
352 	ASSERT(!PP_ISFREE(conpp));
353 
354 	*nreloc = 0;
355 	pp = page_lookup_create(vp, off, SE_SHARED, conpp, nreloc, 0);
356 
357 	/*
358 	 * If existing page is found we may need to relocate.
359 	 */
360 	if (pp != conpp) {
361 		ASSERT(rw != S_CREATE);
362 		ASSERT(pszc != NULL);
363 		ASSERT(PAGE_SHARED(pp));
364 		if (pp->p_szc < conpp->p_szc) {
365 			*pszc = pp->p_szc;
366 			page_unlock(pp);
367 			err = -1;
368 		} else if (pp->p_szc > conpp->p_szc &&
369 		    seg->s_szc > conpp->p_szc) {
370 			*pszc = MIN(pp->p_szc, seg->s_szc);
371 			page_unlock(pp);
372 			err = -2;
373 		} else {
374 			pl[0] = pp;
375 			pl[1] = NULL;
376 			if (page_pptonum(pp) &
377 			    (page_get_pagecnt(conpp->p_szc) - 1))
378 				cmn_err(CE_PANIC, "swap_getconpage: no root");
379 		}
380 		return (err);
381 	}
382 
383 	ASSERT(PAGE_EXCL(pp));
384 
385 	if (*nreloc != 0) {
386 		ASSERT(rw != S_CREATE);
387 		pl[0] = pp;
388 		pl[1] = NULL;
389 		return (0);
390 	}
391 
392 	*nreloc = 1;
393 
394 	/*
395 	 * If necessary do the page io.
396 	 */
397 	if (rw != S_CREATE) {
398 		/*
399 		 * Since we are only called now on behalf of an
400 		 * address space operation it's impossible for
401 		 * us to fail unlike swap_getapge() which
402 		 * also gets called from swapslot_free().
403 		 */
404 		if (swap_getphysname(vp, off, &pvp, &poff)) {
405 			cmn_err(CE_PANIC,
406 			    "swap_getconpage: swap_getphysname failed!");
407 		}
408 
409 		if (pvp != NULL) {
410 			err = VOP_PAGEIO(pvp, pp, poff, PAGESIZE, B_READ,
411 			    cr, NULL);
412 			if (err == 0) {
413 				struct anon *ap;
414 				kmutex_t *ahm;
415 
416 				ahm = AH_MUTEX(vp, off);
417 				mutex_enter(ahm);
418 				ap = swap_anon(vp, off);
419 				if (ap == NULL)
420 					panic("swap_getconpage: null anon");
421 				if (ap->an_pvp != pvp || ap->an_poff != poff)
422 					panic("swap_getconpage: bad anon");
423 
424 				swap_phys_free(pvp, poff, PAGESIZE);
425 				ap->an_pvp = NULL;
426 				ap->an_poff = NULL;
427 				hat_setmod(pp);
428 				mutex_exit(ahm);
429 			}
430 		} else {
431 			pagezero(pp, 0, PAGESIZE);
432 		}
433 	}
434 
435 	/*
436 	 * Normally we would let pvn_read_done() destroy
437 	 * the page on IO error. But since this is a preallocated
438 	 * page we'll let the anon layer handle it.
439 	 */
440 	page_io_unlock(pp);
441 	if (err != 0)
442 		page_hashout(pp, NULL);
443 	ASSERT(pp->p_next == pp);
444 	ASSERT(pp->p_prev == pp);
445 
446 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_GETAPAGE,
447 	    "swapfs getconpage:pp %p vp %p off %llx", pp, vp, off);
448 
449 	pl[0] = pp;
450 	pl[1] = NULL;
451 	return (err);
452 }
453 
454 /* Async putpage klustering stuff */
455 int sw_pending_size;
456 extern int klustsize;
457 extern struct async_reqs *sw_getreq();
458 extern void sw_putreq(struct async_reqs *);
459 extern void sw_putbackreq(struct async_reqs *);
460 extern struct async_reqs *sw_getfree();
461 extern void sw_putfree(struct async_reqs *);
462 
463 static size_t swap_putpagecnt, swap_pagespushed;
464 static size_t swap_otherfail, swap_otherpages;
465 static size_t swap_klustfail, swap_klustpages;
466 static size_t swap_getiofail, swap_getiopages;
467 
468 /*
469  * Flags are composed of {B_INVAL, B_DIRTY B_FREE, B_DONTNEED}.
470  * If len == 0, do from off to EOF.
471  */
472 static int swap_nopage = 0;	/* Don't do swap_putpage's if set */
473 
474 /* ARGSUSED */
475 static int
476 swap_putpage(
477 	struct vnode *vp,
478 	offset_t off,
479 	size_t len,
480 	int flags,
481 	struct cred *cr,
482 	caller_context_t *ct)
483 {
484 	page_t *pp;
485 	u_offset_t io_off;
486 	size_t io_len = 0;
487 	int err = 0;
488 	int nowait;
489 	struct async_reqs *arg;
490 
491 	if (swap_nopage)
492 		return (0);
493 
494 	ASSERT(vp->v_count != 0);
495 
496 	nowait = flags & B_PAGE_NOWAIT;
497 
498 	/*
499 	 * Clear force flag so that p_lckcnt pages are not invalidated.
500 	 */
501 	flags &= ~(B_FORCE | B_PAGE_NOWAIT);
502 
503 	SWAPFS_PRINT(SWAP_VOPS,
504 	    "swap_putpage: vp %p, off %llx len %lx, flags %x\n",
505 	    (void *)vp, off, len, flags, 0);
506 	TRACE_3(TR_FAC_SWAPFS, TR_SWAPFS_PUTPAGE,
507 	    "swapfs putpage:vp %p off %llx len %ld", (void *)vp, off, len);
508 
509 	if (vp->v_flag & VNOMAP)
510 		return (ENOSYS);
511 
512 	if (!vn_has_cached_data(vp))
513 		return (0);
514 
515 	if (len == 0) {
516 		if (curproc == proc_pageout)
517 			cmn_err(CE_PANIC, "swapfs: pageout can't block");
518 
519 		/* Search the entire vp list for pages >= off. */
520 		err = pvn_vplist_dirty(vp, (u_offset_t)off, swap_putapage,
521 		    flags, cr);
522 	} else {
523 		u_offset_t eoff;
524 
525 		/*
526 		 * Loop over all offsets in the range [off...off + len]
527 		 * looking for pages to deal with.
528 		 */
529 		eoff = off + len;
530 		for (io_off = (u_offset_t)off; io_off < eoff;
531 		    io_off += io_len) {
532 			/*
533 			 * If we run out of the async req slot, put the page
534 			 * now instead of queuing.
535 			 */
536 			if (flags == (B_ASYNC | B_FREE) &&
537 			    sw_pending_size < klustsize &&
538 			    (arg = sw_getfree())) {
539 				/*
540 				 * If we are clustering, we should allow
541 				 * pageout to feed us more pages because # of
542 				 * pushes is limited by # of I/Os, and one
543 				 * cluster is considered to be one I/O.
544 				 */
545 				if (pushes)
546 					pushes--;
547 
548 				arg->a_vp = vp;
549 				arg->a_off = io_off;
550 				arg->a_len = PAGESIZE;
551 				arg->a_flags = B_ASYNC | B_FREE;
552 				arg->a_cred = kcred;
553 				sw_putreq(arg);
554 				io_len = PAGESIZE;
555 				continue;
556 			}
557 			/*
558 			 * If we are not invalidating pages, use the
559 			 * routine page_lookup_nowait() to prevent
560 			 * reclaiming them from the free list.
561 			 */
562 			if (!nowait && ((flags & B_INVAL) ||
563 			    (flags & (B_ASYNC | B_FREE)) == B_FREE))
564 				pp = page_lookup(vp, io_off, SE_EXCL);
565 			else
566 				pp = page_lookup_nowait(vp, io_off,
567 				    (flags & (B_FREE | B_INVAL)) ?
568 				    SE_EXCL : SE_SHARED);
569 
570 			if (pp == NULL || pvn_getdirty(pp, flags) == 0)
571 				io_len = PAGESIZE;
572 			else {
573 				err = swap_putapage(vp, pp, &io_off, &io_len,
574 				    flags, cr);
575 				if (err != 0)
576 					break;
577 			}
578 		}
579 	}
580 	/* If invalidating, verify all pages on vnode list are gone. */
581 	if (err == 0 && off == 0 && len == 0 &&
582 	    (flags & B_INVAL) && vn_has_cached_data(vp)) {
583 		cmn_err(CE_WARN,
584 		    "swap_putpage: B_INVAL, pages not gone");
585 	}
586 	return (err);
587 }
588 
589 /*
590  * Write out a single page.
591  * For swapfs this means choose a physical swap slot and write the page
592  * out using VOP_PAGEIO.
593  * In the (B_ASYNC | B_FREE) case we try to find a bunch of other dirty
594  * swapfs pages, a bunch of contiguous swap slots and then write them
595  * all out in one clustered i/o.
596  */
597 /*ARGSUSED*/
598 static int
599 swap_putapage(
600 	struct vnode *vp,
601 	page_t *pp,
602 	u_offset_t *offp,
603 	size_t *lenp,
604 	int flags,
605 	struct cred *cr)
606 {
607 	int err;
608 	struct vnode *pvp;
609 	u_offset_t poff, off;
610 	u_offset_t doff;
611 	size_t dlen;
612 	size_t klsz = 0;
613 	u_offset_t klstart = 0;
614 	struct vnode *klvp = NULL;
615 	page_t *pplist;
616 	se_t se;
617 	struct async_reqs *arg;
618 	size_t swap_klustsize;
619 
620 	/*
621 	 * This check is added for callers who access swap_putpage with len = 0.
622 	 * swap_putpage calls swap_putapage page-by-page via pvn_vplist_dirty.
623 	 * And it's necessary to do the same queuing if users have the same
624 	 * B_ASYNC|B_FREE flags on.
625 	 */
626 	if (flags == (B_ASYNC | B_FREE) &&
627 	    sw_pending_size < klustsize && (arg = sw_getfree())) {
628 
629 		hat_setmod(pp);
630 		page_io_unlock(pp);
631 		page_unlock(pp);
632 
633 		arg->a_vp = vp;
634 		arg->a_off = pp->p_offset;
635 		arg->a_len = PAGESIZE;
636 		arg->a_flags = B_ASYNC | B_FREE;
637 		arg->a_cred = kcred;
638 		sw_putreq(arg);
639 
640 		return (0);
641 	}
642 
643 	SWAPFS_PRINT(SWAP_PUTP,
644 	    "swap_putapage: pp %p, vp %p, off %llx, flags %x\n",
645 	    pp, vp, pp->p_offset, flags, 0);
646 
647 	ASSERT(PAGE_LOCKED(pp));
648 
649 	off = pp->p_offset;
650 
651 	doff = off;
652 	dlen = PAGESIZE;
653 
654 	if (err = swap_newphysname(vp, off, &doff, &dlen, &pvp, &poff)) {
655 		err = (flags == (B_ASYNC | B_FREE) ? ENOMEM : 0);
656 		hat_setmod(pp);
657 		page_io_unlock(pp);
658 		page_unlock(pp);
659 		goto out;
660 	}
661 
662 	klvp = pvp;
663 	klstart = poff;
664 	pplist = pp;
665 	/*
666 	 * If this is ASYNC | FREE and we've accumulated a bunch of such
667 	 * pending requests, kluster.
668 	 */
669 	if (flags == (B_ASYNC | B_FREE))
670 		swap_klustsize = klustsize;
671 	else
672 		swap_klustsize = PAGESIZE;
673 	se = (flags & B_FREE ? SE_EXCL : SE_SHARED);
674 	klsz = PAGESIZE;
675 	while (klsz < swap_klustsize) {
676 		if ((arg = sw_getreq()) == NULL) {
677 			swap_getiofail++;
678 			swap_getiopages += btop(klsz);
679 			break;
680 		}
681 		ASSERT(vn_matchops(arg->a_vp, swap_vnodeops));
682 		vp = arg->a_vp;
683 		off = arg->a_off;
684 
685 		if ((pp = page_lookup_nowait(vp, off, se)) == NULL) {
686 			swap_otherfail++;
687 			swap_otherpages += btop(klsz);
688 			sw_putfree(arg);
689 			break;
690 		}
691 		if (pvn_getdirty(pp, flags | B_DELWRI) == 0) {
692 			sw_putfree(arg);
693 			continue;
694 		}
695 		/* Get new physical backing store for the page */
696 		doff = off;
697 		dlen = PAGESIZE;
698 		if (err = swap_newphysname(vp, off, &doff, &dlen,
699 		    &pvp, &poff)) {
700 			swap_otherfail++;
701 			swap_otherpages += btop(klsz);
702 			hat_setmod(pp);
703 			page_io_unlock(pp);
704 			page_unlock(pp);
705 			sw_putbackreq(arg);
706 			break;
707 		}
708 		/* Try to cluster new physical name with previous ones */
709 		if (klvp == pvp && poff == klstart + klsz) {
710 			klsz += PAGESIZE;
711 			page_add(&pplist, pp);
712 			pplist = pplist->p_next;
713 			sw_putfree(arg);
714 		} else if (klvp == pvp && poff == klstart - PAGESIZE) {
715 			klsz += PAGESIZE;
716 			klstart -= PAGESIZE;
717 			page_add(&pplist, pp);
718 			sw_putfree(arg);
719 		} else {
720 			swap_klustfail++;
721 			swap_klustpages += btop(klsz);
722 			hat_setmod(pp);
723 			page_io_unlock(pp);
724 			page_unlock(pp);
725 			sw_putbackreq(arg);
726 			break;
727 		}
728 	}
729 
730 	err = VOP_PAGEIO(klvp, pplist, klstart, klsz,
731 	    B_WRITE | flags, cr, NULL);
732 
733 	if ((flags & B_ASYNC) == 0)
734 		pvn_write_done(pp, ((err) ? B_ERROR : 0) | B_WRITE | flags);
735 
736 	/* Statistics */
737 	if (!err) {
738 		swap_putpagecnt++;
739 		swap_pagespushed += btop(klsz);
740 	}
741 out:
742 	TRACE_4(TR_FAC_SWAPFS, TR_SWAPFS_PUTAPAGE,
743 	    "swapfs putapage:vp %p klvp %p, klstart %lx, klsz %lx",
744 	    vp, klvp, klstart, klsz);
745 	if (err && err != ENOMEM)
746 		cmn_err(CE_WARN, "swapfs_putapage: err %d\n", err);
747 	if (lenp)
748 		*lenp = PAGESIZE;
749 	return (err);
750 }
751 
752 static void
753 swap_dispose(
754 	vnode_t *vp,
755 	page_t *pp,
756 	int fl,
757 	int dn,
758 	cred_t *cr,
759 	caller_context_t *ct)
760 {
761 	int err;
762 	u_offset_t off = pp->p_offset;
763 	vnode_t *pvp;
764 	u_offset_t poff;
765 
766 	ASSERT(PAGE_EXCL(pp));
767 
768 	/*
769 	 * The caller will free/invalidate large page in one shot instead of
770 	 * one small page at a time.
771 	 */
772 	if (pp->p_szc != 0) {
773 		page_unlock(pp);
774 		return;
775 	}
776 
777 	err = swap_getphysname(vp, off, &pvp, &poff);
778 	if (!err && pvp != NULL)
779 		VOP_DISPOSE(pvp, pp, fl, dn, cr, ct);
780 	else
781 		fs_dispose(vp, pp, fl, dn, cr, ct);
782 }
783