|
|
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: * File: mapfs.c ! 33: * Author: Avadis Tevanian, Jr. ! 34: * ! 35: * Copyright (C) 1987, Avadis Tevanian, Jr. ! 36: * ! 37: * Support for mapped file system implementation. ! 38: * ! 39: * HISTORY ! 40: * 2-Jun-1998 Umesh Vaishampayan ! 41: * Changed error handling to check for all errors. ! 42: * ! 43: * 6-Dec-1997 A.Ramesh at Apple ! 44: * Made the chages for Rhapsody; Reanamed mfs to mapfs to avoid confusion ! 45: * with memory based filesystem. ! 46: * ! 47: * 18-Nov-92 Phillip Dibner at NeXT ! 48: * Made the i/o throttle global. This is a hack on top of a hack and ! 49: * should be fixed properly, probably in the vm system. ! 50: * ! 51: * 3-Sep-92 Joe Murdock at NeXT ! 52: * Added an i/o throttle to mfs_io as a cheap work-around for a i/o buffer ! 53: * resource conflict with usr-space system bottle-necks (nfs servers, etc) ! 54: * ! 55: * 7-Feb-92 Jim Hays ! 56: * There are still bugs in this code dealing with vmp_pushing wired ! 57: * pages. We need to modify the sound drivers locks to be breakable ! 58: * except during the actual playing. ! 59: * ! 60: * 3-Aug-90 Doug Mitchell at NeXT ! 61: * Added primitives for loadable file system support. ! 62: * ! 63: * 7-Mar-90 Brian Pinkerton (bpinker) at NeXT ! 64: * Changed mfs_trunc to return an indication of change. ! 65: * ! 66: * 9-Mar-88 John Seamons (jks) at NeXT ! 67: * SUN_VFS: allocate vm_info structures from a zone. ! 68: * ! 69: * 29-Jan-88 David Golub (dbg) at Carnegie-Mellon University ! 70: * Corrected calls to inode_pager_setup and kmem_alloc. ! 71: * ! 72: * 15-Sep-87 Michael Young (mwyoung) at Carnegie-Mellon University ! 73: * De-linted. ! 74: * ! 75: * 18-Jun-87 Michael Young (mwyoung) at Carnegie-Mellon University ! 76: * Make most of this file dependent on MACH_NBC. ! 77: * ! 78: * 30-Apr-87 Avadis Tevanian (avie) at Carnegie-Mellon University ! 79: * Created. ! 80: */ ! 81: ! 82: #import <mach_nbc.h> ! 83: ! 84: #import <kern/lock.h> ! 85: #import <kern/mapfs.h> ! 86: #import <kern/sched_prim.h> ! 87: #import <kern/assert.h> ! 88: ! 89: #import <sys/param.h> ! 90: #import <sys/systm.h> ! 91: #import <sys/mount.h> ! 92: #import <sys/proc.h> ! 93: #import <sys/user.h> ! 94: #import <sys/vnode.h> ! 95: #import <sys/uio.h> ! 96: /* Needed for VOP_DEBLOCKSIZE, ip usage */ ! 97: #include <ufs/ufs/quota.h> ! 98: #include <ufs/ufs/inode.h> ! 99: #import <sys/dir.h> ! 100: ! 101: #import <vm/vm_kern.h> ! 102: #import <vm/vm_pager.h> ! 103: #import <mach/vm_param.h> ! 104: #import <mach/machine.h> ! 105: #import <vm/vnode_pager.h> ! 106: #import <vm/pmap.h> ! 107: ! 108: #include <nfs/rpcv2.h> ! 109: #include <nfs/nfsproto.h> ! 110: #include <nfs/nfs.h> ! 111: #include <nfs/nfsnode.h> ! 112: ! 113: #define PERFMODS 1 ! 114: ! 115: struct zone *vm_info_zone; ! 116: ! 117: /* ! 118: * Private variables and macros. ! 119: */ ! 120: ! 121: queue_head_t vm_info_queue; /* lru list of structures */ ! 122: decl_simple_lock_data(, vm_info_lock_data) /* lock for lru list */ ! 123: int vm_info_version = 0; /* version number */ ! 124: ! 125: ! 126: ! 127: ! 128: #define vm_info_lock() simple_lock(&vm_info_lock_data) ! 129: #define vm_info_unlock() simple_unlock(&vm_info_lock_data) ! 130: ! 131: #if MACH_NBC ! 132: lock_data_t mfsbuf_lock; /* lock for active_mfsbufs */ ! 133: lock_data_t mfs_alloc_lock_data; ! 134: boolean_t mfs_alloc_wanted; ! 135: long mfs_alloc_blocks = 0; ! 136: ! 137: #define mfs_alloc_lock() lock_write(&mfs_alloc_lock_data) ! 138: #define mfs_alloc_unlock() lock_write_done(&mfs_alloc_lock_data) ! 139: ! 140: vm_map_t mfs_map; ! 141: ! 142: /* ! 143: * mfs_map_size is the number of bytes of VM to use for file mapping. ! 144: * It should be set by machine dependent code (before the call to ! 145: * mapfs_init) if the default is inappropriate. ! 146: * ! 147: * mfs_max_window is the largest window size that will be given to ! 148: * a file mapping. A default value is computed in mapfs_init based on ! 149: * mfs_map_size. This too may be set by machine dependent code ! 150: * if the default is not appropriate. ! 151: * ! 152: * mfs_files_max is the maximum number of files that we will ! 153: * simultaneously leave mapped. Note th memory for unmapped ! 154: * files will not necessarily leave the memory cache, but by ! 155: * unmapping these files the file system can throw away any ! 156: * file system related info (like vnodes). Again, this value ! 157: * can be sent by machine dependent code if the default is not ! 158: * appropriate. ! 159: */ ! 160: ! 161: #ifdef ppc ! 162: vm_size_t mfs_map_size = 64*1024*1024; /* size in bytes */ ! 163: #else ! 164: vm_size_t mfs_map_size = 8*1024*1024; /* size in bytes */ ! 165: #endif ! 166: vm_size_t mfs_max_window = 0; /* largest window to use */ ! 167: ! 168: #ifdef ppc ! 169: int mfs_files_max = 400; /* maximum # of files mapped */ ! 170: #else ! 171: int mfs_files_max = 100; /* maximum # of files mapped */ ! 172: #endif ! 173: int mfs_files_mapped = 0; /* current # mapped */ ! 174: ! 175: #define CHUNK_SIZE (128 * 1024) ! 176: #endif /* MACH_NBC */ ! 177: ! 178: #ifdef ppc ! 179: #define MFS_MAP_SIZE_MAX (64 * 1024 * 1024) ! 180: #else ! 181: #define MFS_MAP_SIZE_MAX (16 * 1024 * 1024) ! 182: #endif ! 183: ! 184: /* The MFS_MAP_SIZE_PER_UNIT is used in remap; as well as in init */ ! 185: #define MFS_MAP_SIZE_PER_UNIT (1024 * 1024) ! 186: #define MFS_MEMORY_UNIT (1024 * 1024) ! 187: #define MFS_FILES_PER_UNIT 12 ! 188: ! 189: void vm_info_enqueue __P((struct vm_info *)); ! 190: void vm_info_dequeue __P((struct vm_info *)); ! 191: void mapfs_put __P((struct vnode *)); ! 192: int mapfs_get __P((struct vnode *,vm_offset_t, vm_size_t)); ! 193: int remap_vnode __P((struct vnode *,vm_offset_t, vm_size_t)); ! 194: void vmp_put __P((struct vm_info *)); ! 195: void vmp_get __P((struct vm_info *)); ! 196: void mapfs_cache_trim __P((void)); ! 197: void mapfs_memfree __P((struct vm_info *, boolean_t)); ! 198: int mapfs_map_remove __P((struct vm_info *, vm_offset_t, vm_size_t, boolean_t)); ! 199: void vno_flush __P((struct vnode *, vm_offset_t, vm_size_t)); ! 200: void vmp_invalidate __P((struct vm_info *)); ! 201: int vmp_push __P((struct vm_info *)); ! 202: int vmp_push_range __P((struct vm_info *,vm_offset_t, vm_size_t)); ! 203: void vmp_push_all __P((struct vm_info *)); ! 204: /* Missing from headers so provided the prototypes */ ! 205: void vm_object_deactivate_pages __P((vm_object_t)); ! 206: void vm_object_deactivate_pages_first __P((vm_object_t)); ! 207: void vm_page_deactivate __P((vm_page_t)); ! 208: void vm_page_activate __P((vm_page_t)); ! 209: kern_return_t vm_allocate_with_pager __P((vm_map_t, vm_offset_t *, vm_size_t, boolean_t, vm_pager_t,vm_offset_t)); ! 210: ! 211: #if PERFMODS ! 212: int mapfs_map_cleanup __P((struct vm_info *,vm_offset_t,vm_size_t,boolean_t)); ! 213: #endif ! 214: ! 215: /* ! 216: * mapfs_init: ! 217: * ! 218: * Initialize the mapped FS module. ! 219: */ ! 220: int ! 221: mapfs_init() ! 222: { ! 223: int i; ! 224: #if MACH_NBC ! 225: int min, max; ! 226: #endif /* MACH_NBC */ ! 227: ! 228: queue_init(&vm_info_queue); ! 229: simple_lock_init(&vm_info_lock_data); ! 230: #if MACH_NBC ! 231: lock_init(&mfs_alloc_lock_data, TRUE); ! 232: mfs_alloc_wanted = FALSE; ! 233: mfs_map = kmem_suballoc(kernel_map, &min, &max, mfs_map_size, TRUE); ! 234: ! 235: mfs_map_size = (int) ((long long) MFS_MAP_SIZE_PER_UNIT / ! 236: (long long) MFS_MEMORY_UNIT * ! 237: (long long) machine_info.memory_size); ! 238: ! 239: if (mfs_map_size > MFS_MAP_SIZE_MAX) ! 240: mfs_map_size = MFS_MAP_SIZE_MAX; ! 241: ! 242: #if notdef ! 243: mfs_files_max = (int)((long long) MFS_FILES_PER_UNIT * ! 244: (long long) machine_info.memory_size / ! 245: (long long) MFS_MEMORY_UNIT); ! 246: #endif /* notdef */ ! 247: ! 248: /* Get atleast a Meg and instead of 5% choose 6.25% */ ! 249: if (mfs_max_window == 0) ! 250: mfs_max_window = mfs_map_size / 16; ! 251: if (mfs_max_window < MFS_MEMORY_UNIT) ! 252: mfs_max_window = MFS_MEMORY_UNIT; ! 253: #endif /* MACH_NBC */ ! 254: i = (vm_size_t) sizeof (struct vm_info); ! 255: vm_info_zone = zinit (i, 10000*i, 8192, FALSE, "vm_info zone"); ! 256: ! 257: return(0); ! 258: } ! 259: ! 260: /* ! 261: * vm_info_init: ! 262: * ! 263: * Initialize a vm_info structure for a vnode. ! 264: */ ! 265: int ! 266: vm_info_init(vp) ! 267: struct vnode *vp; ! 268: { ! 269: register struct vm_info *vmp; ! 270: ! 271: vmp = vp->v_vm_info; ! 272: if (vmp == VM_INFO_NULL) ! 273: vmp = (struct vm_info *) zalloc(vm_info_zone); ! 274: vmp->pager = vm_pager_null; ! 275: vmp->map_count = 0; ! 276: vmp->use_count = 0; ! 277: vmp->va = 0; ! 278: vmp->size = 0; ! 279: vmp->offset = 0; ! 280: #if PERFMODS ! 281: vmp->dirtysize = 0; ! 282: vmp->dirtyoffset = 0; ! 283: #endif ! 284: vmp->cred = (struct ucred *) NULL; ! 285: vmp->error = 0; ! 286: ! 287: vmp->queued = FALSE; ! 288: vmp->dirty = FALSE; ! 289: vmp->nfsdirty = FALSE; ! 290: vmp->close_flush = TRUE; /* for safety, reconsider later */ ! 291: vmp->invalidate = FALSE; ! 292: vmp->busy = FALSE; ! 293: vmp->delayed_fsync = FALSE; ! 294: vmp->filesize = FALSE; ! 295: vmp->mapped = FALSE; ! 296: vmp->dying = FALSE; ! 297: ! 298: vmp->vnode_size = 0; ! 299: vmp->vnode = vp; ! 300: lock_init(&vmp->lock, TRUE); /* sleep lock */ ! 301: vmp->object = VM_OBJECT_NULL; ! 302: vp->v_vm_info = vmp; ! 303: return(0); ! 304: } ! 305: ! 306: /* ! 307: * Loadable file system support to avoid exporting struct vm_info. ! 308: */ ! 309: void vm_info_free(struct vnode *vp) ! 310: { ! 311: register struct vm_info *vmp = vp->v_vm_info; ! 312: ! 313: if (vmp == VM_INFO_NULL) ! 314: return; ! 315: ! 316: /* ! 317: * If vmp->dying is set then we have reentered. ! 318: * Uninterruptible wait for the other thead to finish and return. ! 319: */ ! 320: if (vmp->dying == TRUE) { ! 321: (void)tsleep(vmp, 0, "vminfofree", 0); ! 322: return; ! 323: } ! 324: ! 325: /* Prevent other threads from racing in */ ! 326: vmp->dying = TRUE; ! 327: ! 328: #if MACH_NBC ! 329: mapfs_uncache(vp); /* could block here */ ! 330: #endif ! 331: vp->v_vm_info = VM_INFO_NULL; ! 332: wakeup(vmp); /* wakeup other threads blocked on vmp */ ! 333: ! 334: zfree(vm_info_zone, (vm_offset_t)vmp); /* could block here */ ! 335: } ! 336: ! 337: #if MACH_NBC /* [ */ ! 338: void ! 339: vm_info_enqueue(vmp) ! 340: struct vm_info *vmp; ! 341: { ! 342: mfs_assert(!vmp->queued); ! 343: mfs_assert(vmp->mapped); ! 344: #if 0 ! 345: mfs_assert(vmp->size); ! 346: if ((vmp->size == 0) || !vmp->mapped) ! 347: panic("VMP SIZE IS ZERO\n"); ! 348: ! 349: #endif ! 350: queue_enter(&vm_info_queue, vmp, struct vm_info *, lru_links); ! 351: vmp->queued = TRUE; ! 352: mfs_files_mapped++; ! 353: vm_info_version++; ! 354: } ! 355: ! 356: void ! 357: vm_info_dequeue(vmp) ! 358: struct vm_info *vmp; ! 359: { ! 360: mfs_assert(vmp->queued); ! 361: queue_remove(&vm_info_queue, vmp, struct vm_info *, lru_links); ! 362: vmp->queued = FALSE; ! 363: mfs_files_mapped--; ! 364: vm_info_version++; ! 365: } ! 366: ! 367: /* ! 368: * map_vnode: ! 369: * ! 370: * Indicate that the specified vnode should be mapped into VM. ! 371: * A reference count is maintained for each mapped file. ! 372: */ ! 373: void ! 374: map_vnode(vp,p) ! 375: register struct vnode *vp; ! 376: register struct proc *p; ! 377: { ! 378: register struct vm_info *vmp; ! 379: vm_pager_t pager; ! 380: extern lock_data_t vm_alloc_lock; ! 381: struct vattr vattr; ! 382: #if 1 ! 383: /* Needed as in some cases the exec, namei returned vp ! 384: * with no vm_info attached -- XXX (Verify this ) ! 385: */ ! 386: if (vp->v_vm_info == (struct vm_info *)0) ! 387: vm_info_init(vp); ! 388: #endif ! 389: vmp = vp->v_vm_info; ! 390: ! 391: if (vmp->map_count++ > 0) ! 392: return; /* file already mapped */ ! 393: ! 394: if (vmp->mapped) ! 395: return; /* file was still cached */ ! 396: ! 397: vmp_get(vmp); ! 398: ! 399: pager = vmp->pager = (vm_pager_t) vnode_pager_setup(vp, FALSE, TRUE); ! 400: /* not a TEXT file, can cache */ ! 401: /* ! 402: * Lookup what object is actually holding this file's ! 403: * pages so we can flush them when necessary. This ! 404: * would be done differently in an out-of-kernel implementation. ! 405: * ! 406: * Note that the lookup keeps a reference to the object which ! 407: * we must release elsewhere. ! 408: */ ! 409: lock_write(&vm_alloc_lock); ! 410: vmp->object = vm_object_lookup(pager); ! 411: vm_stat.lookups++; ! 412: if (vmp->object == VM_OBJECT_NULL) { ! 413: vmp->object = vm_object_allocate(0); ! 414: vm_object_enter(vmp->object, pager); ! 415: vm_object_setpager(vmp->object, pager, (vm_offset_t) 0, FALSE); ! 416: } ! 417: else { ! 418: vm_stat.hits++; ! 419: } ! 420: lock_write_done(&vm_alloc_lock); ! 421: ! 422: vmp->error = 0; ! 423: ! 424: VOP_GETATTR(vp, &vattr, p->p_ucred ,p); ! 425: ! 426: vmp->vnode_size = vattr.va_size; /* must be before setting ! 427: mapped below to prevent ! 428: mapfs_fsync from recursive ! 429: locking */ ! 430: ! 431: vmp->va = 0; ! 432: vmp->size = 0; ! 433: vmp->offset = 0; ! 434: vmp->mapped = TRUE; ! 435: ! 436: vmp_put(vmp); /* put will queue on LRU list */ ! 437: } ! 438: ! 439: int close_flush = 1; ! 440: ! 441: /* ! 442: * unmap_vnode: ! 443: * ! 444: * Called when an vnode is closed. ! 445: */ ! 446: void ! 447: unmap_vnode(vp, p) ! 448: register struct vnode *vp; ! 449: register struct proc *p; ! 450: { ! 451: register struct vm_info *vmp; ! 452: register struct vm_object *object; ! 453: int links; ! 454: register struct pcred *pcred = p->p_cred; ! 455: register struct ucred *cred = pcred->pc_ucred; ! 456: struct vattr vattr; ! 457: ! 458: vmp = vp->v_vm_info; ! 459: if (!vmp->mapped) ! 460: return; /* not a mapped file */ ! 461: /* ! 462: * If the file, which was prev mapped and closed is opened with ! 463: * O_NO_MFS, the map_count will be zero when close ! 464: * is called. SO, if it is already zero, there is nothing to ! 465: * be done here. (Otherwise 2269452 and 2269437) ! 466: */ ! 467: if (vmp->map_count == 0) ! 468: return; ! 469: if (--vmp->map_count > 0) { ! 470: return; ! 471: } ! 472: ! 473: /* ! 474: * If there are no links left to the file then release ! 475: * the resources held. If there are links left, then keep ! 476: * the file mapped under the assumption that someone else ! 477: * will soon map the same file. However, the pages in ! 478: * the object are deactivated to put them near the list ! 479: * of pages to be reused by the VM system (this would ! 480: * be done differently out of the kernel, of course, then ! 481: * again, the primitives for this don't exist out of the ! 482: * kernel yet. ! 483: */ ! 484: ! 485: vmp->map_count++; ! 486: ! 487: VOP_GETATTR(vp, &vattr, cred, p); ! 488: links = vattr.va_nlink; /* may uncache, see below */ ! 489: vmp->map_count--; ! 490: ! 491: if (links == 0) { ! 492: mapfs_memfree(vmp, FALSE); ! 493: } else { ! 494: /* ! 495: * pushing the pages may cause an uncache ! 496: * operation (thanks NFS), so gain an extra ! 497: * reference to guarantee that the object ! 498: * does not go away. (Note that such an ! 499: * uncache actually takes place since we have ! 500: * already released the map_count above). ! 501: */ ! 502: object = vmp->object; ! 503: if (close_flush || vmp->close_flush) { ! 504: vmp->map_count++; /* prevent uncache race */ ! 505: vmp_get(vmp); ! 506: #if PERFMODS ! 507: if (vmp->dirty) ! 508: (void)vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize); ! 509: #else ! 510: (void)vmp_push(vmp); /* Ignore errors! XXX */ ! 511: #endif ! 512: } ! 513: vm_object_lock(object); ! 514: vm_object_deactivate_pages(object); ! 515: vm_object_unlock(object); ! 516: if (close_flush || vmp->close_flush) { ! 517: vmp_put(vmp); ! 518: vmp->map_count--; ! 519: } ! 520: } ! 521: } ! 522: ! 523: /* ! 524: * remap_vnode: ! 525: * ! 526: * Remap the specified vnode (due to extension of the file perhaps). ! 527: * Upon return, it should be possible to access data in the file ! 528: * starting at the "start" address for "size" bytes. ! 529: */ ! 530: int ! 531: remap_vnode(vp, start, size) ! 532: register struct vnode *vp; ! 533: vm_offset_t start; ! 534: register vm_size_t size; ! 535: { ! 536: register struct vm_info *vmp; ! 537: vm_offset_t addr, offset; ! 538: kern_return_t ret; ! 539: int error=0; ! 540: vmp = vp->v_vm_info; ! 541: /* ! 542: * Remove old mapping (making its space available). ! 543: */ ! 544: ! 545: if (vmp->size > 0) { ! 546: #if PERFMODS ! 547: if (vmp->dirty) ! 548: (void)vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize); ! 549: error = mapfs_map_remove(vmp, vmp->va, vmp->va + vmp->size, FALSE); ! 550: #else ! 551: error = mapfs_map_remove(vmp, vmp->va, vmp->va + vmp->size, TRUE); ! 552: #endif /* PERFMODS */ ! 553: if (error) ! 554: goto out; ! 555: } ! 556: ! 557: offset = trunc_page(start); ! 558: size = round_page(start + size) - offset; ! 559: ! 560: if (size < CHUNK_SIZE) ! 561: size = CHUNK_SIZE; ! 562: do { ! 563: addr = vm_map_min(mfs_map); ! 564: mfs_alloc_lock(); ! 565: ret = vm_allocate_with_pager(mfs_map, &addr, size, TRUE, ! 566: vmp->pager, offset); ! 567: /* ! 568: * If there was no space, see if we can free up mappings ! 569: * on the LRU list. If not, just wait for someone else ! 570: * to free their memory. ! 571: */ ! 572: if (ret == KERN_NO_SPACE) { ! 573: register struct vm_info *vmp1; ! 574: ! 575: vm_info_lock(); ! 576: vmp1 = VM_INFO_NULL; ! 577: if (!queue_empty(&vm_info_queue)) { ! 578: vmp1 = (struct vm_info *) ! 579: queue_first(&vm_info_queue); ! 580: vm_info_dequeue(vmp1); ! 581: } ! 582: vm_info_unlock(); ! 583: /* ! 584: * If we found someone, free up its memory. ! 585: */ ! 586: if (vmp1 != VM_INFO_NULL) { ! 587: mfs_alloc_unlock(); ! 588: mapfs_memfree(vmp1, TRUE); ! 589: mfs_alloc_lock(); ! 590: } ! 591: else { ! 592: mfs_alloc_wanted = TRUE; ! 593: assert_wait(&mfs_map, FALSE); ! 594: mfs_alloc_blocks++; /* statistic only */ ! 595: mfs_alloc_unlock(); ! 596: thread_block(); ! 597: mfs_alloc_lock(); ! 598: } ! 599: } ! 600: else if (ret != KERN_SUCCESS) { ! 601: printf("Unexpected error on file map, ret = %d.\n", ! 602: ret); ! 603: panic("remap_vnode"); ! 604: } ! 605: mfs_alloc_unlock(); ! 606: } while (ret != KERN_SUCCESS); ! 607: /* ! 608: * Fill in variables corresponding to new mapping. ! 609: */ ! 610: vmp->va = addr; ! 611: vmp->size = size; ! 612: vmp->offset = offset; ! 613: out: ! 614: return(error); ! 615: } ! 616: ! 617: /* ! 618: * mapfs_trunc: ! 619: * ! 620: * The specified vnode is truncated to the specified size. ! 621: * Returns 0 if successful error otherwise. ! 622: */ ! 623: int ! 624: mapfs_trunc(vp, length) ! 625: register struct vnode *vp; ! 626: register vm_offset_t length; ! 627: { ! 628: register struct vm_info *vmp; ! 629: register vm_size_t size, rsize; ! 630: int error = 0; ! 631: ! 632: vmp = vp->v_vm_info; ! 633: ! 634: if ((vp->v_type != VREG) || (vmp == (struct vm_info *)0)) ! 635: return (0); ! 636: if (!vmp->mapped) { /* file not mapped, just update size */ ! 637: vmp->vnode_size = length; ! 638: return (0); ! 639: } ! 640: vmp_get(vmp); ! 641: ! 642: vmp->nfsdirty = TRUE; ! 643: /* ! 644: * Unmap everything past the new end page. ! 645: * Also flush any pages that may be left in the object using ! 646: * vno_flush (is this necessary?). ! 647: * rsize is the size relative to the mapped offset. ! 648: */ ! 649: NFSTRACE4(NFSTRC_MTR, vp, length, vmp->size, vmp->offset); ! 650: size = round_page(length); ! 651: if (size >= vmp->offset) { ! 652: rsize = size - vmp->offset; ! 653: } else { ! 654: rsize = 0; ! 655: } ! 656: if (rsize < vmp->size) { ! 657: error = mapfs_map_remove(vmp, vmp->va + rsize, ! 658: vmp->va + vmp->size, FALSE); ! 659: NFSTRACE4(NFSTRC_MTR_MREM, vp, vmp->va, vmp->size, rsize); ! 660: if (error) { ! 661: #if DIAGNOSTIC ! 662: kprintf("mapfs_trunc: mapfs_map_remove %d\n", error); ! 663: #endif /* DIAGNOSTIC */ ! 664: goto out; ! 665: } ! 666: if ((vmp->size = rsize) == 0) /* mapped size */ ! 667: vmp->offset = 0; ! 668: } ! 669: if (vmp->vnode_size > size) ! 670: vno_flush(vp, size, vmp->vnode_size - size); ! 671: vmp->vnode_size = length; /* file size */ ! 672: /* ! 673: * If the new length isn't page aligned, zero the extra ! 674: * bytes in the last page. ! 675: */ ! 676: if (length != size) { ! 677: vm_size_t n; ! 678: ! 679: n = size - length; ! 680: /* ! 681: * Make sure the bytes to be zeroed are mapped. ! 682: */ ! 683: if ((length < vmp->offset) || ! 684: ((length + n - 1) >= (vmp->offset + vmp->size))) { ! 685: NFSTRACE4(NFSTRC_MTR_RMAP, vp, vmp->offset, vmp->size, n); ! 686: error = remap_vnode(vp, length, n); ! 687: if (error) { ! 688: #if DIAGNOSTIC ! 689: kprintf("mapfs_trunc: remap_vnode %d\n", error); ! 690: #endif /* DIAGNOSTIC */ ! 691: goto out; ! 692: } ! 693: } ! 694: NFSTRACE(NFSTRC_MTR_DIRT, vmp->va); ! 695: vmp->nfsdirty = TRUE; ! 696: error = safe_bzero((void *)(vmp->va + length - vmp->offset), n); ! 697: if (error) { ! 698: NFSTRACE4(NFSTRC_MTR_BZER, vp, vmp->va, vmp->offset, n); ! 699: #if DIAGNOSTIC ! 700: kprintf("mapfs_trunc: safe_bzero %d\n", error); ! 701: kprintf("mapfs_trunc: va %x vp %x n %x length %x offset %x size %x\n", vmp->va, (unsigned)vp, n, length, vmp->offset, vmp->size); ! 702: #endif /* DIAGNOSTIC */ ! 703: goto out; ! 704: } ! 705: ! 706: /* ! 707: * Do NOT set dirty flag... the cached memory copy ! 708: * is zeroed, but this change doesn't need to be ! 709: * flushed to disk (the vnode already has the right ! 710: * size. Besides, if we set this bit, we would need ! 711: * to clean it immediately to prevent a later sync ! 712: * operation from incorrectly cleaning a cached-only ! 713: * copy of this vmp (which causes problems with NFS ! 714: * due to the fact that we have changed the mod time ! 715: * by truncating and will need to do an mapfs_uncache). ! 716: * NFS is a pain. Note that this means that there ! 717: * will be a dirty page left in the vmp. If this ! 718: * turns out to be a problem we'll have to set the dirty ! 719: * flag and immediately do a flush. ! 720: * ! 721: * UPDATE: 4/4/13. We need to really flush this. ! 722: * Use the map_count hack to prevent a race with ! 723: * uncaching. ! 724: */ ! 725: vmp->dirty = TRUE; ! 726: } ! 727: ! 728: vmp->map_count++; /* prevent uncache race */ ! 729: error = vmp_push(vmp); ! 730: #if DIAGNOSTIC ! 731: if (error) ! 732: kprintf("mapfs_trunc: vmp_push %d\n", error); ! 733: #endif /* DIAGNOSTIC */ ! 734: vmp->map_count--; ! 735: ! 736: out: ! 737: vmp_put(vmp); ! 738: return (error); ! 739: } ! 740: ! 741: /* ! 742: * mapfs_get: ! 743: * ! 744: * Get locked access to the specified file. The start and size describe ! 745: * the address range that will be accessed in the near future and ! 746: * serves as a hint of where to map the file if it is not already ! 747: * mapped. Upon return, it is guaranteed that there is enough VM ! 748: * available for remapping operations within that range (each window ! 749: * no larger than the chunk size). ! 750: */ ! 751: int ! 752: mapfs_get(vp, start, size) ! 753: register struct vnode *vp; ! 754: vm_offset_t start; ! 755: register vm_size_t size; ! 756: { ! 757: register struct vm_info *vmp; ! 758: int error=0; ! 759: vmp = vp->v_vm_info; ! 760: ! 761: vmp_get(vmp); ! 762: ! 763: /* ! 764: * If the requested size is larger than the size we have ! 765: * mapped, be sure we can get enough VM now. This size ! 766: * is bounded by the maximum window size. ! 767: */ ! 768: ! 769: if (size > mfs_max_window) ! 770: size = mfs_max_window; ! 771: ! 772: if (size > vmp->size) { ! 773: error = remap_vnode(vp, start, size); ! 774: } ! 775: return(error); ! 776: } ! 777: ! 778: /* ! 779: * mapfs_put: ! 780: * ! 781: * Indicate that locked access is no longer desired of a file. ! 782: */ ! 783: void ! 784: mapfs_put(vp) ! 785: register struct vnode *vp; ! 786: { ! 787: vmp_put(vp->v_vm_info); ! 788: } ! 789: ! 790: /* ! 791: * vmp_get: ! 792: * ! 793: * Get exclusive access to the specified vm_info structure. ! 794: * NeXT: Note mapfs_fsync_invalidate inlines part of this. ! 795: */ ! 796: void ! 797: vmp_get(vmp) ! 798: struct vm_info *vmp; ! 799: { ! 800: /* ! 801: * Remove from LRU list (if its there). ! 802: */ ! 803: vm_info_lock(); ! 804: if (vmp->queued) { ! 805: vm_info_dequeue(vmp); ! 806: } ! 807: vmp->use_count++; /* to protect requeueing in vmp_put */ ! 808: vm_info_unlock(); ! 809: ! 810: /* ! 811: * Lock out others using this file. ! 812: */ ! 813: lock_write(&vmp->lock); ! 814: lock_set_recursive(&vmp->lock); ! 815: } ! 816: ! 817: /* ! 818: * vmp_put: ! 819: * ! 820: * Release exclusive access gained in vmp_get. ! 821: */ ! 822: void ! 823: vmp_put(vmp) ! 824: register struct vm_info *vmp; ! 825: { ! 826: /* ! 827: * Place back on LRU list if noone else using it. ! 828: */ ! 829: vm_info_lock(); ! 830: if (--vmp->use_count == 0) { ! 831: vm_info_enqueue(vmp); ! 832: } ! 833: vm_info_unlock(); ! 834: /* ! 835: * Let others at file. ! 836: */ ! 837: lock_clear_recursive(&vmp->lock); ! 838: lock_write_done(&vmp->lock); ! 839: ! 840: if (mfs_files_mapped > mfs_files_max) ! 841: mapfs_cache_trim(); ! 842: ! 843: if (vmp->invalidate) { ! 844: vmp->invalidate = FALSE; ! 845: vmp_invalidate(vmp); ! 846: } ! 847: } ! 848: ! 849: /* ! 850: * mapfs_uncache: ! 851: * ! 852: * Make sure there are no cached mappings for the specified vnode. ! 853: */ ! 854: void ! 855: mapfs_uncache(vp) ! 856: register struct vnode *vp; ! 857: { ! 858: register struct vm_info *vmp; ! 859: ! 860: vmp = vp->v_vm_info; ! 861: /* ! 862: * If the file is mapped but there is none actively using ! 863: * it then remove its mappings. ! 864: */ ! 865: if (vmp->mapped && vmp->map_count == 0) { ! 866: mapfs_memfree(vmp, FALSE); ! 867: } ! 868: } ! 869: ! 870: void ! 871: mapfs_memfree(vmp, flush) ! 872: register struct vm_info *vmp; ! 873: boolean_t flush; ! 874: { ! 875: struct ucred *cred; ! 876: vm_object_t object; ! 877: int error = 0; ! 878: ! 879: vm_info_lock(); ! 880: if (vmp->queued) { ! 881: vm_info_dequeue(vmp); ! 882: } ! 883: vm_info_unlock(); ! 884: ! 885: lock_write(&vmp->lock); ! 886: lock_set_recursive(&vmp->lock); ! 887: ! 888: if (vmp->map_count == 0) { /* cached only */ ! 889: vmp->mapped = FALSE; /* prevent recursive flushes */ ! 890: } ! 891: ! 892: error = mapfs_map_remove(vmp, vmp->va, vmp->va + vmp->size, flush); ! 893: if (error) ! 894: panic("mapfs_memfree: mapfs_map_remove failed %d", error); /* XXX */ ! 895: vmp->size = 0; ! 896: vmp->va = 0; ! 897: object = VM_OBJECT_NULL; ! 898: if (vmp->map_count == 0) { /* cached only */ ! 899: /* ! 900: * lookup (in map_vnode) gained a reference, so need to ! 901: * lose it. ! 902: */ ! 903: object = vmp->object; ! 904: vmp->object = VM_OBJECT_NULL; ! 905: cred = vmp->cred; ! 906: if (cred != NOCRED) { ! 907: vmp->cred = NOCRED; ! 908: crfree(cred); ! 909: } ! 910: } ! 911: lock_clear_recursive(&vmp->lock); ! 912: lock_write_done(&vmp->lock); ! 913: ! 914: if (object != VM_OBJECT_NULL) ! 915: vm_object_deallocate(object); ! 916: } ! 917: ! 918: /* ! 919: * mapfs_cache_trim: ! 920: * ! 921: * trim the number of files in the cache to be less than the max ! 922: * we want. ! 923: */ ! 924: void ! 925: mapfs_cache_trim() ! 926: { ! 927: register struct vm_info *vmp; ! 928: ! 929: while (TRUE) { ! 930: vm_info_lock(); ! 931: if (mfs_files_mapped <= mfs_files_max) { ! 932: vm_info_unlock(); ! 933: return; ! 934: } ! 935: /* ! 936: * grab file at head of lru list. ! 937: */ ! 938: vmp = (struct vm_info *) queue_first(&vm_info_queue); ! 939: vm_info_dequeue(vmp); ! 940: vm_info_unlock(); ! 941: /* ! 942: * Free up its memory. ! 943: */ ! 944: mapfs_memfree(vmp, TRUE); ! 945: } ! 946: } ! 947: ! 948: /* ! 949: * mapfs_cache_clear: ! 950: * ! 951: * Clear the mapped file cache. Note that the map_count is implicitly ! 952: * locked by the Unix file system code that calls this routine. ! 953: */ ! 954: int ! 955: mapfs_cache_clear() ! 956: { ! 957: register struct vm_info *vmp; ! 958: int last_version; ! 959: ! 960: vm_info_lock(); ! 961: last_version = vm_info_version; ! 962: vmp = (struct vm_info *) queue_first(&vm_info_queue); ! 963: while (!queue_end(&vm_info_queue, (queue_entry_t) vmp)) { ! 964: if (vmp->map_count == 0) { ! 965: vm_info_unlock(); ! 966: mapfs_memfree(vmp, TRUE); ! 967: vm_info_lock(); ! 968: /* ! 969: * mapfs_memfree increments version number, causing ! 970: * restart below. ! 971: */ ! 972: } ! 973: /* ! 974: * If the version didn't change, just keep scanning ! 975: * down the queue. If the version did change, we ! 976: * need to restart from the beginning. ! 977: */ ! 978: if (last_version == vm_info_version) { ! 979: vmp = (struct vm_info *) queue_next(&vmp->lru_links); ! 980: } ! 981: else { ! 982: vmp = (struct vm_info *) queue_first(&vm_info_queue); ! 983: last_version = vm_info_version; ! 984: } ! 985: } ! 986: vm_info_unlock(); ! 987: return(0); ! 988: } ! 989: ! 990: /* ! 991: * mapfs_map_remove: ! 992: * ! 993: * Remove specified address range from the mfs map and wake up anyone ! 994: * waiting for map space. Be sure pages are flushed back to vnode. ! 995: */ ! 996: int ! 997: mapfs_map_remove(vmp, start, end, flush) ! 998: struct vm_info *vmp; ! 999: vm_offset_t start; ! 1000: vm_size_t end; ! 1001: boolean_t flush; ! 1002: { ! 1003: vm_object_t object; ! 1004: int error = 0; ! 1005: /* ! 1006: * Note: If we do need to flush, the vmp is already ! 1007: * locked at this point. ! 1008: */ ! 1009: if (flush) { ! 1010: /* vmp->map_count++; *//* prevent recursive flushes */ ! 1011: error = vmp_push(vmp); ! 1012: /* vmp->map_count--;*/ ! 1013: if (error) ! 1014: goto out; ! 1015: } ! 1016: ! 1017: /* ! 1018: * Free the address space. ! 1019: */ ! 1020: mfs_alloc_lock(); ! 1021: vm_map_remove(mfs_map, start, end); ! 1022: if (mfs_alloc_wanted) { ! 1023: mfs_alloc_wanted = FALSE; ! 1024: thread_wakeup(&mfs_map); ! 1025: } ! 1026: mfs_alloc_unlock(); ! 1027: /* ! 1028: * Deactivate the pages. ! 1029: */ ! 1030: object = vmp->object; ! 1031: if (object != VM_OBJECT_NULL) { ! 1032: vm_object_lock(object); ! 1033: vm_object_deactivate_pages_first(object); ! 1034: vm_object_unlock(object); ! 1035: } ! 1036: ! 1037: out: ! 1038: return(error); ! 1039: } ! 1040: ! 1041: #if PERFMODS ! 1042: /* ! 1043: * mapfs_map_cleanup: ! 1044: * ! 1045: * Remove specified address range from the mfs map and wake up anyone ! 1046: * waiting for map space. Be sure pages are flushed back to vnode. ! 1047: */ ! 1048: int ! 1049: mapfs_map_cleanup(vmp, start, end, flush) ! 1050: struct vm_info *vmp; ! 1051: vm_offset_t start; ! 1052: vm_size_t end; ! 1053: boolean_t flush; ! 1054: { ! 1055: /* ! 1056: * Free the address space. ! 1057: */ ! 1058: mfs_alloc_lock(); ! 1059: vm_map_remove(mfs_map, start, end); ! 1060: if (mfs_alloc_wanted) { ! 1061: mfs_alloc_wanted = FALSE; ! 1062: thread_wakeup(&mfs_map); ! 1063: } ! 1064: mfs_alloc_unlock(); ! 1065: return(0); ! 1066: } ! 1067: #endif ! 1068: ! 1069: #ifdef notdef ! 1070: vnode_size(vp) ! 1071: struct vnode *vp; ! 1072: { ! 1073: struct vattr vattr; ! 1074: ! 1075: VOP_GETATTR(vp, &vattr, u.u_cred,p); ! 1076: return(vattr.va_size); ! 1077: } ! 1078: #endif /* notdef */ ! 1079: ! 1080: ! 1081: int active_mfsbufs = 0; /* global record of buf count in use by mfs */ ! 1082: extern int nbuf; ! 1083: extern int nmfsbuf; /* global limit to mfs buffer allocation */ ! 1084: ! 1085: int ! 1086: mapfs_io(vp, uio, rw, ioflag, cred) ! 1087: register struct vnode *vp; ! 1088: register struct uio *uio; ! 1089: enum uio_rw rw; ! 1090: int ioflag; ! 1091: struct ucred *cred; ! 1092: { ! 1093: register vm_offset_t va; ! 1094: register struct vm_info *vmp; ! 1095: register int n, diff, bsize; ! 1096: int error=0; ! 1097: #if PERFMODS ! 1098: vm_offset_t newoffset; ! 1099: vm_size_t newsize; ! 1100: vm_size_t mapfsio_size; ! 1101: #endif ! 1102: struct ucred *cr; ! 1103: struct proc *p; ! 1104: ! 1105: ! 1106: if (uio->uio_resid == 0) { ! 1107: return (0); ! 1108: } ! 1109: ! 1110: if ((int) uio->uio_offset < 0 || ! 1111: (int) ((int)uio->uio_offset + uio->uio_resid) < 0) { ! 1112: return (EINVAL); ! 1113: } ! 1114: ! 1115: mfs_assert(vp->v_type==VREG || vp->v_type==VLNK); ! 1116: ! 1117: p = uio->uio_procp; ! 1118: if (p && (vp->v_type == VREG) && ! 1119: uio->uio_offset + uio->uio_resid > ! 1120: p->p_rlimit[RLIMIT_FSIZE].rlim_cur) { ! 1121: psignal(p, SIGXFSZ); ! 1122: return (EFBIG); ! 1123: } ! 1124: ! 1125: /* ! 1126: * The following code is adapted from code in nfs_bio{read,write}. ! 1127: * The point of having it here is to keep us as synchronized with the ! 1128: * server as we would have been had the nfs file not been mapped. Also ! 1129: * helping in that synchronization goal are the mapfs_memfree calls in ! 1130: * nfs_{get,load}attrcache. ! 1131: */ ! 1132: if (vp->v_tag == VT_NFS) { ! 1133: struct nfsnode *np = VTONFS(vp); ! 1134: struct proc *p = uio->uio_procp; ! 1135: struct vattr vattr; ! 1136: ! 1137: if (rw == UIO_WRITE) { ! 1138: NFSTRACE4(NFSTRC_MIO_WRT, vp, ! 1139: uio->uio_offset, uio->uio_resid, ! 1140: (ioflag & IO_APPEND ? 0x0010 : 0) | ! 1141: (ioflag & IO_SYNC ? 0x0020 : 0) | ! 1142: (np->n_flag & NMODIFIED ? 0x0001 : 0) | ! 1143: (vp->v_vm_info->nfsdirty ? 0x0002 : 0)); ! 1144: if (ioflag & (IO_APPEND | IO_SYNC)) { ! 1145: if (np->n_flag & NMODIFIED || vp->v_vm_info->nfsdirty) { ! 1146: np->n_attrstamp = 0; ! 1147: if ((error = nfs_vinvalbuf(vp, V_SAVE, ! 1148: cred, p, 1))) ! 1149: return (error); ! 1150: } ! 1151: if (ioflag & IO_APPEND) { ! 1152: np->n_attrstamp = 0; ! 1153: if ((error = VOP_GETATTR(vp, &vattr, ! 1154: cred, p))) ! 1155: return (error); ! 1156: } ! 1157: } ! 1158: } else { /* UIO_READ we presume */ ! 1159: NFSTRACE4(NFSTRC_MIO_READ, vp, ! 1160: uio->uio_offset, uio->uio_resid, ! 1161: (np->n_flag & NMODIFIED ? 0x0001 : 0) | ! 1162: (vp->v_vm_info->nfsdirty ? 0x0002 : 0)); ! 1163: if (np->n_flag & NMODIFIED || vp->v_vm_info->nfsdirty) { ! 1164: np->n_attrstamp = 0; ! 1165: if ((error = VOP_GETATTR(vp, &vattr, cred, p))) ! 1166: return (error); ! 1167: np->n_mtime = vattr.va_mtime.tv_sec; ! 1168: } else { ! 1169: if ((error = VOP_GETATTR(vp, &vattr, cred, p))) ! 1170: return (error); ! 1171: else if (np->n_mtime != vattr.va_mtime.tv_sec) { ! 1172: NFSTRACE(NFSTRC_MIO_RINV, vp); ! 1173: if ((error = nfs_vinvalbuf(vp, V_SAVE, ! 1174: cred, p, 1))) ! 1175: return (error); ! 1176: np->n_mtime = vattr.va_mtime.tv_sec; ! 1177: } ! 1178: } ! 1179: } ! 1180: } ! 1181: ! 1182: error = mapfs_get(vp, (vm_offset_t)uio->uio_offset, uio->uio_resid); ! 1183: if (error) ! 1184: goto out; ! 1185: vmp = vp->v_vm_info; ! 1186: ! 1187: if ((rw == UIO_WRITE) && (ioflag & IO_APPEND)) { ! 1188: uio->uio_offset = vmp->vnode_size; ! 1189: } ! 1190: #if PERFMODS ! 1191: bsize = PAGE_SIZE; ! 1192: #else ! 1193: bsize = vp->v_mount->mnt_stat.f_bsize; ! 1194: ! 1195: #define MAPFS_DEFAULT_BLOCKSIZE 4096 ! 1196: /* In some cases the f_bsize is not set; then force it to ! 1197: * default; porbably should consider changing to f_iosize ! 1198: * but not sure whether this will be any accurate either ! 1199: * We need this anyway ! 1200: */ ! 1201: if (bsize == 0) ! 1202: bsize = MAPFS_DEFAULT_BLOCKSIZE; ! 1203: #endif ! 1204: /* ! 1205: * Set credentials. ! 1206: */ ! 1207: if (rw == UIO_WRITE || (rw == UIO_READ && vmp->cred == NULL)) { ! 1208: cred = crdup(cred); ! 1209: cr = vmp->cred; ! 1210: if (cr != NOCRED) { ! 1211: vmp->cred = NOCRED; ! 1212: crfree(cr); ! 1213: } ! 1214: vmp->cred = cred; ! 1215: } ! 1216: ! 1217: /* Clear errors before we start */ ! 1218: vmp->error = 0; ! 1219: ! 1220: #if PERFMODS ! 1221: if (rw == UIO_WRITE) { ! 1222: /* ! 1223: * set up range for this I/O ! 1224: */ ! 1225: newoffset = uio->uio_offset; ! 1226: newsize = uio->uio_resid; ! 1227: ! 1228: if (vmp->dirtysize) { ! 1229: /* ! 1230: * if a dirty range already exists, coalesce with the new range, but ! 1231: * don't update the vmp fields yet, because if there was no intersection ! 1232: * between the old range and the range that encompasses the new I/O ! 1233: * we may want to push the old range and not do the coalesce if the new coalesced ! 1234: * size exceeds CHUNK_SIZE ! 1235: */ ! 1236: if (newoffset > vmp->dirtyoffset) ! 1237: newoffset = vmp->dirtyoffset; ! 1238: ! 1239: if ((uio->uio_offset + uio->uio_resid) > (vmp->dirtyoffset + vmp->dirtysize)) ! 1240: newsize = (uio->uio_offset + uio->uio_resid) - newoffset; ! 1241: else ! 1242: newsize = (vmp->dirtyoffset + vmp->dirtysize) - newoffset; ! 1243: ! 1244: if (newsize > CHUNK_SIZE && ((uio->uio_offset > (vmp->dirtyoffset + vmp->dirtysize)) || ! 1245: (uio->uio_offset + uio->uio_resid) < vmp->dirtyoffset)) { ! 1246: /* ! 1247: * the new coalasced size exceeded CHUNK_SIZE, and there was no intersection ! 1248: * with the current dirty range, so push the current dirty range.... ! 1249: * the new dirty range will be set to the range encompassing this I/O request ! 1250: */ ! 1251: vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize); ! 1252: newoffset = uio->uio_offset; ! 1253: newsize = uio->uio_resid; ! 1254: } ! 1255: } ! 1256: /* ! 1257: * now make sure that the proposed dirty range is fully encompassed by the ! 1258: * current vm mapping of the file... if not, we'll clip at either end ! 1259: * if there is no intersection at all with the current mapping, than ! 1260: * we'll set the dirty size to 0.... note that any previous dirty pages would ! 1261: * have been pushed above since they must have fit in the current mapping and ! 1262: * if the new range doesn't intersect with the current mapping, than we couldn't ! 1263: * have coalesced with the old range... in this case, we'll be going through the ! 1264: * remap path before issuing any I/O... that path will set the dirty range accordingly ! 1265: */ ! 1266: if (newoffset < vmp->offset) { ! 1267: if ((vmp->offset - newoffset) < newsize) ! 1268: newsize -= vmp->offset - newoffset; ! 1269: else ! 1270: newsize = 0; ! 1271: newoffset = vmp->offset; ! 1272: } ! 1273: if ((newoffset + newsize) > (vmp->offset + vmp->size)) ! 1274: newsize = (vmp->offset + vmp->size) - newoffset; ! 1275: ! 1276: vmp->dirtyoffset = newoffset; ! 1277: vmp->dirtysize = newsize; ! 1278: } ! 1279: #endif /* PERFMODS */ ! 1280: ! 1281: do { ! 1282: n = MIN((unsigned)bsize, uio->uio_resid); ! 1283: ! 1284: if (rw == UIO_READ) { ! 1285: /* ! 1286: * only read up to the end of the file ! 1287: */ ! 1288: if ((diff = (int)(vmp->vnode_size - uio->uio_offset)) <= 0) { ! 1289: mapfs_put(vp); ! 1290: return (0); ! 1291: } ! 1292: if (diff < n) ! 1293: n = diff; ! 1294: } else if (((vm_size_t)uio->uio_offset) + n > vmp->vnode_size) ! 1295: vmp->vnode_size = (vm_size_t)uio->uio_offset + n; ! 1296: ! 1297: /* ! 1298: * Check to be sure we have a valid window ! 1299: * for the mapped file. ! 1300: */ ! 1301: if (((vm_offset_t)uio->uio_offset < vmp->offset) || ! 1302: (((vm_offset_t)uio->uio_offset + n) > (vmp->offset + vmp->size))) { ! 1303: ! 1304: if ((mapfsio_size = (vmp->size << 1)) > mfs_max_window) ! 1305: mapfsio_size = mfs_max_window; ! 1306: ! 1307: error = remap_vnode(vp, (vm_offset_t)uio->uio_offset, mapfsio_size); ! 1308: /* ! 1309: * remap_vnode does a push of the dirty pages and then ! 1310: * sets vmp->dirtyoffset and vmp->dirtysize to 0 ! 1311: */ ! 1312: if (error) ! 1313: goto out; ! 1314: /* ! 1315: * new dirty range encompasses the remaining I/O of this request ! 1316: */ ! 1317: vmp->dirtyoffset = uio->uio_offset; ! 1318: vmp->dirtysize = uio->uio_resid; ! 1319: ! 1320: /* ! 1321: * make sure the new dirty range doesn't extend beyond the end of the map ! 1322: */ ! 1323: if ((vmp->dirtyoffset + vmp->dirtysize) > (vmp->offset + vmp->size)) ! 1324: vmp->dirtysize = (vmp->offset + vmp->size) - vmp->dirtyoffset; ! 1325: } ! 1326: va = vmp->va + (vm_offset_t)uio->uio_offset - vmp->offset; ! 1327: ! 1328: vmp->busy = TRUE; ! 1329: ! 1330: if (rw == UIO_WRITE) ! 1331: vmp->nfsdirty = TRUE; ! 1332: ! 1333: error = uiomove((caddr_t)va, (int)n, uio); ! 1334: ! 1335: vmp->busy = FALSE; ! 1336: ! 1337: if (error) ! 1338: goto out; ! 1339: ! 1340: if (vmp->delayed_fsync) { ! 1341: vmp->delayed_fsync = FALSE; ! 1342: ! 1343: if (rw == UIO_WRITE) ! 1344: vmp->dirtysize = uio->uio_offset - vmp->dirtyoffset; ! 1345: ! 1346: error = vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize); ! 1347: if (error) ! 1348: goto out; ! 1349: ! 1350: if (rw == UIO_WRITE) { ! 1351: /* ! 1352: * new dirty range encompasses the remaining I/O of this request ! 1353: */ ! 1354: vmp->dirtyoffset = uio->uio_offset; ! 1355: vmp->dirtysize = uio->uio_resid; ! 1356: ! 1357: /* ! 1358: * make sure the new dirty range doesn't extend beyond ! 1359: * the end of the map ! 1360: */ ! 1361: if ((vmp->dirtyoffset + vmp->dirtysize) > (vmp->offset + vmp->size)) ! 1362: vmp->dirtysize = (vmp->offset + vmp->size) - vmp->dirtyoffset; ! 1363: } ! 1364: } else if (rw == UIO_WRITE) ! 1365: /* ! 1366: * Set dirty bit each time through loop just in ! 1367: * case remap above caused it to be cleared. ! 1368: */ ! 1369: vmp->dirty = TRUE; ! 1370: ! 1371: /* ! 1372: * Check for errors left by the pager. Report the ! 1373: * error only once. ! 1374: */ ! 1375: if (vmp->error) { ! 1376: error = vmp->error; ! 1377: vmp->error = 0; ! 1378: /* ! 1379: * The error might have been a permission ! 1380: * error based on the credential. We release it ! 1381: * so that the next person who tries a read doesn't ! 1382: * get stuck with it. ! 1383: */ ! 1384: cr = vmp->cred; ! 1385: if (cr != NOCRED) { ! 1386: vmp->cred = NOCRED; ! 1387: crfree(cr); ! 1388: } ! 1389: } ! 1390: ! 1391: /* ! 1392: * Test to prevent mfs from swamping the buffer cache, ! 1393: * locking out higher-priority transfers, like ! 1394: * pageins, and causing system hangs. ! 1395: */ ! 1396: } while (error == 0 && uio->uio_resid > 0); ! 1397: ! 1398: #if PERFMODS ! 1399: if (error == 0 && rw == UIO_WRITE) { ! 1400: /* ! 1401: * Since the window may be as much as 4 Mbytes; write it out ! 1402: * when we reach or exceed CHUNK_SIZE to avoid flooding the ! 1403: * underlying disks with a huge stream of writes all at once ! 1404: */ ! 1405: if ((ioflag & IO_SYNC) || vmp->dirtysize >= CHUNK_SIZE) { ! 1406: ! 1407: error = vmp_push_range(vmp, vmp->dirtyoffset, vmp->dirtysize); ! 1408: ! 1409: if (error == 0 && (ioflag & IO_SYNC)) { ! 1410: error = VOP_FSYNC(vp, cred, MNT_WAIT, (struct proc *)0); ! 1411: if (error) ! 1412: goto out; ! 1413: } ! 1414: ! 1415: /* This looks like redundant info; but I am keeping this ! 1416: * as this worked at least from one reported case ! 1417: */ ! 1418: if (vmp->error) { ! 1419: error = vmp->error; ! 1420: vmp->error = 0; ! 1421: } ! 1422: } ! 1423: } ! 1424: #else ! 1425: if ( ! 1426: (error == 0) && ! 1427: (rw == UIO_WRITE) && ! 1428: (ioflag & IO_SYNC)) { ! 1429: ! 1430: ! 1431: error = vmp_push(vmp); /* initiate all i/o */ ! 1432: if (!error) { ! 1433: error = VOP_FSYNC(vp, cred, MNT_WAIT, (struct proc *)0); ! 1434: if (error) ! 1435: goto out; ! 1436: } ! 1437: /* This looks like redundant info; but I am keeping this ! 1438: * as this worked at least from one reported case ! 1439: */ ! 1440: if (vmp->error) { ! 1441: error = vmp->error; ! 1442: vmp->error = 0; ! 1443: } ! 1444: } ! 1445: #endif /* PERFMODS */ ! 1446: out: ! 1447: mapfs_put(vp); ! 1448: return(error); ! 1449: } ! 1450: ! 1451: /* ! 1452: * mapfs_sync: ! 1453: * ! 1454: * Sync the mfs cache (called by sync()). ! 1455: */ ! 1456: int ! 1457: mapfs_sync() ! 1458: { ! 1459: register struct vm_info *vmp, *next; ! 1460: int last_version; ! 1461: int error = 0; ! 1462: ! 1463: vm_info_lock(); ! 1464: last_version = vm_info_version; ! 1465: vmp = (struct vm_info *) queue_first(&vm_info_queue); ! 1466: while (!queue_end(&vm_info_queue, (queue_entry_t) vmp)) { ! 1467: next = (struct vm_info *) queue_next(&vmp->lru_links); ! 1468: if (vmp->dirty) { ! 1469: vm_info_unlock(); ! 1470: vmp_get(vmp); ! 1471: error = vmp_push(vmp); ! 1472: vmp_put(vmp); ! 1473: if (error) ! 1474: goto out; ! 1475: vm_info_lock(); ! 1476: /* ! 1477: * Since we unlocked, the get and put ! 1478: * operations would increment version by ! 1479: * two, so add two to our version. ! 1480: * If anything else happened in the meantime, ! 1481: * version numbers will not match and we ! 1482: * will restart. ! 1483: */ ! 1484: last_version += 2; ! 1485: } ! 1486: /* ! 1487: * If the version didn't change, just keep scanning ! 1488: * down the queue. If the version did change, we ! 1489: * need to restart from the beginning. ! 1490: */ ! 1491: if (last_version == vm_info_version) { ! 1492: vmp = next; ! 1493: } ! 1494: else { ! 1495: vmp = (struct vm_info *) queue_first(&vm_info_queue); ! 1496: last_version = vm_info_version; ! 1497: } ! 1498: } ! 1499: vm_info_unlock(); ! 1500: out: ! 1501: return(error); ! 1502: } ! 1503: ! 1504: /* ! 1505: * Sync pages in specified vnode. ! 1506: */ ! 1507: int ! 1508: mapfs_fsync(vp) ! 1509: struct vnode *vp; ! 1510: { ! 1511: struct vm_info *vmp; ! 1512: int error=0; ! 1513: vmp = vp->v_vm_info; ! 1514: if (vp->v_type == VREG && vmp != VM_INFO_NULL && vmp->mapped) { ! 1515: vmp_get(vmp); ! 1516: error = vmp_push(vmp); ! 1517: vmp_put(vmp); ! 1518: ! 1519: return(error); ! 1520: } ! 1521: return(0); ! 1522: } ! 1523: ! 1524: ! 1525: #if 0 /* dead code elimination */ ! 1526: /* ! 1527: * Sync pages in specified vnode, annd invalidate clean. ! 1528: * The vm_info lock protects the vm_info from modification, ! 1529: * or removal. XXX Must protect against sync/invalidate race ! 1530: */ ! 1531: int ! 1532: mapfs_fsync_invalidate(vp, flag) ! 1533: struct vnode *vp; ! 1534: { ! 1535: struct vm_info *vmp; ! 1536: ! 1537: vmp = vp->v_vm_info; ! 1538: if (vp->v_type == VREG && vmp != VM_INFO_NULL && vmp->mapped) { ! 1539: ! 1540: /* Part of vmp_get(vmp), we don't actually ! 1541: * need the write lock if we hold a ref as ! 1542: * we are not changing the vm_info data ! 1543: * ! 1544: * Remove from LRU list (if its there). ! 1545: */ ! 1546: vm_info_lock(); ! 1547: if (vmp->queued) { ! 1548: vm_info_dequeue(vmp); ! 1549: } ! 1550: vmp->use_count++; /* to protect requeueing in vmp_put */ ! 1551: vm_info_unlock(); ! 1552: ! 1553: if (!(flag & MFS_NOFLUSH)) ! 1554: vmp_push_all(vmp); ! 1555: ! 1556: /* This is not under a lock, nor is it in vm_put XXX */ ! 1557: /* But it is below */ ! 1558: if (!(flag & MFS_NOINVALID)){ ! 1559: vmp->invalidate = FALSE; ! 1560: vmp_invalidate(vmp); ! 1561: } ! 1562: /* ! 1563: * Place back on LRU list if noone else using it. ! 1564: */ ! 1565: vm_info_lock(); ! 1566: if (--vmp->use_count == 0) { ! 1567: vm_info_enqueue(vmp); ! 1568: } ! 1569: vm_info_unlock(); ! 1570: return(vmp->error); ! 1571: ! 1572: } ! 1573: return(0); ! 1574: } ! 1575: #endif ! 1576: ! 1577: ! 1578: ! 1579: /* ! 1580: * Invalidate pages in specified vnode. ! 1581: */ ! 1582: int ! 1583: mapfs_invalidate(vp) ! 1584: struct vnode *vp; ! 1585: { ! 1586: struct vm_info *vmp; ! 1587: ! 1588: vmp = vp->v_vm_info; ! 1589: if (vp->v_type == VREG && vmp != VM_INFO_NULL && vmp->mapped) { ! 1590: if (vmp->use_count > 0) ! 1591: vmp->invalidate = TRUE; ! 1592: else { ! 1593: vmp_get(vmp); ! 1594: vmp_invalidate(vmp); ! 1595: vmp_put(vmp); ! 1596: } ! 1597: } ! 1598: return(vmp ? vmp->error : 0); ! 1599: } ! 1600: ! 1601: #import <vm/vm_page.h> ! 1602: #import <vm/vm_object.h> ! 1603: ! 1604: /* ! 1605: * Search for and flush pages in the specified range. For now, it is ! 1606: * unnecessary to flush to disk since I do that synchronously. ! 1607: */ ! 1608: void vno_flush(vp, start, size) ! 1609: struct vnode *vp; ! 1610: register vm_offset_t start; ! 1611: vm_size_t size; ! 1612: { ! 1613: register vm_offset_t end; ! 1614: register vm_object_t object; ! 1615: register vm_page_t m; ! 1616: ! 1617: object = vp->v_vm_info->object; ! 1618: if (object == VM_OBJECT_NULL) ! 1619: return; ! 1620: ! 1621: #if SCRUBVM3 ! 1622: /* Isn't this the wrong order to aquire the lock */ ! 1623: #endif ! 1624: vm_page_lock_queues(); ! 1625: vm_object_lock(object); /* mfs code holds reference */ ! 1626: end = round_page(size + start); /* must be first */ ! 1627: start = trunc_page(start); ! 1628: while (start < end) { ! 1629: m = vm_page_lookup(object, start); ! 1630: if (m != VM_PAGE_NULL) { ! 1631: if (m->busy) { ! 1632: #if SCRUBVM3 ! 1633: /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC ! 1634: * on SWAP */ ! 1635: /* hint if we miss it its ok */ ! 1636: if (m->dry_vp){ ! 1637: /* object and page queues locked, note ! 1638: * page might not be clean wrt backing ! 1639: * store */ ! 1640: (void) vm_page_completeio(m, TRUE); ! 1641: } else { ! 1642: #endif ! 1643: PAGE_ASSERT_WAIT(m, FALSE); ! 1644: vm_object_unlock(object); ! 1645: vm_page_unlock_queues(); ! 1646: thread_block(); ! 1647: vm_page_lock_queues(); ! 1648: vm_object_lock(object); ! 1649: continue; /* try again */ ! 1650: #if SCRUBVM3 ! 1651: } ! 1652: #endif ! 1653: } ! 1654: vm_page_free(m); ! 1655: } ! 1656: start += PAGE_SIZE; ! 1657: } ! 1658: vm_object_unlock(object); ! 1659: vm_page_unlock_queues(); ! 1660: } ! 1661: ! 1662: ! 1663: int mfs_mdirty; ! 1664: int mfs_mclean; ! 1665: /* ! 1666: * Search for and free pages in the specified vmp. ! 1667: */ ! 1668: void ! 1669: vmp_invalidate(struct vm_info *vmp) ! 1670: { ! 1671: register vm_object_t object; ! 1672: register vm_page_t m; ! 1673: ! 1674: NFSTRACE(NFSTRC_VMP_INV, vmp); ! 1675: object = vmp->object; ! 1676: if (object == VM_OBJECT_NULL) ! 1677: return; ! 1678: ! 1679: vm_page_lock_queues(); ! 1680: vm_object_lock(object); /* mfs code holds reference */ ! 1681: ! 1682: /* Sanity. Different code calls this with and without the vminfo ! 1683: * lock. The locking needs to be fixed for MP. XXX ! 1684: */ ! 1685: if (vmp->object != object) { ! 1686: vm_object_unlock(object); ! 1687: vm_page_unlock_queues(); ! 1688: return; ! 1689: } ! 1690: ! 1691: retry: ! 1692: m = (vm_page_t) queue_first(&object->memq); ! 1693: while (!queue_end(&object->memq, (queue_entry_t) m)) { ! 1694: vm_page_t next = (vm_page_t) queue_next(&m->listq); ! 1695: ! 1696: /* If NFS is paging us in we are not really valid yet. XXX ! 1697: * Re-address this. Without this check we can block forever ! 1698: * waiting on the busy bit that we set. */ ! 1699: if (m->nfspagereq == TRUE){ ! 1700: m = next; ! 1701: continue; ! 1702: } ! 1703: ! 1704: if (m->busy) { ! 1705: #if SCRUBVM3 ! 1706: /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC ! 1707: * on SWAP */ ! 1708: /* hint if we miss it its ok */ ! 1709: if (m->dry_vp){ ! 1710: /* object and page queues locked, note ! 1711: * page might not be clean wrt backing ! 1712: * store */ ! 1713: (void) vm_page_completeio(m, TRUE); ! 1714: } else { ! 1715: #endif ! 1716: PAGE_ASSERT_WAIT(m, FALSE); ! 1717: vm_object_unlock(object); ! 1718: vm_page_unlock_queues(); ! 1719: thread_block(); ! 1720: vm_page_lock_queues(); ! 1721: vm_object_lock(object); ! 1722: goto retry; ! 1723: #if SCRUBVM3 ! 1724: } ! 1725: #endif ! 1726: } ! 1727: ! 1728: /* Kill off the translation as well. ! 1729: * mapfs_map_remove removes them as well, but as ! 1730: * we have seen not everyone calls that. ! 1731: * ! 1732: * If there is a ref to this file and we are being called ! 1733: * and the page is wired we will skip this page. If there ! 1734: * are no more refs to this file and we are being called ! 1735: * the wire count should always be zero. In the future we ! 1736: * may want to block on the wired count. XXX joh ! 1737: */ ! 1738: if (m->wire_count == 0){ ! 1739: pmap_remove_all(VM_PAGE_TO_PHYS(m)); ! 1740: /* In the case of mfs only one guy can be in here at a ! 1741: * a time. In the case of mmap they can be dirtying ! 1742: * pages in parallel . So after our sync and invalidate ! 1743: * above we need to check again. If someone has re- ! 1744: * written them again, then they get to keep the page. ! 1745: * NFS does not give any assurances for multiple ! 1746: * writers on different nodes. ! 1747: */ ! 1748: if ((m->clean == FALSE) || ! 1749: pmap_is_modified(VM_PAGE_TO_PHYS(m))){ ! 1750: mfs_mdirty++; ! 1751: } else { ! 1752: mfs_mclean++; ! 1753: vm_page_free(m); ! 1754: } ! 1755: } ! 1756: m = next; ! 1757: } ! 1758: vm_object_unlock(object); ! 1759: vm_page_unlock_queues(); ! 1760: } ! 1761: ! 1762: ! 1763: /* ! 1764: * Search for and push (to disk) pages in the specified range. ! 1765: * We need some better interactions with the VM system to simplify ! 1766: * the code. Force tries to push the object regardless of whether ! 1767: * the MFS thinks it is dirty (mmap could have written it). Some day ! 1768: * vmp_push could support ranges vmp_push(vmp,start,size). ! 1769: */ ! 1770: ! 1771: /* Something must be done to handle dirty wired pages. XXX joh */ ! 1772: int ! 1773: vmp_push(vmp) ! 1774: struct vm_info *vmp; ! 1775: { ! 1776: register vm_offset_t start; ! 1777: vm_size_t size; ! 1778: int error=0; ! 1779: ! 1780: if (!vmp->dirty) ! 1781: return(0); ! 1782: start = vmp->offset; ! 1783: size = vmp->size; ! 1784: ! 1785: /* vmp->dirty is set FALSE in vmp_push_range */ ! 1786: error = vmp_push_range(vmp, start, size); ! 1787: ! 1788: return(error); ! 1789: } ! 1790: ! 1791: int ! 1792: vmp_push_range(vmp, start, size) ! 1793: struct vm_info *vmp; ! 1794: register vm_offset_t start; ! 1795: vm_size_t size; ! 1796: { ! 1797: register vm_offset_t end; ! 1798: register vm_object_t object; ! 1799: register vm_page_t m; ! 1800: struct vattr vattr; ! 1801: int error=0; ! 1802: ! 1803: NFSTRACE4(NFSTRC_VPR, vmp->vnode, start, size, vmp->busy); ! 1804: if (!vmp->dirty) ! 1805: return(0); ! 1806: if (vmp->busy) { ! 1807: vmp->delayed_fsync = TRUE; ! 1808: return(0); ! 1809: } ! 1810: vmp->dirty = FALSE; ! 1811: vmp->dirtysize = 0; ! 1812: vmp->dirtyoffset = 0; ! 1813: ! 1814: object = vmp->object; ! 1815: /* We are trying to catch BSd error; no need to bother ! 1816: * about these errors for now ! 1817: */ ! 1818: if (object == VM_OBJECT_NULL) ! 1819: return(0); ! 1820: ! 1821: vm_page_lock_queues(); ! 1822: vm_object_lock(object); /* mfs code holds reference */ ! 1823: ! 1824: end = round_page(size + start); /* must be first */ ! 1825: start = trunc_page(start); ! 1826: /* Cleanup error before we start */ ! 1827: vmp->error = 0; ! 1828: ! 1829: while (start < end) { ! 1830: m = vm_page_lookup(object, start); ! 1831: /* We don't want to deadlock on the page we are bring in */ ! 1832: if ((m != VM_PAGE_NULL) && (m->nfspagereq == FALSE)){ ! 1833: if (m->busy) { ! 1834: #if SCRUBVM3 ! 1835: /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC ! 1836: * on SWAP */ ! 1837: /* hint if we miss it its ok */ ! 1838: if (m->dry_vp){ ! 1839: /* object and page queues locked, note ! 1840: * page might not be clean wrt backing ! 1841: * store */ ! 1842: (void) vm_page_completeio(m, TRUE); ! 1843: } else { ! 1844: #endif ! 1845: PAGE_ASSERT_WAIT(m, FALSE); ! 1846: vm_object_unlock(object); ! 1847: vm_page_unlock_queues(); ! 1848: thread_block(); ! 1849: vm_page_lock_queues(); ! 1850: vm_object_lock(object); ! 1851: continue; /* try again */ ! 1852: #if SCRUBVM3 ! 1853: } ! 1854: #endif ! 1855: } ! 1856: if (!m->active) { ! 1857: vm_page_activate(m); /* so deactivate works */ ! 1858: } ! 1859: vm_page_deactivate(m); /* gets dirty/laundry bit */ ! 1860: /* ! 1861: * Prevent pageout from playing with ! 1862: * this page. We know it is inactive right ! 1863: * now (and are holding lots of locks keeping ! 1864: * it there). ! 1865: */ ! 1866: queue_remove(&vm_page_queue_inactive, m, vm_page_t, ! 1867: pageq); ! 1868: m->inactive = FALSE; ! 1869: vm_page_inactive_count--; ! 1870: m->busy = TRUE; ! 1871: if (m->laundry) { ! 1872: pager_return_t ret; ! 1873: ! 1874: pmap_remove_all(VM_PAGE_TO_PHYS(m)); ! 1875: object->paging_in_progress++; ! 1876: vm_object_unlock(object); ! 1877: vm_page_unlock_queues(); ! 1878: /* should call pageout daemon code */ ! 1879: ret = vnode_pageout(m); ! 1880: vm_page_lock_queues(); ! 1881: vm_object_lock(object); ! 1882: object->paging_in_progress--; ! 1883: if (ret == PAGER_SUCCESS) { ! 1884: /* vnode_pageout marks clean */ ! 1885: #if PERFMODS ! 1886: pmap_clear_reference(VM_PAGE_TO_PHYS(m)); ! 1887: #endif /* PERFMODS */ ! 1888: m->laundry = FALSE; ! 1889: } else { ! 1890: /* don't set dirty bit, unrecoverable ! 1891: errors will cause update to go ! 1892: crazy. User is responsible for ! 1893: retrying the write */ ! 1894: /* vmp->dirty = TRUE; */ ! 1895: error = vmp->error; ! 1896: vmp->error =0; ! 1897: } ! 1898: /* if pager failed, activate below */ ! 1899: } ! 1900: vm_page_activate(m); ! 1901: m->busy = FALSE; ! 1902: PAGE_WAKEUP(m); ! 1903: } ! 1904: start += PAGE_SIZE; ! 1905: } ! 1906: vmp->nfsdirty = FALSE; ! 1907: vm_object_unlock(object); ! 1908: vm_page_unlock_queues(); ! 1909: ! 1910: /* ! 1911: * On error we have to reset the true file size in the vmp ! 1912: * structure. The lack of a credential structure pointer ! 1913: * would indicate nothing was changing in the file. ! 1914: */ ! 1915: if (error && vmp->cred) { ! 1916: vmp->filesize=TRUE; ! 1917: VOP_GETATTR (vmp->vnode, &vattr, vmp->cred, current_proc()); ! 1918: vmp->filesize=FALSE; ! 1919: vmp->vnode_size = vattr.va_size; ! 1920: } ! 1921: NFSTRACE(NFSTRC_VPR_DONE, error); ! 1922: ! 1923: return(error); ! 1924: } ! 1925: ! 1926: ! 1927: #if 0 /* dead code elimination */ ! 1928: /* Something must be done to handle dirty wired pages. XXX joh */ ! 1929: void ! 1930: vmp_push_all(vmp) ! 1931: struct vm_info *vmp; ! 1932: { ! 1933: register vm_object_t object; ! 1934: register vm_page_t m; ! 1935: struct vattr vattr; ! 1936: int error=0; ! 1937: ! 1938: vmp->dirty = FALSE; ! 1939: ! 1940: object = vmp->object; ! 1941: if (object == VM_OBJECT_NULL) ! 1942: return; ! 1943: ! 1944: vm_page_lock_queues(); ! 1945: vm_object_lock(object); /* mfs code holds reference */ ! 1946: ! 1947: retry: ! 1948: m = (vm_page_t) queue_first(&object->memq); ! 1949: while (!queue_end(&object->memq, (queue_entry_t) m)) { ! 1950: /* We don't want to deadlock on the page we are bring in */ ! 1951: if (m->nfspagereq == FALSE){ ! 1952: if (m->busy) { ! 1953: #if SCRUBVM3 ! 1954: /* THIS SHOULD NOT HAPPEN IF ONLY ASYNC ! 1955: * on SWAP */ ! 1956: /* hint if we miss it its ok */ ! 1957: if (m->dry_vp){ ! 1958: /* object and page queues locked, note ! 1959: * page might not be clean wrt backing ! 1960: * store */ ! 1961: (void) vm_page_completeio(m, TRUE); ! 1962: } else { ! 1963: #endif ! 1964: PAGE_ASSERT_WAIT(m, FALSE); ! 1965: vm_object_unlock(object); ! 1966: vm_page_unlock_queues(); ! 1967: thread_block(); ! 1968: vm_page_lock_queues(); ! 1969: vm_object_lock(object); ! 1970: /* Page may be long gone, XXX Forward ! 1971: * progress */ ! 1972: goto retry; ! 1973: #if SCRUBVM3 ! 1974: } ! 1975: #endif ! 1976: } ! 1977: if (!m->active) { ! 1978: vm_page_activate(m); /* so deactivate works */ ! 1979: } ! 1980: vm_page_deactivate(m); /* gets dirty/laundry bit */ ! 1981: /* ! 1982: * Prevent pageout from playing with ! 1983: * this page. We know it is inactive right ! 1984: * now (and are holding lots of locks keeping ! 1985: * it there). ! 1986: */ ! 1987: queue_remove(&vm_page_queue_inactive, m, vm_page_t, ! 1988: pageq); ! 1989: m->inactive = FALSE; ! 1990: vm_page_inactive_count--; ! 1991: m->busy = TRUE; ! 1992: if (m->laundry) { ! 1993: pager_return_t ret; ! 1994: ! 1995: pmap_remove_all(VM_PAGE_TO_PHYS(m)); ! 1996: object->paging_in_progress++; ! 1997: vm_object_unlock(object); ! 1998: vm_page_unlock_queues(); ! 1999: /* should call pageout daemon code */ ! 2000: ret = vnode_pageout(m); ! 2001: vm_page_lock_queues(); ! 2002: vm_object_lock(object); ! 2003: object->paging_in_progress--; ! 2004: if (ret == PAGER_SUCCESS) { ! 2005: /* vnode_pageout marks clean */ ! 2006: m->laundry = FALSE; ! 2007: } else { ! 2008: /* don't set dirty bit, unrecoverable ! 2009: errors will cause update to go ! 2010: crazy. User is responsible for ! 2011: retrying the write */ ! 2012: /* vmp->dirty = TRUE; */ ! 2013: error = vmp->error; ! 2014: vmp->error=0; ! 2015: } ! 2016: /* if pager failed, activate below */ ! 2017: } ! 2018: vm_page_activate(m); ! 2019: m->busy = FALSE; ! 2020: PAGE_WAKEUP(m); ! 2021: } ! 2022: m = (vm_page_t) queue_next(&m->listq); ! 2023: } ! 2024: vmp->nfsdirty = FALSE; ! 2025: vm_object_unlock(object); ! 2026: vm_page_unlock_queues(); ! 2027: ! 2028: /* ! 2029: * On error we have to reset the true file size in the vmp ! 2030: * structure. The lack of a credential structure pointer ! 2031: * would indicate nothing was changing in the file. ! 2032: */ ! 2033: if (error && vmp->cred) { ! 2034: vmp->filesize=TRUE; ! 2035: VOP_GETATTR (vmp->vnode, &vattr, vmp->cred, current_proc()); ! 2036: vmp->filesize=FALSE; ! 2037: vmp->vnode_size = vattr.va_size; ! 2038: } ! 2039: } ! 2040: #endif ! 2041: ! 2042: ! 2043: vm_size_t vm_get_vnode_size(struct vnode *vp) ! 2044: { ! 2045: return(vp->v_vm_info->vnode_size); ! 2046: } ! 2047: ! 2048: void vm_set_vnode_size(struct vnode *vp, vm_size_t vnode_size) ! 2049: { ! 2050: vp->v_vm_info->vnode_size = vnode_size; ! 2051: } ! 2052: ! 2053: void vm_set_close_flush(struct vnode *vp, boolean_t close_flush) ! 2054: { ! 2055: vp->v_vm_info->close_flush = close_flush ? 1 : 0; ! 2056: } ! 2057: ! 2058: void vm_set_error(struct vnode *vp, int error) ! 2059: { ! 2060: vp->v_vm_info->error = error; ! 2061: } ! 2062: #endif /* MACH_NBC ] */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.