|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1987 Carnegie-Mellon University ! 28: * All rights reserved. The CMU software License Agreement specifies ! 29: * the terms and conditions for use and redistribution. ! 30: */ ! 31: ! 32: /* ! 33: * File: vnode_pager.c ! 34: * ! 35: * "Swap" pager that pages to/from vnodes. Also ! 36: * handles demand paging from files. ! 37: * ! 38: * 12-Mar-86 David Golub (dbg) at Carnegie-Mellon University ! 39: * Created. ! 40: */ ! 41: ! 42: #import <mach_nbc.h> ! 43: ! 44: #import <mach/boolean.h> ! 45: #import <sys/param.h> ! 46: #import <sys/systm.h> ! 47: #import <kern/lock.h> ! 48: #import <sys/proc.h> ! 49: #import <sys/buf.h> ! 50: #import <sys/uio.h> ! 51: #import <sys/vnode.h> ! 52: #import <ufs/ufs/quota.h> ! 53: #import <ufs/ufs/inode.h> ! 54: #import <sys/namei.h> ! 55: #import <sys/mach_swapon.h> ! 56: #import <ufs/ffs/fs.h> ! 57: #import <sys/mount.h> ! 58: #import <net/if.h> ! 59: #import <netinet/in.h> ! 60: #import <nfs/rpcv2.h> ! 61: #import <nfs/nfsproto.h> ! 62: #import <nfs/nfs.h> ! 63: #undef fs_fsok ! 64: #undef fs_tsize ! 65: #undef fs_bsize ! 66: #undef fs_blocks ! 67: #undef fs_bfree ! 68: #undef fs_bavail ! 69: ! 70: #import <mach/mach_types.h> ! 71: #import <vm/vm_page.h> ! 72: #if defined(ppc) ! 73: #import <vm/pmap.h> ! 74: #endif /* ppc */ ! 75: #import <vm/vm_map.h> ! 76: #import <vm/vm_kern.h> ! 77: #import <kern/parallel.h> ! 78: #import <kern/zalloc.h> ! 79: #import <kern/kalloc.h> ! 80: ! 81: #import <vm/vnode_pager.h> ! 82: #import <kern/mapfs.h> ! 83: ! 84: #import <kern/assert.h> ! 85: ! 86: extern struct vnodeops nfs_vnodeops; ! 87: extern struct vnodeops spec_vnodeops; ! 88: ! 89: #if NBBY == 8 ! 90: #define BYTEMASK 0xff ! 91: #else NBBY ! 92: Define a byte mask for this machine. ! 93: #endif NBBY ! 94: ! 95: ! 96: #define PAGEMAP_THRESHOLD 64 /* Integral of sizeof(vm_offset_t) */ ! 97: #define PAGEMAP_ENTRIES (PAGEMAP_THRESHOLD/sizeof(vm_offset_t)) ! 98: #define PAGEMAP_SIZE(npgs) (npgs*sizeof(long)) ! 99: ! 100: #define INDIR_PAGEMAP_ENTRIES(npgs) \ ! 101: (((npgs-1)/PAGEMAP_ENTRIES) + 1) ! 102: #define INDIR_PAGEMAP_SIZE(npgs) \ ! 103: (INDIR_PAGEMAP_ENTRIES(npgs) * sizeof(caddr_t)) ! 104: #define INDIR_PAGEMAP(size) \ ! 105: (PAGEMAP_SIZE(size) > PAGEMAP_THRESHOLD) ! 106: ! 107: #define RMAPSIZE(blocks) \ ! 108: (howmany(blocks,NBBY)) ! 109: ! 110: /* ! 111: * Sigh... with NFS/vnodes it is highly likely that we will need ! 112: * to allocate memory at page-out time, so use the XP hack to reserve ! 113: * pages and always use kalloc/zalloc instead of kget/zget. ! 114: * This must be fixed!!! FIXME - XXX. ! 115: */ ! 116: ! 117: #define kget(size) kalloc_noblock(size) ! 118: #define zget(zone) zalloc_noblock(zone) ! 119: ! 120: /* ! 121: * Basic vnode pager data structures ! 122: */ ! 123: zone_t vstruct_zone; ! 124: simple_lock_data_t vstruct_lock; ! 125: ! 126: static queue_head_t pager_files; ! 127: static int pager_file_count; ! 128: static pager_file_t pager_file_list[MAXPAGERFILES]; ! 129: ! 130: static pf_entry seen_files[MAXPAGERFILES]; ! 131: static int seen_files_max = 0; ! 132: ! 133: ! 134: /* ! 135: * Routine: vnode_pager_vput ! 136: * Function: ! 137: * Release one use of this vnode_pager_t ! 138: */ ! 139: void ! 140: vnode_pager_vput(vs) ! 141: register vnode_pager_t vs; ! 142: { ! 143: ! 144: simple_lock(&vstruct_lock); ! 145: vs->vs_count--; ! 146: simple_unlock(&vstruct_lock); ! 147: } ! 148: ! 149: /* ! 150: * vnode_pager_vget: ! 151: * ! 152: * Return a vnode corresponding to the specified paging space ! 153: * and guarantee that it will remain in memory (until furthur action ! 154: * is taken). ! 155: * ! 156: * The vnode is returned unlocked. ! 157: */ ! 158: struct vnode * ! 159: vnode_pager_vget(vs) ! 160: vnode_pager_t vs; ! 161: { ! 162: register struct vnode *vp; ! 163: ! 164: simple_lock(&vstruct_lock); ! 165: vs->vs_count++; ! 166: simple_unlock(&vstruct_lock); ! 167: vp = vs->vs_vp; ! 168: return(vp); ! 169: } ! 170: ! 171: ! 172: /* ! 173: * vnode_pager_allocpage - allocate a page in a paging file ! 174: */ ! 175: daddr_t ! 176: vnode_pager_allocpage(pf) ! 177: register struct pager_file *pf; ! 178: { ! 179: int bp; /* byte counter */ ! 180: int i; /* bit counter */ ! 181: daddr_t page; /* page number */ ! 182: ! 183: lock_write(&pf->pf_lock); ! 184: ! 185: if (pf->pf_pfree == 0) { ! 186: lock_done(&pf->pf_lock); ! 187: return(-1); ! 188: } ! 189: ! 190: /* ! 191: * Start at hint page and work up. ! 192: */ ! 193: i = 0; ! 194: for (bp = pf->pf_hint / NBBY; bp < howmany(pf->pf_npgs, NBBY); bp++) { ! 195: if (*(pf->pf_bmap + bp) != BYTEMASK) { ! 196: for (i = 0; i < NBBY; i++) { ! 197: if (isclr((pf->pf_bmap + bp), i)) ! 198: break; ! 199: } ! 200: break; ! 201: } ! 202: } ! 203: page = bp*NBBY+i; ! 204: if (page >= pf->pf_npgs) { ! 205: panic("vnode_pager_allocpage"); ! 206: } ! 207: if (page > pf->pf_hipage) { ! 208: pf->pf_hipage = page; ! 209: } ! 210: setbit(pf->pf_bmap,page); ! 211: --pf->pf_pfree; ! 212: pf->pf_hint = page; ! 213: ! 214: lock_done(&pf->pf_lock); ! 215: return(page); ! 216: } ! 217: ! 218: ! 219: /* ! 220: * vnode_pager_findpage - find an available page in some paging file, using the ! 221: * argument as a preference. If the pager_file argument is NULL, any file will ! 222: * do. Return the designated page and file in entry. ! 223: */ ! 224: kern_return_t ! 225: vnode_pager_findpage(struct pager_file *preferPf, pf_entry *entry) ! 226: { ! 227: daddr_t result; ! 228: pager_file_t pf; ! 229: ! 230: if (preferPf == PAGER_FILE_NULL) { ! 231: if (!queue_empty(&pager_files)) ! 232: preferPf = (pager_file_t) queue_first(&pager_files); ! 233: else ! 234: return KERN_FAILURE; ! 235: } ! 236: ! 237: pf = preferPf; ! 238: do { ! 239: result = vnode_pager_allocpage(pf); ! 240: if (result != -1) { ! 241: entry->index = pf->pf_index; ! 242: entry->offset = result; ! 243: return KERN_SUCCESS; ! 244: } ! 245: ! 246: if (queue_end(&pager_files, &pf->pf_chain)) ! 247: pf = (pager_file_t) queue_first(&pager_files); ! 248: else ! 249: pf = (pager_file_t) queue_next(&pf->pf_chain); ! 250: ! 251: } while (preferPf != pf); ! 252: ! 253: return KERN_FAILURE; ! 254: } ! 255: ! 256: static void ! 257: vnode_pager_deallocpage(pf_entry entry) ! 258: { ! 259: register struct pager_file *pf; ! 260: daddr_t page; ! 261: ! 262: if (entry.index == INDEX_NULL) ! 263: return; ! 264: ! 265: assert(entry.index <= pager_file_count); ! 266: ! 267: pf = pager_file_list[entry.index]; ! 268: page = entry.offset; ! 269: ! 270: lock_write(&pf->pf_lock); ! 271: ! 272: if (page >= (daddr_t) pf->pf_npgs) ! 273: panic("vnode_pager_deallocpage"); ! 274: if (page < pf->pf_hint) ! 275: pf->pf_hint = page; ! 276: clrbit(pf->pf_bmap, page); ! 277: ++pf->pf_pfree; ! 278: ! 279: lock_done(&pf->pf_lock); ! 280: } ! 281: ! 282: ! 283: /* ! 284: * pagerfile_pager_create ! 285: * ! 286: * Create an vstruct corresponding to the given pagerfile. ! 287: * ! 288: */ ! 289: vnode_pager_t ! 290: pagerfile_pager_create(pf, size) ! 291: register pager_file_t pf; ! 292: vm_size_t size; ! 293: { ! 294: register vnode_pager_t vs; ! 295: register int i; ! 296: ! 297: /* ! 298: * XXX This can still livelock -- if the ! 299: * pageout daemon needs an vnode_pager record ! 300: * it won't get one until someone else ! 301: * refills the zone. ! 302: */ ! 303: ! 304: vs = (struct vstruct *) zget(vstruct_zone); ! 305: ! 306: if (vs == VNODE_PAGER_NULL) ! 307: return(vs); ! 308: ! 309: vs->vs_size = atop(round_page(size)); ! 310: ! 311: if (vs->vs_size == 0) ! 312: vs->vs_pmap = (pf_entry **) 0; ! 313: else { ! 314: if (INDIR_PAGEMAP(vs->vs_size)) { ! 315: vs->vs_pmap = (pf_entry **) ! 316: kget(INDIR_PAGEMAP_SIZE(vs->vs_size)); ! 317: } else { ! 318: vs->vs_pmap = (pf_entry **) ! 319: kget(PAGEMAP_SIZE(vs->vs_size)); ! 320: } ! 321: if (vs->vs_pmap == (pf_entry **) 0) { ! 322: /* ! 323: * We can't sleep here, so if there are no free pages, then ! 324: * just return nothing. ! 325: */ ! 326: zfree(vstruct_zone, (vm_offset_t) vs); ! 327: return(VNODE_PAGER_NULL); ! 328: } ! 329: ! 330: if (INDIR_PAGEMAP(vs->vs_size)) { ! 331: bzero((caddr_t)vs->vs_pmap, ! 332: INDIR_PAGEMAP_SIZE(vs->vs_size)); ! 333: } else { ! 334: for (i = 0; i < vs->vs_size; i++) ! 335: ((pf_entry *) &vs->vs_pmap[i])->index = INDEX_NULL; ! 336: } ! 337: } ! 338: ! 339: vs->is_device = FALSE; ! 340: vs->vs_count = 1; ! 341: vs->vs_vp = pf->pf_vp; ! 342: vs->vs_swapfile = TRUE; ! 343: vs->vs_pf = pf; ! 344: pf->pf_count++; ! 345: ! 346: vnode_pager_vput(vs); ! 347: ! 348: return(vs); ! 349: } ! 350: ! 351: ! 352: /* ! 353: * pagerfile_lookup ! 354: * ! 355: * Look for an entry at the specified offset in vstruct. If it's there, ! 356: * fill in the entry and return TRUE, otherwise return FALSE. ! 357: */ ! 358: static boolean_t ! 359: pagerfile_lookup(struct vstruct *vs, vm_offset_t f_offset, pf_entry *entry) ! 360: { ! 361: vm_offset_t f_page = atop(f_offset); ! 362: int indirBlock; ! 363: int blockOffset; ! 364: ! 365: if (f_page >= vs->vs_size) ! 366: return FALSE; ! 367: ! 368: /* ! 369: * Now look for the entry in the map. ! 370: */ ! 371: if (INDIR_PAGEMAP(vs->vs_size)) { ! 372: indirBlock = f_page / PAGEMAP_ENTRIES; ! 373: blockOffset = f_page % PAGEMAP_ENTRIES; ! 374: ! 375: if (vs->vs_pmap[indirBlock] == NULL || ! 376: vs->vs_pmap[indirBlock][blockOffset].index == INDEX_NULL) ! 377: return FALSE; ! 378: else ! 379: *entry = vs->vs_pmap[indirBlock][blockOffset]; ! 380: ! 381: } else { /* direct map */ ! 382: ! 383: if (((pf_entry *) &vs->vs_pmap[f_page])->index == INDEX_NULL) ! 384: return FALSE; ! 385: else ! 386: *entry = *((pf_entry *) &vs->vs_pmap[f_page]); ! 387: } ! 388: return TRUE; ! 389: } ! 390: ! 391: ! 392: /* ! 393: * pagerfile_bmap ! 394: * ! 395: * Fill in the map entry (pager file, offset) for a given f_offset into an ! 396: * object backed this pager map. ! 397: * ! 398: * Returns: KERN_FAILURE if page not in map or no room left ! 399: */ ! 400: static kern_return_t ! 401: pagerfile_bmap(vs, f_offset, flag, entry) ! 402: struct vstruct *vs; ! 403: vm_offset_t f_offset; ! 404: int flag; ! 405: pf_entry *entry; ! 406: { ! 407: vm_offset_t f_page = atop(f_offset); ! 408: boolean_t found; ! 409: int i; ! 410: ! 411: /* ! 412: * Check the map to see if we can find it. If we can't, then we'll ! 413: * make room below. ! 414: */ ! 415: found = pagerfile_lookup(vs, f_offset, entry); ! 416: ! 417: if ((found) && (entry->index > pager_file_count)) ! 418: panic("pagerfile_bmap: bad index %d", entry->index); ! 419: ! 420: if (flag == B_READ) ! 421: return found ? KERN_SUCCESS : KERN_FAILURE; ! 422: else if (found) { ! 423: /* ! 424: * Deallocate the page here, if the hint says that there's free ! 425: * space earlier in the file. We do this to keep the swapfile ! 426: * as small as possible, and to enable the swapfile compactor. ! 427: */ ! 428: struct pager_file *pf; ! 429: ! 430: if (entry->index == 0) ! 431: panic("pagerfile_bmap: 0 index"); ! 432: ! 433: pf = pager_file_list[entry->index]; ! 434: if (pf->pf_hint < entry->offset) ! 435: vnode_pager_deallocpage(*entry); ! 436: else ! 437: return KERN_SUCCESS; ! 438: } ! 439: ! 440: /* ! 441: * If the object has grown, expand the page map. ! 442: */ ! 443: if (f_page + 1 > vs->vs_size) { ! 444: pf_entry **new_pmap; ! 445: int new_size; ! 446: ! 447: new_size = f_page + 1; ! 448: assert(new_size > 0); ! 449: ! 450: if (INDIR_PAGEMAP(new_size)) { /* new map is indirect */ ! 451: ! 452: if (vs->vs_size == 0) { ! 453: /* ! 454: * Nothing to copy, just get a new ! 455: * map and zero it. ! 456: */ ! 457: new_pmap = (pf_entry **) kget(INDIR_PAGEMAP_SIZE(new_size)); ! 458: if (new_pmap == NULL) ! 459: return (KERN_FAILURE); ! 460: bzero((caddr_t)new_pmap, INDIR_PAGEMAP_SIZE(new_size)); ! 461: } ! 462: else if (INDIR_PAGEMAP(vs->vs_size)) { ! 463: ! 464: if (INDIR_PAGEMAP_SIZE(new_size) == ! 465: INDIR_PAGEMAP_SIZE(vs->vs_size)) { ! 466: goto leavemapalone; ! 467: } ! 468: ! 469: /* Get a new indirect map */ ! 470: new_pmap = (pf_entry **) kget(INDIR_PAGEMAP_SIZE(new_size)); ! 471: if (new_pmap == NULL) ! 472: return KERN_FAILURE; ! 473: ! 474: bzero((caddr_t)new_pmap, INDIR_PAGEMAP_SIZE(new_size)); ! 475: ! 476: /* Old map is indirect, copy the entries */ ! 477: for (i = 0; i < INDIR_PAGEMAP_ENTRIES(vs->vs_size); i++) ! 478: new_pmap[i] = vs->vs_pmap[i]; ! 479: ! 480: /* And free the old map */ ! 481: kfree(vs->vs_pmap, INDIR_PAGEMAP_SIZE(vs->vs_size)); ! 482: ! 483: } else { /* old map was direct, new map is indirect */ ! 484: ! 485: /* Get a new indirect map */ ! 486: new_pmap = (pf_entry **) kget(INDIR_PAGEMAP_SIZE(new_size)); ! 487: if (new_pmap == NULL) ! 488: return KERN_FAILURE; ! 489: ! 490: bzero((caddr_t)new_pmap, INDIR_PAGEMAP_SIZE(new_size)); ! 491: ! 492: /* ! 493: * Old map is direct, move it to the first indirect block. ! 494: */ ! 495: new_pmap[0] = (pf_entry *) kget(PAGEMAP_THRESHOLD); ! 496: if (new_pmap[0] == NULL) { ! 497: kfree(new_pmap, INDIR_PAGEMAP_SIZE(new_size)); ! 498: return KERN_FAILURE; ! 499: } ! 500: for (i = 0; i < vs->vs_size; i++) ! 501: new_pmap[0][i] = *((pf_entry *) &vs->vs_pmap[i]); ! 502: ! 503: /* Initialize the remainder of the block */ ! 504: for (i = vs->vs_size; i < PAGEMAP_ENTRIES; i++) ! 505: new_pmap[0][i].index = INDEX_NULL; ! 506: ! 507: /* And free the old map */ ! 508: kfree(vs->vs_pmap, PAGEMAP_SIZE(vs->vs_size)); ! 509: } ! 510: ! 511: } else { /* The new map is a direct one */ ! 512: ! 513: new_pmap = (pf_entry **) kget(PAGEMAP_SIZE(new_size)); ! 514: if (new_pmap == NULL) ! 515: return KERN_FAILURE; ! 516: ! 517: /* Copy info from the old map */ ! 518: for (i = 0; i < vs->vs_size; i++) ! 519: new_pmap[i] = vs->vs_pmap[i]; ! 520: ! 521: /* Initialize the rest of the new map */ ! 522: for (i = vs->vs_size; i < new_size; i++) ! 523: ((pf_entry *) &new_pmap[i])->index = INDEX_NULL; ! 524: ! 525: if (vs->vs_size > 0) ! 526: kfree(vs->vs_pmap, PAGEMAP_SIZE(vs->vs_size)); ! 527: } ! 528: ! 529: vs->vs_pmap = new_pmap; ! 530: leavemapalone: ! 531: vs->vs_size = new_size; ! 532: } ! 533: ! 534: /* ! 535: * Now allocate the spot for the new page. ! 536: */ ! 537: if (INDIR_PAGEMAP(vs->vs_size)) { ! 538: ! 539: int indirBlock = f_page / PAGEMAP_ENTRIES; /* the indirect block */ ! 540: int blockOffset = f_page % PAGEMAP_ENTRIES; /* offset into block */ ! 541: ! 542: /* ! 543: * In an indirect map, we may need to allocate space for the ! 544: * indirect block itself. ! 545: */ ! 546: if (vs->vs_pmap[indirBlock] == NULL) { ! 547: vs->vs_pmap[indirBlock]=(pf_entry *) kget(PAGEMAP_THRESHOLD); ! 548: ! 549: if (vs->vs_pmap[indirBlock] == NULL) ! 550: return KERN_FAILURE; ! 551: ! 552: for (i = 0; i < PAGEMAP_ENTRIES; i++) ! 553: vs->vs_pmap[indirBlock][i].index = INDEX_NULL; ! 554: } ! 555: ! 556: if (vnode_pager_findpage(vs->vs_pf, entry) == KERN_FAILURE) ! 557: return KERN_FAILURE; ! 558: else ! 559: vs->vs_pmap[indirBlock][blockOffset] = *entry; ! 560: ! 561: } else { /* direct map */ ! 562: ! 563: if (vnode_pager_findpage(vs->vs_pf, entry) == KERN_FAILURE) ! 564: return KERN_FAILURE; ! 565: ! 566: *(pf_entry *) &vs->vs_pmap[f_page] = *entry; ! 567: } ! 568: ! 569: return KERN_SUCCESS; ! 570: } ! 571: ! 572: /* ! 573: * vnode_pager_create ! 574: * ! 575: * Create an vstruct corresponding to the given vp. ! 576: * ! 577: */ ! 578: vnode_pager_t ! 579: vnode_pager_create(vp) ! 580: register struct vnode *vp; ! 581: { ! 582: vnode_pager_t vs; ! 583: struct vattr vattr; ! 584: vm_size_t size; ! 585: struct proc *p = current_proc(); ! 586: int error; ! 587: ! 588: /* ! 589: * XXX This can still livelock -- if the ! 590: * pageout daemon needs a vnode_pager record ! 591: * it won't get one until someone else ! 592: * refills the zone. ! 593: */ ! 594: ! 595: vs = (struct vstruct *) zalloc(vstruct_zone); ! 596: ! 597: if (vs == VNODE_PAGER_NULL) ! 598: return(vs); ! 599: ! 600: bzero((caddr_t)vs, sizeof(struct vstruct)); ! 601: ! 602: vs->is_device = FALSE; ! 603: vs->vs_count = 1; ! 604: vp->v_vm_info->pager = (vm_pager_t) vs; ! 605: vs->vs_vp = vp; ! 606: vs->vs_swapfile = FALSE; ! 607: ! 608: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); ! 609: if (!error) { ! 610: size = vattr.va_size; ! 611: vp->v_vm_info->vnode_size = size; ! 612: } ! 613: else ! 614: vp->v_vm_info->vnode_size = 0; ! 615: ! 616: VREF(vp); ! 617: ! 618: vnode_pager_vput(vs); ! 619: ! 620: return(vs); ! 621: } ! 622: ! 623: /* ! 624: * vnode_pager_setup ! 625: * ! 626: * Set up a vstruct for a given vnode. This is an exported routine. ! 627: */ ! 628: vm_pager_t ! 629: vnode_pager_setup(vp, is_text, can_cache) ! 630: struct vnode *vp; ! 631: boolean_t is_text; ! 632: boolean_t can_cache; ! 633: { ! 634: register pager_file_t pf; ! 635: ! 636: unix_master(); ! 637: ! 638: if (is_text) ! 639: vp->v_flag |= VTEXT; ! 640: #if !MACH_NBC ! 641: if(!vp->v_vm_info) ! 642: vm_info_init(vp); ! 643: #endif /* MACH_NBC */ ! 644: ! 645: if (vp->v_vm_info->pager == vm_pager_null) { ! 646: /* ! 647: * Check to make sure this isn't in use as a pager file. ! 648: */ ! 649: for (pf = (pager_file_t) queue_first(&pager_files); ! 650: !queue_end(&pager_files, &pf->pf_chain); ! 651: pf = (pager_file_t) queue_next(&pf->pf_chain)) { ! 652: if (pf->pf_vp == vp) { ! 653: return(vm_pager_null); ! 654: } ! 655: } ! 656: (void) vnode_pager_create(vp); ! 657: if (can_cache) ! 658: vm_object_cache_object( ! 659: vm_object_lookup(vp->v_vm_info->pager), TRUE); ! 660: } ! 661: ! 662: unix_release(); ! 663: /* ! 664: * Try to keep something in the vstruct zone since we can sleep ! 665: * here if necessary. ! 666: */ ! 667: zfree(vstruct_zone, zalloc(vstruct_zone)); ! 668: return(vp->v_vm_info->pager); ! 669: } ! 670: ! 671: #ifdef i386 ! 672: ! 673: static __inline__ vm_offset_t ! 674: vnode_pageio_setup( ! 675: vm_page_t m ! 676: ) ! 677: { ! 678: return (VM_PAGE_TO_PHYS(m)); ! 679: } ! 680: ! 681: static __inline__ void ! 682: vnode_pageio_complete( ! 683: vm_page_t m, ! 684: vm_offset_t addr ! 685: ) ! 686: { ! 687: /* do nothing */ ! 688: } ! 689: ! 690: #else /* notdef i386 */ ! 691: ! 692: static vm_offset_t ! 693: vnode_pageio_setup( ! 694: vm_page_t m ! 695: ) ! 696: { ! 697: kern_return_t result; ! 698: vm_offset_t addr = vm_map_min(kernel_map); ! 699: ! 700: result = vm_map_find(kernel_map, VM_OBJECT_NULL, 0, ! 701: &addr, PAGE_SIZE, TRUE); ! 702: if (result != KERN_SUCCESS) ! 703: return (0); ! 704: ! 705: pmap_enter_phys_page(VM_PAGE_TO_PHYS(m), addr); ! 706: ! 707: return (addr); ! 708: } ! 709: ! 710: static void ! 711: vnode_pageio_complete( ! 712: vm_page_t m, ! 713: vm_offset_t addr ! 714: ) ! 715: { ! 716: vm_offset_t taddr = trunc_page(addr); ! 717: ! 718: (void) vm_map_remove(kernel_map, taddr, taddr + PAGE_SIZE); ! 719: } ! 720: ! 721: #endif /* notdef i386 */ ! 722: ! 723: pager_return_t ! 724: vnode_pagein( ! 725: vm_page_t m, ! 726: int *errorp ! 727: ) ! 728: { ! 729: struct vnode *vp; ! 730: vnode_pager_t vs; ! 731: pager_return_t result = PAGER_SUCCESS; ! 732: vm_offset_t f_offset; ! 733: pf_entry entry; ! 734: struct proc *p = current_proc(); ! 735: int error = 0; ! 736: ! 737: unix_master(); ! 738: ! 739: vs = (vnode_pager_t) m->object->pager; ! 740: vp = vnode_pager_vget(vs); ! 741: f_offset = m->offset + m->object->paging_offset; ! 742: ! 743: if (vs->vs_swapfile) { ! 744: if (pagerfile_bmap(vs, f_offset, B_READ, &entry) == KERN_FAILURE) ! 745: result = PAGER_ABSENT; ! 746: else { ! 747: f_offset = ptoa(entry.offset); ! 748: vp = pager_file_list[entry.index]->pf_vp; ! 749: } ! 750: } ! 751: ! 752: if (result != PAGER_ABSENT) { ! 753: vm_offset_t ioaddr = vnode_pageio_setup(m); ! 754: struct uio auio; ! 755: struct iovec aiov; ! 756: ! 757: if (ioaddr) { ! 758: auio.uio_iov = &aiov; ! 759: auio.uio_iovcnt = 1; ! 760: auio.uio_offset = f_offset; ! 761: auio.uio_segflg = UIO_SYSSPACE; ! 762: auio.uio_rw = UIO_READ; ! 763: auio.uio_resid = PAGE_SIZE; ! 764: auio.uio_procp = NULL; ! 765: ! 766: aiov.iov_len = PAGE_SIZE; ! 767: aiov.iov_base = (caddr_t)ioaddr; ! 768: ! 769: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p); ! 770: ! 771: m->nfspagereq=TRUE; ! 772: error = VOP_PAGEIN(vp, &auio, 0, p->p_ucred); ! 773: m->nfspagereq=FALSE; ! 774: if (error) ! 775: result = PAGER_ERROR; ! 776: vp->v_vm_info->error = error; ! 777: ! 778: VOP_UNLOCK(vp, 0, p); ! 779: ! 780: if (!error && auio.uio_resid > 0) ! 781: (void) memset((void *)(ioaddr + PAGE_SIZE - ! 782: auio.uio_resid), 0, auio.uio_resid); ! 783: ! 784: vnode_pageio_complete(m, ioaddr); ! 785: #ifdef ppc ! 786: /* ! 787: * After a pagein, we must synchronize the processor caches. ! 788: * On PPC, the i-cache is not coherent in all models, thus ! 789: * it needs to be invalidated. ! 790: */ ! 791: flush_cache(VM_PAGE_TO_PHYS(m), PAGE_SIZE); ! 792: #endif /* ppc */ ! 793: } ! 794: else ! 795: result = PAGER_ERROR; ! 796: } ! 797: ! 798: vnode_pager_vput(vs); ! 799: ! 800: if (errorp) ! 801: *errorp = error; ! 802: ! 803: unix_release(); ! 804: ! 805: return (result); ! 806: } ! 807: ! 808: pager_return_t ! 809: vnode_pageout( ! 810: vm_page_t m ! 811: ) ! 812: { ! 813: struct vnode *vp; ! 814: vnode_pager_t vs; ! 815: pager_return_t result = PAGER_SUCCESS; ! 816: vm_offset_t f_offset; ! 817: vm_size_t size = PAGE_SIZE; ! 818: pf_entry entry; ! 819: struct proc *p = current_proc(); ! 820: int error = 0; ! 821: ! 822: unix_master(); ! 823: ! 824: vs = (vnode_pager_t) m->object->pager; ! 825: vp = vnode_pager_vget(vs); ! 826: f_offset = m->offset + m->object->paging_offset; ! 827: ! 828: #if MACH_NBC ! 829: if (!vs->vs_swapfile) { ! 830: /* ! 831: * Be sure that a paging operation doesn't ! 832: * accidently extend the size of "mapped" file. ! 833: * ! 834: * However, we do extend the size up to the current ! 835: * size kept in the vm_info structure. ! 836: */ ! 837: if (f_offset + size > vp->v_vm_info->vnode_size) { ! 838: if (f_offset > vp->v_vm_info->vnode_size) ! 839: size = 0; ! 840: else ! 841: size = vp->v_vm_info->vnode_size - f_offset; ! 842: } ! 843: } ! 844: #endif MACH_NBC ! 845: ! 846: if (vs->vs_swapfile) { ! 847: if (pagerfile_bmap(vs, f_offset, B_WRITE, &entry) == KERN_FAILURE) ! 848: result = PAGER_ERROR; ! 849: else { ! 850: /* ! 851: * If the paging operation extends the size of the ! 852: * pagerfile, update the information in the vm_info ! 853: * structure ! 854: */ ! 855: f_offset = ptoa(entry.offset); ! 856: vp = pager_file_list[entry.index]->pf_vp; ! 857: if (f_offset + size > vp->v_vm_info->vnode_size) ! 858: vp->v_vm_info->vnode_size = f_offset + size; ! 859: } ! 860: } ! 861: ! 862: if (result != PAGER_ERROR && size > 0) { ! 863: vm_offset_t ioaddr = vnode_pageio_setup(m); ! 864: struct uio auio; ! 865: struct iovec aiov; ! 866: ! 867: if (ioaddr) { ! 868: auio.uio_iov = &aiov; ! 869: auio.uio_iovcnt = 1; ! 870: auio.uio_offset = f_offset; ! 871: auio.uio_segflg = UIO_SYSSPACE; ! 872: auio.uio_rw = UIO_WRITE; ! 873: auio.uio_procp = NULL; ! 874: aiov.iov_base = (caddr_t)ioaddr; ! 875: #if MACH_NBC ! 876: auio.uio_resid = size; ! 877: aiov.iov_len = size; ! 878: #else ! 879: auio.uio_resid = PAGE_SIZE; ! 880: aiov.iov_len = PAGE_SIZE; ! 881: #endif /* MACH_NBC */ ! 882: ! 883: #if MACH_NBC ! 884: { ! 885: #define VNODE_LOCK_RETRY_COUNT 1 ! 886: #define VNODE_LOCK_RETRY_TICKS 2 ! 887: ! 888: int retry = VNODE_LOCK_RETRY_COUNT; ! 889: vnode_lock_retry: ! 890: error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_CANRECURSE, p); ! 891: if (error) { ! 892: /* ! 893: * Retry the lock after yielding to other threads. ! 894: * Not doing this makes the pageout thread compute bound. ! 895: * Yielding lets I/O threads to run ! 896: * and make forward progress. ! 897: */ ! 898: if (retry-- > 0) { ! 899: thread_will_wait(current_thread()); ! 900: thread_set_timeout(VNODE_LOCK_RETRY_TICKS); ! 901: thread_block(); ! 902: goto vnode_lock_retry; ! 903: } ! 904: ! 905: result = PAGER_ERROR; ! 906: vnode_pageio_complete(m, ioaddr); ! 907: goto out; ! 908: } ! 909: } ! 910: #else /* MACH_NBC */ ! 911: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 912: #endif /* MACH_NBC */ ! 913: ! 914: error = VOP_PAGEOUT(vp, &auio, 0, p->p_ucred); ! 915: if (error) ! 916: result = PAGER_ERROR; ! 917: vp->v_vm_info->error = error; ! 918: ! 919: VOP_UNLOCK(vp, 0, p); ! 920: ! 921: vnode_pageio_complete(m, ioaddr); ! 922: } ! 923: else ! 924: result = PAGER_ERROR; ! 925: } ! 926: ! 927: if (result == PAGER_SUCCESS) { ! 928: m->clean = TRUE; /* XXX - wrong place */ ! 929: pmap_clear_modify(VM_PAGE_TO_PHYS(m)); /* XXX - wrong place */ ! 930: } ! 931: ! 932: out: ! 933: vnode_pager_vput(vs); ! 934: ! 935: unix_release(); ! 936: ! 937: return (result); ! 938: } ! 939: ! 940: /* ! 941: * vnode_has_page: ! 942: * ! 943: * Parameters: ! 944: * pager ! 945: * id paging object ! 946: * offset Offset in paging object to test ! 947: * ! 948: * Assumptions: ! 949: * This is only used on shadowing (copy) objects. ! 950: * Since copy objects are always backed by a swapfile, we just ! 951: * test the map for that swapfile to see if the page is present. ! 952: */ ! 953: boolean_t ! 954: vnode_has_page(pager, offset) ! 955: vm_pager_t pager; ! 956: vm_offset_t offset; ! 957: { ! 958: vnode_pager_t vs = (vnode_pager_t) pager; ! 959: pf_entry entry; ! 960: ! 961: /* ! 962: * For now, we do all inode hacking on the master cpu. ! 963: */ ! 964: unix_master(); ! 965: ! 966: if (vs == VNODE_PAGER_NULL) ! 967: panic("vnode_has_page: failed lookup"); ! 968: ! 969: if (vs->vs_swapfile) { ! 970: unix_release(); ! 971: if (pagerfile_bmap(vs, offset, B_READ, &entry) == KERN_FAILURE) ! 972: return FALSE; ! 973: else ! 974: return TRUE; ! 975: } ! 976: else { ! 977: panic("vnode_has_page called on non-default pager"); ! 978: } ! 979: /*NOTREACHED*/ ! 980: ! 981: return FALSE; ! 982: } ! 983: ! 984: ! 985: /* ! 986: * Routine: vnode_pager_file_init ! 987: * Function: ! 988: * Create a pager_file structure for a new pager file. ! 989: * Arguments: ! 990: * The file in question is specified by vnode pointer. ! 991: * lowat and hiwat are the low water and high water marks ! 992: * that the size of pager file will float between. If ! 993: * the low water mark is zero, then the file will not ! 994: * shrink after paging space is freed. If the high water ! 995: * mark is zero, the file will grow without bounds. ! 996: * ! 997: * The vp is locked on entry to and exit from this function. ! 998: */ ! 999: int ! 1000: vnode_pager_file_init(pfp, vp, lowat, hiwat) ! 1001: pager_file_t *pfp; ! 1002: struct vnode *vp; ! 1003: long lowat; ! 1004: long hiwat; ! 1005: { ! 1006: struct vattr vattr; ! 1007: register pager_file_t pf; ! 1008: int error; ! 1009: long i; ! 1010: struct proc *p = current_proc(); ! 1011: struct ucred *cred; ! 1012: vm_size_t size; ! 1013: ! 1014: *pfp = PAGER_FILE_NULL; ! 1015: ! 1016: /* ! 1017: * Make sure no other object paging to this file? ! 1018: */ ! 1019: #if MACH_NBC ! 1020: mapfs_uncache(vp); ! 1021: #endif /* MACH_NBC */ ! 1022: ! 1023: if(!vp->v_vm_info) { ! 1024: vm_info_init(vp); ! 1025: } ! 1026: ! 1027: if (vp->v_vm_info->mapped) { ! 1028: return(EBUSY); ! 1029: } ! 1030: ! 1031: /* ! 1032: * Clean up the file blocks on a pager file by ! 1033: * truncating to length "lowat". ! 1034: */ ! 1035: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); ! 1036: size = vattr.va_size; ! 1037: if (size > lowat) { ! 1038: vattr_null(&vattr); ! 1039: vattr.va_size = size = lowat; ! 1040: error = VOP_SETATTR(vp, &vattr, p->p_ucred, p); ! 1041: if (error) { ! 1042: return(error); ! 1043: } ! 1044: } ! 1045: ! 1046: /* ! 1047: * Initialize the vnode_size field ! 1048: */ ! 1049: vp->v_vm_info->vnode_size = size; ! 1050: ! 1051: pf = (pager_file_t) kalloc(sizeof(struct pager_file)); ! 1052: VREF(vp); ! 1053: pf->pf_vp = vp; ! 1054: cred = p->p_ucred; ! 1055: crhold(cred); ! 1056: vp->v_vm_info->cred = cred; ! 1057: pf->pf_count = 0; ! 1058: pf->pf_hint = 0; ! 1059: pf->pf_lowat = atop(round_page(lowat)); ! 1060: /* ! 1061: * If no maximum space is specified, then we should make a map that ! 1062: * can cover the entire disk, otherwise the block map need only ! 1063: * cover the maximum space allowed. ! 1064: */ ! 1065: if (!hiwat) ! 1066: hiwat = vp->v_mount->mnt_stat.f_blocks * ! 1067: vp->v_mount->mnt_stat.f_bsize; ! 1068: pf->pf_pfree = pf->pf_npgs = atop(hiwat); ! 1069: pf->pf_bmap = (u_char *) kalloc(RMAPSIZE(pf->pf_npgs)); ! 1070: for (i = 0; i < pf->pf_npgs; i++) { ! 1071: clrbit(pf->pf_bmap, i); ! 1072: } ! 1073: pf->pf_hipage = -1; ! 1074: pf->pf_prefer = FALSE; ! 1075: lock_init(&pf->pf_lock, TRUE); ! 1076: ! 1077: /* ! 1078: * Put the new pager file in the list. ! 1079: */ ! 1080: queue_enter(&pager_files, pf, pager_file_t, pf_chain); ! 1081: pager_file_count++; ! 1082: pf->pf_index = pager_file_count; ! 1083: pager_file_list[pager_file_count] = pf; ! 1084: *pfp = pf; ! 1085: return (0); ! 1086: } ! 1087: ! 1088: void ! 1089: vnode_pager_shutdown() ! 1090: { ! 1091: pager_file_t pf; ! 1092: ! 1093: while (!queue_empty(&pager_files)) { ! 1094: pf = (pager_file_t) queue_first(&pager_files); ! 1095: vrele(pf->pf_vp); ! 1096: queue_remove(&pager_files, pf, pager_file_t, pf_chain); ! 1097: pager_file_count--; ! 1098: } ! 1099: } ! 1100: ! 1101: ! 1102: /* ! 1103: * Routine: mach_swapon ! 1104: * Function: ! 1105: * Syscall interface to mach_swapon. ! 1106: */ ! 1107: int ! 1108: mach_swapon(filename, flags, lowat, hiwat) ! 1109: char *filename; ! 1110: int flags; ! 1111: long lowat; ! 1112: long hiwat; ! 1113: { ! 1114: struct vnode *vp; ! 1115: struct nameidata nd, *ndp; ! 1116: struct proc *p = current_proc(); ! 1117: pager_file_t pf; ! 1118: register int error; ! 1119: ! 1120: ndp = &nd; ! 1121: ! 1122: if ((error = suser(p->p_ucred, &p->p_acflag))) ! 1123: return (error); ! 1124: ! 1125: unix_master(); ! 1126: ! 1127: /* ! 1128: * Get a vnode for the paging area. ! 1129: */ ! 1130: NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, ! 1131: filename, p); ! 1132: if ((error = namei(ndp))) ! 1133: return (error); ! 1134: vp = ndp->ni_vp; ! 1135: ! 1136: if (vp->v_type != VREG) { ! 1137: error = EINVAL; ! 1138: goto bailout; ! 1139: } ! 1140: ! 1141: /* ! 1142: * Look to see if we are already paging to this file. ! 1143: */ ! 1144: for (pf = (pager_file_t) queue_first(&pager_files); ! 1145: !queue_end(&pager_files, &pf->pf_chain); ! 1146: pf = (pager_file_t) queue_next(&pf->pf_chain)) { ! 1147: if (pf->pf_vp == vp) ! 1148: break; ! 1149: } ! 1150: if (!queue_end(&pager_files, &pf->pf_chain)) { ! 1151: error = EBUSY; ! 1152: goto bailout; ! 1153: } ! 1154: ! 1155: error = vnode_pager_file_init(&pf, vp, lowat, hiwat); ! 1156: if (error) { ! 1157: goto bailout; ! 1158: } ! 1159: pf->pf_prefer = ((flags & MS_PREFER) != 0); ! 1160: ! 1161: /* ! 1162: * Create dummy symbol file for current mach_kernel executable. ! 1163: * See bsd/kern/kern_symfile.c ! 1164: */ ! 1165: output_kernel_symbols(p); ! 1166: ! 1167: error = 0; ! 1168: bailout: ! 1169: if (vp) { ! 1170: VOP_UNLOCK(vp, 0, p); ! 1171: vrele(vp); ! 1172: } ! 1173: unix_release(); ! 1174: return(error); ! 1175: } ! 1176: ! 1177: /* ! 1178: * Routine: vswap_allocate ! 1179: * Function: ! 1180: * Allocate a place for paging out a kernel-created ! 1181: * memory object. ! 1182: * ! 1183: * Implementation: ! 1184: * Looks through the paging files for the one with the ! 1185: * most free space. First, only "preferred" paging files ! 1186: * are considered, then local paging files, and then ! 1187: * remote paging files. In each case, the pager file ! 1188: * the most free blocks will be chosen. ! 1189: * ! 1190: * In/out conditions: ! 1191: * If the paging area is on a local disk, the inode is ! 1192: * returned locked. ! 1193: */ ! 1194: pager_file_t ! 1195: vswap_allocate() ! 1196: { ! 1197: int pass; ! 1198: int mostspace; ! 1199: pager_file_t pf, mostpf; ! 1200: ! 1201: extern int (**ffs_vnodeop_p)(); ! 1202: ! 1203: mostpf = PAGER_FILE_NULL; ! 1204: mostspace = 0; ! 1205: ! 1206: if (pager_file_count > 1) { ! 1207: for (pass = 0; pass < 4; pass++) { ! 1208: for (pf = (pager_file_t)queue_first(&pager_files); ! 1209: !queue_end(&pager_files, &pf->pf_chain); ! 1210: pf = (pager_file_t)queue_next(&pf->pf_chain)) { ! 1211: ! 1212: if ((pass < 2) && !pf->pf_prefer) ! 1213: continue; ! 1214: if ((!(pass &1) && ! 1215: (pf->pf_vp->v_op != ffs_vnodeop_p))) ! 1216: continue; ! 1217: ! 1218: if (pf->pf_pfree > mostspace) { ! 1219: mostspace = pf->pf_pfree; ! 1220: mostpf = pf; ! 1221: } ! 1222: } ! 1223: /* ! 1224: * If we found space, then break out of loop. ! 1225: */ ! 1226: if (mostpf != PAGER_FILE_NULL) ! 1227: break; ! 1228: } ! 1229: } else if (pager_file_count == 1) { ! 1230: mostpf = (pager_file_t) queue_first(&pager_files); ! 1231: } ! 1232: ! 1233: return(mostpf); ! 1234: } ! 1235: ! 1236: vm_pager_t ! 1237: vnode_alloc(size) ! 1238: vm_size_t size; ! 1239: { ! 1240: pager_file_t pf; ! 1241: vnode_pager_t vs = (vnode_pager_t) vm_pager_null; ! 1242: ! 1243: #ifdef lint ! 1244: size++; ! 1245: #endif lint ! 1246: ! 1247: unix_master(); ! 1248: ! 1249: /* ! 1250: * Get a pager_file, then turn it into a paging space. ! 1251: */ ! 1252: ! 1253: if ((pf = vswap_allocate()) == PAGER_FILE_NULL) { ! 1254: goto out; ! 1255: } ! 1256: if ((vs = pagerfile_pager_create(pf, size)) == ! 1257: VNODE_PAGER_NULL) { ! 1258: vs = (vnode_pager_t) vm_pager_null; ! 1259: goto out; ! 1260: } ! 1261: out: ! 1262: unix_release(); ! 1263: return((vm_pager_t) vs); ! 1264: } ! 1265: ! 1266: ! 1267: /* ! 1268: * Try to truncate the paging files. ! 1269: */ ! 1270: void ! 1271: vnode_pager_truncate(pf_entry entry) ! 1272: { ! 1273: struct pager_file *pf = pager_file_list[entry.index]; ! 1274: struct vnode *vp = pf->pf_vp; ! 1275: struct vattr vattr; ! 1276: int error; ! 1277: struct proc *p = current_proc(); ! 1278: long truncpage; ! 1279: int i; ! 1280: ! 1281: /* ! 1282: * If this is not the last page in the file, return now. ! 1283: * If the swaptimizer is enabled we cannot free blocks out from ! 1284: * underneath it. ! 1285: */ ! 1286: assert(entry.offset <= pf->pf_hipage); ! 1287: if (entry.offset < pf->pf_hipage) ! 1288: return; ! 1289: ! 1290: lock_write(&pf->pf_lock); ! 1291: ! 1292: /* ! 1293: * Find a new high page ! 1294: */ ! 1295: for (i = entry.offset - 1; i >= 0; i--) { ! 1296: if (isset(pf->pf_bmap, i)) { ! 1297: pf->pf_hipage = i; ! 1298: break; ! 1299: } ! 1300: } ! 1301: ! 1302: /* ! 1303: * If we are higher than the low water mark, truncate ! 1304: * the file. ! 1305: */ ! 1306: truncpage = pf->pf_hipage + 1; ! 1307: if (pf->pf_lowat == 0 || truncpage <= pf->pf_lowat || ! 1308: vp->v_vm_info->vnode_size < ptoa(truncpage)) { ! 1309: lock_done(&pf->pf_lock); ! 1310: return; ! 1311: } ! 1312: ! 1313: vattr_null(&vattr); ! 1314: vattr.va_size = ptoa(truncpage); ! 1315: ASSERT( (int) vattr.va_size >= 0 ); ! 1316: ! 1317: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1318: if ((error = VOP_SETATTR(vp, &vattr, vp->v_vm_info->cred, p))) { ! 1319: printf("vnode_deallocpage: error truncating %s," ! 1320: " error = %d\n", pf->pf_name, error); ! 1321: } ! 1322: VOP_UNLOCK(vp, 0, p); ! 1323: ! 1324: ! 1325: lock_done(&pf->pf_lock); ! 1326: } ! 1327: ! 1328: ! 1329: static void ! 1330: visit_file(pf_entry entry) ! 1331: { ! 1332: int i; ! 1333: ! 1334: if (entry.index == INDEX_NULL) ! 1335: return; ! 1336: ! 1337: for (i = 0; i < seen_files_max; i++) ! 1338: if (seen_files[i].index == entry.index) { ! 1339: seen_files[i].offset = max(seen_files[i].offset,entry.offset); ! 1340: return; ! 1341: } ! 1342: ! 1343: seen_files[seen_files_max++] = entry; ! 1344: } ! 1345: ! 1346: ! 1347: void ! 1348: vnode_dealloc(pager) ! 1349: vm_pager_t pager; ! 1350: { ! 1351: struct vnode *vp; ! 1352: vnode_pager_t vs = (vnode_pager_t) pager; ! 1353: int i; ! 1354: ! 1355: unix_master(); ! 1356: ! 1357: vp = vnode_pager_vget(vs); ! 1358: ! 1359: ASSERT(vs->vs_count == 1); ! 1360: ! 1361: seen_files_max = 0; ! 1362: if (vs->vs_swapfile) { ! 1363: pager_file_t pf; ! 1364: int i,j; ! 1365: ! 1366: ASSERT(vs->vs_pf); ! 1367: ! 1368: pf = vs->vs_pf; ! 1369: if (INDIR_PAGEMAP(vs->vs_size)) { ! 1370: for (i = 0; i < INDIR_PAGEMAP_ENTRIES(vs->vs_size); i++) { ! 1371: if (vs->vs_pmap[i] != NULL) { ! 1372: for(j = 0; j < PAGEMAP_ENTRIES; j++) { ! 1373: vnode_pager_deallocpage(vs->vs_pmap[i][j]); ! 1374: visit_file(vs->vs_pmap[i][j]); ! 1375: } ! 1376: kfree(vs->vs_pmap[i], PAGEMAP_THRESHOLD); ! 1377: } ! 1378: } ! 1379: kfree(vs->vs_pmap, INDIR_PAGEMAP_SIZE(vs->vs_size)); ! 1380: } else { ! 1381: for (i = 0; i < vs->vs_size; i++) { ! 1382: vnode_pager_deallocpage(*(pf_entry *)&vs->vs_pmap[i]); ! 1383: visit_file(*(pf_entry *)&vs->vs_pmap[i]); ! 1384: } ! 1385: if (vs->vs_size > 0) ! 1386: kfree(vs->vs_pmap, PAGEMAP_SIZE(vs->vs_size)); ! 1387: } ! 1388: pf->pf_count--; ! 1389: } else { ! 1390: vp->v_flag &= ~VTEXT; ! 1391: vp->v_vm_info->pager = vm_pager_null; /* so vrele will free */ ! 1392: ! 1393: vp->v_flag |= VAGE; /* put this vnode at the head of freelist */ ! 1394: vrele(vp); ! 1395: } ! 1396: ! 1397: for (i=0; i < seen_files_max; i++) ! 1398: vnode_pager_truncate(seen_files[i]); ! 1399: zfree(vstruct_zone, (vm_offset_t) vs); ! 1400: unix_release(); ! 1401: } ! 1402: ! 1403: /* ! 1404: * Remove vnode associated object from the object cache. ! 1405: * ! 1406: * XXX unlock the vnode if it is currently locked. ! 1407: * We must do this since uncaching the object may result in its ! 1408: * destruction which may initiate paging activity which may necessitate ! 1409: * re-locking the vnode. ! 1410: */ ! 1411: int ! 1412: vnode_uncache(vp) ! 1413: register struct vnode *vp; ! 1414: { ! 1415: struct proc *p = current_proc(); ! 1416: ! 1417: if (vp->v_type != VREG) ! 1418: return (1); ! 1419: ! 1420: if (vp->v_vm_info == 0 || vp->v_vm_info->pager == vm_pager_null) ! 1421: return (1); ! 1422: ! 1423: #ifdef DEBUG ! 1424: if (!VOP_ISLOCKED(vp)) { ! 1425: extern int (**nfsv2_vnodeop_p)(); ! 1426: ! 1427: if (vp->v_op != nfsv2_vnodeop_p) ! 1428: panic("vnode_uncache: vnode not locked!"); ! 1429: } ! 1430: #endif ! 1431: ! 1432: /* ! 1433: * The act of uncaching may cause an object to be deallocated ! 1434: * which may need to wait for the pageout daemon which in turn ! 1435: * may be waiting for this inode's lock, so be sure to unlock ! 1436: * and relock later if necessary. (This of course means that ! 1437: * code calling this routine must be able to handle the fact ! 1438: * that the inode has been unlocked temporarily). This code, of ! 1439: * course depends on the Unix master restriction for proper ! 1440: * synchronization. ! 1441: */ ! 1442: #if MACH_NBC ! 1443: mapfs_uncache(vp); ! 1444: #endif /* MACH_NBC */ ! 1445: ! 1446: VOP_UNLOCK(vp, 0, p); ! 1447: vm_object_uncache(vp->v_vm_info->pager); ! 1448: #if MACH_NBC ! 1449: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p); ! 1450: #else ! 1451: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1452: #endif ! 1453: return (1); ! 1454: } ! 1455: ! 1456: void ! 1457: vnode_pager_init() ! 1458: { ! 1459: register vm_size_t size; ! 1460: ! 1461: /* ! 1462: * Initialize zone of paging structures. ! 1463: */ ! 1464: ! 1465: size = (vm_size_t) sizeof(struct vstruct); ! 1466: vstruct_zone = zinit(size, ! 1467: (vm_size_t) 10000*size, /* XXX */ ! 1468: PAGE_SIZE, ! 1469: FALSE, "vnode pager structures"); ! 1470: simple_lock_init(&vstruct_lock); ! 1471: queue_init(&pager_files); ! 1472: } ! 1473: ! 1474: void ! 1475: vnode_pager_setsize(vp, nsize) ! 1476: struct vnode *vp; ! 1477: u_long nsize; ! 1478: { ! 1479: if (vp->v_vm_info) { ! 1480: if (vp->v_type != VREG) ! 1481: panic("vnode_pager_setsize not VREG"); ! 1482: vp->v_vm_info->vnode_size = nsize; ! 1483: } ! 1484: } ! 1485: ! 1486: void ! 1487: vnode_pager_umount(mp) ! 1488: register struct mount *mp; ! 1489: { ! 1490: struct proc *p = current_proc(); ! 1491: struct vnode *vp, *nvp; ! 1492: ! 1493: loop: ! 1494: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { ! 1495: if (vp->v_mount != mp) ! 1496: goto loop; ! 1497: nvp = vp->v_mntvnodes.le_next; ! 1498: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1499: (void) vnode_uncache(vp); ! 1500: VOP_UNLOCK(vp, 0, p); ! 1501: } ! 1502: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.