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