|
|
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.