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