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