xref: /freebsd/sys/vm/vnode_pager.c (revision 06cb7259518269e4c6534171e8ac05aedad2e5e8)
1df8bae1dSRodney W. Grimes /*
2df8bae1dSRodney W. Grimes  * Copyright (c) 1990 University of Utah.
326f9a767SRodney W. Grimes  * Copyright (c) 1991 The Regents of the University of California.
426f9a767SRodney W. Grimes  * All rights reserved.
526f9a767SRodney W. Grimes  * Copyright (c) 1993,1994 John S. Dyson
6df8bae1dSRodney W. Grimes  *
7df8bae1dSRodney W. Grimes  * This code is derived from software contributed to Berkeley by
8df8bae1dSRodney W. Grimes  * the Systems Programming Group of the University of Utah Computer
9df8bae1dSRodney W. Grimes  * Science Department.
10df8bae1dSRodney W. Grimes  *
11df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
12df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
13df8bae1dSRodney W. Grimes  * are met:
14df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
15df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
16df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
17df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
18df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
19df8bae1dSRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
20df8bae1dSRodney W. Grimes  *    must display the following acknowledgement:
21df8bae1dSRodney W. Grimes  *	This product includes software developed by the University of
22df8bae1dSRodney W. Grimes  *	California, Berkeley and its contributors.
23df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
24df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
25df8bae1dSRodney W. Grimes  *    without specific prior written permission.
26df8bae1dSRodney W. Grimes  *
27df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
38df8bae1dSRodney W. Grimes  *
3926f9a767SRodney W. Grimes  *	from: @(#)vnode_pager.c	7.5 (Berkeley) 4/20/91
4006cb7259SDavid Greenman  *	$Id: vnode_pager.c,v 1.42 1995/07/06 11:48:48 davidg Exp $
41df8bae1dSRodney W. Grimes  */
42df8bae1dSRodney W. Grimes 
43df8bae1dSRodney W. Grimes /*
44df8bae1dSRodney W. Grimes  * Page to/from files (vnodes).
45df8bae1dSRodney W. Grimes  *
46df8bae1dSRodney W. Grimes  * TODO:
47df8bae1dSRodney W. Grimes  *	pageouts
48df8bae1dSRodney W. Grimes  *	fix credential use (uses current process credentials now)
49df8bae1dSRodney W. Grimes  */
50df8bae1dSRodney W. Grimes 
5126f9a767SRodney W. Grimes /*
52f6b04d2bSDavid Greenman  * 1) Supports multiple - block reads/writes
5326f9a767SRodney W. Grimes  * 2) Bypasses buffer cache for reads
5426f9a767SRodney W. Grimes  *
5526f9a767SRodney W. Grimes  * TODO:
56f6b04d2bSDavid Greenman  *	Implement getpage/putpage interface for filesystems.  Should
57f6b04d2bSDavid Greenman  *	greatly re-simplify the vnode_pager.
5826f9a767SRodney W. Grimes  *
5926f9a767SRodney W. Grimes  */
6026f9a767SRodney W. Grimes 
61df8bae1dSRodney W. Grimes #include <sys/param.h>
62df8bae1dSRodney W. Grimes #include <sys/systm.h>
630d94caffSDavid Greenman #include <sys/kernel.h>
64df8bae1dSRodney W. Grimes #include <sys/proc.h>
65df8bae1dSRodney W. Grimes #include <sys/malloc.h>
66df8bae1dSRodney W. Grimes #include <sys/vnode.h>
67df8bae1dSRodney W. Grimes #include <sys/uio.h>
68df8bae1dSRodney W. Grimes #include <sys/mount.h>
69df8bae1dSRodney W. Grimes 
70df8bae1dSRodney W. Grimes #include <vm/vm.h>
71df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
72df8bae1dSRodney W. Grimes #include <vm/vnode_pager.h>
73df8bae1dSRodney W. Grimes 
7426f9a767SRodney W. Grimes #include <sys/buf.h>
7526f9a767SRodney W. Grimes #include <miscfs/specfs/specdev.h>
76df8bae1dSRodney W. Grimes 
7726f9a767SRodney W. Grimes int vnode_pager_putmulti();
78df8bae1dSRodney W. Grimes 
7926f9a767SRodney W. Grimes void vnode_pager_init();
8026f9a767SRodney W. Grimes void vnode_pager_dealloc();
8126f9a767SRodney W. Grimes int vnode_pager_getpage();
8226f9a767SRodney W. Grimes int vnode_pager_getmulti();
8326f9a767SRodney W. Grimes int vnode_pager_putpage();
8426f9a767SRodney W. Grimes boolean_t vnode_pager_haspage();
85df8bae1dSRodney W. Grimes 
86df8bae1dSRodney W. Grimes struct pagerops vnodepagerops = {
87df8bae1dSRodney W. Grimes 	vnode_pager_init,
88df8bae1dSRodney W. Grimes 	vnode_pager_alloc,
89df8bae1dSRodney W. Grimes 	vnode_pager_dealloc,
90df8bae1dSRodney W. Grimes 	vnode_pager_getpage,
9126f9a767SRodney W. Grimes 	vnode_pager_getmulti,
92df8bae1dSRodney W. Grimes 	vnode_pager_putpage,
9326f9a767SRodney W. Grimes 	vnode_pager_putmulti,
9426f9a767SRodney W. Grimes 	vnode_pager_haspage
95df8bae1dSRodney W. Grimes };
96df8bae1dSRodney W. Grimes 
9716f62314SDavid Greenman 
9816f62314SDavid Greenman 
9926f9a767SRodney W. Grimes static int vnode_pager_input(vn_pager_t vnp, vm_page_t * m, int count, int reqpage);
10026f9a767SRodney W. Grimes static int vnode_pager_output(vn_pager_t vnp, vm_page_t * m, int count, int *rtvals);
10126f9a767SRodney W. Grimes 
10226f9a767SRodney W. Grimes extern vm_map_t pager_map;
10326f9a767SRodney W. Grimes 
10426f9a767SRodney W. Grimes struct pagerlst vnode_pager_list;	/* list of managed vnodes */
10526f9a767SRodney W. Grimes 
10626f9a767SRodney W. Grimes #define MAXBP (PAGE_SIZE/DEV_BSIZE);
10726f9a767SRodney W. Grimes 
10826f9a767SRodney W. Grimes void
109df8bae1dSRodney W. Grimes vnode_pager_init()
110df8bae1dSRodney W. Grimes {
111df8bae1dSRodney W. Grimes 	TAILQ_INIT(&vnode_pager_list);
112df8bae1dSRodney W. Grimes }
113df8bae1dSRodney W. Grimes 
114df8bae1dSRodney W. Grimes /*
115df8bae1dSRodney W. Grimes  * Allocate (or lookup) pager for a vnode.
116df8bae1dSRodney W. Grimes  * Handle is a vnode pointer.
117df8bae1dSRodney W. Grimes  */
11826f9a767SRodney W. Grimes vm_pager_t
11926f9a767SRodney W. Grimes vnode_pager_alloc(handle, size, prot, offset)
120ee3a64c9SDavid Greenman 	void *handle;
121df8bae1dSRodney W. Grimes 	vm_size_t size;
122df8bae1dSRodney W. Grimes 	vm_prot_t prot;
12326f9a767SRodney W. Grimes 	vm_offset_t offset;
124df8bae1dSRodney W. Grimes {
125df8bae1dSRodney W. Grimes 	register vm_pager_t pager;
126df8bae1dSRodney W. Grimes 	register vn_pager_t vnp;
12706cb7259SDavid Greenman 	vm_object_t object;
128df8bae1dSRodney W. Grimes 	struct vnode *vp;
129df8bae1dSRodney W. Grimes 
130df8bae1dSRodney W. Grimes 	/*
131df8bae1dSRodney W. Grimes 	 * Pageout to vnode, no can do yet.
132df8bae1dSRodney W. Grimes 	 */
133df8bae1dSRodney W. Grimes 	if (handle == NULL)
134df8bae1dSRodney W. Grimes 		return (NULL);
135df8bae1dSRodney W. Grimes 
136df8bae1dSRodney W. Grimes 	vp = (struct vnode *) handle;
13739d38f93SDavid Greenman 
13839d38f93SDavid Greenman 	/*
13939d38f93SDavid Greenman 	 * Prevent race condition when allocating the object. This
14039d38f93SDavid Greenman 	 * can happen with NFS vnodes since the nfsnode isn't locked.
14139d38f93SDavid Greenman 	 */
14239d38f93SDavid Greenman 	while (vp->v_flag & VOLOCK) {
14339d38f93SDavid Greenman 		vp->v_flag |= VOWANT;
14439d38f93SDavid Greenman 		tsleep(vp, PVM, "vnpobj", 0);
14539d38f93SDavid Greenman 	}
14639d38f93SDavid Greenman 	vp->v_flag |= VOLOCK;
14739d38f93SDavid Greenman 
14839d38f93SDavid Greenman 	/*
14939d38f93SDavid Greenman 	 * If the object is being terminated, wait for it to
15039d38f93SDavid Greenman 	 * go away.
15139d38f93SDavid Greenman 	 */
15239d38f93SDavid Greenman 	while (((object = vp->v_object) != NULL) && (object->flags & OBJ_DEAD))
153aa2cabb9SDavid Greenman 		tsleep(object, PVM, "vadead", 0);
1540d94caffSDavid Greenman 
1558e58bf68SDavid Greenman 	pager = NULL;
1568e58bf68SDavid Greenman 	if (object != NULL)
1578e58bf68SDavid Greenman 		pager = object->pager;
158df8bae1dSRodney W. Grimes 	if (pager == NULL) {
159bbc0ec52SDavid Greenman 
160df8bae1dSRodney W. Grimes 		/*
161df8bae1dSRodney W. Grimes 		 * Allocate pager structures
162df8bae1dSRodney W. Grimes 		 */
163df8bae1dSRodney W. Grimes 		pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
164df8bae1dSRodney W. Grimes 		vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
16539d38f93SDavid Greenman 
166df8bae1dSRodney W. Grimes 		/*
167df8bae1dSRodney W. Grimes 		 * And an object of the appropriate size
168df8bae1dSRodney W. Grimes 		 */
16906cb7259SDavid Greenman 		object = vm_object_allocate(round_page(size));
1704bb62461SDavid Greenman 		object->flags = OBJ_CANPERSIST;
171df8bae1dSRodney W. Grimes 		vm_object_enter(object, pager);
1727fb0c17eSDavid Greenman 		object->pager = pager;
173bbc0ec52SDavid Greenman 
174df8bae1dSRodney W. Grimes 		/*
175df8bae1dSRodney W. Grimes 		 * Hold a reference to the vnode and initialize pager data.
176df8bae1dSRodney W. Grimes 		 */
177df8bae1dSRodney W. Grimes 		VREF(vp);
178df8bae1dSRodney W. Grimes 		vnp->vnp_flags = 0;
179df8bae1dSRodney W. Grimes 		vnp->vnp_vp = vp;
18006cb7259SDavid Greenman 		vnp->vnp_size = size;
18126f9a767SRodney W. Grimes 
182df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list);
183df8bae1dSRodney W. Grimes 		pager->pg_handle = handle;
184df8bae1dSRodney W. Grimes 		pager->pg_type = PG_VNODE;
185df8bae1dSRodney W. Grimes 		pager->pg_ops = &vnodepagerops;
18626f9a767SRodney W. Grimes 		pager->pg_data = (caddr_t) vnp;
187aa2cabb9SDavid Greenman 		vp->v_object = (caddr_t) object;
188df8bae1dSRodney W. Grimes 	} else {
189bbc0ec52SDavid Greenman 
190df8bae1dSRodney W. Grimes 		/*
191bbc0ec52SDavid Greenman 		 * vm_object_lookup() will remove the object from the cache if
192bbc0ec52SDavid Greenman 		 * found and also gain a reference to the object.
193df8bae1dSRodney W. Grimes 		 */
1948e58bf68SDavid Greenman 		(void) vm_object_lookup(pager);
195df8bae1dSRodney W. Grimes 	}
19639d38f93SDavid Greenman 
197f6b04d2bSDavid Greenman 	if (vp->v_type == VREG)
198f6b04d2bSDavid Greenman 		vp->v_flag |= VVMIO;
19939d38f93SDavid Greenman 
20039d38f93SDavid Greenman 	vp->v_flag &= ~VOLOCK;
20139d38f93SDavid Greenman 	if (vp->v_flag & VOWANT) {
20239d38f93SDavid Greenman 		vp->v_flag &= ~VOWANT;
20339d38f93SDavid Greenman 		wakeup(vp);
20439d38f93SDavid Greenman 	}
205df8bae1dSRodney W. Grimes 	return (pager);
206df8bae1dSRodney W. Grimes }
207df8bae1dSRodney W. Grimes 
20826f9a767SRodney W. Grimes void
209df8bae1dSRodney W. Grimes vnode_pager_dealloc(pager)
210df8bae1dSRodney W. Grimes 	vm_pager_t pager;
211df8bae1dSRodney W. Grimes {
212df8bae1dSRodney W. Grimes 	register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
213df8bae1dSRodney W. Grimes 	register struct vnode *vp;
2140d94caffSDavid Greenman 	vm_object_t object;
215df8bae1dSRodney W. Grimes 
21605f0fdd2SPoul-Henning Kamp 	vp = vnp->vnp_vp;
21705f0fdd2SPoul-Henning Kamp 	if (vp) {
2180d94caffSDavid Greenman 		int s = splbio();
2190d94caffSDavid Greenman 
220aa2cabb9SDavid Greenman 		object = vp->v_object;
2210d94caffSDavid Greenman 		if (object) {
2220d94caffSDavid Greenman 			while (object->paging_in_progress) {
223c0503609SDavid Greenman 				object->flags |= OBJ_PIPWNT;
2240d94caffSDavid Greenman 				tsleep(object, PVM, "vnpdea", 0);
2250d94caffSDavid Greenman 			}
2260d94caffSDavid Greenman 		}
2270d94caffSDavid Greenman 		splx(s);
2280d94caffSDavid Greenman 
229aa2cabb9SDavid Greenman 		vp->v_object = NULL;
2308e58bf68SDavid Greenman 		vp->v_flag &= ~(VTEXT | VVMIO);
23100072442SDavid Greenman 		vp->v_flag |= VAGE;
232df8bae1dSRodney W. Grimes 		vrele(vp);
233df8bae1dSRodney W. Grimes 	}
234df8bae1dSRodney W. Grimes 	TAILQ_REMOVE(&vnode_pager_list, pager, pg_list);
235df8bae1dSRodney W. Grimes 	free((caddr_t) vnp, M_VMPGDATA);
236df8bae1dSRodney W. Grimes 	free((caddr_t) pager, M_VMPAGER);
237df8bae1dSRodney W. Grimes }
238df8bae1dSRodney W. Grimes 
23926f9a767SRodney W. Grimes int
24026f9a767SRodney W. Grimes vnode_pager_getmulti(pager, m, count, reqpage, sync)
241df8bae1dSRodney W. Grimes 	vm_pager_t pager;
24226f9a767SRodney W. Grimes 	vm_page_t *m;
24326f9a767SRodney W. Grimes 	int count;
24426f9a767SRodney W. Grimes 	int reqpage;
245df8bae1dSRodney W. Grimes 	boolean_t sync;
246df8bae1dSRodney W. Grimes {
247df8bae1dSRodney W. Grimes 
24826f9a767SRodney W. Grimes 	return vnode_pager_input((vn_pager_t) pager->pg_data, m, count, reqpage);
249df8bae1dSRodney W. Grimes }
250df8bae1dSRodney W. Grimes 
25126f9a767SRodney W. Grimes int
25226f9a767SRodney W. Grimes vnode_pager_getpage(pager, m, sync)
253df8bae1dSRodney W. Grimes 	vm_pager_t pager;
25426f9a767SRodney W. Grimes 	vm_page_t m;
25526f9a767SRodney W. Grimes 	boolean_t sync;
25626f9a767SRodney W. Grimes {
25726f9a767SRodney W. Grimes 
25826f9a767SRodney W. Grimes 	vm_page_t marray[1];
259bbc0ec52SDavid Greenman 
26026f9a767SRodney W. Grimes 	if (pager == NULL)
26126f9a767SRodney W. Grimes 		return FALSE;
26226f9a767SRodney W. Grimes 	marray[0] = m;
26326f9a767SRodney W. Grimes 
26426f9a767SRodney W. Grimes 	return vnode_pager_input((vn_pager_t) pager->pg_data, marray, 1, 0);
26526f9a767SRodney W. Grimes }
26626f9a767SRodney W. Grimes 
26726f9a767SRodney W. Grimes boolean_t
26826f9a767SRodney W. Grimes vnode_pager_putpage(pager, m, sync)
26926f9a767SRodney W. Grimes 	vm_pager_t pager;
27026f9a767SRodney W. Grimes 	vm_page_t m;
271df8bae1dSRodney W. Grimes 	boolean_t sync;
272df8bae1dSRodney W. Grimes {
27326f9a767SRodney W. Grimes 	vm_page_t marray[1];
27426f9a767SRodney W. Grimes 	int rtvals[1];
275df8bae1dSRodney W. Grimes 
276df8bae1dSRodney W. Grimes 	if (pager == NULL)
27726f9a767SRodney W. Grimes 		return FALSE;
27826f9a767SRodney W. Grimes 	marray[0] = m;
27926f9a767SRodney W. Grimes 	vnode_pager_output((vn_pager_t) pager->pg_data, marray, 1, rtvals);
28026f9a767SRodney W. Grimes 	return rtvals[0];
281df8bae1dSRodney W. Grimes }
282df8bae1dSRodney W. Grimes 
28326f9a767SRodney W. Grimes int
28426f9a767SRodney W. Grimes vnode_pager_putmulti(pager, m, c, sync, rtvals)
28526f9a767SRodney W. Grimes 	vm_pager_t pager;
28626f9a767SRodney W. Grimes 	vm_page_t *m;
28726f9a767SRodney W. Grimes 	int c;
28826f9a767SRodney W. Grimes 	boolean_t sync;
28926f9a767SRodney W. Grimes 	int *rtvals;
29026f9a767SRodney W. Grimes {
29126f9a767SRodney W. Grimes 	return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals);
29226f9a767SRodney W. Grimes }
29326f9a767SRodney W. Grimes 
29426f9a767SRodney W. Grimes 
29526f9a767SRodney W. Grimes boolean_t
296df8bae1dSRodney W. Grimes vnode_pager_haspage(pager, offset)
297df8bae1dSRodney W. Grimes 	vm_pager_t pager;
298df8bae1dSRodney W. Grimes 	vm_offset_t offset;
299df8bae1dSRodney W. Grimes {
300df8bae1dSRodney W. Grimes 	register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
3014abc71c0SDavid Greenman 	register struct vnode *vp = vnp->vnp_vp;
302df8bae1dSRodney W. Grimes 	daddr_t bn;
303df8bae1dSRodney W. Grimes 	int err;
304317205caSDavid Greenman 	daddr_t block;
305df8bae1dSRodney W. Grimes 
306df8bae1dSRodney W. Grimes 	/*
3070d94caffSDavid Greenman 	 * If filesystem no longer mounted or offset beyond end of file we do
3080d94caffSDavid Greenman 	 * not have the page.
309df8bae1dSRodney W. Grimes 	 */
3104abc71c0SDavid Greenman 	if ((vp->v_mount == NULL) || (offset >= vnp->vnp_size))
3114abc71c0SDavid Greenman 		return FALSE;
312df8bae1dSRodney W. Grimes 
3134abc71c0SDavid Greenman 	block = offset / vp->v_mount->mnt_stat.f_iosize;
3144abc71c0SDavid Greenman 	if (incore(vp, block))
315317205caSDavid Greenman 		return TRUE;
3160bdb7528SDavid Greenman 
317df8bae1dSRodney W. Grimes 	/*
318bbc0ec52SDavid Greenman 	 * Read the index to find the disk block to read from.  If there is no
319bbc0ec52SDavid Greenman 	 * block, report that we don't have this data.
320df8bae1dSRodney W. Grimes 	 *
321df8bae1dSRodney W. Grimes 	 * Assumes that the vnode has whole page or nothing.
322df8bae1dSRodney W. Grimes 	 */
3234abc71c0SDavid Greenman 	err = VOP_BMAP(vp, block, (struct vnode **) 0, &bn, 0);
3240d94caffSDavid Greenman 	if (err)
325df8bae1dSRodney W. Grimes 		return (TRUE);
326df8bae1dSRodney W. Grimes 	return ((long) bn < 0 ? FALSE : TRUE);
327df8bae1dSRodney W. Grimes }
328df8bae1dSRodney W. Grimes 
329df8bae1dSRodney W. Grimes /*
330df8bae1dSRodney W. Grimes  * Lets the VM system know about a change in size for a file.
331df8bae1dSRodney W. Grimes  * If this vnode is mapped into some address space (i.e. we have a pager
332df8bae1dSRodney W. Grimes  * for it) we adjust our own internal size and flush any cached pages in
333df8bae1dSRodney W. Grimes  * the associated object that are affected by the size change.
334df8bae1dSRodney W. Grimes  *
335df8bae1dSRodney W. Grimes  * Note: this routine may be invoked as a result of a pager put
336df8bae1dSRodney W. Grimes  * operation (possibly at object termination time), so we must be careful.
337df8bae1dSRodney W. Grimes  */
338df8bae1dSRodney W. Grimes void
339df8bae1dSRodney W. Grimes vnode_pager_setsize(vp, nsize)
340df8bae1dSRodney W. Grimes 	struct vnode *vp;
341df8bae1dSRodney W. Grimes 	u_long nsize;
342df8bae1dSRodney W. Grimes {
343df8bae1dSRodney W. Grimes 	register vn_pager_t vnp;
344df8bae1dSRodney W. Grimes 	register vm_object_t object;
345df8bae1dSRodney W. Grimes 	vm_pager_t pager;
346df8bae1dSRodney W. Grimes 
347df8bae1dSRodney W. Grimes 	/*
348df8bae1dSRodney W. Grimes 	 * Not a mapped vnode
349df8bae1dSRodney W. Grimes 	 */
350aa2cabb9SDavid Greenman 	if (vp == NULL || vp->v_type != VREG || vp->v_object == NULL)
351df8bae1dSRodney W. Grimes 		return;
352bbc0ec52SDavid Greenman 
353df8bae1dSRodney W. Grimes 	/*
354df8bae1dSRodney W. Grimes 	 * Hasn't changed size
355df8bae1dSRodney W. Grimes 	 */
356aa2cabb9SDavid Greenman 	object = vp->v_object;
3578e58bf68SDavid Greenman 	if (object == NULL)
3588e58bf68SDavid Greenman 		return;
3598e58bf68SDavid Greenman 	if ((pager = object->pager) == NULL)
3608e58bf68SDavid Greenman 		return;
361df8bae1dSRodney W. Grimes 	vnp = (vn_pager_t) pager->pg_data;
362df8bae1dSRodney W. Grimes 	if (nsize == vnp->vnp_size)
363df8bae1dSRodney W. Grimes 		return;
364bbc0ec52SDavid Greenman 
365df8bae1dSRodney W. Grimes 	/*
366bbc0ec52SDavid Greenman 	 * File has shrunk. Toss any cached pages beyond the new EOF.
367df8bae1dSRodney W. Grimes 	 */
368bbc0ec52SDavid Greenman 	if (nsize < vnp->vnp_size) {
3690d94caffSDavid Greenman 		if (round_page((vm_offset_t) nsize) < vnp->vnp_size) {
370df8bae1dSRodney W. Grimes 			vm_object_lock(object);
371df8bae1dSRodney W. Grimes 			vm_object_page_remove(object,
3727c1f6cedSDavid Greenman 			    round_page((vm_offset_t) nsize), vnp->vnp_size, FALSE);
373bbc0ec52SDavid Greenman 			vm_object_unlock(object);
3740d94caffSDavid Greenman 		}
375bbc0ec52SDavid Greenman 		/*
376bbc0ec52SDavid Greenman 		 * this gets rid of garbage at the end of a page that is now
377bbc0ec52SDavid Greenman 		 * only partially backed by the vnode...
378bbc0ec52SDavid Greenman 		 */
379bbc0ec52SDavid Greenman 		if (nsize & PAGE_MASK) {
380bbc0ec52SDavid Greenman 			vm_offset_t kva;
381bbc0ec52SDavid Greenman 			vm_page_t m;
382bbc0ec52SDavid Greenman 
383bbc0ec52SDavid Greenman 			m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize));
384bbc0ec52SDavid Greenman 			if (m) {
385bbc0ec52SDavid Greenman 				kva = vm_pager_map_page(m);
386bbc0ec52SDavid Greenman 				bzero((caddr_t) kva + (nsize & PAGE_MASK),
387bbc0ec52SDavid Greenman 				    round_page(nsize) - nsize);
388bbc0ec52SDavid Greenman 				vm_pager_unmap_page(kva);
389bbc0ec52SDavid Greenman 			}
390bbc0ec52SDavid Greenman 		}
391bbc0ec52SDavid Greenman 	}
392df8bae1dSRodney W. Grimes 	vnp->vnp_size = (vm_offset_t) nsize;
393bbc0ec52SDavid Greenman 	object->size = round_page(nsize);
394df8bae1dSRodney W. Grimes }
395df8bae1dSRodney W. Grimes 
396df8bae1dSRodney W. Grimes void
397df8bae1dSRodney W. Grimes vnode_pager_umount(mp)
398df8bae1dSRodney W. Grimes 	register struct mount *mp;
399df8bae1dSRodney W. Grimes {
400df8bae1dSRodney W. Grimes 	register vm_pager_t pager, npager;
401df8bae1dSRodney W. Grimes 	struct vnode *vp;
402df8bae1dSRodney W. Grimes 
403c01a9b8cSDavid Greenman 	for (pager = vnode_pager_list.tqh_first; pager != NULL; pager = npager) {
404df8bae1dSRodney W. Grimes 		/*
405bbc0ec52SDavid Greenman 		 * Save the next pointer now since uncaching may terminate the
406bbc0ec52SDavid Greenman 		 * object and render pager invalid
407df8bae1dSRodney W. Grimes 		 */
40826f9a767SRodney W. Grimes 		npager = pager->pg_list.tqe_next;
409c01a9b8cSDavid Greenman 		vp = ((vn_pager_t) pager->pg_data)->vnp_vp;
410c01a9b8cSDavid Greenman 		if (mp == (struct mount *) 0 || vp->v_mount == mp) {
411c01a9b8cSDavid Greenman 			VOP_LOCK(vp);
412df8bae1dSRodney W. Grimes 			(void) vnode_pager_uncache(vp);
413c01a9b8cSDavid Greenman 			VOP_UNLOCK(vp);
414c01a9b8cSDavid Greenman 		}
415df8bae1dSRodney W. Grimes 	}
416df8bae1dSRodney W. Grimes }
417df8bae1dSRodney W. Grimes 
418df8bae1dSRodney W. Grimes /*
419df8bae1dSRodney W. Grimes  * Remove vnode associated object from the object cache.
420c01a9b8cSDavid Greenman  * This routine must be called with the vnode locked.
421df8bae1dSRodney W. Grimes  *
422c01a9b8cSDavid Greenman  * XXX unlock the vnode.
423c01a9b8cSDavid Greenman  * We must do this since uncaching the object may result in its
424c01a9b8cSDavid Greenman  * destruction which may initiate paging activity which may necessitate
425c01a9b8cSDavid Greenman  * re-locking the vnode.
42626f9a767SRodney W. Grimes  */
42726f9a767SRodney W. Grimes boolean_t
42826f9a767SRodney W. Grimes vnode_pager_uncache(vp)
42926f9a767SRodney W. Grimes 	register struct vnode *vp;
43026f9a767SRodney W. Grimes {
43126f9a767SRodney W. Grimes 	register vm_object_t object;
432c01a9b8cSDavid Greenman 	boolean_t uncached;
43326f9a767SRodney W. Grimes 	vm_pager_t pager;
43426f9a767SRodney W. Grimes 
43526f9a767SRodney W. Grimes 	/*
43626f9a767SRodney W. Grimes 	 * Not a mapped vnode
43726f9a767SRodney W. Grimes 	 */
438aa2cabb9SDavid Greenman 	object = vp->v_object;
4398e58bf68SDavid Greenman 	if (object == NULL)
4408e58bf68SDavid Greenman 		return (TRUE);
4410d94caffSDavid Greenman 
4428e58bf68SDavid Greenman 	pager = object->pager;
44326f9a767SRodney W. Grimes 	if (pager == NULL)
44426f9a767SRodney W. Grimes 		return (TRUE);
445bbc0ec52SDavid Greenman 
446c01a9b8cSDavid Greenman #ifdef DEBUG
447c01a9b8cSDavid Greenman 	if (!VOP_ISLOCKED(vp)) {
448c01a9b8cSDavid Greenman 		extern int (**nfsv2_vnodeop_p)();
449bbc0ec52SDavid Greenman 
450c01a9b8cSDavid Greenman 		if (vp->v_op != nfsv2_vnodeop_p)
451c01a9b8cSDavid Greenman 			panic("vnode_pager_uncache: vnode not locked!");
452c01a9b8cSDavid Greenman 	}
453c01a9b8cSDavid Greenman #endif
45426f9a767SRodney W. Grimes 	/*
455bbc0ec52SDavid Greenman 	 * Must use vm_object_lookup() as it actually removes the object from
456bbc0ec52SDavid Greenman 	 * the cache list.
45726f9a767SRodney W. Grimes 	 */
45826f9a767SRodney W. Grimes 	object = vm_object_lookup(pager);
45926f9a767SRodney W. Grimes 	if (object) {
46026f9a767SRodney W. Grimes 		uncached = (object->ref_count <= 1);
461c01a9b8cSDavid Greenman 		VOP_UNLOCK(vp);
46226f9a767SRodney W. Grimes 		pager_cache(object, FALSE);
463c01a9b8cSDavid Greenman 		VOP_LOCK(vp);
46426f9a767SRodney W. Grimes 	} else
46526f9a767SRodney W. Grimes 		uncached = TRUE;
46626f9a767SRodney W. Grimes 	return (uncached);
46726f9a767SRodney W. Grimes }
468df8bae1dSRodney W. Grimes 
46926f9a767SRodney W. Grimes 
47026f9a767SRodney W. Grimes void
47126f9a767SRodney W. Grimes vnode_pager_freepage(m)
47226f9a767SRodney W. Grimes 	vm_page_t m;
473df8bae1dSRodney W. Grimes {
47426f9a767SRodney W. Grimes 	PAGE_WAKEUP(m);
47526f9a767SRodney W. Grimes 	vm_page_free(m);
47626f9a767SRodney W. Grimes }
47726f9a767SRodney W. Grimes 
47826f9a767SRodney W. Grimes /*
47926f9a767SRodney W. Grimes  * calculate the linear (byte) disk address of specified virtual
48026f9a767SRodney W. Grimes  * file address
48126f9a767SRodney W. Grimes  */
48226f9a767SRodney W. Grimes vm_offset_t
483efc68ce1SDavid Greenman vnode_pager_addr(vp, address, run)
48426f9a767SRodney W. Grimes 	struct vnode *vp;
48526f9a767SRodney W. Grimes 	vm_offset_t address;
486efc68ce1SDavid Greenman 	int *run;
48726f9a767SRodney W. Grimes {
48826f9a767SRodney W. Grimes 	int rtaddress;
48926f9a767SRodney W. Grimes 	int bsize;
49026f9a767SRodney W. Grimes 	vm_offset_t block;
49126f9a767SRodney W. Grimes 	struct vnode *rtvp;
49226f9a767SRodney W. Grimes 	int err;
49326f9a767SRodney W. Grimes 	int vblock, voffset;
49426f9a767SRodney W. Grimes 
4950d94caffSDavid Greenman 	if ((int) address < 0)
4960d94caffSDavid Greenman 		return -1;
4970d94caffSDavid Greenman 
49826f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
49926f9a767SRodney W. Grimes 	vblock = address / bsize;
50026f9a767SRodney W. Grimes 	voffset = address % bsize;
50126f9a767SRodney W. Grimes 
502efc68ce1SDavid Greenman 	err = VOP_BMAP(vp, vblock, &rtvp, &block, run);
50326f9a767SRodney W. Grimes 
504efc68ce1SDavid Greenman 	if (err || (block == -1))
50526f9a767SRodney W. Grimes 		rtaddress = -1;
506efc68ce1SDavid Greenman 	else {
507187f0071SDavid Greenman 		rtaddress = block + voffset / DEV_BSIZE;
508efc68ce1SDavid Greenman 		if( run) {
509efc68ce1SDavid Greenman 			*run += 1;
510efc68ce1SDavid Greenman 			*run *= bsize/PAGE_SIZE;
511efc68ce1SDavid Greenman 			*run -= voffset/PAGE_SIZE;
512efc68ce1SDavid Greenman 		}
513efc68ce1SDavid Greenman 	}
51426f9a767SRodney W. Grimes 
51526f9a767SRodney W. Grimes 	return rtaddress;
51626f9a767SRodney W. Grimes }
51726f9a767SRodney W. Grimes 
51826f9a767SRodney W. Grimes /*
51926f9a767SRodney W. Grimes  * interrupt routine for I/O completion
52026f9a767SRodney W. Grimes  */
52126f9a767SRodney W. Grimes void
52226f9a767SRodney W. Grimes vnode_pager_iodone(bp)
52326f9a767SRodney W. Grimes 	struct buf *bp;
52426f9a767SRodney W. Grimes {
52526f9a767SRodney W. Grimes 	bp->b_flags |= B_DONE;
52626f9a767SRodney W. Grimes 	wakeup((caddr_t) bp);
52726f9a767SRodney W. Grimes }
52826f9a767SRodney W. Grimes 
52926f9a767SRodney W. Grimes /*
53026f9a767SRodney W. Grimes  * small block file system vnode pager input
53126f9a767SRodney W. Grimes  */
53226f9a767SRodney W. Grimes int
53326f9a767SRodney W. Grimes vnode_pager_input_smlfs(vnp, m)
53426f9a767SRodney W. Grimes 	vn_pager_t vnp;
53526f9a767SRodney W. Grimes 	vm_page_t m;
53626f9a767SRodney W. Grimes {
53726f9a767SRodney W. Grimes 	int i;
53826f9a767SRodney W. Grimes 	int s;
53926f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
54026f9a767SRodney W. Grimes 	struct buf *bp;
54126f9a767SRodney W. Grimes 	vm_offset_t kva;
54226f9a767SRodney W. Grimes 	int fileaddr;
54326f9a767SRodney W. Grimes 	int block;
54426f9a767SRodney W. Grimes 	vm_offset_t bsize;
54526f9a767SRodney W. Grimes 	int error = 0;
54626f9a767SRodney W. Grimes 
54726f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
54826f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
54926f9a767SRodney W. Grimes 
5500bdb7528SDavid Greenman 
5510d94caffSDavid Greenman 	VOP_BMAP(vp, 0, &dp, 0, 0);
55226f9a767SRodney W. Grimes 
55326f9a767SRodney W. Grimes 	kva = vm_pager_map_page(m);
55426f9a767SRodney W. Grimes 
55526f9a767SRodney W. Grimes 	for (i = 0; i < PAGE_SIZE / bsize; i++) {
556bbc0ec52SDavid Greenman 
5570d94caffSDavid Greenman 		if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid))
55826f9a767SRodney W. Grimes 			continue;
55926f9a767SRodney W. Grimes 
560efc68ce1SDavid Greenman 		fileaddr = vnode_pager_addr(vp, m->offset + i * bsize, (int *)0);
56126f9a767SRodney W. Grimes 		if (fileaddr != -1) {
56226f9a767SRodney W. Grimes 			bp = getpbuf();
56326f9a767SRodney W. Grimes 
56426f9a767SRodney W. Grimes 			/* build a minimal buffer header */
56526f9a767SRodney W. Grimes 			bp->b_flags = B_BUSY | B_READ | B_CALL;
56626f9a767SRodney W. Grimes 			bp->b_iodone = vnode_pager_iodone;
56726f9a767SRodney W. Grimes 			bp->b_proc = curproc;
56826f9a767SRodney W. Grimes 			bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
56926f9a767SRodney W. Grimes 			if (bp->b_rcred != NOCRED)
57026f9a767SRodney W. Grimes 				crhold(bp->b_rcred);
57126f9a767SRodney W. Grimes 			if (bp->b_wcred != NOCRED)
57226f9a767SRodney W. Grimes 				crhold(bp->b_wcred);
57326f9a767SRodney W. Grimes 			bp->b_un.b_addr = (caddr_t) kva + i * bsize;
574187f0071SDavid Greenman 			bp->b_blkno = fileaddr;
5750d94caffSDavid Greenman 			pbgetvp(dp, bp);
57626f9a767SRodney W. Grimes 			bp->b_bcount = bsize;
57726f9a767SRodney W. Grimes 			bp->b_bufsize = bsize;
57826f9a767SRodney W. Grimes 
57926f9a767SRodney W. Grimes 			/* do the input */
58026f9a767SRodney W. Grimes 			VOP_STRATEGY(bp);
58126f9a767SRodney W. Grimes 
58226f9a767SRodney W. Grimes 			/* we definitely need to be at splbio here */
58326f9a767SRodney W. Grimes 
58426f9a767SRodney W. Grimes 			s = splbio();
58526f9a767SRodney W. Grimes 			while ((bp->b_flags & B_DONE) == 0) {
586aa2cabb9SDavid Greenman 				tsleep(bp, PVM, "vnsrd", 0);
58726f9a767SRodney W. Grimes 			}
58826f9a767SRodney W. Grimes 			splx(s);
58926f9a767SRodney W. Grimes 			if ((bp->b_flags & B_ERROR) != 0)
59026f9a767SRodney W. Grimes 				error = EIO;
59126f9a767SRodney W. Grimes 
59226f9a767SRodney W. Grimes 			/*
59326f9a767SRodney W. Grimes 			 * free the buffer header back to the swap buffer pool
59426f9a767SRodney W. Grimes 			 */
59526f9a767SRodney W. Grimes 			relpbuf(bp);
59626f9a767SRodney W. Grimes 			if (error)
59726f9a767SRodney W. Grimes 				break;
5980d94caffSDavid Greenman 
599f6b04d2bSDavid Greenman 			vm_page_set_clean(m, (i * bsize) & (PAGE_SIZE-1), bsize);
600f6b04d2bSDavid Greenman 			vm_page_set_valid(m, (i * bsize) & (PAGE_SIZE-1), bsize);
60126f9a767SRodney W. Grimes 		} else {
602f6b04d2bSDavid Greenman 			vm_page_set_clean(m, (i * bsize) & (PAGE_SIZE-1), bsize);
60326f9a767SRodney W. Grimes 			bzero((caddr_t) kva + i * bsize, bsize);
60426f9a767SRodney W. Grimes 		}
60526f9a767SRodney W. Grimes nextblock:
60626f9a767SRodney W. Grimes 	}
60726f9a767SRodney W. Grimes 	vm_pager_unmap_page(kva);
6080d94caffSDavid Greenman 	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
60926f9a767SRodney W. Grimes 	if (error) {
610a83c285cSDavid Greenman 		return VM_PAGER_ERROR;
61126f9a767SRodney W. Grimes 	}
61226f9a767SRodney W. Grimes 	return VM_PAGER_OK;
61326f9a767SRodney W. Grimes 
61426f9a767SRodney W. Grimes }
61526f9a767SRodney W. Grimes 
61626f9a767SRodney W. Grimes 
61726f9a767SRodney W. Grimes /*
61826f9a767SRodney W. Grimes  * old style vnode pager output routine
61926f9a767SRodney W. Grimes  */
62026f9a767SRodney W. Grimes int
62126f9a767SRodney W. Grimes vnode_pager_input_old(vnp, m)
62226f9a767SRodney W. Grimes 	vn_pager_t vnp;
62326f9a767SRodney W. Grimes 	vm_page_t m;
62426f9a767SRodney W. Grimes {
625df8bae1dSRodney W. Grimes 	struct uio auio;
626df8bae1dSRodney W. Grimes 	struct iovec aiov;
62726f9a767SRodney W. Grimes 	int error;
62826f9a767SRodney W. Grimes 	int size;
62926f9a767SRodney W. Grimes 	vm_offset_t kva;
630df8bae1dSRodney W. Grimes 
63126f9a767SRodney W. Grimes 	error = 0;
632bbc0ec52SDavid Greenman 
633df8bae1dSRodney W. Grimes 	/*
63426f9a767SRodney W. Grimes 	 * Return failure if beyond current EOF
63526f9a767SRodney W. Grimes 	 */
6360d94caffSDavid Greenman 	if (m->offset >= vnp->vnp_size) {
63726f9a767SRodney W. Grimes 		return VM_PAGER_BAD;
63826f9a767SRodney W. Grimes 	} else {
63926f9a767SRodney W. Grimes 		size = PAGE_SIZE;
6400d94caffSDavid Greenman 		if (m->offset + size > vnp->vnp_size)
6410d94caffSDavid Greenman 			size = vnp->vnp_size - m->offset;
6420bdb7528SDavid Greenman 
64326f9a767SRodney W. Grimes 		/*
644df8bae1dSRodney W. Grimes 		 * Allocate a kernel virtual address and initialize so that
645df8bae1dSRodney W. Grimes 		 * we can use VOP_READ/WRITE routines.
646df8bae1dSRodney W. Grimes 		 */
64726f9a767SRodney W. Grimes 		kva = vm_pager_map_page(m);
6480bdb7528SDavid Greenman 
649df8bae1dSRodney W. Grimes 		aiov.iov_base = (caddr_t) kva;
650df8bae1dSRodney W. Grimes 		aiov.iov_len = size;
651df8bae1dSRodney W. Grimes 		auio.uio_iov = &aiov;
652df8bae1dSRodney W. Grimes 		auio.uio_iovcnt = 1;
6530d94caffSDavid Greenman 		auio.uio_offset = m->offset;
654df8bae1dSRodney W. Grimes 		auio.uio_segflg = UIO_SYSSPACE;
65526f9a767SRodney W. Grimes 		auio.uio_rw = UIO_READ;
656df8bae1dSRodney W. Grimes 		auio.uio_resid = size;
657df8bae1dSRodney W. Grimes 		auio.uio_procp = (struct proc *) 0;
65826f9a767SRodney W. Grimes 
65926f9a767SRodney W. Grimes 		error = VOP_READ(vnp->vnp_vp, &auio, 0, curproc->p_ucred);
660df8bae1dSRodney W. Grimes 		if (!error) {
661df8bae1dSRodney W. Grimes 			register int count = size - auio.uio_resid;
662df8bae1dSRodney W. Grimes 
663df8bae1dSRodney W. Grimes 			if (count == 0)
664df8bae1dSRodney W. Grimes 				error = EINVAL;
66526f9a767SRodney W. Grimes 			else if (count != PAGE_SIZE)
66626f9a767SRodney W. Grimes 				bzero((caddr_t) kva + count, PAGE_SIZE - count);
667df8bae1dSRodney W. Grimes 		}
66826f9a767SRodney W. Grimes 		vm_pager_unmap_page(kva);
669df8bae1dSRodney W. Grimes 	}
67026f9a767SRodney W. Grimes 	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
6710d94caffSDavid Greenman 	m->dirty = 0;
672a83c285cSDavid Greenman 	return error ? VM_PAGER_ERROR : VM_PAGER_OK;
67326f9a767SRodney W. Grimes }
67426f9a767SRodney W. Grimes 
67526f9a767SRodney W. Grimes /*
67626f9a767SRodney W. Grimes  * generic vnode pager input routine
67726f9a767SRodney W. Grimes  */
67826f9a767SRodney W. Grimes int
67926f9a767SRodney W. Grimes vnode_pager_input(vnp, m, count, reqpage)
68026f9a767SRodney W. Grimes 	register vn_pager_t vnp;
68126f9a767SRodney W. Grimes 	vm_page_t *m;
68226f9a767SRodney W. Grimes 	int count, reqpage;
68326f9a767SRodney W. Grimes {
68405f0fdd2SPoul-Henning Kamp 	int i;
68526f9a767SRodney W. Grimes 	vm_offset_t kva, foff;
6860bdb7528SDavid Greenman 	int size;
68726f9a767SRodney W. Grimes 	vm_object_t object;
68826f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
68926f9a767SRodney W. Grimes 	int bsize;
69026f9a767SRodney W. Grimes 
69126f9a767SRodney W. Grimes 	int first, last;
692efc68ce1SDavid Greenman 	int firstaddr;
69326f9a767SRodney W. Grimes 	int block, offset;
694efc68ce1SDavid Greenman 	int runpg;
695efc68ce1SDavid Greenman 	int runend;
69626f9a767SRodney W. Grimes 
6970bdb7528SDavid Greenman 	struct buf *bp;
69826f9a767SRodney W. Grimes 	int s;
69926f9a767SRodney W. Grimes 	int failflag;
70026f9a767SRodney W. Grimes 
70126f9a767SRodney W. Grimes 	int error = 0;
70226f9a767SRodney W. Grimes 
703bbc0ec52SDavid Greenman 	object = m[reqpage]->object;	/* all vm_page_t items are in same
704bbc0ec52SDavid Greenman 					 * object */
70526f9a767SRodney W. Grimes 
70626f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
70726f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
70826f9a767SRodney W. Grimes 
70926f9a767SRodney W. Grimes 	/* get the UNDERLYING device for the file with VOP_BMAP() */
710bbc0ec52SDavid Greenman 
71126f9a767SRodney W. Grimes 	/*
712bbc0ec52SDavid Greenman 	 * originally, we did not check for an error return value -- assuming
713bbc0ec52SDavid Greenman 	 * an fs always has a bmap entry point -- that assumption is wrong!!!
71426f9a767SRodney W. Grimes 	 */
7150d94caffSDavid Greenman 	foff = m[reqpage]->offset;
716bbc0ec52SDavid Greenman 
71726f9a767SRodney W. Grimes 	/*
71816f62314SDavid Greenman 	 * if we can't bmap, use old VOP code
71926f9a767SRodney W. Grimes 	 */
7200d94caffSDavid Greenman 	if (VOP_BMAP(vp, 0, &dp, 0, 0)) {
72126f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
72226f9a767SRodney W. Grimes 			if (i != reqpage) {
72326f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
72426f9a767SRodney W. Grimes 			}
72526f9a767SRodney W. Grimes 		}
726976e77fcSDavid Greenman 		cnt.v_vnodein++;
727976e77fcSDavid Greenman 		cnt.v_vnodepgsin++;
72826f9a767SRodney W. Grimes 		return vnode_pager_input_old(vnp, m[reqpage]);
729bbc0ec52SDavid Greenman 
73026f9a767SRodney W. Grimes 		/*
73126f9a767SRodney W. Grimes 		 * if the blocksize is smaller than a page size, then use
73226f9a767SRodney W. Grimes 		 * special small filesystem code.  NFS sometimes has a small
73326f9a767SRodney W. Grimes 		 * blocksize, but it can handle large reads itself.
73426f9a767SRodney W. Grimes 		 */
73526f9a767SRodney W. Grimes 	} else if ((PAGE_SIZE / bsize) > 1 &&
73626f9a767SRodney W. Grimes 	    (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
73726f9a767SRodney W. Grimes 
73826f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
73926f9a767SRodney W. Grimes 			if (i != reqpage) {
74026f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
74126f9a767SRodney W. Grimes 			}
74226f9a767SRodney W. Grimes 		}
743976e77fcSDavid Greenman 		cnt.v_vnodein++;
744976e77fcSDavid Greenman 		cnt.v_vnodepgsin++;
74526f9a767SRodney W. Grimes 		return vnode_pager_input_smlfs(vnp, m[reqpage]);
74626f9a767SRodney W. Grimes 	}
74726f9a767SRodney W. Grimes 	/*
7480d94caffSDavid Greenman 	 * if ANY DEV_BSIZE blocks are valid on a large filesystem block
7490d94caffSDavid Greenman 	 * then, the entire page is valid --
7500d94caffSDavid Greenman 	 */
7510d94caffSDavid Greenman 	if (m[reqpage]->valid) {
7520d94caffSDavid Greenman 		m[reqpage]->valid = VM_PAGE_BITS_ALL;
7530d94caffSDavid Greenman 		for (i = 0; i < count; i++) {
7540d94caffSDavid Greenman 			if (i != reqpage)
7550d94caffSDavid Greenman 				vnode_pager_freepage(m[i]);
7560d94caffSDavid Greenman 		}
7570d94caffSDavid Greenman 		return VM_PAGER_OK;
7580d94caffSDavid Greenman 	}
7590bdb7528SDavid Greenman 
7600d94caffSDavid Greenman 	/*
76126f9a767SRodney W. Grimes 	 * here on direct device I/O
76226f9a767SRodney W. Grimes 	 */
76326f9a767SRodney W. Grimes 
764efc68ce1SDavid Greenman 	firstaddr = -1;
76526f9a767SRodney W. Grimes 	/*
766efc68ce1SDavid Greenman 	 * calculate the run that includes the required page
76726f9a767SRodney W. Grimes 	 */
768efc68ce1SDavid Greenman 	for(first = 0, i = 0; i < count; i = runend) {
769efc68ce1SDavid Greenman 		firstaddr = vnode_pager_addr(vp, m[i]->offset, &runpg);
770efc68ce1SDavid Greenman 		if (firstaddr == -1) {
771efc68ce1SDavid Greenman 			if( i == reqpage && foff < vnp->vnp_size) {
772efc68ce1SDavid Greenman 				printf("vnode_pager_input: unexpected missing page: firstaddr: %d, foff: %d, vnp_size: %d\n",
773efc68ce1SDavid Greenman 			   	 firstaddr, foff, vnp->vnp_size);
774efc68ce1SDavid Greenman 				panic("vnode_pager_input:...");
775efc68ce1SDavid Greenman 			}
77626f9a767SRodney W. Grimes 			vnode_pager_freepage(m[i]);
777efc68ce1SDavid Greenman 			runend = i + 1;
778efc68ce1SDavid Greenman 			first = runend;
779efc68ce1SDavid Greenman 			continue;
780efc68ce1SDavid Greenman 		}
781efc68ce1SDavid Greenman 		runend = i + runpg;
782efc68ce1SDavid Greenman 		if( runend <= reqpage) {
783efc68ce1SDavid Greenman 			int j;
784efc68ce1SDavid Greenman 			for(j = i; j < runend; j++) {
785efc68ce1SDavid Greenman 				vnode_pager_freepage(m[j]);
786efc68ce1SDavid Greenman 			}
78726f9a767SRodney W. Grimes 		} else {
788efc68ce1SDavid Greenman 			if( runpg < (count - first)) {
789efc68ce1SDavid Greenman 				for(i=first + runpg; i < count; i++)
79026f9a767SRodney W. Grimes 					vnode_pager_freepage(m[i]);
791efc68ce1SDavid Greenman 				count = first + runpg;
79226f9a767SRodney W. Grimes 			}
793efc68ce1SDavid Greenman 			break;
79426f9a767SRodney W. Grimes 		}
795efc68ce1SDavid Greenman 		first = runend;
796efc68ce1SDavid Greenman 	}
79726f9a767SRodney W. Grimes 
79826f9a767SRodney W. Grimes 	/*
799bbc0ec52SDavid Greenman 	 * the first and last page have been calculated now, move input pages
800bbc0ec52SDavid Greenman 	 * to be zero based...
80126f9a767SRodney W. Grimes 	 */
80226f9a767SRodney W. Grimes 	if (first != 0) {
80326f9a767SRodney W. Grimes 		for (i = first; i < count; i++) {
80426f9a767SRodney W. Grimes 			m[i - first] = m[i];
80526f9a767SRodney W. Grimes 		}
80626f9a767SRodney W. Grimes 		count -= first;
80726f9a767SRodney W. Grimes 		reqpage -= first;
80826f9a767SRodney W. Grimes 	}
809efc68ce1SDavid Greenman 
81026f9a767SRodney W. Grimes 	/*
81126f9a767SRodney W. Grimes 	 * calculate the file virtual address for the transfer
81226f9a767SRodney W. Grimes 	 */
8130d94caffSDavid Greenman 	foff = m[0]->offset;
81426f9a767SRodney W. Grimes 
81526f9a767SRodney W. Grimes 	/*
81626f9a767SRodney W. Grimes 	 * calculate the size of the transfer
81726f9a767SRodney W. Grimes 	 */
81826f9a767SRodney W. Grimes 	size = count * PAGE_SIZE;
81926f9a767SRodney W. Grimes 	if ((foff + size) > vnp->vnp_size)
82026f9a767SRodney W. Grimes 		size = vnp->vnp_size - foff;
82126f9a767SRodney W. Grimes 
82226f9a767SRodney W. Grimes 	/*
82326f9a767SRodney W. Grimes 	 * round up physical size for real devices
82426f9a767SRodney W. Grimes 	 */
82526f9a767SRodney W. Grimes 	if (dp->v_type == VBLK || dp->v_type == VCHR)
82626f9a767SRodney W. Grimes 		size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
82726f9a767SRodney W. Grimes 
8286d40c3d3SDavid Greenman 	bp = getpbuf();
82916f62314SDavid Greenman 	kva = (vm_offset_t) bp->b_data;
83016f62314SDavid Greenman 
83126f9a767SRodney W. Grimes 	/*
83226f9a767SRodney W. Grimes 	 * and map the pages to be read into the kva
83326f9a767SRodney W. Grimes 	 */
83416f62314SDavid Greenman 	pmap_qenter(kva, m, count);
83526f9a767SRodney W. Grimes 
83626f9a767SRodney W. Grimes 	/* build a minimal buffer header */
83726f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY | B_READ | B_CALL;
83826f9a767SRodney W. Grimes 	bp->b_iodone = vnode_pager_iodone;
83926f9a767SRodney W. Grimes 	/* B_PHYS is not set, but it is nice to fill this in */
84026f9a767SRodney W. Grimes 	bp->b_proc = curproc;
84126f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
84226f9a767SRodney W. Grimes 	if (bp->b_rcred != NOCRED)
84326f9a767SRodney W. Grimes 		crhold(bp->b_rcred);
84426f9a767SRodney W. Grimes 	if (bp->b_wcred != NOCRED)
84526f9a767SRodney W. Grimes 		crhold(bp->b_wcred);
846187f0071SDavid Greenman 	bp->b_blkno = firstaddr;
8470d94caffSDavid Greenman 	pbgetvp(dp, bp);
84826f9a767SRodney W. Grimes 	bp->b_bcount = size;
84926f9a767SRodney W. Grimes 	bp->b_bufsize = size;
85026f9a767SRodney W. Grimes 
851976e77fcSDavid Greenman 	cnt.v_vnodein++;
852976e77fcSDavid Greenman 	cnt.v_vnodepgsin += count;
853976e77fcSDavid Greenman 
85426f9a767SRodney W. Grimes 	/* do the input */
85526f9a767SRodney W. Grimes 	VOP_STRATEGY(bp);
856976e77fcSDavid Greenman 
85726f9a767SRodney W. Grimes 	s = splbio();
85826f9a767SRodney W. Grimes 	/* we definitely need to be at splbio here */
85926f9a767SRodney W. Grimes 
86026f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
861aa2cabb9SDavid Greenman 		tsleep(bp, PVM, "vnread", 0);
86226f9a767SRodney W. Grimes 	}
86326f9a767SRodney W. Grimes 	splx(s);
86426f9a767SRodney W. Grimes 	if ((bp->b_flags & B_ERROR) != 0)
86526f9a767SRodney W. Grimes 		error = EIO;
86626f9a767SRodney W. Grimes 
86726f9a767SRodney W. Grimes 	if (!error) {
86826f9a767SRodney W. Grimes 		if (size != count * PAGE_SIZE)
86926f9a767SRodney W. Grimes 			bzero((caddr_t) kva + size, PAGE_SIZE * count - size);
87026f9a767SRodney W. Grimes 	}
87116f62314SDavid Greenman 	pmap_qremove(kva, count);
87226f9a767SRodney W. Grimes 
87326f9a767SRodney W. Grimes 	/*
87426f9a767SRodney W. Grimes 	 * free the buffer header back to the swap buffer pool
87526f9a767SRodney W. Grimes 	 */
87626f9a767SRodney W. Grimes 	relpbuf(bp);
87726f9a767SRodney W. Grimes 
87826f9a767SRodney W. Grimes finishup:
87926f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
880fff93ab6SDavid Greenman 		pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
8810d94caffSDavid Greenman 		m[i]->dirty = 0;
8820d94caffSDavid Greenman 		m[i]->valid = VM_PAGE_BITS_ALL;
88326f9a767SRodney W. Grimes 		if (i != reqpage) {
884bbc0ec52SDavid Greenman 
88526f9a767SRodney W. Grimes 			/*
886bbc0ec52SDavid Greenman 			 * whether or not to leave the page activated is up in
887bbc0ec52SDavid Greenman 			 * the air, but we should put the page on a page queue
888bbc0ec52SDavid Greenman 			 * somewhere. (it already is in the object). Result:
889bbc0ec52SDavid Greenman 			 * It appears that emperical results show that
890bbc0ec52SDavid Greenman 			 * deactivating pages is best.
89126f9a767SRodney W. Grimes 			 */
892bbc0ec52SDavid Greenman 
89326f9a767SRodney W. Grimes 			/*
894bbc0ec52SDavid Greenman 			 * just in case someone was asking for this page we
895bbc0ec52SDavid Greenman 			 * now tell them that it is ok to use
89626f9a767SRodney W. Grimes 			 */
89726f9a767SRodney W. Grimes 			if (!error) {
89826f9a767SRodney W. Grimes 				vm_page_deactivate(m[i]);
89926f9a767SRodney W. Grimes 				PAGE_WAKEUP(m[i]);
90026f9a767SRodney W. Grimes 			} else {
90126f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
90226f9a767SRodney W. Grimes 			}
90326f9a767SRodney W. Grimes 		}
90426f9a767SRodney W. Grimes 	}
90526f9a767SRodney W. Grimes 	if (error) {
906a83c285cSDavid Greenman 		printf("vnode_pager_input: I/O read error\n");
90726f9a767SRodney W. Grimes 	}
908a83c285cSDavid Greenman 	return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
90926f9a767SRodney W. Grimes }
91026f9a767SRodney W. Grimes 
91126f9a767SRodney W. Grimes /*
91226f9a767SRodney W. Grimes  * generic vnode pager output routine
91326f9a767SRodney W. Grimes  */
91426f9a767SRodney W. Grimes int
91526f9a767SRodney W. Grimes vnode_pager_output(vnp, m, count, rtvals)
91626f9a767SRodney W. Grimes 	vn_pager_t vnp;
91726f9a767SRodney W. Grimes 	vm_page_t *m;
91826f9a767SRodney W. Grimes 	int count;
91926f9a767SRodney W. Grimes 	int *rtvals;
92026f9a767SRodney W. Grimes {
921f6b04d2bSDavid Greenman 	int i;
92226f9a767SRodney W. Grimes 
923f6b04d2bSDavid Greenman 	struct vnode *vp;
924f6b04d2bSDavid Greenman 	int maxsize, ncount;
925f6b04d2bSDavid Greenman 	struct uio auio;
926f6b04d2bSDavid Greenman 	struct iovec aiov;
927f6b04d2bSDavid Greenman 	int error;
92826f9a767SRodney W. Grimes 
92926f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
93026f9a767SRodney W. Grimes 	for (i = 0; i < count; i++)
93126f9a767SRodney W. Grimes 		rtvals[i] = VM_PAGER_AGAIN;
93226f9a767SRodney W. Grimes 
9330d94caffSDavid Greenman 	if ((int) m[0]->offset < 0) {
934f6b04d2bSDavid Greenman 		printf("vnode_pager_output: attempt to write meta-data!!! -- 0x%x(%x)\n", m[0]->offset, m[0]->dirty);
935f6b04d2bSDavid Greenman 		rtvals[0] = VM_PAGER_BAD;
936f6b04d2bSDavid Greenman 		return VM_PAGER_BAD;
9370d94caffSDavid Greenman 	}
9380bdb7528SDavid Greenman 
939f6b04d2bSDavid Greenman 	maxsize = count * PAGE_SIZE;
940f6b04d2bSDavid Greenman 	ncount = count;
94126f9a767SRodney W. Grimes 
942f6b04d2bSDavid Greenman 	if (maxsize + m[0]->offset > vnp->vnp_size) {
9435f55e841SDavid Greenman 		if (vnp->vnp_size > m[0]->offset)
944f6b04d2bSDavid Greenman 			maxsize = vnp->vnp_size - m[0]->offset;
9455f55e841SDavid Greenman 		else
9465f55e841SDavid Greenman 			maxsize = 0;
947f6b04d2bSDavid Greenman 		ncount = (maxsize + PAGE_SIZE - 1) / PAGE_SIZE;
948f6b04d2bSDavid Greenman 		if (ncount < count) {
949f6b04d2bSDavid Greenman 			for (i = ncount; i < count; i++) {
950f6b04d2bSDavid Greenman 				rtvals[i] = VM_PAGER_BAD;
951f6b04d2bSDavid Greenman 			}
952f6b04d2bSDavid Greenman 			if (ncount == 0) {
953f6b04d2bSDavid Greenman 				printf("vnode_pager_output: write past end of file: %d, %d\n",
954f6b04d2bSDavid Greenman 					m[0]->offset, vnp->vnp_size);
95526f9a767SRodney W. Grimes 				return rtvals[0];
95626f9a767SRodney W. Grimes 			}
957f6b04d2bSDavid Greenman 		}
958f6b04d2bSDavid Greenman 	}
95926f9a767SRodney W. Grimes 
96026f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
9615f55e841SDavid Greenman 		m[i]->busy++;
962f6b04d2bSDavid Greenman 		m[i]->flags &= ~PG_BUSY;
96326f9a767SRodney W. Grimes 	}
964f6b04d2bSDavid Greenman 
965f6b04d2bSDavid Greenman 	aiov.iov_base = (caddr_t) 0;
966f6b04d2bSDavid Greenman 	aiov.iov_len = maxsize;
967f6b04d2bSDavid Greenman 	auio.uio_iov = &aiov;
968f6b04d2bSDavid Greenman 	auio.uio_iovcnt = 1;
969f6b04d2bSDavid Greenman 	auio.uio_offset = m[0]->offset;
970f6b04d2bSDavid Greenman 	auio.uio_segflg = UIO_NOCOPY;
971f6b04d2bSDavid Greenman 	auio.uio_rw = UIO_WRITE;
972f6b04d2bSDavid Greenman 	auio.uio_resid = maxsize;
973f6b04d2bSDavid Greenman 	auio.uio_procp = (struct proc *) 0;
974f6b04d2bSDavid Greenman 	error = VOP_WRITE(vp, &auio, IO_VMIO, curproc->p_ucred);
975976e77fcSDavid Greenman 	cnt.v_vnodeout++;
976f6b04d2bSDavid Greenman 	cnt.v_vnodepgsout += ncount;
977f6b04d2bSDavid Greenman 
978f6b04d2bSDavid Greenman 	if (error) {
979f6b04d2bSDavid Greenman 		printf("vnode_pager_output: I/O error %d\n", error);
980f6b04d2bSDavid Greenman 	}
981f6b04d2bSDavid Greenman 	if (auio.uio_resid) {
982f6b04d2bSDavid Greenman 		printf("vnode_pager_output: residual I/O %d at %d\n", auio.uio_resid, m[0]->offset);
98326f9a767SRodney W. Grimes 	}
98426f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
9855f55e841SDavid Greenman 		m[i]->busy--;
986f6b04d2bSDavid Greenman 		if (i < ncount) {
98726f9a767SRodney W. Grimes 			rtvals[i] = VM_PAGER_OK;
98826f9a767SRodney W. Grimes 		}
989f6b04d2bSDavid Greenman 		if ((m[i]->busy == 0) && (m[i]->flags & PG_WANTED))
990f6b04d2bSDavid Greenman 			wakeup((caddr_t) m[i]);
99126f9a767SRodney W. Grimes 	}
992f6b04d2bSDavid Greenman 	return rtvals[0];
99326f9a767SRodney W. Grimes }
994f6b04d2bSDavid Greenman 
995f6b04d2bSDavid Greenman struct vnode *
996f6b04d2bSDavid Greenman vnode_pager_lock(vm_object_t object) {
997f6b04d2bSDavid Greenman 
998f6b04d2bSDavid Greenman 	for(;object;object=object->shadow) {
999f6b04d2bSDavid Greenman 		vn_pager_t vnp;
1000f6b04d2bSDavid Greenman 		if( !object->pager || (object->pager->pg_type != PG_VNODE))
1001f6b04d2bSDavid Greenman 			continue;
1002f6b04d2bSDavid Greenman 
1003f6b04d2bSDavid Greenman 		vnp = (vn_pager_t) object->pager->pg_data;
1004f6b04d2bSDavid Greenman 		VOP_LOCK(vnp->vnp_vp);
1005f6b04d2bSDavid Greenman 		return vnp->vnp_vp;
100626f9a767SRodney W. Grimes 	}
1007f6b04d2bSDavid Greenman 	return (struct vnode *)NULL;
1008f6b04d2bSDavid Greenman }
1009f6b04d2bSDavid Greenman 
1010f6b04d2bSDavid Greenman void
1011f6b04d2bSDavid Greenman vnode_pager_unlock(struct vnode *vp) {
1012f6b04d2bSDavid Greenman 	VOP_UNLOCK(vp);
1013f6b04d2bSDavid Greenman }
1014f6b04d2bSDavid Greenman 
1015