xref: /csrg-svn/sys/vm/vnode_pager.c (revision 66075)
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*66075Shibler  *	@(#)vnode_pager.c	8.7 (Berkeley) 02/13/94
1345749Smckusick  */
1445749Smckusick 
1545749Smckusick  * Page to/from files (vnodes).
1645749Smckusick  *
1745749Smckusick  * TODO:
1845749Smckusick  *	pageouts
1947977Skarels  *	fix credential use (uses current process credentials now)
2045749Smckusick  */
2145749Smckusick 
2253342Sbostic #include <sys/param.h>
2353342Sbostic #include <sys/systm.h>
2453342Sbostic #include <sys/proc.h>
2553342Sbostic #include <sys/malloc.h>
2653342Sbostic #include <sys/vnode.h>
2753342Sbostic #include <sys/uio.h>
2853342Sbostic #include <sys/mount.h>
2947977Skarels 
3053342Sbostic #include <vm/vm.h>
3153342Sbostic #include <vm/vm_page.h>
3253342Sbostic #include <vm/vnode_pager.h>
3345749Smckusick 
3465231Smckusick struct pagerlst	vnode_pager_list;	/* list of managed vnodes */
3545749Smckusick 
3645749Smckusick #ifdef DEBUG
3745749Smckusick int	vpagerdebug = 0x00;
3845749Smckusick #define	VDB_FOLLOW	0x01
3945749Smckusick #define VDB_INIT	0x02
4045749Smckusick #define VDB_IO		0x04
4145749Smckusick #define VDB_FAIL	0x08
4245749Smckusick #define VDB_ALLOC	0x10
4345749Smckusick #define VDB_SIZE	0x20
4445749Smckusick #endif
4545749Smckusick 
4664827Storek static vm_pager_t	 vnode_pager_alloc
4764827Storek 			    __P((caddr_t, vm_size_t, vm_prot_t, vm_offset_t));
4865695Shibler static void		 vnode_pager_cluster
4965695Shibler 			    __P((vm_pager_t, vm_offset_t,
5065695Shibler 				 vm_offset_t *, vm_offset_t *));
5153342Sbostic static void		 vnode_pager_dealloc __P((vm_pager_t));
5253342Sbostic static int		 vnode_pager_getpage
5365695Shibler 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
5453342Sbostic static boolean_t	 vnode_pager_haspage __P((vm_pager_t, vm_offset_t));
5553342Sbostic static void		 vnode_pager_init __P((void));
5653342Sbostic static int		 vnode_pager_io
5765695Shibler 			    __P((vn_pager_t, vm_page_t *, int,
5865695Shibler 				 boolean_t, enum uio_rw));
5953342Sbostic static boolean_t	 vnode_pager_putpage
6065695Shibler 			    __P((vm_pager_t, vm_page_t *, int, boolean_t));
6153342Sbostic 
6253342Sbostic struct pagerops vnodepagerops = {
6353342Sbostic 	vnode_pager_init,
6453342Sbostic 	vnode_pager_alloc,
6553342Sbostic 	vnode_pager_dealloc,
6653342Sbostic 	vnode_pager_getpage,
6753342Sbostic 	vnode_pager_putpage,
6865695Shibler 	vnode_pager_haspage,
6965695Shibler 	vnode_pager_cluster
7053342Sbostic };
7153342Sbostic 
7253342Sbostic static void
7345749Smckusick vnode_pager_init()
7445749Smckusick {
7545749Smckusick #ifdef DEBUG
7645749Smckusick 	if (vpagerdebug & VDB_FOLLOW)
7745749Smckusick 		printf("vnode_pager_init()\n");
7845749Smckusick #endif
7965231Smckusick 	TAILQ_INIT(&vnode_pager_list);
8045749Smckusick }
8145749Smckusick 
8245749Smckusick /*
8345749Smckusick  * Allocate (or lookup) pager for a vnode.
8445749Smckusick  * Handle is a vnode pointer.
8545749Smckusick  */
8653342Sbostic static vm_pager_t
8764827Storek vnode_pager_alloc(handle, size, prot, foff)
8845749Smckusick 	caddr_t handle;
8945749Smckusick 	vm_size_t size;
9045749Smckusick 	vm_prot_t prot;
9164827Storek 	vm_offset_t foff;
9245749Smckusick {
9345749Smckusick 	register vm_pager_t pager;
9445749Smckusick 	register vn_pager_t vnp;
9545749Smckusick 	vm_object_t object;
9645749Smckusick 	struct vattr vattr;
9745749Smckusick 	struct vnode *vp;
9848042Smckusick 	struct proc *p = curproc;	/* XXX */
9945749Smckusick 
10045749Smckusick #ifdef DEBUG
10145749Smckusick 	if (vpagerdebug & (VDB_FOLLOW|VDB_ALLOC))
10245749Smckusick 		printf("vnode_pager_alloc(%x, %x, %x)\n", handle, size, prot);
10345749Smckusick #endif
10445749Smckusick 	/*
10545749Smckusick 	 * Pageout to vnode, no can do yet.
10645749Smckusick 	 */
10745749Smckusick 	if (handle == NULL)
10848397Skarels 		return(NULL);
10945749Smckusick 
11045749Smckusick 	/*
11145749Smckusick 	 * Vnodes keep a pointer to any associated pager so no need to
11245749Smckusick 	 * lookup with vm_pager_lookup.
11345749Smckusick 	 */
11445749Smckusick 	vp = (struct vnode *)handle;
11545749Smckusick 	pager = (vm_pager_t)vp->v_vmdata;
11648397Skarels 	if (pager == NULL) {
11745749Smckusick 		/*
11845749Smckusick 		 * Allocate pager structures
11945749Smckusick 		 */
12045749Smckusick 		pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
12148397Skarels 		if (pager == NULL)
12248397Skarels 			return(NULL);
12345749Smckusick 		vnp = (vn_pager_t)malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
12448397Skarels 		if (vnp == NULL) {
12545749Smckusick 			free((caddr_t)pager, M_VMPAGER);
12648397Skarels 			return(NULL);
12745749Smckusick 		}
12845749Smckusick 		/*
12945749Smckusick 		 * And an object of the appropriate size
13045749Smckusick 		 */
13148042Smckusick 		if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) {
13245749Smckusick 			object = vm_object_allocate(round_page(vattr.va_size));
13345749Smckusick 			vm_object_enter(object, pager);
13445749Smckusick 			vm_object_setpager(object, pager, 0, TRUE);
13545749Smckusick 		} else {
13645749Smckusick 			free((caddr_t)vnp, M_VMPGDATA);
13745749Smckusick 			free((caddr_t)pager, M_VMPAGER);
13848397Skarels 			return(NULL);
13945749Smckusick 		}
14045749Smckusick 		/*
14145749Smckusick 		 * Hold a reference to the vnode and initialize pager data.
14245749Smckusick 		 */
14345749Smckusick 		VREF(vp);
14445749Smckusick 		vnp->vnp_flags = 0;
14545749Smckusick 		vnp->vnp_vp = vp;
14645749Smckusick 		vnp->vnp_size = vattr.va_size;
14765231Smckusick 		TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list);
14845749Smckusick 		pager->pg_handle = handle;
14945749Smckusick 		pager->pg_type = PG_VNODE;
15065695Shibler 		pager->pg_flags = 0;
15145749Smckusick 		pager->pg_ops = &vnodepagerops;
15264858Shibler 		pager->pg_data = vnp;
15345749Smckusick 		vp->v_vmdata = (caddr_t)pager;
15445749Smckusick 	} else {
15545749Smckusick 		/*
15645749Smckusick 		 * vm_object_lookup() will remove the object from the
15745749Smckusick 		 * cache if found and also gain a reference to the object.
15845749Smckusick 		 */
15945749Smckusick 		object = vm_object_lookup(pager);
16047977Skarels #ifdef DEBUG
16145749Smckusick 		vnp = (vn_pager_t)pager->pg_data;
16247977Skarels #endif
16345749Smckusick 	}
16445749Smckusick #ifdef DEBUG
16545749Smckusick 	if (vpagerdebug & VDB_ALLOC)
16645749Smckusick 		printf("vnode_pager_setup: vp %x sz %x pager %x object %x\n",
16745749Smckusick 		       vp, vnp->vnp_size, pager, object);
16845749Smckusick #endif
16945749Smckusick 	return(pager);
17045749Smckusick }
17145749Smckusick 
17253342Sbostic static void
17345749Smckusick vnode_pager_dealloc(pager)
17445749Smckusick 	vm_pager_t pager;
17545749Smckusick {
17645749Smckusick 	register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
17745749Smckusick 	register struct vnode *vp;
17865722Sbostic #ifdef NOTDEF
17948042Smckusick 	struct proc *p = curproc;		/* XXX */
18065722Sbostic #endif
18145749Smckusick 
18245749Smckusick #ifdef DEBUG
18345749Smckusick 	if (vpagerdebug & VDB_FOLLOW)
18445749Smckusick 		printf("vnode_pager_dealloc(%x)\n", pager);
18545749Smckusick #endif
18645749Smckusick 	if (vp = vnp->vnp_vp) {
18745749Smckusick 		vp->v_vmdata = NULL;
18845749Smckusick 		vp->v_flag &= ~VTEXT;
18965722Sbostic #if NOTDEF
19045749Smckusick 		/* can hang if done at reboot on NFS FS */
19148042Smckusick 		(void) VOP_FSYNC(vp, p->p_ucred, p);
19245749Smckusick #endif
19345749Smckusick 		vrele(vp);
19445749Smckusick 	}
19565231Smckusick 	TAILQ_REMOVE(&vnode_pager_list, pager, pg_list);
19645749Smckusick 	free((caddr_t)vnp, M_VMPGDATA);
19745749Smckusick 	free((caddr_t)pager, M_VMPAGER);
19845749Smckusick }
19945749Smckusick 
20053342Sbostic static int
20165695Shibler vnode_pager_getpage(pager, mlist, npages, sync)
20245749Smckusick 	vm_pager_t pager;
20365695Shibler 	vm_page_t *mlist;
20465695Shibler 	int npages;
20545749Smckusick 	boolean_t sync;
20645749Smckusick {
20745749Smckusick 
20845749Smckusick #ifdef DEBUG
20945749Smckusick 	if (vpagerdebug & VDB_FOLLOW)
21065695Shibler 		printf("vnode_pager_getpage(%x, %x, %x, %x)\n",
21165695Shibler 		       pager, mlist, npages, sync);
21245749Smckusick #endif
21365695Shibler 	return(vnode_pager_io((vn_pager_t)pager->pg_data,
21465695Shibler 			      mlist, npages, sync, UIO_READ));
21545749Smckusick }
21645749Smckusick 
21753342Sbostic static boolean_t
21865695Shibler vnode_pager_putpage(pager, mlist, npages, sync)
21945749Smckusick 	vm_pager_t pager;
22065695Shibler 	vm_page_t *mlist;
22165695Shibler 	int npages;
22245749Smckusick 	boolean_t sync;
22345749Smckusick {
22445749Smckusick 	int err;
22545749Smckusick 
22645749Smckusick #ifdef DEBUG
22745749Smckusick 	if (vpagerdebug & VDB_FOLLOW)
22865695Shibler 		printf("vnode_pager_putpage(%x, %x, %x, %x)\n",
22965695Shibler 		       pager, mlist, npages, sync);
23045749Smckusick #endif
23148397Skarels 	if (pager == NULL)
23254818Storek 		return (FALSE);			/* ??? */
23365695Shibler 	err = vnode_pager_io((vn_pager_t)pager->pg_data,
23465695Shibler 			     mlist, npages, sync, UIO_WRITE);
23565695Shibler 	/*
23665695Shibler 	 * If the operation was successful, mark the pages clean.
23765695Shibler 	 */
23845749Smckusick 	if (err == VM_PAGER_OK) {
23965695Shibler 		while (npages--) {
24065695Shibler 			(*mlist)->flags |= PG_CLEAN;
24165695Shibler 			pmap_clear_modify(VM_PAGE_TO_PHYS(*mlist));
24265695Shibler 			mlist++;
24365695Shibler 		}
24445749Smckusick 	}
24545749Smckusick 	return(err);
24645749Smckusick }
24745749Smckusick 
24853342Sbostic static boolean_t
24945749Smckusick vnode_pager_haspage(pager, offset)
25045749Smckusick 	vm_pager_t pager;
25145749Smckusick 	vm_offset_t offset;
25245749Smckusick {
25345749Smckusick 	register vn_pager_t vnp = (vn_pager_t)pager->pg_data;
25445749Smckusick 	daddr_t bn;
25545749Smckusick 	int err;
25645749Smckusick 
25745749Smckusick #ifdef DEBUG
25845749Smckusick 	if (vpagerdebug & VDB_FOLLOW)
25945749Smckusick 		printf("vnode_pager_haspage(%x, %x)\n", pager, offset);
26045749Smckusick #endif
26145749Smckusick 
26245749Smckusick 	/*
26345749Smckusick 	 * Offset beyond end of file, do not have the page
264*66075Shibler 	 * Lock the vnode first to make sure we have the most recent
265*66075Shibler 	 * version of the size.
26645749Smckusick 	 */
267*66075Shibler 	VOP_LOCK(vnp->vnp_vp);
26845749Smckusick 	if (offset >= vnp->vnp_size) {
269*66075Shibler 		VOP_UNLOCK(vnp->vnp_vp);
27045749Smckusick #ifdef DEBUG
27145749Smckusick 		if (vpagerdebug & (VDB_FAIL|VDB_SIZE))
27245749Smckusick 			printf("vnode_pager_haspage: pg %x, off %x, size %x\n",
27345749Smckusick 			       pager, offset, vnp->vnp_size);
27445749Smckusick #endif
27545749Smckusick 		return(FALSE);
27645749Smckusick 	}
27745749Smckusick 
27845749Smckusick 	/*
27945749Smckusick 	 * Read the index to find the disk block to read
28045749Smckusick 	 * from.  If there is no block, report that we don't
28145749Smckusick 	 * have this data.
28245749Smckusick 	 *
28345749Smckusick 	 * Assumes that the vnode has whole page or nothing.
28445749Smckusick 	 */
28545749Smckusick 	err = VOP_BMAP(vnp->vnp_vp,
28651941Smckusick 		       offset / vnp->vnp_vp->v_mount->mnt_stat.f_iosize,
28756457Smargo 		       (struct vnode **)0, &bn, NULL);
28865695Shibler 	VOP_UNLOCK(vnp->vnp_vp);
28945749Smckusick 	if (err) {
29045749Smckusick #ifdef DEBUG
29145749Smckusick 		if (vpagerdebug & VDB_FAIL)
29245749Smckusick 			printf("vnode_pager_haspage: BMAP err %d, pg %x, off %x\n",
29345749Smckusick 			       err, pager, offset);
29445749Smckusick #endif
29545749Smckusick 		return(TRUE);
29645749Smckusick 	}
29745749Smckusick 	return((long)bn < 0 ? FALSE : TRUE);
29845749Smckusick }
29945749Smckusick 
30065695Shibler static void
30165695Shibler vnode_pager_cluster(pager, offset, loffset, hoffset)
30265695Shibler 	vm_pager_t	pager;
30365695Shibler 	vm_offset_t	offset;
30465695Shibler 	vm_offset_t	*loffset;
30565695Shibler 	vm_offset_t	*hoffset;
30665695Shibler {
30765695Shibler 	vn_pager_t vnp = (vn_pager_t)pager->pg_data;
30865695Shibler 	vm_offset_t loff, hoff;
30965695Shibler 
31065695Shibler #ifdef DEBUG
31165695Shibler 	if (vpagerdebug & VDB_FOLLOW)
31265695Shibler 		printf("vnode_pager_cluster(%x, %x) ", pager, offset);
31365695Shibler #endif
31465695Shibler 	loff = offset;
31565695Shibler 	if (loff >= vnp->vnp_size)
31665695Shibler 		panic("vnode_pager_cluster: bad offset");
31765695Shibler 	/*
31865695Shibler 	 * XXX could use VOP_BMAP to get maxcontig value
31965695Shibler 	 */
32065695Shibler 	hoff = loff + MAXBSIZE;
32165695Shibler 	if (hoff > round_page(vnp->vnp_size))
32265695Shibler 		hoff = round_page(vnp->vnp_size);
32365695Shibler 
32465695Shibler 	*loffset = loff;
32565695Shibler 	*hoffset = hoff;
32665695Shibler #ifdef DEBUG
32765695Shibler 	if (vpagerdebug & VDB_FOLLOW)
32865695Shibler 		printf("returns [%x-%x]\n", loff, hoff);
32965695Shibler #endif
33065695Shibler }
33165695Shibler 
33245749Smckusick /*
33345749Smckusick  * (XXX)
33445749Smckusick  * Lets the VM system know about a change in size for a file.
33545749Smckusick  * If this vnode is mapped into some address space (i.e. we have a pager
33645749Smckusick  * for it) we adjust our own internal size and flush any cached pages in
33745749Smckusick  * the associated object that are affected by the size change.
33845749Smckusick  *
33945749Smckusick  * Note: this routine may be invoked as a result of a pager put
34045749Smckusick  * operation (possibly at object termination time), so we must be careful.
34145749Smckusick  */
34253480Smckusick void
34345749Smckusick vnode_pager_setsize(vp, nsize)
34445749Smckusick 	struct vnode *vp;
34545749Smckusick 	u_long nsize;
34645749Smckusick {
34745749Smckusick 	register vn_pager_t vnp;
34845749Smckusick 	register vm_object_t object;
34945749Smckusick 	vm_pager_t pager;
35045749Smckusick 
35145749Smckusick 	/*
35245749Smckusick 	 * Not a mapped vnode
35345749Smckusick 	 */
35445749Smckusick 	if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
35545749Smckusick 		return;
35645749Smckusick 	/*
35745749Smckusick 	 * Hasn't changed size
35845749Smckusick 	 */
35945749Smckusick 	pager = (vm_pager_t)vp->v_vmdata;
36045749Smckusick 	vnp = (vn_pager_t)pager->pg_data;
36145749Smckusick 	if (nsize == vnp->vnp_size)
36245749Smckusick 		return;
36345749Smckusick 	/*
36445749Smckusick 	 * No object.
36545749Smckusick 	 * This can happen during object termination since
36645749Smckusick 	 * vm_object_page_clean is called after the object
36745749Smckusick 	 * has been removed from the hash table, and clean
36845749Smckusick 	 * may cause vnode write operations which can wind
36945749Smckusick 	 * up back here.
37045749Smckusick 	 */
37145749Smckusick 	object = vm_object_lookup(pager);
37248397Skarels 	if (object == NULL)
37345749Smckusick 		return;
37445749Smckusick 
37545749Smckusick #ifdef DEBUG
37645749Smckusick 	if (vpagerdebug & (VDB_FOLLOW|VDB_SIZE))
37745749Smckusick 		printf("vnode_pager_setsize: vp %x obj %x osz %d nsz %d\n",
37845749Smckusick 		       vp, object, vnp->vnp_size, nsize);
37945749Smckusick #endif
38045749Smckusick 	/*
38145749Smckusick 	 * File has shrunk.
38245749Smckusick 	 * Toss any cached pages beyond the new EOF.
38345749Smckusick 	 */
38445749Smckusick 	if (nsize < vnp->vnp_size) {
38545749Smckusick 		vm_object_lock(object);
38645749Smckusick 		vm_object_page_remove(object,
38745749Smckusick 				      (vm_offset_t)nsize, vnp->vnp_size);
38845749Smckusick 		vm_object_unlock(object);
38945749Smckusick 	}
39045749Smckusick 	vnp->vnp_size = (vm_offset_t)nsize;
39145749Smckusick 	vm_object_deallocate(object);
39245749Smckusick }
39345749Smckusick 
39453480Smckusick void
39545749Smckusick vnode_pager_umount(mp)
39645749Smckusick 	register struct mount *mp;
39745749Smckusick {
39845749Smckusick 	register vm_pager_t pager, npager;
39945749Smckusick 	struct vnode *vp;
40045749Smckusick 
40165231Smckusick 	for (pager = vnode_pager_list.tqh_first; pager != NULL; pager = npager){
40245749Smckusick 		/*
40345749Smckusick 		 * Save the next pointer now since uncaching may
40445749Smckusick 		 * terminate the object and render pager invalid
40545749Smckusick 		 */
40665231Smckusick 		npager = pager->pg_list.tqe_next;
40745749Smckusick 		vp = ((vn_pager_t)pager->pg_data)->vnp_vp;
40865695Shibler 		if (mp == (struct mount *)0 || vp->v_mount == mp) {
40965695Shibler 			VOP_LOCK(vp);
41045749Smckusick 			(void) vnode_pager_uncache(vp);
41165695Shibler 			VOP_UNLOCK(vp);
41265695Shibler 		}
41345749Smckusick 	}
41445749Smckusick }
41545749Smckusick 
41645749Smckusick /*
41745749Smckusick  * Remove vnode associated object from the object cache.
41845749Smckusick  *
41965695Shibler  * XXX unlock the vnode if it is currently locked.
42065695Shibler  * We must do this since uncaching the object may result in its
42165695Shibler  * destruction which may initiate paging activity which may necessitate
42265695Shibler  * re-locking the vnode.
42345749Smckusick  */
42453480Smckusick boolean_t
42545749Smckusick vnode_pager_uncache(vp)
42645749Smckusick 	register struct vnode *vp;
42745749Smckusick {
42845749Smckusick 	register vm_object_t object;
42965695Shibler 	boolean_t uncached;
43045749Smckusick 	vm_pager_t pager;
43145749Smckusick 
43245749Smckusick 	/*
43345749Smckusick 	 * Not a mapped vnode
43445749Smckusick 	 */
43545749Smckusick 	pager = (vm_pager_t)vp->v_vmdata;
43648397Skarels 	if (pager == NULL)
43745749Smckusick 		return (TRUE);
43865695Shibler #ifdef DEBUG
43965695Shibler 	if (!VOP_ISLOCKED(vp)) {
44065695Shibler 		extern int (**nfsv2_vnodeop_p)();
44165695Shibler 
44265695Shibler 		if (vp->v_op != nfsv2_vnodeop_p)
44365695Shibler 			panic("vnode_pager_uncache: vnode not locked!");
44465695Shibler 	}
44565695Shibler #endif
44645749Smckusick 	/*
44745749Smckusick 	 * Must use vm_object_lookup() as it actually removes
44845749Smckusick 	 * the object from the cache list.
44945749Smckusick 	 */
45045749Smckusick 	object = vm_object_lookup(pager);
45145749Smckusick 	if (object) {
45245749Smckusick 		uncached = (object->ref_count <= 1);
45365695Shibler 		VOP_UNLOCK(vp);
45445749Smckusick 		pager_cache(object, FALSE);
45565695Shibler 		VOP_LOCK(vp);
45645749Smckusick 	} else
45745749Smckusick 		uncached = TRUE;
45845749Smckusick 	return(uncached);
45945749Smckusick }
46045749Smckusick 
46153342Sbostic static int
46265695Shibler vnode_pager_io(vnp, mlist, npages, sync, rw)
46345749Smckusick 	register vn_pager_t vnp;
46465695Shibler 	vm_page_t *mlist;
46565695Shibler 	int npages;
46665695Shibler 	boolean_t sync;
46745749Smckusick 	enum uio_rw rw;
46845749Smckusick {
46945749Smckusick 	struct uio auio;
47045749Smckusick 	struct iovec aiov;
47145749Smckusick 	vm_offset_t kva, foff;
47245749Smckusick 	int error, size;
47348042Smckusick 	struct proc *p = curproc;		/* XXX */
47445749Smckusick 
47565695Shibler 	/* XXX */
47665695Shibler 	vm_page_t m;
47765695Shibler 	if (npages != 1)
47865695Shibler 		panic("vnode_pager_io: cannot handle multiple pages");
47965695Shibler 	m = *mlist;
48065695Shibler 	/* XXX */
48165695Shibler 
48245749Smckusick #ifdef DEBUG
48345749Smckusick 	if (vpagerdebug & VDB_FOLLOW)
48445749Smckusick 		printf("vnode_pager_io(%x, %x, %c): vnode %x\n",
48545749Smckusick 		       vnp, m, rw == UIO_READ ? 'R' : 'W', vnp->vnp_vp);
48645749Smckusick #endif
48745749Smckusick 	foff = m->offset + m->object->paging_offset;
48845749Smckusick 	/*
489*66075Shibler 	 * Allocate a kernel virtual address and initialize so that
490*66075Shibler 	 * we can use VOP_READ/WRITE routines.
49145749Smckusick 	 */
492*66075Shibler 	kva = vm_pager_map_pages(mlist, npages, sync);
493*66075Shibler 	if (kva == NULL)
494*66075Shibler 		return(VM_PAGER_AGAIN);
495*66075Shibler 	/*
496*66075Shibler 	 * After all of the potentially blocking operations have been
497*66075Shibler 	 * performed, we can do the size checks:
498*66075Shibler 	 *	read beyond EOF (returns error)
499*66075Shibler 	 *	short read
500*66075Shibler 	 */
501*66075Shibler 	VOP_LOCK(vnp->vnp_vp);
50245749Smckusick 	if (foff >= vnp->vnp_size) {
503*66075Shibler 		VOP_UNLOCK(vnp->vnp_vp);
504*66075Shibler 		vm_pager_unmap_pages(kva, npages);
50545749Smckusick #ifdef DEBUG
50645749Smckusick 		if (vpagerdebug & VDB_SIZE)
50745749Smckusick 			printf("vnode_pager_io: vp %x, off %d size %d\n",
50845749Smckusick 			       vnp->vnp_vp, foff, vnp->vnp_size);
50945749Smckusick #endif
51045749Smckusick 		return(VM_PAGER_BAD);
51145749Smckusick 	}
51245749Smckusick 	if (foff + PAGE_SIZE > vnp->vnp_size)
51345749Smckusick 		size = vnp->vnp_size - foff;
51445749Smckusick 	else
51545749Smckusick 		size = PAGE_SIZE;
51645749Smckusick 	aiov.iov_base = (caddr_t)kva;
51745749Smckusick 	aiov.iov_len = size;
51845749Smckusick 	auio.uio_iov = &aiov;
51945749Smckusick 	auio.uio_iovcnt = 1;
52045749Smckusick 	auio.uio_offset = foff;
52145749Smckusick 	auio.uio_segflg = UIO_SYSSPACE;
52245749Smckusick 	auio.uio_rw = rw;
52345749Smckusick 	auio.uio_resid = size;
52448042Smckusick 	auio.uio_procp = (struct proc *)0;
52545749Smckusick #ifdef DEBUG
52645749Smckusick 	if (vpagerdebug & VDB_IO)
52745749Smckusick 		printf("vnode_pager_io: vp %x kva %x foff %x size %x",
52845749Smckusick 		       vnp->vnp_vp, kva, foff, size);
52945749Smckusick #endif
53045749Smckusick 	if (rw == UIO_READ)
53148042Smckusick 		error = VOP_READ(vnp->vnp_vp, &auio, 0, p->p_ucred);
53245749Smckusick 	else
53348042Smckusick 		error = VOP_WRITE(vnp->vnp_vp, &auio, 0, p->p_ucred);
53465695Shibler 	VOP_UNLOCK(vnp->vnp_vp);
53545749Smckusick #ifdef DEBUG
53645749Smckusick 	if (vpagerdebug & VDB_IO) {
53745749Smckusick 		if (error || auio.uio_resid)
53845749Smckusick 			printf(" returns error %x, resid %x",
53945749Smckusick 			       error, auio.uio_resid);
54045749Smckusick 		printf("\n");
54145749Smckusick 	}
54245749Smckusick #endif
54345749Smckusick 	if (!error) {
54445749Smckusick 		register int count = size - auio.uio_resid;
54545749Smckusick 
54645749Smckusick 		if (count == 0)
54745749Smckusick 			error = EINVAL;
54845749Smckusick 		else if (count != PAGE_SIZE && rw == UIO_READ)
54953342Sbostic 			bzero((void *)(kva + count), PAGE_SIZE - count);
55045749Smckusick 	}
55165695Shibler 	vm_pager_unmap_pages(kva, npages);
55256321Shibler 	return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
55345749Smckusick }
554