|
|
1.1 root 1: /*
2: * Copyright (c) 1990 University of Utah.
3: * Copyright (c) 1991 The Regents of the University of California.
4: * All rights reserved.
5: *
6: * This code is derived from software contributed to Berkeley by
7: * the Systems Programming Group of the University of Utah Computer
8: * Science Department.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the University of
21: * California, Berkeley and its contributors.
22: * 4. Neither the name of the University nor the names of its contributors
23: * may be used to endorse or promote products derived from this software
24: * without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36: * SUCH DAMAGE.
37: *
1.1.1.2 ! root 38: * from: @(#)vnode_pager.c 7.5 (Berkeley) 4/20/91
! 39: * vnode_pager.c,v 1.2 1993/05/20 03:59:53 cgd Exp
1.1 root 40: */
41:
42: /*
43: * Page to/from files (vnodes).
44: *
45: * TODO:
46: * pageouts
47: * fix credential use (uses current process credentials now)
48: */
49: #include "vnodepager.h"
50: #if NVNODEPAGER > 0
51:
52: #include "param.h"
53: #include "proc.h"
54: #include "malloc.h"
55: #include "vnode.h"
56: #include "uio.h"
57: #include "mount.h"
58:
59: #include "vm_param.h"
60: #include "lock.h"
61: #include "queue.h"
62: #include "vm_prot.h"
63: #include "vm_object.h"
64: #include "vm_page.h"
65: #include "vnode_pager.h"
66:
67: queue_head_t vnode_pager_list; /* list of managed vnodes */
68:
69: #ifdef DEBUG
70: int vpagerdebug = 0x00;
71: #define VDB_FOLLOW 0x01
72: #define VDB_INIT 0x02
73: #define VDB_IO 0x04
74: #define VDB_FAIL 0x08
75: #define VDB_ALLOC 0x10
76: #define VDB_SIZE 0x20
77: #endif
78:
79: void
80: vnode_pager_init()
81: {
82: #ifdef DEBUG
83: if (vpagerdebug & VDB_FOLLOW)
84: printf("vnode_pager_init()\n");
85: #endif
86: queue_init(&vnode_pager_list);
87: }
88:
89: /*
90: * Allocate (or lookup) pager for a vnode.
91: * Handle is a vnode pointer.
92: */
93: vm_pager_t
94: vnode_pager_alloc(handle, size, prot)
95: caddr_t handle;
96: vm_size_t size;
97: vm_prot_t prot;
98: {
99: register vm_pager_t pager;
100: register vn_pager_t vnp;
101: vm_object_t object;
102: struct vattr vattr;
103: struct vnode *vp;
104: struct proc *p = curproc; /* XXX */
105:
106: #ifdef DEBUG
107: if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC))
108: printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot);
109: #endif
110: /*
111: * Pageout to vnode, no can do yet.
112: */
113: if (handle == NULL)
114: return(NULL);
115:
116: /*
117: * Vnodes keep a pointer to any associated pager so no need to
118: * lookup with vm_pager_lookup.
119: */
120: vp = (struct vnode *)handle;
121: pager = (vm_pager_t)vp->v_vmdata;
122: if (pager == NULL) {
123: /*
124: * Allocate pager structures
125: */
126: pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
127: if (pager == NULL)
128: return(NULL);
129: vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
130: if (vnp == NULL) {
131: free((caddr_t)pager, M_VMPAGER);
132: return(NULL);
133: }
134: /*
135: * And an object of the appropriate size
136: */
137: if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) {
138: object = vm_object_allocate(round_page(vattr.va_size));
139: vm_object_enter(object, pager);
140: vm_object_setpager(object, pager, 0, TRUE);
141: } else {
142: free((caddr_t)vnp, M_VMPGDATA);
143: free((caddr_t)pager, M_VMPAGER);
144: return(NULL);
145: }
146: /*
147: * Hold a reference to the vnode and initialize pager data.
148: */
149: VREF(vp);
150: vnp->vnp_flags = 0;
151: vnp->vnp_vp = vp;
152: vnp->vnp_size = vattr.va_size;
153: queue_enter(&vnode_pager_list, pager, vm_pager_t, pg_list);
154: pager->pg_handle = handle;
155: pager->pg_type = PG_VNODE;
156: pager->pg_ops = &vnodepagerops;
157: pager->pg_data = (caddr_t)vnp;
158: vp->v_vmdata = (caddr_t)pager;
159: } else {
160: /*
161: * vm_object_lookup() will remove the object from the
162: * cache if found and also gain a reference to the object.
163: */
164: object = vm_object_lookup(pager);
165: #ifdef DEBUG
166: vnp = (vn_pager_t)pager->pg_data;
167: #endif
168: }
169: #ifdef DEBUG
170: if (vpagerdebug & VDB_ALLOC)
171: printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n",
172: vp, vnp->vnp_size, pager, object);
173: #endif
174: return(pager);
175: }
176:
177: void
178: vnode_pager_dealloc(pager)
179: vm_pager_t pager;
180: {
181: register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
182: register struct vnode *vp;
183: struct proc *p = curproc; /* XXX */
184:
185: #ifdef DEBUG
186: if (vpagerdebug & VDB_FOLLOW)
187: printf("vnode_pager_dealloc(%x)\n", pager);
188: #endif
189: if (vp = vnp->vnp_vp) {
190: vp->v_vmdata = NULL;
191: vp->v_flag &= ~VTEXT;
192: #if 0
193: /* can hang if done at reboot on NFS FS */
194: (void) VOP_FSYNC(vp, p->p_ucred, p);
195: #endif
196: vrele(vp);
197: }
198: queue_remove(&vnode_pager_list, pager, vm_pager_t, pg_list);
199: free((caddr_t)vnp, M_VMPGDATA);
200: free((caddr_t)pager, M_VMPAGER);
201: }
202:
203: vnode_pager_getpage(pager, m, sync)
204: vm_pager_t pager;
205: vm_page_t m;
206: boolean_t sync;
207: {
208:
209: #ifdef DEBUG
210: if (vpagerdebug & VDB_FOLLOW)
211: printf("vnode_pager_getpage(%x, %x)\n", pager, m);
212: #endif
213: return(vnode_pager_io((vn_pager_t)pager->pg_data, m, UIO_READ));
214: }
215:
216: boolean_t
217: vnode_pager_putpage(pager, m, sync)
218: vm_pager_t pager;
219: vm_page_t m;
220: boolean_t sync;
221: {
222: int err;
223:
224: #ifdef DEBUG
225: if (vpagerdebug & VDB_FOLLOW)
226: printf("vnode_pager_putpage(%x, %x)\n", pager, m);
227: #endif
228: if (pager == NULL)
229: return;
230: err = vnode_pager_io((vn_pager_t)pager->pg_data, m, UIO_WRITE);
231: if (err == VM_PAGER_OK) {
232: m->clean = TRUE; /* XXX - wrong place */
233: pmap_clear_modify(VM_PAGE_TO_PHYS(m)); /* XXX - wrong place */
234: }
235: return(err);
236: }
237:
238: boolean_t
239: vnode_pager_haspage(pager, offset)
240: vm_pager_t pager;
241: vm_offset_t offset;
242: {
243: register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
244: daddr_t bn;
245: int err;
246:
247: #ifdef DEBUG
248: if (vpagerdebug & VDB_FOLLOW)
249: printf("vnode_pager_haspage(%x, %x)\n", pager, offset);
250: #endif
251:
252: /*
253: * Offset beyond end of file, do not have the page
254: */
255: if (offset >= vnp->vnp_size) {
256: #ifdef DEBUG
257: if (vpagerdebug & (VDB_FAIL|VDB_SIZE))
258: printf("vnode_pager_haspage: pg %x, off %x, size %x\n",
259: pager, offset, vnp->vnp_size);
260: #endif
261: return(FALSE);
262: }
263:
264: /*
265: * Read the index to find the disk block to read
266: * from. If there is no block, report that we don't
267: * have this data.
268: *
269: * Assumes that the vnode has whole page or nothing.
270: */
271: err = VOP_BMAP(vnp->vnp_vp,
272: offset / vnp->vnp_vp->v_mount->mnt_stat.f_bsize,
273: (struct vnode **)0, &bn);
274: if (err) {
275: #ifdef DEBUG
276: if (vpagerdebug & VDB_FAIL)
277: printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n",
278: err, pager, offset);
279: #endif
280: return(TRUE);
281: }
282: return((long)bn < 0 ? FALSE : TRUE);
283: }
284:
285: /*
286: * (XXX)
287: * Lets the VM system know about a change in size for a file.
288: * If this vnode is mapped into some address space (i.e. we have a pager
289: * for it) we adjust our own internal size and flush any cached pages in
290: * the associated object that are affected by the size change.
291: *
292: * Note: this routine may be invoked as a result of a pager put
293: * operation (possibly at object termination time), so we must be careful.
294: */
295: vnode_pager_setsize(vp, nsize)
296: struct vnode *vp;
297: u_long nsize;
298: {
299: register vn_pager_t vnp;
300: register vm_object_t object;
301: vm_pager_t pager;
302:
303: /*
304: * Not a mapped vnode
305: */
306: if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
307: return;
308: /*
309: * Hasn't changed size
310: */
311: pager = (vm_pager_t)vp->v_vmdata;
312: vnp = (vn_pager_t)pager->pg_data;
313: if (nsize == vnp->vnp_size)
314: return;
315: /*
316: * No object.
317: * This can happen during object termination since
318: * vm_object_page_clean is called after the object
319: * has been removed from the hash table, and clean
320: * may cause vnode write operations which can wind
321: * up back here.
322: */
323: object = vm_object_lookup(pager);
324: if (object == NULL)
325: return;
326:
327: #ifdef DEBUG
328: if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE))
329: printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n",
330: vp, object, vnp->vnp_size, nsize);
331: #endif
332: /*
333: * File has shrunk.
334: * Toss any cached pages beyond the new EOF.
335: */
336: if (nsize < vnp->vnp_size) {
337: vm_object_lock(object);
338: vm_object_page_remove(object,
339: (vm_offset_t)nsize, vnp->vnp_size);
340: vm_object_unlock(object);
341: }
342: vnp->vnp_size = (vm_offset_t)nsize;
343: vm_object_deallocate(object);
344: }
345:
346: vnode_pager_umount(mp)
347: register struct mount *mp;
348: {
349: register vm_pager_t pager, npager;
350: struct vnode *vp;
351:
352: pager = (vm_pager_t) queue_first(&vnode_pager_list);
353: while (!queue_end(&vnode_pager_list, (queue_entry_t)pager)) {
354: /*
355: * Save the next pointer now since uncaching may
356: * terminate the object and render pager invalid
357: */
358: vp = ((vn_pager_t)pager->pg_data)->vnp_vp;
359: npager = (vm_pager_t) queue_next(&pager->pg_list);
360: if (mp == (struct mount *)0 || vp->v_mount == mp)
361: (void) vnode_pager_uncache(vp);
362: pager = npager;
363: }
364: }
365:
366: /*
367: * Remove vnode associated object from the object cache.
368: *
369: * Note: this routine may be invoked as a result of a pager put
370: * operation (possibly at object termination time), so we must be careful.
371: */
372: boolean_t
373: vnode_pager_uncache(vp)
374: register struct vnode *vp;
375: {
376: register vm_object_t object;
377: boolean_t uncached, locked;
378: vm_pager_t pager;
379:
380: /*
381: * Not a mapped vnode
382: */
383: pager = (vm_pager_t)vp->v_vmdata;
384: if (pager == NULL)
385: return (TRUE);
386: /*
387: * Unlock the vnode if it is currently locked.
388: * We do this since uncaching the object may result
389: * in its destruction which may initiate paging
390: * activity which may necessitate locking the vnode.
391: */
392: locked = VOP_ISLOCKED(vp);
393: if (locked)
394: VOP_UNLOCK(vp);
395: /*
396: * Must use vm_object_lookup() as it actually removes
397: * the object from the cache list.
398: */
399: object = vm_object_lookup(pager);
400: if (object) {
401: uncached = (object->ref_count <= 1);
402: pager_cache(object, FALSE);
403: } else
404: uncached = TRUE;
405: if (locked)
406: VOP_LOCK(vp);
407: return(uncached);
408: }
409:
410: vnode_pager_io(vnp, m, rw)
411: register vn_pager_t vnp;
412: vm_page_t m;
413: enum uio_rw rw;
414: {
415: struct uio auio;
416: struct iovec aiov;
417: vm_offset_t kva, foff;
418: int error, size;
419: struct proc *p = curproc; /* XXX */
420:
421: #ifdef DEBUG
422: if (vpagerdebug & VDB_FOLLOW)
423: printf("vnode_pager_io(%x, %x, %c): vnode %x\n",
424: vnp, m, rw == UIO_READ ? 'R' : 'W', vnp->vnp_vp);
425: #endif
426: foff = m->offset + m->object->paging_offset;
427: /*
428: * Return failure if beyond current EOF
429: */
430: if (foff >= vnp->vnp_size) {
431: #ifdef DEBUG
432: if (vpagerdebug & VDB_SIZE)
433: printf("vnode_pager_io: vp %x, off %d size %d\n",
434: vnp->vnp_vp, foff, vnp->vnp_size);
435: #endif
436: return(VM_PAGER_BAD);
437: }
438: if (foff + PAGE_SIZE > vnp->vnp_size)
439: size = vnp->vnp_size - foff;
440: else
441: size = PAGE_SIZE;
442: /*
443: * Allocate a kernel virtual address and initialize so that
444: * we can use VOP_READ/WRITE routines.
445: */
446: kva = vm_pager_map_page(m);
447: aiov.iov_base = (caddr_t)kva;
448: aiov.iov_len = size;
449: auio.uio_iov = &aiov;
450: auio.uio_iovcnt = 1;
451: auio.uio_offset = foff;
452: auio.uio_segflg = UIO_SYSSPACE;
453: auio.uio_rw = rw;
454: auio.uio_resid = size;
455: auio.uio_procp = (struct proc *)0;
456: #ifdef DEBUG
457: if (vpagerdebug & VDB_IO)
458: printf("vnode_pager_io: vp %x kva %x foff %x size %x",
459: vnp->vnp_vp, kva, foff, size);
460: #endif
461: if (rw == UIO_READ)
462: error = VOP_READ(vnp->vnp_vp, &auio, 0, p->p_ucred);
463: else
464: error = VOP_WRITE(vnp->vnp_vp, &auio, 0, p->p_ucred);
465: #ifdef DEBUG
466: if (vpagerdebug & VDB_IO) {
467: if (error || auio.uio_resid)
468: printf(" returns error %x, resid %x",
469: error, auio.uio_resid);
470: printf("\n");
471: }
472: #endif
473: if (!error) {
474: register int count = size - auio.uio_resid;
475:
476: if (count == 0)
477: error = EINVAL;
478: else if (count != PAGE_SIZE && rw == UIO_READ)
479: bzero(kva + count, PAGE_SIZE - count);
480: }
481: vm_pager_unmap_page(kva);
482: return (error ? VM_PAGER_FAIL : VM_PAGER_OK);
483: }
484: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.