145749Smckusick /*
245749Smckusick * Copyright (c) 1990 University of Utah.
363379Sbostic * Copyright (c) 1991, 1993
463379Sbostic * The Regents of the University of California. All rights reserved.
545749Smckusick *
645749Smckusick * This code is derived from software contributed to Berkeley by
745749Smckusick * the Systems Programming Group of the University of Utah Computer
845749Smckusick * Science Department.
945749Smckusick *
1045749Smckusick * %sccs.include.redist.c%
1145749Smckusick *
12*69431Smckusick * @(#)vnode_pager.c 8.10 (Berkeley) 05/14/95
1345749Smckusick */
1445749Smckusick
1566082Sbostic /*
1645749Smckusick * Page to/from files (vnodes).
1745749Smckusick *
1845749Smckusick * TODO:
1945749Smckusick * pageouts
2047977Skarels * fix credential use (uses current process credentials now)
2145749Smckusick */
2245749Smckusick
2353342Sbostic #include <sys/param.h>
2453342Sbostic #include <sys/systm.h>
2553342Sbostic #include <sys/proc.h>
2653342Sbostic #include <sys/malloc.h>
2753342Sbostic #include <sys/vnode.h>
2853342Sbostic #include <sys/uio.h>
2953342Sbostic #include <sys/mount.h>
3047977Skarels
3153342Sbostic #include <vm/vm.h>
3253342Sbostic #include <vm/vm_page.h>
3353342Sbostic #include <vm/vnode_pager.h>
3445749Smckusick
3565231Smckusick struct pagerlst vnode_pager_list; /* list of managed vnodes */
3645749Smckusick
3745749Smckusick #ifdef DEBUG
3845749Smckusick int vpagerdebug = 0x00;
3945749Smckusick #define VDB_FOLLOW 0x01
4045749Smckusick #define VDB_INIT 0x02
4145749Smckusick #define VDB_IO 0x04
4245749Smckusick #define VDB_FAIL 0x08
4345749Smckusick #define VDB_ALLOC 0x10
4445749Smckusick #define VDB_SIZE 0x20
4545749Smckusick #endif
4645749Smckusick
4764827Storek static vm_pager_t vnode_pager_alloc
4864827Storek __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
4965695Shibler static void vnode_pager_cluster
5065695Shibler __P((vm_pager_t, vm_offset_t,
5165695Shibler vm_offset_t *, vm_offset_t *));
5253342Sbostic static void vnode_pager_dealloc __P((vm_pager_t));
5353342Sbostic static int vnode_pager_getpage
5465695Shibler __P((vm_pager_t, vm_page_t *, int, boolean_t));
5553342Sbostic static boolean_t vnode_pager_haspage __P((vm_pager_t, vm_offset_t));
5653342Sbostic static void vnode_pager_init __P((void));
5753342Sbostic static int vnode_pager_io
5865695Shibler __P((vn_pager_t, vm_page_t *, int,
5965695Shibler boolean_t, enum uio_rw));
6053342Sbostic static boolean_t vnode_pager_putpage
6165695Shibler __P((vm_pager_t, vm_page_t *, int, boolean_t));
6253342Sbostic
6353342Sbostic struct pagerops vnodepagerops = {
6453342Sbostic vnode_pager_init,
6553342Sbostic vnode_pager_alloc,
6653342Sbostic vnode_pager_dealloc,
6753342Sbostic vnode_pager_getpage,
6853342Sbostic vnode_pager_putpage,
6965695Shibler vnode_pager_haspage,
7065695Shibler vnode_pager_cluster
7153342Sbostic };
7253342Sbostic
7353342Sbostic static void
vnode_pager_init()7445749Smckusick vnode_pager_init()
7545749Smckusick {
7645749Smckusick #ifdef DEBUG
7745749Smckusick if (vpagerdebug & VDB_FOLLOW)
7845749Smckusick printf("vnode_pager_init()\n");
7945749Smckusick #endif
8065231Smckusick TAILQ_INIT(&vnode_pager_list);
8145749Smckusick }
8245749Smckusick
8345749Smckusick /*
8445749Smckusick * Allocate (or lookup) pager for a vnode.
8545749Smckusick * Handle is a vnode pointer.
8645749Smckusick */
8753342Sbostic static vm_pager_t
vnode_pager_alloc(handle,size,prot,foff)8864827Storek vnode_pager_alloc(handle, size, prot, foff)
8945749Smckusick caddr_t handle;
9045749Smckusick vm_size_t size;
9145749Smckusick vm_prot_t prot;
9264827Storek vm_offset_t foff;
9345749Smckusick {
9445749Smckusick register vm_pager_t pager;
9545749Smckusick register vn_pager_t vnp;
9645749Smckusick vm_object_t object;
9745749Smckusick struct vattr vattr;
9845749Smckusick struct vnode *vp;
9948042Smckusick struct proc *p = curproc; /* XXX */
10045749Smckusick
10145749Smckusick #ifdef DEBUG
10245749Smckusick if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC))
10345749Smckusick printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot);
10445749Smckusick #endif
10545749Smckusick /*
10645749Smckusick * Pageout to vnode, no can do yet.
10745749Smckusick */
10845749Smckusick if (handle == NULL)
10948397Skarels return(NULL);
11045749Smckusick
11145749Smckusick /*
11245749Smckusick * Vnodes keep a pointer to any associated pager so no need to
11345749Smckusick * lookup with vm_pager_lookup.
11445749Smckusick */
11545749Smckusick vp = (struct vnode *)handle;
11645749Smckusick pager = (vm_pager_t)vp->v_vmdata;
11748397Skarels if (pager == NULL) {
11845749Smckusick /*
11945749Smckusick * Allocate pager structures
12045749Smckusick */
12145749Smckusick pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
12248397Skarels if (pager == NULL)
12348397Skarels return(NULL);
12445749Smckusick vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
12548397Skarels if (vnp == NULL) {
12645749Smckusick free((caddr_t)pager, M_VMPAGER);
12748397Skarels return(NULL);
12845749Smckusick }
12945749Smckusick /*
13045749Smckusick * And an object of the appropriate size
13145749Smckusick */
13248042Smckusick if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) {
13345749Smckusick object = vm_object_allocate(round_page(vattr.va_size));
13445749Smckusick vm_object_enter(object, pager);
13545749Smckusick vm_object_setpager(object, pager, 0, TRUE);
13645749Smckusick } else {
13745749Smckusick free((caddr_t)vnp, M_VMPGDATA);
13845749Smckusick free((caddr_t)pager, M_VMPAGER);
13948397Skarels return(NULL);
14045749Smckusick }
14145749Smckusick /*
14245749Smckusick * Hold a reference to the vnode and initialize pager data.
14345749Smckusick */
14445749Smckusick VREF(vp);
14545749Smckusick vnp->vnp_flags = 0;
14645749Smckusick vnp->vnp_vp = vp;
14745749Smckusick vnp->vnp_size = vattr.va_size;
14865231Smckusick TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list);
14945749Smckusick pager->pg_handle = handle;
15045749Smckusick pager->pg_type = PG_VNODE;
15165695Shibler pager->pg_flags = 0;
15245749Smckusick pager->pg_ops = &vnodepagerops;
15364858Shibler pager->pg_data = vnp;
15445749Smckusick vp->v_vmdata = (caddr_t)pager;
15545749Smckusick } else {
15645749Smckusick /*
15745749Smckusick * vm_object_lookup() will remove the object from the
15845749Smckusick * cache if found and also gain a reference to the object.
15945749Smckusick */
16045749Smckusick object = vm_object_lookup(pager);
16147977Skarels #ifdef DEBUG
16245749Smckusick vnp = (vn_pager_t)pager->pg_data;
16347977Skarels #endif
16445749Smckusick }
16545749Smckusick #ifdef DEBUG
16645749Smckusick if (vpagerdebug & VDB_ALLOC)
16745749Smckusick printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n",
16845749Smckusick vp, vnp->vnp_size, pager, object);
16945749Smckusick #endif
17045749Smckusick return(pager);
17145749Smckusick }
17245749Smckusick
17353342Sbostic static void
vnode_pager_dealloc(pager)17445749Smckusick vnode_pager_dealloc(pager)
17545749Smckusick vm_pager_t pager;
17645749Smckusick {
17745749Smckusick register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
17845749Smckusick register struct vnode *vp;
17965722Sbostic #ifdef NOTDEF
18048042Smckusick struct proc *p = curproc; /* XXX */
18165722Sbostic #endif
18245749Smckusick
18345749Smckusick #ifdef DEBUG
18445749Smckusick if (vpagerdebug & VDB_FOLLOW)
18545749Smckusick printf("vnode_pager_dealloc(%x)\n", pager);
18645749Smckusick #endif
18745749Smckusick if (vp = vnp->vnp_vp) {
18845749Smckusick vp->v_vmdata = NULL;
18945749Smckusick vp->v_flag &= ~VTEXT;
19065722Sbostic #if NOTDEF
19145749Smckusick /* can hang if done at reboot on NFS FS */
19248042Smckusick (void) VOP_FSYNC(vp, p->p_ucred, p);
19345749Smckusick #endif
19445749Smckusick vrele(vp);
19545749Smckusick }
19665231Smckusick TAILQ_REMOVE(&vnode_pager_list, pager, pg_list);
19745749Smckusick free((caddr_t)vnp, M_VMPGDATA);
19845749Smckusick free((caddr_t)pager, M_VMPAGER);
19945749Smckusick }
20045749Smckusick
20153342Sbostic static int
vnode_pager_getpage(pager,mlist,npages,sync)20265695Shibler vnode_pager_getpage(pager, mlist, npages, sync)
20345749Smckusick vm_pager_t pager;
20465695Shibler vm_page_t *mlist;
20565695Shibler int npages;
20645749Smckusick boolean_t sync;
20745749Smckusick {
20845749Smckusick
20945749Smckusick #ifdef DEBUG
21045749Smckusick if (vpagerdebug & VDB_FOLLOW)
21165695Shibler printf("vnode_pager_getpage(%x, %x, %x, %x)\n",
21265695Shibler pager, mlist, npages, sync);
21345749Smckusick #endif
21465695Shibler return(vnode_pager_io((vn_pager_t)pager->pg_data,
21565695Shibler mlist, npages, sync, UIO_READ));
21645749Smckusick }
21745749Smckusick
21853342Sbostic static boolean_t
vnode_pager_putpage(pager,mlist,npages,sync)21965695Shibler vnode_pager_putpage(pager, mlist, npages, sync)
22045749Smckusick vm_pager_t pager;
22165695Shibler vm_page_t *mlist;
22265695Shibler int npages;
22345749Smckusick boolean_t sync;
22445749Smckusick {
22545749Smckusick int err;
22645749Smckusick
22745749Smckusick #ifdef DEBUG
22845749Smckusick if (vpagerdebug & VDB_FOLLOW)
22965695Shibler printf("vnode_pager_putpage(%x, %x, %x, %x)\n",
23065695Shibler pager, mlist, npages, sync);
23145749Smckusick #endif
23248397Skarels if (pager == NULL)
23354818Storek return (FALSE); /* ??? */
23465695Shibler err = vnode_pager_io((vn_pager_t)pager->pg_data,
23565695Shibler mlist, npages, sync, UIO_WRITE);
23665695Shibler /*
23765695Shibler * If the operation was successful, mark the pages clean.
23865695Shibler */
23945749Smckusick if (err == VM_PAGER_OK) {
24065695Shibler while (npages--) {
24165695Shibler (*mlist)->flags |= PG_CLEAN;
24265695Shibler pmap_clear_modify(VM_PAGE_TO_PHYS(*mlist));
24365695Shibler mlist++;
24465695Shibler }
24545749Smckusick }
24645749Smckusick return(err);
24745749Smckusick }
24845749Smckusick
24953342Sbostic static boolean_t
vnode_pager_haspage(pager,offset)25045749Smckusick vnode_pager_haspage(pager, offset)
25145749Smckusick vm_pager_t pager;
25245749Smckusick vm_offset_t offset;
25345749Smckusick {
254*69431Smckusick struct proc *p = curproc; /* XXX */
255*69431Smckusick vn_pager_t vnp = (vn_pager_t)pager->pg_data;
25645749Smckusick daddr_t bn;
25745749Smckusick int err;
25845749Smckusick
25945749Smckusick #ifdef DEBUG
26045749Smckusick if (vpagerdebug & VDB_FOLLOW)
26145749Smckusick printf("vnode_pager_haspage(%x, %x)\n", pager, offset);
26245749Smckusick #endif
26345749Smckusick
26445749Smckusick /*
26545749Smckusick * Offset beyond end of file, do not have the page
26666075Shibler * Lock the vnode first to make sure we have the most recent
26766075Shibler * version of the size.
26845749Smckusick */
269*69431Smckusick vn_lock(vnp->vnp_vp, LK_EXCLUSIVE | LK_RETRY, p);
27045749Smckusick if (offset >= vnp->vnp_size) {
271*69431Smckusick VOP_UNLOCK(vnp->vnp_vp, 0, p);
27245749Smckusick #ifdef DEBUG
27345749Smckusick if (vpagerdebug & (VDB_FAIL|VDB_SIZE))
27445749Smckusick printf("vnode_pager_haspage: pg %x, off %x, size %x\n",
27545749Smckusick pager, offset, vnp->vnp_size);
27645749Smckusick #endif
27745749Smckusick return(FALSE);
27845749Smckusick }
27945749Smckusick
28045749Smckusick /*
28145749Smckusick * Read the index to find the disk block to read
28245749Smckusick * from. If there is no block, report that we don't
28345749Smckusick * have this data.
28445749Smckusick *
28545749Smckusick * Assumes that the vnode has whole page or nothing.
28645749Smckusick */
28745749Smckusick err = VOP_BMAP(vnp->vnp_vp,
28851941Smckusick offset / vnp->vnp_vp->v_mount->mnt_stat.f_iosize,
28956457Smargo (struct vnode **)0, &bn, NULL);
290*69431Smckusick VOP_UNLOCK(vnp->vnp_vp, 0, p);
29145749Smckusick if (err) {
29245749Smckusick #ifdef DEBUG
29345749Smckusick if (vpagerdebug & VDB_FAIL)
29445749Smckusick printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n",
29545749Smckusick err, pager, offset);
29645749Smckusick #endif
29745749Smckusick return(TRUE);
29845749Smckusick }
29945749Smckusick return((long)bn < 0 ? FALSE : TRUE);
30045749Smckusick }
30145749Smckusick
30265695Shibler static void
vnode_pager_cluster(pager,offset,loffset,hoffset)30365695Shibler vnode_pager_cluster(pager, offset, loffset, hoffset)
30465695Shibler vm_pager_t pager;
30565695Shibler vm_offset_t offset;
30665695Shibler vm_offset_t *loffset;
30765695Shibler vm_offset_t *hoffset;
30865695Shibler {
30965695Shibler vn_pager_t vnp = (vn_pager_t)pager->pg_data;
31065695Shibler vm_offset_t loff, hoff;
31165695Shibler
31265695Shibler #ifdef DEBUG
31365695Shibler if (vpagerdebug & VDB_FOLLOW)
31465695Shibler printf("vnode_pager_cluster(%x, %x) ", pager, offset);
31565695Shibler #endif
31665695Shibler loff = offset;
31765695Shibler if (loff >= vnp->vnp_size)
31865695Shibler panic("vnode_pager_cluster: bad offset");
31965695Shibler /*
32065695Shibler * XXX could use VOP_BMAP to get maxcontig value
32165695Shibler */
32265695Shibler hoff = loff + MAXBSIZE;
32365695Shibler if (hoff > round_page(vnp->vnp_size))
32465695Shibler hoff = round_page(vnp->vnp_size);
32565695Shibler
32665695Shibler *loffset = loff;
32765695Shibler *hoffset = hoff;
32865695Shibler #ifdef DEBUG
32965695Shibler if (vpagerdebug & VDB_FOLLOW)
33065695Shibler printf("returns [%x-%x]\n", loff, hoff);
33165695Shibler #endif
33265695Shibler }
33365695Shibler
33445749Smckusick /*
33545749Smckusick * (XXX)
33645749Smckusick * Lets the VM system know about a change in size for a file.
33745749Smckusick * If this vnode is mapped into some address space (i.e. we have a pager
33845749Smckusick * for it) we adjust our own internal size and flush any cached pages in
33945749Smckusick * the associated object that are affected by the size change.
34045749Smckusick *
34145749Smckusick * Note: this routine may be invoked as a result of a pager put
34245749Smckusick * operation (possibly at object termination time), so we must be careful.
34345749Smckusick */
34453480Smckusick void
vnode_pager_setsize(vp,nsize)34545749Smckusick vnode_pager_setsize(vp, nsize)
34645749Smckusick struct vnode *vp;
34745749Smckusick u_long nsize;
34845749Smckusick {
34945749Smckusick register vn_pager_t vnp;
35045749Smckusick register vm_object_t object;
35145749Smckusick vm_pager_t pager;
35245749Smckusick
35345749Smckusick /*
35445749Smckusick * Not a mapped vnode
35545749Smckusick */
35645749Smckusick if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
35745749Smckusick return;
35845749Smckusick /*
35945749Smckusick * Hasn't changed size
36045749Smckusick */
36145749Smckusick pager = (vm_pager_t)vp->v_vmdata;
36245749Smckusick vnp = (vn_pager_t)pager->pg_data;
36345749Smckusick if (nsize == vnp->vnp_size)
36445749Smckusick return;
36545749Smckusick /*
36645749Smckusick * No object.
36745749Smckusick * This can happen during object termination since
36845749Smckusick * vm_object_page_clean is called after the object
36945749Smckusick * has been removed from the hash table, and clean
37045749Smckusick * may cause vnode write operations which can wind
37145749Smckusick * up back here.
37245749Smckusick */
37345749Smckusick object = vm_object_lookup(pager);
37448397Skarels if (object == NULL)
37545749Smckusick return;
37645749Smckusick
37745749Smckusick #ifdef DEBUG
37845749Smckusick if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE))
37945749Smckusick printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n",
38045749Smckusick vp, object, vnp->vnp_size, nsize);
38145749Smckusick #endif
38245749Smckusick /*
38345749Smckusick * File has shrunk.
38445749Smckusick * Toss any cached pages beyond the new EOF.
38545749Smckusick */
38645749Smckusick if (nsize < vnp->vnp_size) {
38745749Smckusick vm_object_lock(object);
38845749Smckusick vm_object_page_remove(object,
38945749Smckusick (vm_offset_t)nsize, vnp->vnp_size);
39045749Smckusick vm_object_unlock(object);
39145749Smckusick }
39245749Smckusick vnp->vnp_size = (vm_offset_t)nsize;
39345749Smckusick vm_object_deallocate(object);
39445749Smckusick }
39545749Smckusick
39653480Smckusick void
vnode_pager_umount(mp)39745749Smckusick vnode_pager_umount(mp)
39845749Smckusick register struct mount *mp;
39945749Smckusick {
400*69431Smckusick struct proc *p = curproc; /* XXX */
401*69431Smckusick vm_pager_t pager, npager;
40245749Smckusick struct vnode *vp;
40345749Smckusick
40465231Smckusick for (pager = vnode_pager_list.tqh_first; pager != NULL; pager = npager){
40545749Smckusick /*
40645749Smckusick * Save the next pointer now since uncaching may
40745749Smckusick * terminate the object and render pager invalid
40845749Smckusick */
40965231Smckusick npager = pager->pg_list.tqe_next;
41045749Smckusick vp = ((vn_pager_t)pager->pg_data)->vnp_vp;
41165695Shibler if (mp == (struct mount *)0 || vp->v_mount == mp) {
412*69431Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
41345749Smckusick (void) vnode_pager_uncache(vp);
414*69431Smckusick VOP_UNLOCK(vp, 0, p);
41565695Shibler }
41645749Smckusick }
41745749Smckusick }
41845749Smckusick
41945749Smckusick /*
42045749Smckusick * Remove vnode associated object from the object cache.
42145749Smckusick *
42265695Shibler * XXX unlock the vnode if it is currently locked.
42365695Shibler * We must do this since uncaching the object may result in its
42465695Shibler * destruction which may initiate paging activity which may necessitate
42565695Shibler * re-locking the vnode.
42645749Smckusick */
42753480Smckusick boolean_t
vnode_pager_uncache(vp)42845749Smckusick vnode_pager_uncache(vp)
42945749Smckusick register struct vnode *vp;
43045749Smckusick {
431*69431Smckusick struct proc *p = curproc; /* XXX */
432*69431Smckusick vm_object_t object;
43365695Shibler boolean_t uncached;
43445749Smckusick vm_pager_t pager;
43545749Smckusick
43645749Smckusick /*
43745749Smckusick * Not a mapped vnode
43845749Smckusick */
43967958Smckusick if (vp->v_type != VREG || (pager = (vm_pager_t)vp->v_vmdata) == NULL)
44045749Smckusick return (TRUE);
44165695Shibler #ifdef DEBUG
44265695Shibler if (!VOP_ISLOCKED(vp)) {
44365695Shibler extern int (**nfsv2_vnodeop_p)();
44465695Shibler
44565695Shibler if (vp->v_op != nfsv2_vnodeop_p)
44665695Shibler panic("vnode_pager_uncache: vnode not locked!");
44765695Shibler }
44865695Shibler #endif
44945749Smckusick /*
45045749Smckusick * Must use vm_object_lookup() as it actually removes
45145749Smckusick * the object from the cache list.
45245749Smckusick */
45345749Smckusick object = vm_object_lookup(pager);
45445749Smckusick if (object) {
45545749Smckusick uncached = (object->ref_count <= 1);
456*69431Smckusick VOP_UNLOCK(vp, 0, p);
45745749Smckusick pager_cache(object, FALSE);
458*69431Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
45945749Smckusick } else
46045749Smckusick uncached = TRUE;
46145749Smckusick return(uncached);
46245749Smckusick }
46345749Smckusick
46453342Sbostic static int
vnode_pager_io(vnp,mlist,npages,sync,rw)46565695Shibler vnode_pager_io(vnp, mlist, npages, sync, rw)
46645749Smckusick register vn_pager_t vnp;
46765695Shibler vm_page_t *mlist;
46865695Shibler int npages;
46965695Shibler boolean_t sync;
47045749Smckusick enum uio_rw rw;
47145749Smckusick {
47245749Smckusick struct uio auio;
47345749Smckusick struct iovec aiov;
47445749Smckusick vm_offset_t kva, foff;
47545749Smckusick int error, size;
47648042Smckusick struct proc *p = curproc; /* XXX */
47745749Smckusick
47865695Shibler /* XXX */
47965695Shibler vm_page_t m;
48065695Shibler if (npages != 1)
48165695Shibler panic("vnode_pager_io: cannot handle multiple pages");
48265695Shibler m = *mlist;
48365695Shibler /* XXX */
48465695Shibler
48545749Smckusick #ifdef DEBUG
48645749Smckusick if (vpagerdebug & VDB_FOLLOW)
48745749Smckusick printf("vnode_pager_io(%x, %x, %c): vnode %x\n",
48845749Smckusick vnp, m, rw == UIO_READ ? 'R' : 'W', vnp->vnp_vp);
48945749Smckusick #endif
49045749Smckusick foff = m->offset + m->object->paging_offset;
49145749Smckusick /*
49266075Shibler * Allocate a kernel virtual address and initialize so that
49366075Shibler * we can use VOP_READ/WRITE routines.
49445749Smckusick */
49566075Shibler kva = vm_pager_map_pages(mlist, npages, sync);
49666075Shibler if (kva == NULL)
49766075Shibler return(VM_PAGER_AGAIN);
49866075Shibler /*
49966075Shibler * After all of the potentially blocking operations have been
50066075Shibler * performed, we can do the size checks:
50166075Shibler * read beyond EOF (returns error)
50266075Shibler * short read
50366075Shibler */
504*69431Smckusick vn_lock(vnp->vnp_vp, LK_EXCLUSIVE | LK_RETRY, p);
50545749Smckusick if (foff >= vnp->vnp_size) {
506*69431Smckusick VOP_UNLOCK(vnp->vnp_vp, 0, p);
50766075Shibler vm_pager_unmap_pages(kva, npages);
50845749Smckusick #ifdef DEBUG
50945749Smckusick if (vpagerdebug & VDB_SIZE)
51045749Smckusick printf("vnode_pager_io: vp %x, off %d size %d\n",
51145749Smckusick vnp->vnp_vp, foff, vnp->vnp_size);
51245749Smckusick #endif
51345749Smckusick return(VM_PAGER_BAD);
51445749Smckusick }
51545749Smckusick if (foff + PAGE_SIZE > vnp->vnp_size)
51645749Smckusick size = vnp->vnp_size - foff;
51745749Smckusick else
51845749Smckusick size = PAGE_SIZE;
51945749Smckusick aiov.iov_base = (caddr_t)kva;
52045749Smckusick aiov.iov_len = size;
52145749Smckusick auio.uio_iov = &aiov;
52245749Smckusick auio.uio_iovcnt = 1;
52345749Smckusick auio.uio_offset = foff;
52445749Smckusick auio.uio_segflg = UIO_SYSSPACE;
52545749Smckusick auio.uio_rw = rw;
52645749Smckusick auio.uio_resid = size;
52748042Smckusick auio.uio_procp = (struct proc *)0;
52845749Smckusick #ifdef DEBUG
52945749Smckusick if (vpagerdebug & VDB_IO)
53045749Smckusick printf("vnode_pager_io: vp %x kva %x foff %x size %x",
53145749Smckusick vnp->vnp_vp, kva, foff, size);
53245749Smckusick #endif
53345749Smckusick if (rw == UIO_READ)
53448042Smckusick error = VOP_READ(vnp->vnp_vp, &auio, 0, p->p_ucred);
53545749Smckusick else
53648042Smckusick error = VOP_WRITE(vnp->vnp_vp, &auio, 0, p->p_ucred);
537*69431Smckusick VOP_UNLOCK(vnp->vnp_vp, 0, p);
53845749Smckusick #ifdef DEBUG
53945749Smckusick if (vpagerdebug & VDB_IO) {
54045749Smckusick if (error || auio.uio_resid)
54145749Smckusick printf(" returns error %x, resid %x",
54245749Smckusick error, auio.uio_resid);
54345749Smckusick printf("\n");
54445749Smckusick }
54545749Smckusick #endif
54645749Smckusick if (!error) {
54745749Smckusick register int count = size - auio.uio_resid;
54845749Smckusick
54945749Smckusick if (count == 0)
55045749Smckusick error = EINVAL;
55145749Smckusick else if (count != PAGE_SIZE && rw == UIO_READ)
55253342Sbostic bzero((void *)(kva + count), PAGE_SIZE - count);
55345749Smckusick }
55465695Shibler vm_pager_unmap_pages(kva, npages);
55556321Shibler return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
55645749Smckusick }
557