|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Mach Operating System ! 24: * Copyright (c) 1987 Carnegie-Mellon University ! 25: * All rights reserved. The CMU software License Agreement specifies ! 26: * the terms and conditions for use and redistribution. ! 27: */ ! 28: /* ! 29: * File: vnode_pager.c ! 30: * ! 31: * "Swap" pager that pages to/from vnodes. Also ! 32: * handles demand paging from files. ! 33: * ! 34: * HISTORY ! 35: * 12-Mar-86 David Golub (dbg) at Carnegie-Mellon University ! 36: * Created. ! 37: */ ! 38: ! 39: #include <mach_nbc.h> ! 40: ! 41: #include <mach/boolean.h> ! 42: #include <sys/param.h> ! 43: #include <sys/systm.h> ! 44: #include <sys/proc.h> ! 45: #include <sys/buf.h> ! 46: #include <sys/uio.h> ! 47: #include <sys/vnode.h> ! 48: #include <ufs/ufs/quota.h> ! 49: #include <ufs/ufs/inode.h> ! 50: #include <sys/namei.h> ! 51: #include <sys/mach_swapon.h> ! 52: #include <ufs/ffs/fs.h> ! 53: #include <sys/mount.h> ! 54: #include <net/if.h> ! 55: #include <netinet/in.h> ! 56: #include <nfs/rpcv2.h> ! 57: #include <nfs/nfsproto.h> ! 58: #include <nfs/nfs.h> ! 59: #include <sys/lock.h> ! 60: #undef fs_fsok ! 61: #undef fs_tsize ! 62: #undef fs_bsize ! 63: #undef fs_blocks ! 64: #undef fs_bfree ! 65: #undef fs_bavail ! 66: ! 67: #include <mach/mach_types.h> ! 68: #include <vm/vm_map.h> ! 69: #include <vm/vm_kern.h> ! 70: #include <kern/parallel.h> ! 71: #include <kern/zalloc.h> ! 72: #include <kern/kalloc.h> ! 73: #include <libkern/libkern.h> ! 74: ! 75: #include <vm/vnode_pager.h> ! 76: #include <kern/mapfs.h> ! 77: ! 78: #include <kern/assert.h> ! 79: ! 80: int print_nfs_addr=0; ! 81: ! 82: extern struct proc proc0; ! 83: extern struct vnode *default_pager_vnode; ! 84: ! 85: pager_return_t ! 86: pager_vnode_pageout(struct vnode *vp, ! 87: void *addr, ! 88: vm_offset_t f_offset, ! 89: vm_size_t size, ! 90: int * errorp) ! 91: { ! 92: int result = PAGER_SUCCESS; ! 93: pf_entry entry; ! 94: struct proc *p = &proc0; ! 95: int error = 0; ! 96: vm_offset_t ioaddr = (vm_offset_t)addr; ! 97: struct uio auio; ! 98: struct iovec aiov; ! 99: int file_max_size = 0; ! 100: int sub_size = 0; ! 101: boolean_t funnel_state; ! 102: ! 103: funnel_state = thread_set_funneled(TRUE); ! 104: ! 105: if (ioaddr) { ! 106: ! 107: while(TRUE) { ! 108: auio.uio_iov = &aiov; ! 109: auio.uio_iovcnt = 1; ! 110: auio.uio_offset = f_offset; ! 111: auio.uio_segflg = UIO_SYSSPACE; ! 112: auio.uio_rw = UIO_WRITE; ! 113: auio.uio_procp = NULL; ! 114: ! 115: #if MACH_NBC ! 116: auio.uio_resid = size; ! 117: aiov.iov_len = size; ! 118: sub_size = size; ! 119: #else ! 120: auio.uio_resid = PAGE_SIZE; ! 121: aiov.iov_len = PAGE_SIZE; ! 122: sub_size = PAGE_SIZE; ! 123: #endif ! 124: aiov.iov_base = (caddr_t)ioaddr; ! 125: ! 126: ! 127: /* this is necessary if we are locking only to sync read/write */ ! 128: #if MACH_NBC ! 129: { ! 130: #define VNODE_LOCK_RETRY_COUNT 1 ! 131: #define VNODE_LOCK_RETRY_TICKS 2 ! 132: ! 133: int retry = VNODE_LOCK_RETRY_COUNT; ! 134: vnode_lock_retry: ! 135: error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_CANRECURSE, p); ! 136: if (error) { ! 137: /* ! 138: * Retry the lock after yielding to other threads. ! 139: * Not doing this makes the pageout thread compute ! 140: * bound. Yielding lets I/O threads run ! 141: * and make forward progress. ! 142: */ ! 143: if (retry-- > 0) { ! 144: assert_wait_timeout( ! 145: VNODE_LOCK_RETRY_TICKS, ! 146: THREAD_INTERRUPTIBLE); ! 147: thread_block((void (*)(void)) 0); ! 148: goto vnode_lock_retry; ! 149: } ! 150: ! 151: result = KERN_FAILURE; ! 152: break; ! 153: } ! 154: } ! 155: #else /* MACH_NBC */ ! 156: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p); ! 157: #endif /* MACH_NBC */ ! 158: ! 159: /* ! 160: error = VOP_PAGEOUT(vp, &auio, IO_SYNC, p->p_ucred); ! 161: */ ! 162: error = VOP_PAGEOUT(vp, &auio, 0, p->p_ucred); ! 163: ! 164: if (error) { ! 165: if (error == ENOSPC) ! 166: result = KERN_RESOURCE_SHORTAGE; ! 167: else ! 168: result = KERN_FAILURE; ! 169: ! 170: error = PAGER_ERROR; ! 171: } ! 172: if(vp->v_vm_info) ! 173: vp->v_vm_info->error = error; ! 174: ! 175: VOP_UNLOCK(vp, 0, p); ! 176: ! 177: /* vnode_pageio_complete(m, ioaddr); */ ! 178: #if MACH_NBC ! 179: break; ! 180: #else ! 181: size -= PAGE_SIZE; ! 182: if ((size <= 0) || error) ! 183: break; ! 184: f_offset += PAGE_SIZE; ! 185: ioaddr += PAGE_SIZE; ! 186: #endif ! 187: } ! 188: } ! 189: else { ! 190: result = KERN_FAILURE; ! 191: error = PAGER_ERROR; ! 192: } ! 193: ! 194: if (errorp) ! 195: *errorp = result; ! 196: ! 197: (void) thread_set_funneled(funnel_state); ! 198: ! 199: return (error); ! 200: } ! 201: ! 202: pager_return_t ! 203: vnode_pageout(struct vnode *vp, ! 204: void *addr, ! 205: vm_offset_t f_offset, ! 206: vm_size_t size, ! 207: int * errorp) ! 208: { ! 209: int result = PAGER_SUCCESS; ! 210: pf_entry entry; ! 211: struct proc *p = current_proc(); ! 212: int error = 0; ! 213: vm_offset_t ioaddr = (vm_offset_t)addr; ! 214: struct uio auio; ! 215: struct iovec aiov; ! 216: int file_max_size = 0; ! 217: int sub_size = 0; ! 218: boolean_t funnel_state; ! 219: ! 220: funnel_state = thread_set_funneled(TRUE); ! 221: ! 222: if (ioaddr) { ! 223: ! 224: while(TRUE) { ! 225: auio.uio_iov = &aiov; ! 226: auio.uio_iovcnt = 1; ! 227: auio.uio_offset = f_offset; ! 228: auio.uio_segflg = UIO_SYSSPACE; ! 229: auio.uio_rw = UIO_WRITE; ! 230: auio.uio_procp = NULL; ! 231: ! 232: #if MACH_NBC ! 233: auio.uio_resid = size; ! 234: aiov.iov_len = size; ! 235: sub_size = size; ! 236: #else ! 237: auio.uio_resid = PAGE_SIZE; ! 238: aiov.iov_len = PAGE_SIZE; ! 239: sub_size = PAGE_SIZE; ! 240: #endif ! 241: aiov.iov_base = (caddr_t)ioaddr; ! 242: ! 243: /* this is necessary if we are locking only to sync read/write */ ! 244: /* The MACH_NBC flag has been used below also to support multiple pageout */ ! 245: /* request when the file system can only support one. */ ! 246: #if MACH_NBC ! 247: { ! 248: #define VNODE_LOCK_RETRY_COUNT 1 ! 249: #define VNODE_LOCK_RETRY_TICKS 2 ! 250: ! 251: int retry = VNODE_LOCK_RETRY_COUNT; ! 252: vnode_lock_retry: ! 253: error = vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_CANRECURSE, p); ! 254: if (error) { ! 255: /* ! 256: * Retry the lock after yielding to other threads. ! 257: * Not doing this makes the pageout thread compute ! 258: * bound. Yielding lets I/O threads run ! 259: * and make forward progress. ! 260: */ ! 261: if (retry-- > 0) { ! 262: assert_wait_timeout( ! 263: VNODE_LOCK_RETRY_TICKS, ! 264: THREAD_INTERRUPTIBLE); ! 265: thread_block((void (*)(void)) 0); ! 266: goto vnode_lock_retry; ! 267: } ! 268: ! 269: result = KERN_FAILURE; ! 270: break; ! 271: } ! 272: } ! 273: #else /* MACH_NBC */ ! 274: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY | LK_CANRECURSE, p); ! 275: #endif /* MACH_NBC */ ! 276: ! 277: ! 278: ! 279: error = VOP_PAGEOUT(vp, &auio, 0, p->p_ucred); ! 280: ! 281: if (error) { ! 282: result = PAGER_ERROR; ! 283: error = PAGER_ERROR; ! 284: } ! 285: ! 286: if(vp->v_vm_info) ! 287: vp->v_vm_info->error = error; ! 288: ! 289: VOP_UNLOCK(vp, 0, p); ! 290: ! 291: /* vnode_pageio_complete(m, ioaddr); */ ! 292: #if MACH_NBC ! 293: break; ! 294: #else ! 295: size -= PAGE_SIZE; ! 296: if (size <= 0) ! 297: break; ! 298: f_offset += PAGE_SIZE; ! 299: ioaddr += PAGE_SIZE; ! 300: #endif ! 301: } ! 302: } ! 303: else { ! 304: result = PAGER_ERROR; ! 305: error = PAGER_ERROR; ! 306: } ! 307: ! 308: if (errorp) ! 309: *errorp = result; ! 310: ! 311: (void) thread_set_funneled(funnel_state); ! 312: ! 313: return (error); ! 314: } ! 315: ! 316: ! 317: pager_return_t ! 318: pager_vnode_pagein(struct vnode *vp, ! 319: void *addr, ! 320: vm_offset_t f_offset, ! 321: vm_size_t size, ! 322: int * errorp) ! 323: { ! 324: int result = PAGER_SUCCESS; ! 325: pf_entry entry; ! 326: struct proc *p = &proc0; ! 327: int error = 0; ! 328: vm_offset_t ioaddr = (vm_offset_t) addr; ! 329: struct uio auio; ! 330: struct iovec aiov; ! 331: int file_max_size =0; ! 332: boolean_t funnel_state; ! 333: ! 334: funnel_state = thread_set_funneled(TRUE); ! 335: ! 336: if (ioaddr) { ! 337: auio.uio_iov = &aiov; ! 338: auio.uio_iovcnt = 1; ! 339: auio.uio_offset = f_offset; ! 340: auio.uio_segflg = UIO_SYSSPACE; ! 341: auio.uio_rw = UIO_READ; ! 342: auio.uio_resid = size; ! 343: auio.uio_procp = NULL; ! 344: ! 345: aiov.iov_len = size; ! 346: aiov.iov_base = (caddr_t)ioaddr; ! 347: ! 348: vn_lock(vp, LK_SHARED | LK_RETRY | LK_CANRECURSE, p); ! 349: ! 350: error = VOP_PAGEIN(vp, &auio, 0, p->p_ucred); ! 351: if (error) { ! 352: result = PAGER_ERROR; ! 353: } ! 354: if(vp->v_vm_info) ! 355: vp->v_vm_info->error = error; ! 356: ! 357: VOP_UNLOCK(vp, 0, p); ! 358: ! 359: if (!error && auio.uio_resid > 0) ! 360: (void) memset((void *)(ioaddr + size - ! 361: auio.uio_resid), 0, auio.uio_resid); ! 362: ! 363: /* vnode_pageio_complete(m, ioaddr); */ ! 364: #ifdef ppc ! 365: /* ! 366: * After a pagein, we must synchronize the processor caches. ! 367: * On PPC, the i-cache is not coherent in all models, thus ! 368: * it needs to be invalidated. ! 369: */ ! 370: /* flush_cache(VM_PAGE_TO_PHYS(m), PAGE_SIZE); */ ! 371: #endif /* ppc */ ! 372: } ! 373: else ! 374: result = PAGER_ERROR; ! 375: ! 376: if (errorp) ! 377: *errorp = result; ! 378: ! 379: (void) thread_set_funneled(funnel_state); ! 380: ! 381: return (error); ! 382: } ! 383: ! 384: ! 385: pager_return_t ! 386: vnode_pagein(struct vnode *vp, ! 387: void *addr, ! 388: vm_offset_t f_offset, ! 389: vm_size_t size, ! 390: int * errorp) ! 391: { ! 392: int result = PAGER_SUCCESS; ! 393: pf_entry entry; ! 394: struct proc *p = current_proc(); ! 395: int error = 0; ! 396: vm_offset_t ioaddr = (vm_offset_t) addr; ! 397: struct uio auio; ! 398: struct iovec aiov; ! 399: int file_max_size =0; ! 400: boolean_t funnel_state; ! 401: ! 402: funnel_state = thread_set_funneled(TRUE); ! 403: ! 404: if (ioaddr) { ! 405: auio.uio_iov = &aiov; ! 406: auio.uio_iovcnt = 1; ! 407: auio.uio_offset = f_offset; ! 408: auio.uio_segflg = UIO_SYSSPACE; ! 409: auio.uio_rw = UIO_READ; ! 410: auio.uio_resid = size; ! 411: auio.uio_procp = NULL; ! 412: ! 413: aiov.iov_len = size; ! 414: aiov.iov_base = (caddr_t)ioaddr; ! 415: ! 416: vn_lock(vp, LK_SHARED | LK_RETRY | LK_CANRECURSE, p); ! 417: ! 418: error = VOP_PAGEIN(vp, &auio, 0, p->p_ucred); ! 419: if (error) ! 420: result = PAGER_ERROR; ! 421: ! 422: if(vp->v_vm_info) ! 423: vp->v_vm_info->error = error; ! 424: ! 425: VOP_UNLOCK(vp, 0, p); ! 426: ! 427: if (!error && auio.uio_resid > 0) ! 428: (void) memset((void *)(ioaddr + size - ! 429: auio.uio_resid), 0, auio.uio_resid); ! 430: ! 431: /* vnode_pageio_complete(m, ioaddr); */ ! 432: #ifdef ppc ! 433: /* ! 434: * After a pagein, we must synchronize the processor caches. ! 435: * On PPC, the i-cache is not coherent in all models, thus ! 436: * it needs to be invalidated. ! 437: */ ! 438: /* flush_cache(VM_PAGE_TO_PHYS(m), PAGE_SIZE); */ ! 439: #endif /* ppc */ ! 440: } ! 441: else ! 442: result = PAGER_ERROR; ! 443: ! 444: if (errorp) ! 445: *errorp = result; ! 446: ! 447: (void) thread_set_funneled(funnel_state); ! 448: ! 449: return (error); ! 450: } ! 451: ! 452: void ! 453: vnode_pager_shutdown() ! 454: { ! 455: int i; ! 456: extern struct bs_map bs_port_table[]; ! 457: ! 458: if (default_pager_vnode) { ! 459: vrele(default_pager_vnode); ! 460: } ! 461: for(i = 0; i < MAX_BACKING_STORE; i++) { ! 462: if((bs_port_table[i]).vp) { ! 463: vrele((bs_port_table[i]).vp); ! 464: vrele((bs_port_table[i]).vp); ! 465: vrele((bs_port_table[i]).vp); ! 466: vrele((bs_port_table[i]).vp); ! 467: (bs_port_table[i]).vp = 0; ! 468: } ! 469: } ! 470: } ! 471: ! 472: ! 473: ! 474: /* ! 475: * Remove an vnode from the object cache. ! 476: */ ! 477: int ! 478: vnode_uncache(vp) ! 479: register struct vnode *vp; ! 480: { ! 481: return(1); ! 482: } ! 483: ! 484: void ! 485: vnode_pager_setsize(vp, nsize) ! 486: struct vnode *vp; ! 487: u_long nsize; ! 488: { ! 489: if (vp->v_vm_info) ! 490: vp->v_vm_info->vnode_size = nsize; ! 491: } ! 492: ! 493: ! 494: /* ! 495: * Remove vnode associated object from the object cache. ! 496: * ! 497: * XXX unlock the vnode if it is currently locked. ! 498: * We must do this since uncaching the object may result in its ! 499: * destruction which may initiate paging activity which may necessitate ! 500: * re-locking the vnode. ! 501: */ ! 502: boolean_t ! 503: vnode_pager_uncache(vp) ! 504: register struct vnode *vp; ! 505: { ! 506: /* ! 507: * Not a mapped vnode ! 508: */ ! 509: if (vp->v_type != VREG) ! 510: return (TRUE); ! 511: #ifdef DEBUG ! 512: if (!VOP_ISLOCKED(vp)) { ! 513: extern int (**nfsv2_vnodeop_p)(); ! 514: ! 515: if (vp->v_op != nfsv2_vnodeop_p) ! 516: panic("vnode_pager_uncache: vnode not locked!"); ! 517: } ! 518: #endif ! 519: return(vnode_uncache(vp)); ! 520: } ! 521: ! 522: void ! 523: vnode_pager_umount(mp) ! 524: register struct mount *mp; ! 525: { ! 526: struct proc *p = current_proc(); ! 527: struct vnode *vp, *nvp; ! 528: ! 529: loop: ! 530: for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) { ! 531: if (vp->v_mount != mp) ! 532: goto loop; ! 533: nvp = vp->v_mntvnodes.le_next; ! 534: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 535: (void) vnode_pager_uncache(vp); ! 536: VOP_UNLOCK(vp, 0, p); ! 537: } ! 538: } ! 539: int ! 540: vnode_pager_create(vp,pager) ! 541: register struct vnode *vp; ! 542: void * pager; ! 543: { ! 544: vnode_pager_t vs; ! 545: struct vattr vattr; ! 546: vm_size_t size; ! 547: struct proc *p = current_proc(); ! 548: int error; ! 549: ! 550: /* ! 551: * XXX This can still livelock -- if the ! 552: * pageout daemon needs a vnode_pager record ! 553: * it won't get one until someone else ! 554: * refills the zone. ! 555: */ ! 556: #if 0 ! 557: if (!vp->v_vm_info) { ! 558: vm_info_init(vp); ! 559: } ! 560: #endif ! 561: vp->v_vm_info->pager = pager; ! 562: ! 563: error = VOP_GETATTR(vp, &vattr, p->p_ucred, p); ! 564: if (!error) { ! 565: size = vattr.va_size; ! 566: vp->v_vm_info->vnode_size = size; ! 567: } ! 568: else ! 569: vp->v_vm_info->vnode_size = 0; ! 570: ! 571: VREF(vp); ! 572: ! 573: ! 574: return(0); ! 575: } ! 576: ! 577: void ! 578: ubc_truncate( vp, length) ! 579: register struct vnode *vp; ! 580: register vm_offset_t length; ! 581: { ! 582: int error; ! 583: vm_map_t user_map; ! 584: vm_offset_t addr, addr1; ! 585: vm_size_t size, pageoff; ! 586: void * object; ! 587: void * pager_cport; ! 588: kern_return_t kret; ! 589: register struct vm_info *vmp; ! 590: ! 591: vmp = vp->v_vm_info; ! 592: size = round_page(length); ! 593: ! 594: ! 595: if (ISMAPPEDFILE(vp)) { ! 596: if (length >= vp->v_vm_info->vnode_size) ! 597: return; ! 598: ! 599: pageoff = vp->v_vm_info->vnode_size - size; ! 600: ! 601: if (pager_cport = vnode_pager_lookup(vp, ! 602: vp->v_vm_info->pager)) { ! 603: if(object = vm_object_lookup(pager_cport)) { ! 604: kret = memory_object_lock_request(object, ! 605: size, ! 606: round_page(pageoff), ! 607: MEMORY_OBJECT_RETURN_NONE,TRUE, ! 608: VM_PROT_NO_CHANGE,MACH_PORT_NULL); ! 609: #if DIAGNOSTIC ! 610: if (kret != KERN_SUCCESS) { ! 611: printf("ubc:failed to invalidate in truncate\n"); ! 612: } ! 613: #endif /* DIAGNOSTIC */ ! 614: } ! 615: } ! 616: } ! 617: ! 618: } ! 619: ! 620: /* called only if ISMAPPEDFILE */ ! 621: void ! 622: ubc_unlink(vp) ! 623: register struct vnode *vp; ! 624: { ! 625: mach_port_t cport; ! 626: ! 627: if (cport = vnode_pager_lookup(vp, vp->v_vm_info->pager)){ ! 628: memory_object_remove_cached_object(cport); ! 629: } ! 630: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.