xref: /freebsd/sys/vm/vnode_pager.c (revision 4abc71c00895e7c3ccbc99cd122a1a78fbd282fc)
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
404abc71c0SDavid Greenman  *	$Id: vnode_pager.c,v 1.17 1994/11/17 01:22:45 gibbs 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 /*
5226f9a767SRodney W. Grimes  * MODIFICATIONS:
5326f9a767SRodney W. Grimes  * John S. Dyson  08 Dec 93
5426f9a767SRodney W. Grimes  *
5526f9a767SRodney W. Grimes  * This file in conjunction with some vm_fault mods, eliminate the performance
5626f9a767SRodney W. Grimes  * advantage for using the buffer cache and minimize memory copies.
5726f9a767SRodney W. Grimes  *
5826f9a767SRodney W. Grimes  * 1) Supports multiple - block reads
5926f9a767SRodney W. Grimes  * 2) Bypasses buffer cache for reads
6026f9a767SRodney W. Grimes  *
6126f9a767SRodney W. Grimes  * TODO:
6226f9a767SRodney W. Grimes  *
6326f9a767SRodney W. Grimes  * 1) Totally bypass buffer cache for reads
6426f9a767SRodney W. Grimes  *    (Currently will still sometimes use buffer cache for reads)
6526f9a767SRodney W. Grimes  * 2) Bypass buffer cache for writes
6626f9a767SRodney W. Grimes  *    (Code does not support it, but mods are simple)
6726f9a767SRodney W. Grimes  */
6826f9a767SRodney W. Grimes 
69df8bae1dSRodney W. Grimes #include <sys/param.h>
70df8bae1dSRodney W. Grimes #include <sys/systm.h>
71df8bae1dSRodney W. Grimes #include <sys/proc.h>
72df8bae1dSRodney W. Grimes #include <sys/malloc.h>
73df8bae1dSRodney W. Grimes #include <sys/vnode.h>
74df8bae1dSRodney W. Grimes #include <sys/uio.h>
75df8bae1dSRodney W. Grimes #include <sys/mount.h>
76df8bae1dSRodney W. Grimes 
77df8bae1dSRodney W. Grimes #include <vm/vm.h>
78df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
79df8bae1dSRodney W. Grimes #include <vm/vnode_pager.h>
80df8bae1dSRodney W. Grimes 
8126f9a767SRodney W. Grimes #include <sys/buf.h>
8226f9a767SRodney W. Grimes #include <miscfs/specfs/specdev.h>
83df8bae1dSRodney W. Grimes 
8426f9a767SRodney W. Grimes int     vnode_pager_putmulti();
85df8bae1dSRodney W. Grimes 
8626f9a767SRodney W. Grimes void    vnode_pager_init();
8726f9a767SRodney W. Grimes vm_pager_t vnode_pager_alloc(caddr_t, vm_offset_t, vm_prot_t, vm_offset_t);
8826f9a767SRodney W. Grimes void    vnode_pager_dealloc();
8926f9a767SRodney W. Grimes int     vnode_pager_getpage();
9026f9a767SRodney W. Grimes int     vnode_pager_getmulti();
9126f9a767SRodney W. Grimes int     vnode_pager_putpage();
9226f9a767SRodney W. Grimes boolean_t vnode_pager_haspage();
93df8bae1dSRodney W. Grimes 
94df8bae1dSRodney W. Grimes struct pagerops vnodepagerops = {
95df8bae1dSRodney W. Grimes 	vnode_pager_init,
96df8bae1dSRodney W. Grimes 	vnode_pager_alloc,
97df8bae1dSRodney W. Grimes 	vnode_pager_dealloc,
98df8bae1dSRodney W. Grimes 	vnode_pager_getpage,
9926f9a767SRodney W. Grimes 	vnode_pager_getmulti,
100df8bae1dSRodney W. Grimes 	vnode_pager_putpage,
10126f9a767SRodney W. Grimes 	vnode_pager_putmulti,
10226f9a767SRodney W. Grimes 	vnode_pager_haspage
103df8bae1dSRodney W. Grimes };
104df8bae1dSRodney W. Grimes 
10516f62314SDavid Greenman 
10616f62314SDavid Greenman 
10726f9a767SRodney W. Grimes static int vnode_pager_input(vn_pager_t vnp, vm_page_t * m, int count, int reqpage);
10826f9a767SRodney W. Grimes static int vnode_pager_output(vn_pager_t vnp, vm_page_t * m, int count, int *rtvals);
10926f9a767SRodney W. Grimes 
11026f9a767SRodney W. Grimes extern vm_map_t pager_map;
11126f9a767SRodney W. Grimes 
11226f9a767SRodney W. Grimes struct pagerlst vnode_pager_list;	/* list of managed vnodes */
11326f9a767SRodney W. Grimes 
11426f9a767SRodney W. Grimes #define MAXBP (PAGE_SIZE/DEV_BSIZE);
11526f9a767SRodney W. Grimes 
11626f9a767SRodney W. Grimes void
117df8bae1dSRodney W. Grimes vnode_pager_init()
118df8bae1dSRodney W. Grimes {
119df8bae1dSRodney W. Grimes 	TAILQ_INIT(&vnode_pager_list);
120df8bae1dSRodney W. Grimes }
121df8bae1dSRodney W. Grimes 
122df8bae1dSRodney W. Grimes /*
123df8bae1dSRodney W. Grimes  * Allocate (or lookup) pager for a vnode.
124df8bae1dSRodney W. Grimes  * Handle is a vnode pointer.
125df8bae1dSRodney W. Grimes  */
12626f9a767SRodney W. Grimes vm_pager_t
12726f9a767SRodney W. Grimes vnode_pager_alloc(handle, size, prot, offset)
128df8bae1dSRodney W. Grimes 	caddr_t handle;
129df8bae1dSRodney W. Grimes 	vm_size_t size;
130df8bae1dSRodney W. Grimes 	vm_prot_t prot;
13126f9a767SRodney W. Grimes 	vm_offset_t offset;
132df8bae1dSRodney W. Grimes {
133df8bae1dSRodney W. Grimes 	register vm_pager_t pager;
134df8bae1dSRodney W. Grimes 	register vn_pager_t vnp;
135df8bae1dSRodney W. Grimes 	vm_object_t object;
136df8bae1dSRodney W. Grimes 	struct vattr vattr;
137df8bae1dSRodney W. Grimes 	struct vnode *vp;
138df8bae1dSRodney W. Grimes 	struct proc *p = curproc;	/* XXX */
139df8bae1dSRodney W. Grimes 
140df8bae1dSRodney W. Grimes 	/*
141df8bae1dSRodney W. Grimes 	 * Pageout to vnode, no can do yet.
142df8bae1dSRodney W. Grimes 	 */
143df8bae1dSRodney W. Grimes 	if (handle == NULL)
144df8bae1dSRodney W. Grimes 		return (NULL);
145df8bae1dSRodney W. Grimes 
146df8bae1dSRodney W. Grimes 	/*
147bbc0ec52SDavid Greenman 	 * Vnodes keep a pointer to any associated pager so no need to lookup
148bbc0ec52SDavid Greenman 	 * with vm_pager_lookup.
149df8bae1dSRodney W. Grimes 	 */
150df8bae1dSRodney W. Grimes 	vp = (struct vnode *) handle;
1518e58bf68SDavid Greenman 	object = (vm_object_t) vp->v_vmdata;
1528e58bf68SDavid Greenman 	pager = NULL;
1538e58bf68SDavid Greenman 	if( object != NULL)
1548e58bf68SDavid Greenman 		pager = object->pager;
155df8bae1dSRodney W. Grimes 	if (pager == NULL) {
156bbc0ec52SDavid Greenman 
157df8bae1dSRodney W. Grimes 		/*
158df8bae1dSRodney W. Grimes 		 * Allocate pager structures
159df8bae1dSRodney W. Grimes 		 */
160df8bae1dSRodney W. Grimes 		pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
161df8bae1dSRodney W. Grimes 		if (pager == NULL)
162df8bae1dSRodney W. Grimes 			return (NULL);
163df8bae1dSRodney W. Grimes 		vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
164df8bae1dSRodney W. Grimes 		if (vnp == NULL) {
165df8bae1dSRodney W. Grimes 			free((caddr_t) pager, M_VMPAGER);
166df8bae1dSRodney W. Grimes 			return (NULL);
167df8bae1dSRodney W. Grimes 		}
168bbc0ec52SDavid Greenman 
169df8bae1dSRodney W. Grimes 		/*
170df8bae1dSRodney W. Grimes 		 * And an object of the appropriate size
171df8bae1dSRodney W. Grimes 		 */
172df8bae1dSRodney W. Grimes 		if (VOP_GETATTR(vp, &vattr, p->p_ucred, p) == 0) {
173df8bae1dSRodney W. Grimes 			object = vm_object_allocate(round_page(vattr.va_size));
174df8bae1dSRodney W. Grimes 			vm_object_enter(object, pager);
175df8bae1dSRodney W. Grimes 			vm_object_setpager(object, pager, 0, TRUE);
176df8bae1dSRodney W. Grimes 		} else {
177df8bae1dSRodney W. Grimes 			free((caddr_t) vnp, M_VMPGDATA);
178df8bae1dSRodney W. Grimes 			free((caddr_t) pager, M_VMPAGER);
179df8bae1dSRodney W. Grimes 			return (NULL);
180df8bae1dSRodney W. Grimes 		}
181bbc0ec52SDavid Greenman 
182df8bae1dSRodney W. Grimes 		/*
183df8bae1dSRodney W. Grimes 		 * Hold a reference to the vnode and initialize pager data.
184df8bae1dSRodney W. Grimes 		 */
185df8bae1dSRodney W. Grimes 		VREF(vp);
186df8bae1dSRodney W. Grimes 		vnp->vnp_flags = 0;
187df8bae1dSRodney W. Grimes 		vnp->vnp_vp = vp;
188df8bae1dSRodney W. Grimes 		vnp->vnp_size = vattr.va_size;
18926f9a767SRodney W. Grimes 
190df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list);
191df8bae1dSRodney W. Grimes 		pager->pg_handle = handle;
192df8bae1dSRodney W. Grimes 		pager->pg_type = PG_VNODE;
193df8bae1dSRodney W. Grimes 		pager->pg_ops = &vnodepagerops;
19426f9a767SRodney W. Grimes 		pager->pg_data = (caddr_t) vnp;
1958e58bf68SDavid Greenman 		vp->v_vmdata = (caddr_t) object;
196df8bae1dSRodney W. Grimes 	} else {
197bbc0ec52SDavid Greenman 
198df8bae1dSRodney W. Grimes 		/*
199bbc0ec52SDavid Greenman 		 * vm_object_lookup() will remove the object from the cache if
200bbc0ec52SDavid Greenman 		 * found and also gain a reference to the object.
201df8bae1dSRodney W. Grimes 		 */
2028e58bf68SDavid Greenman 		(void) vm_object_lookup(pager);
203df8bae1dSRodney W. Grimes 	}
204df8bae1dSRodney W. Grimes 	return (pager);
205df8bae1dSRodney W. Grimes }
206df8bae1dSRodney W. Grimes 
20726f9a767SRodney W. Grimes void
208df8bae1dSRodney W. Grimes vnode_pager_dealloc(pager)
209df8bae1dSRodney W. Grimes 	vm_pager_t pager;
210df8bae1dSRodney W. Grimes {
211df8bae1dSRodney W. Grimes 	register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
212df8bae1dSRodney W. Grimes 	register struct vnode *vp;
213df8bae1dSRodney W. Grimes 
21405f0fdd2SPoul-Henning Kamp 	vp = vnp->vnp_vp;
21505f0fdd2SPoul-Henning Kamp 	if (vp) {
216df8bae1dSRodney W. Grimes 		vp->v_vmdata = NULL;
2178e58bf68SDavid Greenman 		vp->v_flag &= ~(VTEXT|VVMIO);
218df8bae1dSRodney W. Grimes 		vrele(vp);
219df8bae1dSRodney W. Grimes 	}
220df8bae1dSRodney W. Grimes 	TAILQ_REMOVE(&vnode_pager_list, pager, pg_list);
221df8bae1dSRodney W. Grimes 	free((caddr_t) vnp, M_VMPGDATA);
222df8bae1dSRodney W. Grimes 	free((caddr_t) pager, M_VMPAGER);
223df8bae1dSRodney W. Grimes }
224df8bae1dSRodney W. Grimes 
22526f9a767SRodney W. Grimes int
22626f9a767SRodney W. Grimes vnode_pager_getmulti(pager, m, count, reqpage, sync)
227df8bae1dSRodney W. Grimes 	vm_pager_t pager;
22826f9a767SRodney W. Grimes 	vm_page_t *m;
22926f9a767SRodney W. Grimes 	int     count;
23026f9a767SRodney W. Grimes 	int     reqpage;
231df8bae1dSRodney W. Grimes 	boolean_t sync;
232df8bae1dSRodney W. Grimes {
233df8bae1dSRodney W. Grimes 
23426f9a767SRodney W. Grimes 	return vnode_pager_input((vn_pager_t) pager->pg_data, m, count, reqpage);
235df8bae1dSRodney W. Grimes }
236df8bae1dSRodney W. Grimes 
23726f9a767SRodney W. Grimes int
23826f9a767SRodney W. Grimes vnode_pager_getpage(pager, m, sync)
239df8bae1dSRodney W. Grimes 	vm_pager_t pager;
24026f9a767SRodney W. Grimes 	vm_page_t m;
24126f9a767SRodney W. Grimes 	boolean_t sync;
24226f9a767SRodney W. Grimes {
24326f9a767SRodney W. Grimes 
24426f9a767SRodney W. Grimes 	vm_page_t marray[1];
245bbc0ec52SDavid Greenman 
24626f9a767SRodney W. Grimes 	if (pager == NULL)
24726f9a767SRodney W. Grimes 		return FALSE;
24826f9a767SRodney W. Grimes 	marray[0] = m;
24926f9a767SRodney W. Grimes 
25026f9a767SRodney W. Grimes 	return vnode_pager_input((vn_pager_t) pager->pg_data, marray, 1, 0);
25126f9a767SRodney W. Grimes }
25226f9a767SRodney W. Grimes 
25326f9a767SRodney W. Grimes boolean_t
25426f9a767SRodney W. Grimes vnode_pager_putpage(pager, m, sync)
25526f9a767SRodney W. Grimes 	vm_pager_t pager;
25626f9a767SRodney W. Grimes 	vm_page_t m;
257df8bae1dSRodney W. Grimes 	boolean_t sync;
258df8bae1dSRodney W. Grimes {
25926f9a767SRodney W. Grimes 	vm_page_t marray[1];
26026f9a767SRodney W. Grimes 	int     rtvals[1];
261df8bae1dSRodney W. Grimes 
262df8bae1dSRodney W. Grimes 	if (pager == NULL)
26326f9a767SRodney W. Grimes 		return FALSE;
26426f9a767SRodney W. Grimes 	marray[0] = m;
26526f9a767SRodney W. Grimes 	vnode_pager_output((vn_pager_t) pager->pg_data, marray, 1, rtvals);
26626f9a767SRodney W. Grimes 	return rtvals[0];
267df8bae1dSRodney W. Grimes }
268df8bae1dSRodney W. Grimes 
26926f9a767SRodney W. Grimes int
27026f9a767SRodney W. Grimes vnode_pager_putmulti(pager, m, c, sync, rtvals)
27126f9a767SRodney W. Grimes 	vm_pager_t pager;
27226f9a767SRodney W. Grimes 	vm_page_t *m;
27326f9a767SRodney W. Grimes 	int     c;
27426f9a767SRodney W. Grimes 	boolean_t sync;
27526f9a767SRodney W. Grimes 	int    *rtvals;
27626f9a767SRodney W. Grimes {
27726f9a767SRodney W. Grimes 	return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals);
27826f9a767SRodney W. Grimes }
27926f9a767SRodney W. Grimes 
28026f9a767SRodney W. Grimes 
28126f9a767SRodney W. Grimes boolean_t
282df8bae1dSRodney W. Grimes vnode_pager_haspage(pager, offset)
283df8bae1dSRodney W. Grimes 	vm_pager_t pager;
284df8bae1dSRodney W. Grimes 	vm_offset_t offset;
285df8bae1dSRodney W. Grimes {
286df8bae1dSRodney W. Grimes 	register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
2874abc71c0SDavid Greenman 	register struct vnode *vp = vnp->vnp_vp;
288df8bae1dSRodney W. Grimes 	daddr_t bn;
289df8bae1dSRodney W. Grimes 	int     err;
290317205caSDavid Greenman 	daddr_t block;
291df8bae1dSRodney W. Grimes 
292df8bae1dSRodney W. Grimes 	/*
2934abc71c0SDavid Greenman 	 * If filesystem no longer mounted or offset beyond end of
2944abc71c0SDavid Greenman 	 * file we do not have the page.
295df8bae1dSRodney W. Grimes 	 */
2964abc71c0SDavid Greenman 	if ((vp->v_mount == NULL) || (offset >= vnp->vnp_size))
2974abc71c0SDavid Greenman 		return FALSE;
298df8bae1dSRodney W. Grimes 
2994abc71c0SDavid Greenman 	block = offset / vp->v_mount->mnt_stat.f_iosize;
3004abc71c0SDavid Greenman 	if (incore(vp, block))
301317205caSDavid Greenman 		return TRUE;
302df8bae1dSRodney W. Grimes 	/*
303bbc0ec52SDavid Greenman 	 * Read the index to find the disk block to read from.  If there is no
304bbc0ec52SDavid Greenman 	 * block, report that we don't have this data.
305df8bae1dSRodney W. Grimes 	 *
306df8bae1dSRodney W. Grimes 	 * Assumes that the vnode has whole page or nothing.
307df8bae1dSRodney W. Grimes 	 */
3084abc71c0SDavid Greenman 	err = VOP_BMAP(vp, block, (struct vnode **) 0, &bn, 0);
3098e58bf68SDavid Greenman /*
3108e58bf68SDavid Greenman 	printf("vnode_pager_haspage: (%d)0x%x: err: %d, bn: %d\n",
3118e58bf68SDavid Greenman 		offset, offset, err, bn);
3128e58bf68SDavid Greenman */
313df8bae1dSRodney W. Grimes 	if (err) {
314df8bae1dSRodney W. Grimes 		return (TRUE);
315df8bae1dSRodney W. Grimes 	}
316df8bae1dSRodney W. Grimes 	return ((long) bn < 0 ? FALSE : TRUE);
317df8bae1dSRodney W. Grimes }
318df8bae1dSRodney W. Grimes 
319df8bae1dSRodney W. Grimes /*
320df8bae1dSRodney W. Grimes  * Lets the VM system know about a change in size for a file.
321df8bae1dSRodney W. Grimes  * If this vnode is mapped into some address space (i.e. we have a pager
322df8bae1dSRodney W. Grimes  * for it) we adjust our own internal size and flush any cached pages in
323df8bae1dSRodney W. Grimes  * the associated object that are affected by the size change.
324df8bae1dSRodney W. Grimes  *
325df8bae1dSRodney W. Grimes  * Note: this routine may be invoked as a result of a pager put
326df8bae1dSRodney W. Grimes  * operation (possibly at object termination time), so we must be careful.
327df8bae1dSRodney W. Grimes  */
328df8bae1dSRodney W. Grimes void
329df8bae1dSRodney W. Grimes vnode_pager_setsize(vp, nsize)
330df8bae1dSRodney W. Grimes 	struct vnode *vp;
331df8bae1dSRodney W. Grimes 	u_long  nsize;
332df8bae1dSRodney W. Grimes {
333df8bae1dSRodney W. Grimes 	register vn_pager_t vnp;
334df8bae1dSRodney W. Grimes 	register vm_object_t object;
335df8bae1dSRodney W. Grimes 	vm_pager_t pager;
336df8bae1dSRodney W. Grimes 
337df8bae1dSRodney W. Grimes 	/*
338df8bae1dSRodney W. Grimes 	 * Not a mapped vnode
339df8bae1dSRodney W. Grimes 	 */
340df8bae1dSRodney W. Grimes 	if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
341df8bae1dSRodney W. Grimes 		return;
342bbc0ec52SDavid Greenman 
343df8bae1dSRodney W. Grimes 	/*
344df8bae1dSRodney W. Grimes 	 * Hasn't changed size
345df8bae1dSRodney W. Grimes 	 */
3468e58bf68SDavid Greenman 	object = (vm_object_t) vp->v_vmdata;
3478e58bf68SDavid Greenman 	if( object == NULL)
3488e58bf68SDavid Greenman 		return;
3498e58bf68SDavid Greenman 	if( (pager = object->pager) == NULL)
3508e58bf68SDavid Greenman 		return;
351df8bae1dSRodney W. Grimes 	vnp = (vn_pager_t) pager->pg_data;
352df8bae1dSRodney W. Grimes 	if (nsize == vnp->vnp_size)
353df8bae1dSRodney W. Grimes 		return;
354bbc0ec52SDavid Greenman 
355df8bae1dSRodney W. Grimes 	/*
356bbc0ec52SDavid Greenman 	 * No object. This can happen during object termination since
357bbc0ec52SDavid Greenman 	 * vm_object_page_clean is called after the object has been removed
358bbc0ec52SDavid Greenman 	 * from the hash table, and clean may cause vnode write operations
359bbc0ec52SDavid Greenman 	 * which can wind up back here.
360df8bae1dSRodney W. Grimes 	 */
361df8bae1dSRodney W. Grimes 	object = vm_object_lookup(pager);
362df8bae1dSRodney W. Grimes 	if (object == NULL)
363df8bae1dSRodney W. Grimes 		return;
364df8bae1dSRodney W. Grimes 
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) {
369df8bae1dSRodney W. Grimes 		vm_object_lock(object);
370df8bae1dSRodney W. Grimes 		vm_object_page_remove(object,
371bbc0ec52SDavid Greenman 			     round_page((vm_offset_t) nsize), vnp->vnp_size);
372bbc0ec52SDavid Greenman 		vm_object_unlock(object);
373bbc0ec52SDavid Greenman 
374bbc0ec52SDavid Greenman 		/*
375bbc0ec52SDavid Greenman 		 * this gets rid of garbage at the end of a page that is now
376bbc0ec52SDavid Greenman 		 * only partially backed by the vnode...
377bbc0ec52SDavid Greenman 		 */
378bbc0ec52SDavid Greenman 		if (nsize & PAGE_MASK) {
379bbc0ec52SDavid Greenman 			vm_offset_t kva;
380bbc0ec52SDavid Greenman 			vm_page_t m;
381bbc0ec52SDavid Greenman 
382bbc0ec52SDavid Greenman 			m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize));
383bbc0ec52SDavid Greenman 			if (m) {
384bbc0ec52SDavid Greenman 				kva = vm_pager_map_page(m);
385bbc0ec52SDavid Greenman 				bzero((caddr_t) kva + (nsize & PAGE_MASK),
386bbc0ec52SDavid Greenman 				      round_page(nsize) - nsize);
387bbc0ec52SDavid Greenman 				vm_pager_unmap_page(kva);
388bbc0ec52SDavid Greenman 			}
389bbc0ec52SDavid Greenman 		}
390bbc0ec52SDavid Greenman 	} else {
391bbc0ec52SDavid Greenman 
392bbc0ec52SDavid Greenman 		/*
393bbc0ec52SDavid Greenman 		 * this allows the filesystem and VM cache to stay in sync if
394bbc0ec52SDavid Greenman 		 * the VM page hasn't been modified...  After the page is
395bbc0ec52SDavid Greenman 		 * removed -- it will be faulted back in from the filesystem
396bbc0ec52SDavid Greenman 		 * cache.
397bbc0ec52SDavid Greenman 		 */
398bbc0ec52SDavid Greenman 		if (vnp->vnp_size & PAGE_MASK) {
399bbc0ec52SDavid Greenman 			vm_page_t m;
400bbc0ec52SDavid Greenman 
401bbc0ec52SDavid Greenman 			m = vm_page_lookup(object, trunc_page(vnp->vnp_size));
402bbc0ec52SDavid Greenman 			if (m && (m->flags & PG_CLEAN)) {
403bbc0ec52SDavid Greenman 				vm_object_lock(object);
404bbc0ec52SDavid Greenman 				vm_object_page_remove(object,
405bbc0ec52SDavid Greenman 					       vnp->vnp_size, vnp->vnp_size);
406df8bae1dSRodney W. Grimes 				vm_object_unlock(object);
407df8bae1dSRodney W. Grimes 			}
408bbc0ec52SDavid Greenman 		}
409bbc0ec52SDavid Greenman 	}
410df8bae1dSRodney W. Grimes 	vnp->vnp_size = (vm_offset_t) nsize;
411bbc0ec52SDavid Greenman 	object->size = round_page(nsize);
412bbc0ec52SDavid Greenman 
413df8bae1dSRodney W. Grimes 	vm_object_deallocate(object);
414df8bae1dSRodney W. Grimes }
415df8bae1dSRodney W. Grimes 
416df8bae1dSRodney W. Grimes void
417df8bae1dSRodney W. Grimes vnode_pager_umount(mp)
418df8bae1dSRodney W. Grimes 	register struct mount *mp;
419df8bae1dSRodney W. Grimes {
420df8bae1dSRodney W. Grimes 	register vm_pager_t pager, npager;
421df8bae1dSRodney W. Grimes 	struct vnode *vp;
422df8bae1dSRodney W. Grimes 
42326f9a767SRodney W. Grimes 	pager = vnode_pager_list.tqh_first;
42426f9a767SRodney W. Grimes 	while (pager) {
425bbc0ec52SDavid Greenman 
426df8bae1dSRodney W. Grimes 		/*
427bbc0ec52SDavid Greenman 		 * Save the next pointer now since uncaching may terminate the
428bbc0ec52SDavid Greenman 		 * object and render pager invalid
429df8bae1dSRodney W. Grimes 		 */
430df8bae1dSRodney W. Grimes 		vp = ((vn_pager_t) pager->pg_data)->vnp_vp;
43126f9a767SRodney W. Grimes 		npager = pager->pg_list.tqe_next;
43226f9a767SRodney W. Grimes 		if (mp == (struct mount *) 0 || vp->v_mount == mp)
433df8bae1dSRodney W. Grimes 			(void) vnode_pager_uncache(vp);
43426f9a767SRodney W. Grimes 		pager = npager;
435df8bae1dSRodney W. Grimes 	}
436df8bae1dSRodney W. Grimes }
437df8bae1dSRodney W. Grimes 
438df8bae1dSRodney W. Grimes /*
439df8bae1dSRodney W. Grimes  * Remove vnode associated object from the object cache.
440df8bae1dSRodney W. Grimes  *
44126f9a767SRodney W. Grimes  * Note: this routine may be invoked as a result of a pager put
44226f9a767SRodney W. Grimes  * operation (possibly at object termination time), so we must be careful.
44326f9a767SRodney W. Grimes  */
44426f9a767SRodney W. Grimes boolean_t
44526f9a767SRodney W. Grimes vnode_pager_uncache(vp)
44626f9a767SRodney W. Grimes 	register struct vnode *vp;
44726f9a767SRodney W. Grimes {
44826f9a767SRodney W. Grimes 	register vm_object_t object;
44926f9a767SRodney W. Grimes 	boolean_t uncached, locked;
45026f9a767SRodney W. Grimes 	vm_pager_t pager;
45126f9a767SRodney W. Grimes 
45226f9a767SRodney W. Grimes 	/*
45326f9a767SRodney W. Grimes 	 * Not a mapped vnode
45426f9a767SRodney W. Grimes 	 */
4558e58bf68SDavid Greenman 	object = (vm_object_t) vp->v_vmdata;
4568e58bf68SDavid Greenman 	if( object == NULL)
4578e58bf68SDavid Greenman 		return(TRUE);
4588e58bf68SDavid Greenman 	pager = object->pager;
45926f9a767SRodney W. Grimes 	if (pager == NULL)
46026f9a767SRodney W. Grimes 		return (TRUE);
461bbc0ec52SDavid Greenman 
46226f9a767SRodney W. Grimes 	/*
463bbc0ec52SDavid Greenman 	 * Unlock the vnode if it is currently locked. We do this since
464bbc0ec52SDavid Greenman 	 * uncaching the object may result in its destruction which may
465bbc0ec52SDavid Greenman 	 * initiate paging activity which may necessitate locking the vnode.
46626f9a767SRodney W. Grimes 	 */
46726f9a767SRodney W. Grimes 	locked = VOP_ISLOCKED(vp);
46826f9a767SRodney W. Grimes 	if (locked)
46926f9a767SRodney W. Grimes 		VOP_UNLOCK(vp);
470bbc0ec52SDavid Greenman 
47126f9a767SRodney W. Grimes 	/*
472bbc0ec52SDavid Greenman 	 * Must use vm_object_lookup() as it actually removes the object from
473bbc0ec52SDavid Greenman 	 * the cache list.
47426f9a767SRodney W. Grimes 	 */
47526f9a767SRodney W. Grimes 	object = vm_object_lookup(pager);
47626f9a767SRodney W. Grimes 	if (object) {
47726f9a767SRodney W. Grimes 		uncached = (object->ref_count <= 1);
47826f9a767SRodney W. Grimes 		pager_cache(object, FALSE);
47926f9a767SRodney W. Grimes 	} else
48026f9a767SRodney W. Grimes 		uncached = TRUE;
48126f9a767SRodney W. Grimes 	if (locked)
48226f9a767SRodney W. Grimes 		VOP_LOCK(vp);
48326f9a767SRodney W. Grimes 	return (uncached);
48426f9a767SRodney W. Grimes }
485df8bae1dSRodney W. Grimes 
48626f9a767SRodney W. Grimes 
48726f9a767SRodney W. Grimes void
48826f9a767SRodney W. Grimes vnode_pager_freepage(m)
48926f9a767SRodney W. Grimes 	vm_page_t m;
490df8bae1dSRodney W. Grimes {
49126f9a767SRodney W. Grimes 	PAGE_WAKEUP(m);
49226f9a767SRodney W. Grimes 	vm_page_free(m);
49326f9a767SRodney W. Grimes }
49426f9a767SRodney W. Grimes 
49526f9a767SRodney W. Grimes /*
49626f9a767SRodney W. Grimes  * calculate the linear (byte) disk address of specified virtual
49726f9a767SRodney W. Grimes  * file address
49826f9a767SRodney W. Grimes  */
49926f9a767SRodney W. Grimes vm_offset_t
50026f9a767SRodney W. Grimes vnode_pager_addr(vp, address)
50126f9a767SRodney W. Grimes 	struct vnode *vp;
50226f9a767SRodney W. Grimes 	vm_offset_t address;
50326f9a767SRodney W. Grimes {
50426f9a767SRodney W. Grimes 	int     rtaddress;
50526f9a767SRodney W. Grimes 	int     bsize;
50626f9a767SRodney W. Grimes 	vm_offset_t block;
50726f9a767SRodney W. Grimes 	struct vnode *rtvp;
50826f9a767SRodney W. Grimes 	int     err;
50926f9a767SRodney W. Grimes 	int     vblock, voffset;
51026f9a767SRodney W. Grimes 
51126f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
51226f9a767SRodney W. Grimes 	vblock = address / bsize;
51326f9a767SRodney W. Grimes 	voffset = address % bsize;
51426f9a767SRodney W. Grimes 
51526f9a767SRodney W. Grimes 	err = VOP_BMAP(vp, vblock, &rtvp, &block, 0);
51626f9a767SRodney W. Grimes 
51726f9a767SRodney W. Grimes 	if (err)
51826f9a767SRodney W. Grimes 		rtaddress = -1;
51926f9a767SRodney W. Grimes 	else
52026f9a767SRodney W. Grimes 		rtaddress = block * DEV_BSIZE + voffset;
52126f9a767SRodney W. Grimes 
52226f9a767SRodney W. Grimes 	return rtaddress;
52326f9a767SRodney W. Grimes }
52426f9a767SRodney W. Grimes 
52526f9a767SRodney W. Grimes /*
52626f9a767SRodney W. Grimes  * interrupt routine for I/O completion
52726f9a767SRodney W. Grimes  */
52826f9a767SRodney W. Grimes void
52926f9a767SRodney W. Grimes vnode_pager_iodone(bp)
53026f9a767SRodney W. Grimes 	struct buf *bp;
53126f9a767SRodney W. Grimes {
53226f9a767SRodney W. Grimes 	bp->b_flags |= B_DONE;
53326f9a767SRodney W. Grimes 	wakeup((caddr_t) bp);
53416f62314SDavid Greenman 	if( bp->b_flags & B_ASYNC) {
53516f62314SDavid Greenman 		vm_offset_t paddr;
53616f62314SDavid Greenman 		vm_page_t m;
53716f62314SDavid Greenman 		vm_object_t obj = 0;
53816f62314SDavid Greenman 		int i;
53916f62314SDavid Greenman 		int npages;
54016f62314SDavid Greenman 
54116f62314SDavid Greenman 		paddr = (vm_offset_t) bp->b_data;
54216f62314SDavid Greenman 		if( bp->b_bufsize != bp->b_bcount)
54316f62314SDavid Greenman 			bzero( bp->b_data + bp->b_bcount,
54416f62314SDavid Greenman 				bp->b_bufsize - bp->b_bcount);
54516f62314SDavid Greenman 
54616f62314SDavid Greenman 		npages = (bp->b_bufsize + PAGE_SIZE - 1) / PAGE_SIZE;
547a481f200SDavid Greenman /*
548a481f200SDavid Greenman 		printf("bcount: %d, bufsize: %d, npages: %d\n",
549a481f200SDavid Greenman 			bp->b_bcount, bp->b_bufsize, npages);
550a481f200SDavid Greenman */
55116f62314SDavid Greenman 		for( i = 0; i < npages; i++) {
55216f62314SDavid Greenman 			m = PHYS_TO_VM_PAGE(pmap_kextract(paddr + i * PAGE_SIZE));
55316f62314SDavid Greenman 			obj = m->object;
55416f62314SDavid Greenman 			if( m) {
55516f62314SDavid Greenman 				m->flags |= PG_CLEAN;
55616f62314SDavid Greenman 				m->flags &= ~(PG_LAUNDRY|PG_FAKE);
55716f62314SDavid Greenman 				PAGE_WAKEUP(m);
55816f62314SDavid Greenman 			} else {
55916f62314SDavid Greenman 				panic("vnode_pager_iodone: page is gone!!!");
56016f62314SDavid Greenman 			}
56116f62314SDavid Greenman 		}
562a481f200SDavid Greenman 		pmap_qremove( paddr, npages);
56316f62314SDavid Greenman 		if( obj) {
56416f62314SDavid Greenman 			--obj->paging_in_progress;
56516f62314SDavid Greenman 			if( obj->paging_in_progress == 0)
56616f62314SDavid Greenman 				wakeup((caddr_t) obj);
56716f62314SDavid Greenman 		} else {
56816f62314SDavid Greenman 			panic("vnode_pager_iodone: object is gone???");
56916f62314SDavid Greenman 		}
57016f62314SDavid Greenman 		HOLDRELE(bp->b_vp);
57116f62314SDavid Greenman 		relpbuf(bp);
57216f62314SDavid Greenman 	}
57326f9a767SRodney W. Grimes }
57426f9a767SRodney W. Grimes 
57526f9a767SRodney W. Grimes /*
57626f9a767SRodney W. Grimes  * small block file system vnode pager input
57726f9a767SRodney W. Grimes  */
57826f9a767SRodney W. Grimes int
57926f9a767SRodney W. Grimes vnode_pager_input_smlfs(vnp, m)
58026f9a767SRodney W. Grimes 	vn_pager_t vnp;
58126f9a767SRodney W. Grimes 	vm_page_t m;
58226f9a767SRodney W. Grimes {
58326f9a767SRodney W. Grimes 	int     i;
58426f9a767SRodney W. Grimes 	int     s;
58526f9a767SRodney W. Grimes 	vm_offset_t paging_offset;
58626f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
58726f9a767SRodney W. Grimes 	struct buf *bp;
58826f9a767SRodney W. Grimes 	vm_offset_t foff;
58926f9a767SRodney W. Grimes 	vm_offset_t kva;
59026f9a767SRodney W. Grimes 	int     fileaddr;
59126f9a767SRodney W. Grimes 	int     block;
59226f9a767SRodney W. Grimes 	vm_offset_t bsize;
59326f9a767SRodney W. Grimes 	int     error = 0;
59426f9a767SRodney W. Grimes 
59526f9a767SRodney W. Grimes 	paging_offset = m->object->paging_offset;
59626f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
59726f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
59826f9a767SRodney W. Grimes 	foff = m->offset + paging_offset;
59926f9a767SRodney W. Grimes 
60026f9a767SRodney W. Grimes 	VOP_BMAP(vp, foff, &dp, 0, 0);
60126f9a767SRodney W. Grimes 
60226f9a767SRodney W. Grimes 	kva = vm_pager_map_page(m);
60326f9a767SRodney W. Grimes 
60426f9a767SRodney W. Grimes 	for (i = 0; i < PAGE_SIZE / bsize; i++) {
605bbc0ec52SDavid Greenman 
60626f9a767SRodney W. Grimes 		/*
60726f9a767SRodney W. Grimes 		 * calculate logical block and offset
60826f9a767SRodney W. Grimes 		 */
60926f9a767SRodney W. Grimes 		block = foff / bsize + i;
61026f9a767SRodney W. Grimes 		s = splbio();
61105f0fdd2SPoul-Henning Kamp 		while ((bp = incore(vp, block)) != 0) {
61226f9a767SRodney W. Grimes 			int     amount;
61326f9a767SRodney W. Grimes 
61426f9a767SRodney W. Grimes 			/*
61526f9a767SRodney W. Grimes 			 * wait until the buffer is avail or gone
61626f9a767SRodney W. Grimes 			 */
61726f9a767SRodney W. Grimes 			if (bp->b_flags & B_BUSY) {
61826f9a767SRodney W. Grimes 				bp->b_flags |= B_WANTED;
61926f9a767SRodney W. Grimes 				tsleep((caddr_t) bp, PVM, "vnwblk", 0);
62026f9a767SRodney W. Grimes 				continue;
62126f9a767SRodney W. Grimes 			}
62226f9a767SRodney W. Grimes 			amount = bsize;
62326f9a767SRodney W. Grimes 			if ((foff + bsize) > vnp->vnp_size)
62426f9a767SRodney W. Grimes 				amount = vnp->vnp_size - foff;
62526f9a767SRodney W. Grimes 
62626f9a767SRodney W. Grimes 			/*
62726f9a767SRodney W. Grimes 			 * make sure that this page is in the buffer
62826f9a767SRodney W. Grimes 			 */
62926f9a767SRodney W. Grimes 			if ((amount > 0) && amount <= bp->b_bcount) {
63026f9a767SRodney W. Grimes 				bp->b_flags |= B_BUSY;
63126f9a767SRodney W. Grimes 				splx(s);
63226f9a767SRodney W. Grimes 
63326f9a767SRodney W. Grimes 				/*
63426f9a767SRodney W. Grimes 				 * copy the data from the buffer
63526f9a767SRodney W. Grimes 				 */
63626f9a767SRodney W. Grimes 				bcopy(bp->b_un.b_addr, (caddr_t) kva + i * bsize, amount);
63726f9a767SRodney W. Grimes 				if (amount < bsize) {
63826f9a767SRodney W. Grimes 					bzero((caddr_t) kva + amount, bsize - amount);
63926f9a767SRodney W. Grimes 				}
64026f9a767SRodney W. Grimes 				bp->b_flags &= ~B_BUSY;
64126f9a767SRodney W. Grimes 				wakeup((caddr_t) bp);
64226f9a767SRodney W. Grimes 				goto nextblock;
64326f9a767SRodney W. Grimes 			}
64426f9a767SRodney W. Grimes 			break;
64526f9a767SRodney W. Grimes 		}
64626f9a767SRodney W. Grimes 		splx(s);
64726f9a767SRodney W. Grimes 		fileaddr = vnode_pager_addr(vp, foff + i * bsize);
64826f9a767SRodney W. Grimes 		if (fileaddr != -1) {
64926f9a767SRodney W. Grimes 			bp = getpbuf();
65026f9a767SRodney W. Grimes 			VHOLD(vp);
65126f9a767SRodney W. Grimes 
65226f9a767SRodney W. Grimes 			/* build a minimal buffer header */
65326f9a767SRodney W. Grimes 			bp->b_flags = B_BUSY | B_READ | B_CALL;
65426f9a767SRodney W. Grimes 			bp->b_iodone = vnode_pager_iodone;
65526f9a767SRodney W. Grimes 			bp->b_proc = curproc;
65626f9a767SRodney W. Grimes 			bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
65726f9a767SRodney W. Grimes 			if (bp->b_rcred != NOCRED)
65826f9a767SRodney W. Grimes 				crhold(bp->b_rcred);
65926f9a767SRodney W. Grimes 			if (bp->b_wcred != NOCRED)
66026f9a767SRodney W. Grimes 				crhold(bp->b_wcred);
66126f9a767SRodney W. Grimes 			bp->b_un.b_addr = (caddr_t) kva + i * bsize;
66226f9a767SRodney W. Grimes 			bp->b_blkno = fileaddr / DEV_BSIZE;
66326f9a767SRodney W. Grimes 			bgetvp(dp, bp);
66426f9a767SRodney W. Grimes 			bp->b_bcount = bsize;
66526f9a767SRodney W. Grimes 			bp->b_bufsize = bsize;
66626f9a767SRodney W. Grimes 
66726f9a767SRodney W. Grimes 			/* do the input */
66826f9a767SRodney W. Grimes 			VOP_STRATEGY(bp);
66926f9a767SRodney W. Grimes 
67026f9a767SRodney W. Grimes 			/* we definitely need to be at splbio here */
67126f9a767SRodney W. Grimes 
67226f9a767SRodney W. Grimes 			s = splbio();
67326f9a767SRodney W. Grimes 			while ((bp->b_flags & B_DONE) == 0) {
67426f9a767SRodney W. Grimes 				tsleep((caddr_t) bp, PVM, "vnsrd", 0);
67526f9a767SRodney W. Grimes 			}
67626f9a767SRodney W. Grimes 			splx(s);
67726f9a767SRodney W. Grimes 			if ((bp->b_flags & B_ERROR) != 0)
67826f9a767SRodney W. Grimes 				error = EIO;
67926f9a767SRodney W. Grimes 
68026f9a767SRodney W. Grimes 			/*
68126f9a767SRodney W. Grimes 			 * free the buffer header back to the swap buffer pool
68226f9a767SRodney W. Grimes 			 */
68326f9a767SRodney W. Grimes 			relpbuf(bp);
68426f9a767SRodney W. Grimes 			HOLDRELE(vp);
68526f9a767SRodney W. Grimes 			if (error)
68626f9a767SRodney W. Grimes 				break;
68726f9a767SRodney W. Grimes 		} else {
68826f9a767SRodney W. Grimes 			bzero((caddr_t) kva + i * bsize, bsize);
68926f9a767SRodney W. Grimes 		}
69026f9a767SRodney W. Grimes nextblock:
69126f9a767SRodney W. Grimes 	}
69226f9a767SRodney W. Grimes 	vm_pager_unmap_page(kva);
69326f9a767SRodney W. Grimes 	if (error) {
694a83c285cSDavid Greenman 		return VM_PAGER_ERROR;
69526f9a767SRodney W. Grimes 	}
69626f9a767SRodney W. Grimes 	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
69726f9a767SRodney W. Grimes 	m->flags |= PG_CLEAN;
69826f9a767SRodney W. Grimes 	m->flags &= ~PG_LAUNDRY;
69926f9a767SRodney W. Grimes 	return VM_PAGER_OK;
70026f9a767SRodney W. Grimes 
70126f9a767SRodney W. Grimes }
70226f9a767SRodney W. Grimes 
70326f9a767SRodney W. Grimes 
70426f9a767SRodney W. Grimes /*
70526f9a767SRodney W. Grimes  * old style vnode pager output routine
70626f9a767SRodney W. Grimes  */
70726f9a767SRodney W. Grimes int
70826f9a767SRodney W. Grimes vnode_pager_input_old(vnp, m)
70926f9a767SRodney W. Grimes 	vn_pager_t vnp;
71026f9a767SRodney W. Grimes 	vm_page_t m;
71126f9a767SRodney W. Grimes {
712df8bae1dSRodney W. Grimes 	struct uio auio;
713df8bae1dSRodney W. Grimes 	struct iovec aiov;
71426f9a767SRodney W. Grimes 	int     error;
71526f9a767SRodney W. Grimes 	int     size;
71626f9a767SRodney W. Grimes 	vm_offset_t foff;
71726f9a767SRodney W. Grimes 	vm_offset_t kva;
718df8bae1dSRodney W. Grimes 
71926f9a767SRodney W. Grimes 	error = 0;
720df8bae1dSRodney W. Grimes 	foff = m->offset + m->object->paging_offset;
721bbc0ec52SDavid Greenman 
722df8bae1dSRodney W. Grimes 	/*
72326f9a767SRodney W. Grimes 	 * Return failure if beyond current EOF
72426f9a767SRodney W. Grimes 	 */
72526f9a767SRodney W. Grimes 	if (foff >= vnp->vnp_size) {
72626f9a767SRodney W. Grimes 		return VM_PAGER_BAD;
72726f9a767SRodney W. Grimes 	} else {
72826f9a767SRodney W. Grimes 		size = PAGE_SIZE;
72926f9a767SRodney W. Grimes 		if (foff + size > vnp->vnp_size)
73026f9a767SRodney W. Grimes 			size = vnp->vnp_size - foff;
73126f9a767SRodney W. Grimes /*
732df8bae1dSRodney W. Grimes  * Allocate a kernel virtual address and initialize so that
733df8bae1dSRodney W. Grimes  * we can use VOP_READ/WRITE routines.
734df8bae1dSRodney W. Grimes  */
73526f9a767SRodney W. Grimes 		kva = vm_pager_map_page(m);
736df8bae1dSRodney W. Grimes 		aiov.iov_base = (caddr_t) kva;
737df8bae1dSRodney W. Grimes 		aiov.iov_len = size;
738df8bae1dSRodney W. Grimes 		auio.uio_iov = &aiov;
739df8bae1dSRodney W. Grimes 		auio.uio_iovcnt = 1;
740df8bae1dSRodney W. Grimes 		auio.uio_offset = foff;
741df8bae1dSRodney W. Grimes 		auio.uio_segflg = UIO_SYSSPACE;
74226f9a767SRodney W. Grimes 		auio.uio_rw = UIO_READ;
743df8bae1dSRodney W. Grimes 		auio.uio_resid = size;
744df8bae1dSRodney W. Grimes 		auio.uio_procp = (struct proc *) 0;
74526f9a767SRodney W. Grimes 
74626f9a767SRodney W. Grimes 		error = VOP_READ(vnp->vnp_vp, &auio, 0, curproc->p_ucred);
747df8bae1dSRodney W. Grimes 		if (!error) {
748df8bae1dSRodney W. Grimes 			register int count = size - auio.uio_resid;
749df8bae1dSRodney W. Grimes 
750df8bae1dSRodney W. Grimes 			if (count == 0)
751df8bae1dSRodney W. Grimes 				error = EINVAL;
75226f9a767SRodney W. Grimes 			else if (count != PAGE_SIZE)
75326f9a767SRodney W. Grimes 				bzero((caddr_t) kva + count, PAGE_SIZE - count);
754df8bae1dSRodney W. Grimes 		}
75526f9a767SRodney W. Grimes 		vm_pager_unmap_page(kva);
756df8bae1dSRodney W. Grimes 	}
75726f9a767SRodney W. Grimes 	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
75826f9a767SRodney W. Grimes 	m->flags |= PG_CLEAN;
75926f9a767SRodney W. Grimes 	m->flags &= ~PG_LAUNDRY;
760a83c285cSDavid Greenman 	return error ? VM_PAGER_ERROR : VM_PAGER_OK;
76126f9a767SRodney W. Grimes }
76226f9a767SRodney W. Grimes 
76326f9a767SRodney W. Grimes /*
76426f9a767SRodney W. Grimes  * generic vnode pager input routine
76526f9a767SRodney W. Grimes  */
76626f9a767SRodney W. Grimes int
76726f9a767SRodney W. Grimes vnode_pager_input(vnp, m, count, reqpage)
76826f9a767SRodney W. Grimes 	register vn_pager_t vnp;
76926f9a767SRodney W. Grimes 	vm_page_t *m;
77026f9a767SRodney W. Grimes 	int     count, reqpage;
77126f9a767SRodney W. Grimes {
77205f0fdd2SPoul-Henning Kamp 	int     i;
77326f9a767SRodney W. Grimes 	vm_offset_t kva, foff;
77416f62314SDavid Greenman 	int     size, sizea;
77526f9a767SRodney W. Grimes 	vm_object_t object;
77626f9a767SRodney W. Grimes 	vm_offset_t paging_offset;
77726f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
77826f9a767SRodney W. Grimes 	int     bsize;
77926f9a767SRodney W. Grimes 
78026f9a767SRodney W. Grimes 	int     first, last;
78126f9a767SRodney W. Grimes 	int     reqaddr, firstaddr;
78226f9a767SRodney W. Grimes 	int     block, offset;
78326f9a767SRodney W. Grimes 
78416f62314SDavid Greenman 	struct buf *bp, *bpa;
78516f62314SDavid Greenman 	int	counta;
78626f9a767SRodney W. Grimes 	int     s;
78726f9a767SRodney W. Grimes 	int     failflag;
78826f9a767SRodney W. Grimes 
78926f9a767SRodney W. Grimes 	int     error = 0;
79026f9a767SRodney W. Grimes 
791bbc0ec52SDavid Greenman 	object = m[reqpage]->object;	/* all vm_page_t items are in same
792bbc0ec52SDavid Greenman 					 * object */
79326f9a767SRodney W. Grimes 	paging_offset = object->paging_offset;
79426f9a767SRodney W. Grimes 
79526f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
7964abc71c0SDavid Greenman 
7974abc71c0SDavid Greenman 	/*
7984abc71c0SDavid Greenman 	 * Make sure underlying filesystem is still mounted.
7994abc71c0SDavid Greenman 	 */
8004abc71c0SDavid Greenman 	if (vp->v_mount == NULL)
8014abc71c0SDavid Greenman 		return VM_PAGER_FAIL;
8024abc71c0SDavid Greenman 
80326f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
80426f9a767SRodney W. Grimes 
80526f9a767SRodney W. Grimes 	/* get the UNDERLYING device for the file with VOP_BMAP() */
806bbc0ec52SDavid Greenman 
80726f9a767SRodney W. Grimes 	/*
808bbc0ec52SDavid Greenman 	 * originally, we did not check for an error return value -- assuming
809bbc0ec52SDavid Greenman 	 * an fs always has a bmap entry point -- that assumption is wrong!!!
81026f9a767SRodney W. Grimes 	 */
81126f9a767SRodney W. Grimes 	foff = m[reqpage]->offset + paging_offset;
812bbc0ec52SDavid Greenman 
81326f9a767SRodney W. Grimes 	/*
81416f62314SDavid Greenman 	 * if we can't bmap, use old VOP code
81526f9a767SRodney W. Grimes 	 */
816bf556a16SJustin T. Gibbs 	if (VOP_BMAP(vp, foff, &dp, 0, 0)) {
81726f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
81826f9a767SRodney W. Grimes 			if (i != reqpage) {
81926f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
82026f9a767SRodney W. Grimes 			}
82126f9a767SRodney W. Grimes 		}
822976e77fcSDavid Greenman 		cnt.v_vnodein++;
823976e77fcSDavid Greenman 		cnt.v_vnodepgsin++;
82426f9a767SRodney W. Grimes 		return vnode_pager_input_old(vnp, m[reqpage]);
825bbc0ec52SDavid Greenman 
82626f9a767SRodney W. Grimes 		/*
82726f9a767SRodney W. Grimes 		 * if the blocksize is smaller than a page size, then use
82826f9a767SRodney W. Grimes 		 * special small filesystem code.  NFS sometimes has a small
82926f9a767SRodney W. Grimes 		 * blocksize, but it can handle large reads itself.
83026f9a767SRodney W. Grimes 		 */
83126f9a767SRodney W. Grimes 	} else if ((PAGE_SIZE / bsize) > 1 &&
83226f9a767SRodney W. Grimes 		   (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
83326f9a767SRodney W. Grimes 
83426f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
83526f9a767SRodney W. Grimes 			if (i != reqpage) {
83626f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
83726f9a767SRodney W. Grimes 			}
83826f9a767SRodney W. Grimes 		}
839976e77fcSDavid Greenman 		cnt.v_vnodein++;
840976e77fcSDavid Greenman 		cnt.v_vnodepgsin++;
84126f9a767SRodney W. Grimes 		return vnode_pager_input_smlfs(vnp, m[reqpage]);
84226f9a767SRodney W. Grimes 	}
84326f9a767SRodney W. Grimes /*
84426f9a767SRodney W. Grimes  * here on direct device I/O
84526f9a767SRodney W. Grimes  */
84626f9a767SRodney W. Grimes 
84726f9a767SRodney W. Grimes 
8488e58bf68SDavid Greenman #ifdef NOTYET
8498e58bf68SDavid Greenman 	if( (vp->v_flag & VVMIO) == 0) {
8508e58bf68SDavid Greenman #endif
85126f9a767SRodney W. Grimes 	/*
85226f9a767SRodney W. Grimes 	 * This pathetic hack gets data from the buffer cache, if it's there.
853bbc0ec52SDavid Greenman 	 * I believe that this is not really necessary, and the ends can be
854bbc0ec52SDavid Greenman 	 * gotten by defaulting to the normal vfs read behavior, but this
85526f9a767SRodney W. Grimes 	 * might be more efficient, because the will NOT invoke read-aheads
856bbc0ec52SDavid Greenman 	 * and one of the purposes of this code is to bypass the buffer cache
857bbc0ec52SDavid Greenman 	 * and keep from flushing it by reading in a program.
85826f9a767SRodney W. Grimes 	 */
859bbc0ec52SDavid Greenman 
86026f9a767SRodney W. Grimes 		/*
86126f9a767SRodney W. Grimes 		 * calculate logical block and offset
86226f9a767SRodney W. Grimes 		 */
86326f9a767SRodney W. Grimes 		block = foff / bsize;
86426f9a767SRodney W. Grimes 		offset = foff % bsize;
86526f9a767SRodney W. Grimes 		s = splbio();
86626f9a767SRodney W. Grimes 
86726f9a767SRodney W. Grimes 		/*
86826f9a767SRodney W. Grimes 		 * if we have a buffer in core, then try to use it
86926f9a767SRodney W. Grimes 		 */
87005f0fdd2SPoul-Henning Kamp 		while ((bp = incore(vp, block)) != 0) {
87126f9a767SRodney W. Grimes 			int     amount;
87226f9a767SRodney W. Grimes 
87326f9a767SRodney W. Grimes 			/*
87426f9a767SRodney W. Grimes 			 * wait until the buffer is avail or gone
87526f9a767SRodney W. Grimes 			 */
87626f9a767SRodney W. Grimes 			if (bp->b_flags & B_BUSY) {
87726f9a767SRodney W. Grimes 				bp->b_flags |= B_WANTED;
87826f9a767SRodney W. Grimes 				tsleep((caddr_t) bp, PVM, "vnwblk", 0);
87926f9a767SRodney W. Grimes 				continue;
88026f9a767SRodney W. Grimes 			}
88126f9a767SRodney W. Grimes 			amount = PAGE_SIZE;
88226f9a767SRodney W. Grimes 			if ((foff + amount) > vnp->vnp_size)
88326f9a767SRodney W. Grimes 				amount = vnp->vnp_size - foff;
88426f9a767SRodney W. Grimes 
88526f9a767SRodney W. Grimes 			/*
88626f9a767SRodney W. Grimes 			 * make sure that this page is in the buffer
88726f9a767SRodney W. Grimes 			 */
88826f9a767SRodney W. Grimes 			if ((amount > 0) && (offset + amount) <= bp->b_bcount) {
88926f9a767SRodney W. Grimes 				bp->b_flags |= B_BUSY;
89026f9a767SRodney W. Grimes 				splx(s);
8918e58bf68SDavid Greenman 				kva = kmem_alloc_wait( pager_map, PAGE_SIZE);
89226f9a767SRodney W. Grimes 
89326f9a767SRodney W. Grimes 				/*
89426f9a767SRodney W. Grimes 				 * map the requested page
89526f9a767SRodney W. Grimes 				 */
89616f62314SDavid Greenman 				pmap_qenter(kva, &m[reqpage], 1);
89726f9a767SRodney W. Grimes 
89826f9a767SRodney W. Grimes 				/*
89926f9a767SRodney W. Grimes 				 * copy the data from the buffer
90026f9a767SRodney W. Grimes 				 */
90126f9a767SRodney W. Grimes 				bcopy(bp->b_un.b_addr + offset, (caddr_t) kva, amount);
90226f9a767SRodney W. Grimes 				if (amount < PAGE_SIZE) {
90326f9a767SRodney W. Grimes 					bzero((caddr_t) kva + amount, PAGE_SIZE - amount);
90426f9a767SRodney W. Grimes 				}
905bbc0ec52SDavid Greenman 
90626f9a767SRodney W. Grimes 				/*
90726f9a767SRodney W. Grimes 				 * unmap the page and free the kva
90826f9a767SRodney W. Grimes 				 */
90916f62314SDavid Greenman 				pmap_qremove( kva, 1);
910a481f200SDavid Greenman 				kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
911bbc0ec52SDavid Greenman 
91226f9a767SRodney W. Grimes 				/*
91326f9a767SRodney W. Grimes 				 * release the buffer back to the block subsystem
91426f9a767SRodney W. Grimes 				 */
91526f9a767SRodney W. Grimes 				bp->b_flags &= ~B_BUSY;
91626f9a767SRodney W. Grimes 				wakeup((caddr_t) bp);
917bbc0ec52SDavid Greenman 
91826f9a767SRodney W. Grimes 				/*
91926f9a767SRodney W. Grimes 				 * we did not have to do any work to get the requested
92026f9a767SRodney W. Grimes 				 * page, the read behind/ahead does not justify a read
92126f9a767SRodney W. Grimes 				 */
92226f9a767SRodney W. Grimes 				for (i = 0; i < count; i++) {
92326f9a767SRodney W. Grimes 					if (i != reqpage) {
92426f9a767SRodney W. Grimes 						vnode_pager_freepage(m[i]);
92526f9a767SRodney W. Grimes 					}
92626f9a767SRodney W. Grimes 				}
92726f9a767SRodney W. Grimes 				count = 1;
92826f9a767SRodney W. Grimes 				reqpage = 0;
92926f9a767SRodney W. Grimes 				m[0] = m[reqpage];
93026f9a767SRodney W. Grimes 
93126f9a767SRodney W. Grimes 				/*
93226f9a767SRodney W. Grimes 				 * sorry for the goto
93326f9a767SRodney W. Grimes 				 */
93426f9a767SRodney W. Grimes 				goto finishup;
93526f9a767SRodney W. Grimes 			}
936bbc0ec52SDavid Greenman 
93726f9a767SRodney W. Grimes 			/*
93826f9a767SRodney W. Grimes 			 * buffer is nowhere to be found, read from the disk
93926f9a767SRodney W. Grimes 			 */
94026f9a767SRodney W. Grimes 			break;
94126f9a767SRodney W. Grimes 		}
94226f9a767SRodney W. Grimes 		splx(s);
9438e58bf68SDavid Greenman #ifdef NOTYET
9448e58bf68SDavid Greenman 	}
9458e58bf68SDavid Greenman #endif
94626f9a767SRodney W. Grimes 
94726f9a767SRodney W. Grimes 	reqaddr = vnode_pager_addr(vp, foff);
94826f9a767SRodney W. Grimes 	s = splbio();
949bbc0ec52SDavid Greenman 
95026f9a767SRodney W. Grimes 	/*
951bbc0ec52SDavid Greenman 	 * Make sure that our I/O request is contiguous. Scan backward and
952bbc0ec52SDavid Greenman 	 * stop for the first discontiguous entry or stop for a page being in
953bbc0ec52SDavid Greenman 	 * buffer cache.
95426f9a767SRodney W. Grimes 	 */
95526f9a767SRodney W. Grimes 	failflag = 0;
95626f9a767SRodney W. Grimes 	first = reqpage;
95726f9a767SRodney W. Grimes 	for (i = reqpage - 1; i >= 0; --i) {
95826f9a767SRodney W. Grimes 		if (failflag ||
9598e58bf68SDavid Greenman #ifdef NOTYET
9608e58bf68SDavid Greenman 		    ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
9618e58bf68SDavid Greenman #else
9628e58bf68SDavid Greenman 		    (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
9638e58bf68SDavid Greenman #endif
96426f9a767SRodney W. Grimes 		    (vnode_pager_addr(vp, m[i]->offset + paging_offset))
96526f9a767SRodney W. Grimes 		    != reqaddr + (i - reqpage) * PAGE_SIZE) {
96626f9a767SRodney W. Grimes 			vnode_pager_freepage(m[i]);
96726f9a767SRodney W. Grimes 			failflag = 1;
96826f9a767SRodney W. Grimes 		} else {
96926f9a767SRodney W. Grimes 			first = i;
97026f9a767SRodney W. Grimes 		}
97126f9a767SRodney W. Grimes 	}
97226f9a767SRodney W. Grimes 
97326f9a767SRodney W. Grimes 	/*
974bbc0ec52SDavid Greenman 	 * Scan forward and stop for the first non-contiguous entry or stop
975bbc0ec52SDavid Greenman 	 * for a page being in buffer cache.
97626f9a767SRodney W. Grimes 	 */
97726f9a767SRodney W. Grimes 	failflag = 0;
97826f9a767SRodney W. Grimes 	last = reqpage + 1;
97926f9a767SRodney W. Grimes 	for (i = reqpage + 1; i < count; i++) {
98026f9a767SRodney W. Grimes 		if (failflag ||
9818e58bf68SDavid Greenman #ifdef NOTYET
9828e58bf68SDavid Greenman 		    ((vp->v_flag & VVMIO) == 0 && incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
9838e58bf68SDavid Greenman #else
9848e58bf68SDavid Greenman 		    (incore(vp, (foff + (i - reqpage) * PAGE_SIZE) / bsize)) ||
9858e58bf68SDavid Greenman #endif
98626f9a767SRodney W. Grimes 		    (vnode_pager_addr(vp, m[i]->offset + paging_offset))
98726f9a767SRodney W. Grimes 		    != reqaddr + (i - reqpage) * PAGE_SIZE) {
98826f9a767SRodney W. Grimes 			vnode_pager_freepage(m[i]);
98926f9a767SRodney W. Grimes 			failflag = 1;
99026f9a767SRodney W. Grimes 		} else {
99126f9a767SRodney W. Grimes 			last = i + 1;
99226f9a767SRodney W. Grimes 		}
99326f9a767SRodney W. Grimes 	}
99426f9a767SRodney W. Grimes 	splx(s);
99526f9a767SRodney W. Grimes 
99626f9a767SRodney W. Grimes 	/*
997bbc0ec52SDavid Greenman 	 * the first and last page have been calculated now, move input pages
998bbc0ec52SDavid Greenman 	 * to be zero based...
99926f9a767SRodney W. Grimes 	 */
100026f9a767SRodney W. Grimes 	count = last;
100126f9a767SRodney W. Grimes 	if (first != 0) {
100226f9a767SRodney W. Grimes 		for (i = first; i < count; i++) {
100326f9a767SRodney W. Grimes 			m[i - first] = m[i];
100426f9a767SRodney W. Grimes 		}
100526f9a767SRodney W. Grimes 		count -= first;
100626f9a767SRodney W. Grimes 		reqpage -= first;
100726f9a767SRodney W. Grimes 	}
100826f9a767SRodney W. Grimes 
100926f9a767SRodney W. Grimes 	/*
101026f9a767SRodney W. Grimes 	 * calculate the file virtual address for the transfer
101126f9a767SRodney W. Grimes 	 */
101226f9a767SRodney W. Grimes 	foff = m[0]->offset + paging_offset;
1013bbc0ec52SDavid Greenman 
101426f9a767SRodney W. Grimes 	/*
101526f9a767SRodney W. Grimes 	 * and get the disk physical address (in bytes)
101626f9a767SRodney W. Grimes 	 */
101726f9a767SRodney W. Grimes 	firstaddr = vnode_pager_addr(vp, foff);
101826f9a767SRodney W. Grimes 
101926f9a767SRodney W. Grimes 	/*
102026f9a767SRodney W. Grimes 	 * calculate the size of the transfer
102126f9a767SRodney W. Grimes 	 */
102226f9a767SRodney W. Grimes 	size = count * PAGE_SIZE;
102326f9a767SRodney W. Grimes 	if ((foff + size) > vnp->vnp_size)
102426f9a767SRodney W. Grimes 		size = vnp->vnp_size - foff;
102526f9a767SRodney W. Grimes 
102626f9a767SRodney W. Grimes 	/*
102726f9a767SRodney W. Grimes 	 * round up physical size for real devices
102826f9a767SRodney W. Grimes 	 */
102926f9a767SRodney W. Grimes 	if (dp->v_type == VBLK || dp->v_type == VCHR)
103026f9a767SRodney W. Grimes 		size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
103126f9a767SRodney W. Grimes 
103216f62314SDavid Greenman 	counta = 0;
103316f62314SDavid Greenman 	if( count*PAGE_SIZE > bsize)
103416f62314SDavid Greenman 		counta = (count - reqpage) - 1;
103516f62314SDavid Greenman 	bpa = 0;
103616f62314SDavid Greenman 	sizea = 0;
103716f62314SDavid Greenman 	if( counta) {
103816f62314SDavid Greenman 		bpa = getpbuf();
103916f62314SDavid Greenman 		count -= counta;
104016f62314SDavid Greenman 		sizea = size - count*PAGE_SIZE;
104116f62314SDavid Greenman 		size = count * PAGE_SIZE;
104216f62314SDavid Greenman 	}
104316f62314SDavid Greenman 
104416f62314SDavid Greenman 	bp = getpbuf();
104516f62314SDavid Greenman 	kva = (vm_offset_t)bp->b_data;
104616f62314SDavid Greenman 
104726f9a767SRodney W. Grimes 	/*
104826f9a767SRodney W. Grimes 	 * and map the pages to be read into the kva
104926f9a767SRodney W. Grimes 	 */
105016f62314SDavid Greenman 	pmap_qenter(kva, m, count);
105126f9a767SRodney W. Grimes 	VHOLD(vp);
105226f9a767SRodney W. Grimes 
105326f9a767SRodney W. Grimes 	/* build a minimal buffer header */
105426f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY | B_READ | B_CALL;
105526f9a767SRodney W. Grimes 	bp->b_iodone = vnode_pager_iodone;
105626f9a767SRodney W. Grimes 	/* B_PHYS is not set, but it is nice to fill this in */
105726f9a767SRodney W. Grimes 	bp->b_proc = curproc;
105826f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
105926f9a767SRodney W. Grimes 	if (bp->b_rcred != NOCRED)
106026f9a767SRodney W. Grimes 		crhold(bp->b_rcred);
106126f9a767SRodney W. Grimes 	if (bp->b_wcred != NOCRED)
106226f9a767SRodney W. Grimes 		crhold(bp->b_wcred);
106326f9a767SRodney W. Grimes 	bp->b_blkno = firstaddr / DEV_BSIZE;
106426f9a767SRodney W. Grimes 	bgetvp(dp, bp);
106526f9a767SRodney W. Grimes 	bp->b_bcount = size;
106626f9a767SRodney W. Grimes 	bp->b_bufsize = size;
106726f9a767SRodney W. Grimes 
1068976e77fcSDavid Greenman 	cnt.v_vnodein++;
1069976e77fcSDavid Greenman 	cnt.v_vnodepgsin += count;
1070976e77fcSDavid Greenman 
107126f9a767SRodney W. Grimes 	/* do the input */
107226f9a767SRodney W. Grimes 	VOP_STRATEGY(bp);
1073976e77fcSDavid Greenman 
107416f62314SDavid Greenman 	if( counta) {
107516f62314SDavid Greenman 		for(i=0;i<counta;i++) {
107616f62314SDavid Greenman 			vm_page_deactivate(m[count+i]);
107716f62314SDavid Greenman 		}
1078c87801feSDavid Greenman 		pmap_qenter((vm_offset_t)bpa->b_data, &m[count], counta);
107916f62314SDavid Greenman 		++m[count]->object->paging_in_progress;
108016f62314SDavid Greenman 		VHOLD(vp);
108116f62314SDavid Greenman 		bpa->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC;
108216f62314SDavid Greenman 		bpa->b_iodone = vnode_pager_iodone;
108316f62314SDavid Greenman 		/* B_PHYS is not set, but it is nice to fill this in */
108416f62314SDavid Greenman 		bpa->b_proc = curproc;
108516f62314SDavid Greenman 		bpa->b_rcred = bpa->b_wcred = bpa->b_proc->p_ucred;
108616f62314SDavid Greenman 		if (bpa->b_rcred != NOCRED)
108716f62314SDavid Greenman 			crhold(bpa->b_rcred);
108816f62314SDavid Greenman 		if (bpa->b_wcred != NOCRED)
108916f62314SDavid Greenman 			crhold(bpa->b_wcred);
109016f62314SDavid Greenman 		bpa->b_blkno = (firstaddr + count * PAGE_SIZE) / DEV_BSIZE;
109116f62314SDavid Greenman 		bgetvp(dp, bpa);
109216f62314SDavid Greenman 		bpa->b_bcount = sizea;
109316f62314SDavid Greenman 		bpa->b_bufsize = counta*PAGE_SIZE;
109416f62314SDavid Greenman 
1095976e77fcSDavid Greenman 		cnt.v_vnodepgsin += counta;
109616f62314SDavid Greenman 		VOP_STRATEGY(bpa);
109716f62314SDavid Greenman 	}
109826f9a767SRodney W. Grimes 
109926f9a767SRodney W. Grimes 	s = splbio();
110026f9a767SRodney W. Grimes 	/* we definitely need to be at splbio here */
110126f9a767SRodney W. Grimes 
110226f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
110326f9a767SRodney W. Grimes 		tsleep((caddr_t) bp, PVM, "vnread", 0);
110426f9a767SRodney W. Grimes 	}
110526f9a767SRodney W. Grimes 	splx(s);
110626f9a767SRodney W. Grimes 	if ((bp->b_flags & B_ERROR) != 0)
110726f9a767SRodney W. Grimes 		error = EIO;
110826f9a767SRodney W. Grimes 
110926f9a767SRodney W. Grimes 	if (!error) {
111026f9a767SRodney W. Grimes 		if (size != count * PAGE_SIZE)
111126f9a767SRodney W. Grimes 			bzero((caddr_t) kva + size, PAGE_SIZE * count - size);
111226f9a767SRodney W. Grimes 	}
111316f62314SDavid Greenman 	pmap_qremove( kva, count);
111426f9a767SRodney W. Grimes 
111526f9a767SRodney W. Grimes 	/*
111626f9a767SRodney W. Grimes 	 * free the buffer header back to the swap buffer pool
111726f9a767SRodney W. Grimes 	 */
111826f9a767SRodney W. Grimes 	relpbuf(bp);
111926f9a767SRodney W. Grimes 	HOLDRELE(vp);
112026f9a767SRodney W. Grimes 
112126f9a767SRodney W. Grimes finishup:
112226f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
1123fff93ab6SDavid Greenman 		pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
112426f9a767SRodney W. Grimes 		m[i]->flags |= PG_CLEAN;
112526f9a767SRodney W. Grimes 		m[i]->flags &= ~PG_LAUNDRY;
112626f9a767SRodney W. Grimes 		if (i != reqpage) {
1127bbc0ec52SDavid Greenman 
112826f9a767SRodney W. Grimes 			/*
1129bbc0ec52SDavid Greenman 			 * whether or not to leave the page activated is up in
1130bbc0ec52SDavid Greenman 			 * the air, but we should put the page on a page queue
1131bbc0ec52SDavid Greenman 			 * somewhere. (it already is in the object). Result:
1132bbc0ec52SDavid Greenman 			 * It appears that emperical results show that
1133bbc0ec52SDavid Greenman 			 * deactivating pages is best.
113426f9a767SRodney W. Grimes 			 */
1135bbc0ec52SDavid Greenman 
113626f9a767SRodney W. Grimes 			/*
1137bbc0ec52SDavid Greenman 			 * just in case someone was asking for this page we
1138bbc0ec52SDavid Greenman 			 * now tell them that it is ok to use
113926f9a767SRodney W. Grimes 			 */
114026f9a767SRodney W. Grimes 			if (!error) {
114126f9a767SRodney W. Grimes 				vm_page_deactivate(m[i]);
114226f9a767SRodney W. Grimes 				PAGE_WAKEUP(m[i]);
114326f9a767SRodney W. Grimes 				m[i]->flags &= ~PG_FAKE;
114426f9a767SRodney W. Grimes 			} else {
114526f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
114626f9a767SRodney W. Grimes 			}
114726f9a767SRodney W. Grimes 		}
114826f9a767SRodney W. Grimes 	}
114926f9a767SRodney W. Grimes 	if (error) {
1150a83c285cSDavid Greenman 		printf("vnode_pager_input: I/O read error\n");
115126f9a767SRodney W. Grimes 	}
1152a83c285cSDavid Greenman 	return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
115326f9a767SRodney W. Grimes }
115426f9a767SRodney W. Grimes 
115526f9a767SRodney W. Grimes /*
115626f9a767SRodney W. Grimes  * old-style vnode pager output routine
115726f9a767SRodney W. Grimes  */
115826f9a767SRodney W. Grimes int
115926f9a767SRodney W. Grimes vnode_pager_output_old(vnp, m)
116026f9a767SRodney W. Grimes 	register vn_pager_t vnp;
116126f9a767SRodney W. Grimes 	vm_page_t m;
116226f9a767SRodney W. Grimes {
116326f9a767SRodney W. Grimes 	vm_offset_t foff;
116426f9a767SRodney W. Grimes 	vm_offset_t kva;
116526f9a767SRodney W. Grimes 	vm_offset_t size;
116626f9a767SRodney W. Grimes 	struct iovec aiov;
116726f9a767SRodney W. Grimes 	struct uio auio;
116826f9a767SRodney W. Grimes 	struct vnode *vp;
116926f9a767SRodney W. Grimes 	int     error;
117026f9a767SRodney W. Grimes 
117126f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
117226f9a767SRodney W. Grimes 	foff = m->offset + m->object->paging_offset;
1173bbc0ec52SDavid Greenman 
117426f9a767SRodney W. Grimes 	/*
117526f9a767SRodney W. Grimes 	 * Return failure if beyond current EOF
117626f9a767SRodney W. Grimes 	 */
117726f9a767SRodney W. Grimes 	if (foff >= vnp->vnp_size) {
117826f9a767SRodney W. Grimes 		return VM_PAGER_BAD;
117926f9a767SRodney W. Grimes 	} else {
118026f9a767SRodney W. Grimes 		size = PAGE_SIZE;
118126f9a767SRodney W. Grimes 		if (foff + size > vnp->vnp_size)
118226f9a767SRodney W. Grimes 			size = vnp->vnp_size - foff;
118326f9a767SRodney W. Grimes /*
118426f9a767SRodney W. Grimes  * Allocate a kernel virtual address and initialize so that
118526f9a767SRodney W. Grimes  * we can use VOP_WRITE routines.
118626f9a767SRodney W. Grimes  */
118726f9a767SRodney W. Grimes 		kva = vm_pager_map_page(m);
118826f9a767SRodney W. Grimes 		aiov.iov_base = (caddr_t) kva;
118926f9a767SRodney W. Grimes 		aiov.iov_len = size;
119026f9a767SRodney W. Grimes 		auio.uio_iov = &aiov;
119126f9a767SRodney W. Grimes 		auio.uio_iovcnt = 1;
119226f9a767SRodney W. Grimes 		auio.uio_offset = foff;
119326f9a767SRodney W. Grimes 		auio.uio_segflg = UIO_SYSSPACE;
119426f9a767SRodney W. Grimes 		auio.uio_rw = UIO_WRITE;
119526f9a767SRodney W. Grimes 		auio.uio_resid = size;
119626f9a767SRodney W. Grimes 		auio.uio_procp = (struct proc *) 0;
119726f9a767SRodney W. Grimes 
119826f9a767SRodney W. Grimes 		error = VOP_WRITE(vp, &auio, 0, curproc->p_ucred);
119926f9a767SRodney W. Grimes 
120026f9a767SRodney W. Grimes 		if (!error) {
120126f9a767SRodney W. Grimes 			if ((size - auio.uio_resid) == 0) {
120226f9a767SRodney W. Grimes 				error = EINVAL;
120326f9a767SRodney W. Grimes 			}
120426f9a767SRodney W. Grimes 		}
120526f9a767SRodney W. Grimes 		vm_pager_unmap_page(kva);
1206a83c285cSDavid Greenman 		return error ? VM_PAGER_ERROR: VM_PAGER_OK;
120726f9a767SRodney W. Grimes 	}
120826f9a767SRodney W. Grimes }
120926f9a767SRodney W. Grimes 
121026f9a767SRodney W. Grimes /*
121126f9a767SRodney W. Grimes  * vnode pager output on a small-block file system
121226f9a767SRodney W. Grimes  */
121326f9a767SRodney W. Grimes int
121426f9a767SRodney W. Grimes vnode_pager_output_smlfs(vnp, m)
121526f9a767SRodney W. Grimes 	vn_pager_t vnp;
121626f9a767SRodney W. Grimes 	vm_page_t m;
121726f9a767SRodney W. Grimes {
121826f9a767SRodney W. Grimes 	int     i;
121926f9a767SRodney W. Grimes 	int     s;
122026f9a767SRodney W. Grimes 	vm_offset_t paging_offset;
122126f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
122226f9a767SRodney W. Grimes 	struct buf *bp;
122326f9a767SRodney W. Grimes 	vm_offset_t foff;
122426f9a767SRodney W. Grimes 	vm_offset_t kva;
122526f9a767SRodney W. Grimes 	int     fileaddr;
122626f9a767SRodney W. Grimes 	vm_offset_t bsize;
122726f9a767SRodney W. Grimes 	int     error = 0;
122826f9a767SRodney W. Grimes 
122926f9a767SRodney W. Grimes 	paging_offset = m->object->paging_offset;
123026f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
123126f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
123226f9a767SRodney W. Grimes 	foff = m->offset + paging_offset;
123326f9a767SRodney W. Grimes 
123426f9a767SRodney W. Grimes 	VOP_BMAP(vp, foff, &dp, 0, 0);
123526f9a767SRodney W. Grimes 	kva = vm_pager_map_page(m);
123626f9a767SRodney W. Grimes 	for (i = 0; !error && i < (PAGE_SIZE / bsize); i++) {
1237bbc0ec52SDavid Greenman 
123826f9a767SRodney W. Grimes 		/*
123926f9a767SRodney W. Grimes 		 * calculate logical block and offset
124026f9a767SRodney W. Grimes 		 */
124126f9a767SRodney W. Grimes 		fileaddr = vnode_pager_addr(vp, foff + i * bsize);
124226f9a767SRodney W. Grimes 		if (fileaddr != -1) {
124326f9a767SRodney W. Grimes 			s = splbio();
124405f0fdd2SPoul-Henning Kamp 			bp = incore(vp, (foff / bsize) + i);
124505f0fdd2SPoul-Henning Kamp 			if (bp) {
124626f9a767SRodney W. Grimes 				bp = getblk(vp, (foff / bsize) + i, bp->b_bufsize, 0, 0);
124726f9a767SRodney W. Grimes 				bp->b_flags |= B_INVAL;
124826f9a767SRodney W. Grimes 				brelse(bp);
124926f9a767SRodney W. Grimes 			}
125026f9a767SRodney W. Grimes 			splx(s);
125126f9a767SRodney W. Grimes 
125226f9a767SRodney W. Grimes 			bp = getpbuf();
125326f9a767SRodney W. Grimes 			VHOLD(vp);
125426f9a767SRodney W. Grimes 
125526f9a767SRodney W. Grimes 			/* build a minimal buffer header */
125626f9a767SRodney W. Grimes 			bp->b_flags = B_BUSY | B_CALL | B_WRITE;
125726f9a767SRodney W. Grimes 			bp->b_iodone = vnode_pager_iodone;
125826f9a767SRodney W. Grimes 			bp->b_proc = curproc;
125926f9a767SRodney W. Grimes 			bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
126026f9a767SRodney W. Grimes 			if (bp->b_rcred != NOCRED)
126126f9a767SRodney W. Grimes 				crhold(bp->b_rcred);
126226f9a767SRodney W. Grimes 			if (bp->b_wcred != NOCRED)
126326f9a767SRodney W. Grimes 				crhold(bp->b_wcred);
126426f9a767SRodney W. Grimes 			bp->b_un.b_addr = (caddr_t) kva + i * bsize;
126526f9a767SRodney W. Grimes 			bp->b_blkno = fileaddr / DEV_BSIZE;
126626f9a767SRodney W. Grimes 			bgetvp(dp, bp);
126726f9a767SRodney W. Grimes 			++dp->v_numoutput;
126826f9a767SRodney W. Grimes 			/* for NFS */
126926f9a767SRodney W. Grimes 			bp->b_dirtyoff = 0;
127026f9a767SRodney W. Grimes 			bp->b_dirtyend = bsize;
127126f9a767SRodney W. Grimes 			bp->b_bcount = bsize;
127226f9a767SRodney W. Grimes 			bp->b_bufsize = bsize;
127326f9a767SRodney W. Grimes 
127426f9a767SRodney W. Grimes 			/* do the input */
127526f9a767SRodney W. Grimes 			VOP_STRATEGY(bp);
127626f9a767SRodney W. Grimes 
127726f9a767SRodney W. Grimes 			/* we definitely need to be at splbio here */
127826f9a767SRodney W. Grimes 
127926f9a767SRodney W. Grimes 			s = splbio();
128026f9a767SRodney W. Grimes 			while ((bp->b_flags & B_DONE) == 0) {
128126f9a767SRodney W. Grimes 				tsleep((caddr_t) bp, PVM, "vnswrt", 0);
128226f9a767SRodney W. Grimes 			}
128326f9a767SRodney W. Grimes 			splx(s);
128426f9a767SRodney W. Grimes 			if ((bp->b_flags & B_ERROR) != 0)
128526f9a767SRodney W. Grimes 				error = EIO;
128626f9a767SRodney W. Grimes 
128726f9a767SRodney W. Grimes 			/*
128826f9a767SRodney W. Grimes 			 * free the buffer header back to the swap buffer pool
128926f9a767SRodney W. Grimes 			 */
129026f9a767SRodney W. Grimes 			relpbuf(bp);
129126f9a767SRodney W. Grimes 			HOLDRELE(vp);
129226f9a767SRodney W. Grimes 		}
129326f9a767SRodney W. Grimes 	}
129426f9a767SRodney W. Grimes 	vm_pager_unmap_page(kva);
129526f9a767SRodney W. Grimes 	if (error)
1296a83c285cSDavid Greenman 		return VM_PAGER_ERROR;
129726f9a767SRodney W. Grimes 	else
129826f9a767SRodney W. Grimes 		return VM_PAGER_OK;
129926f9a767SRodney W. Grimes }
130026f9a767SRodney W. Grimes 
130126f9a767SRodney W. Grimes /*
130226f9a767SRodney W. Grimes  * generic vnode pager output routine
130326f9a767SRodney W. Grimes  */
130426f9a767SRodney W. Grimes int
130526f9a767SRodney W. Grimes vnode_pager_output(vnp, m, count, rtvals)
130626f9a767SRodney W. Grimes 	vn_pager_t vnp;
130726f9a767SRodney W. Grimes 	vm_page_t *m;
130826f9a767SRodney W. Grimes 	int     count;
130926f9a767SRodney W. Grimes 	int    *rtvals;
131026f9a767SRodney W. Grimes {
131126f9a767SRodney W. Grimes 	int     i, j;
131226f9a767SRodney W. Grimes 	vm_offset_t kva, foff;
131326f9a767SRodney W. Grimes 	int     size;
131426f9a767SRodney W. Grimes 	vm_object_t object;
131526f9a767SRodney W. Grimes 	vm_offset_t paging_offset;
131626f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
131726f9a767SRodney W. Grimes 	struct buf *bp;
131826f9a767SRodney W. Grimes 	vm_offset_t reqaddr;
131926f9a767SRodney W. Grimes 	int     bsize;
132026f9a767SRodney W. Grimes 	int     s;
132126f9a767SRodney W. Grimes 
132226f9a767SRodney W. Grimes 	int     error = 0;
132326f9a767SRodney W. Grimes 
132426f9a767SRodney W. Grimes retryoutput:
132526f9a767SRodney W. Grimes 	object = m[0]->object;	/* all vm_page_t items are in same object */
132626f9a767SRodney W. Grimes 	paging_offset = object->paging_offset;
132726f9a767SRodney W. Grimes 
132826f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
13294abc71c0SDavid Greenman 
13304abc71c0SDavid Greenman 	/*
13314abc71c0SDavid Greenman 	 * Make sure underlying filesystem is still mounted.
13324abc71c0SDavid Greenman 	 */
13334abc71c0SDavid Greenman 	if (vp->v_mount == NULL)
13344abc71c0SDavid Greenman 		return VM_PAGER_FAIL;
13354abc71c0SDavid Greenman 
133626f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
133726f9a767SRodney W. Grimes 
133826f9a767SRodney W. Grimes 	for (i = 0; i < count; i++)
133926f9a767SRodney W. Grimes 		rtvals[i] = VM_PAGER_AGAIN;
134026f9a767SRodney W. Grimes 
134126f9a767SRodney W. Grimes 	/*
1342bbc0ec52SDavid Greenman 	 * if the filesystem does not have a bmap, then use the old code
134326f9a767SRodney W. Grimes 	 */
134426f9a767SRodney W. Grimes 	if (VOP_BMAP(vp, m[0]->offset + paging_offset, &dp, 0, 0)) {
134526f9a767SRodney W. Grimes 
134626f9a767SRodney W. Grimes 		rtvals[0] = vnode_pager_output_old(vnp, m[0]);
134726f9a767SRodney W. Grimes 
134826f9a767SRodney W. Grimes 		pmap_clear_modify(VM_PAGE_TO_PHYS(m[0]));
134926f9a767SRodney W. Grimes 		m[0]->flags |= PG_CLEAN;
135026f9a767SRodney W. Grimes 		m[0]->flags &= ~PG_LAUNDRY;
1351976e77fcSDavid Greenman 		cnt.v_vnodeout++;
1352976e77fcSDavid Greenman 		cnt.v_vnodepgsout++;
135326f9a767SRodney W. Grimes 		return rtvals[0];
135426f9a767SRodney W. Grimes 	}
135526f9a767SRodney W. Grimes 
135626f9a767SRodney W. Grimes 	/*
1357bbc0ec52SDavid Greenman 	 * if the filesystem has a small blocksize, then use the small block
1358bbc0ec52SDavid Greenman 	 * filesystem output code
135926f9a767SRodney W. Grimes 	 */
136026f9a767SRodney W. Grimes 	if ((bsize < PAGE_SIZE) &&
136126f9a767SRodney W. Grimes 	    (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
136226f9a767SRodney W. Grimes 
136326f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
136426f9a767SRodney W. Grimes 			rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]);
136526f9a767SRodney W. Grimes 			if (rtvals[i] == VM_PAGER_OK) {
136626f9a767SRodney W. Grimes 				pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
136726f9a767SRodney W. Grimes 				m[i]->flags |= PG_CLEAN;
136826f9a767SRodney W. Grimes 				m[i]->flags &= ~PG_LAUNDRY;
136926f9a767SRodney W. Grimes 			}
137026f9a767SRodney W. Grimes 		}
1371976e77fcSDavid Greenman 		cnt.v_vnodeout++;
1372976e77fcSDavid Greenman 		cnt.v_vnodepgsout += count;
137326f9a767SRodney W. Grimes 		return rtvals[0];
137426f9a767SRodney W. Grimes 	}
137526f9a767SRodney W. Grimes 
137626f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
137726f9a767SRodney W. Grimes 		foff = m[i]->offset + paging_offset;
137826f9a767SRodney W. Grimes 		if (foff >= vnp->vnp_size) {
137926f9a767SRodney W. Grimes 			for (j = i; j < count; j++)
138026f9a767SRodney W. Grimes 				rtvals[j] = VM_PAGER_BAD;
138126f9a767SRodney W. Grimes 			count = i;
138226f9a767SRodney W. Grimes 			break;
138326f9a767SRodney W. Grimes 		}
138426f9a767SRodney W. Grimes 	}
138526f9a767SRodney W. Grimes 	if (count == 0) {
138626f9a767SRodney W. Grimes 		return rtvals[0];
138726f9a767SRodney W. Grimes 	}
138826f9a767SRodney W. Grimes 	foff = m[0]->offset + paging_offset;
138926f9a767SRodney W. Grimes 	reqaddr = vnode_pager_addr(vp, foff);
1390bbc0ec52SDavid Greenman 
139126f9a767SRodney W. Grimes 	/*
1392bbc0ec52SDavid Greenman 	 * Scan forward and stop for the first non-contiguous entry or stop
1393bbc0ec52SDavid Greenman 	 * for a page being in buffer cache.
139426f9a767SRodney W. Grimes 	 */
139526f9a767SRodney W. Grimes 	for (i = 1; i < count; i++) {
139626f9a767SRodney W. Grimes 		if (vnode_pager_addr(vp, m[i]->offset + paging_offset)
139726f9a767SRodney W. Grimes 		    != reqaddr + i * PAGE_SIZE) {
139826f9a767SRodney W. Grimes 			count = i;
139926f9a767SRodney W. Grimes 			break;
140026f9a767SRodney W. Grimes 		}
140126f9a767SRodney W. Grimes 	}
140226f9a767SRodney W. Grimes 
140326f9a767SRodney W. Grimes 	/*
140426f9a767SRodney W. Grimes 	 * calculate the size of the transfer
140526f9a767SRodney W. Grimes 	 */
140626f9a767SRodney W. Grimes 	size = count * PAGE_SIZE;
140726f9a767SRodney W. Grimes 	if ((foff + size) > vnp->vnp_size)
140826f9a767SRodney W. Grimes 		size = vnp->vnp_size - foff;
140926f9a767SRodney W. Grimes 
141026f9a767SRodney W. Grimes 	/*
141126f9a767SRodney W. Grimes 	 * round up physical size for real devices
141226f9a767SRodney W. Grimes 	 */
141326f9a767SRodney W. Grimes 	if (dp->v_type == VBLK || dp->v_type == VCHR)
141426f9a767SRodney W. Grimes 		size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
141526f9a767SRodney W. Grimes 
141616f62314SDavid Greenman 	bp = getpbuf();
141716f62314SDavid Greenman 	kva = (vm_offset_t)bp->b_data;
141826f9a767SRodney W. Grimes 	/*
141926f9a767SRodney W. Grimes 	 * and map the pages to be read into the kva
142026f9a767SRodney W. Grimes 	 */
142116f62314SDavid Greenman 	pmap_qenter(kva, m, count);
1422db141545SDavid Greenman #if 0
142326f9a767SRodney W. Grimes 	printf("vnode: writing foff: %d, devoff: %d, size: %d\n",
142426f9a767SRodney W. Grimes 		foff, reqaddr, size);
1425db141545SDavid Greenman #endif
1426bbc0ec52SDavid Greenman 
142726f9a767SRodney W. Grimes 	/*
142826f9a767SRodney W. Grimes 	 * next invalidate the incore vfs_bio data
142926f9a767SRodney W. Grimes 	 */
14308e58bf68SDavid Greenman #ifdef NOTYET
14318e58bf68SDavid Greenman 	if( (vp->v_flag & VVMIO) == 0) {
14328e58bf68SDavid Greenman #endif
143326f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
143426f9a767SRodney W. Grimes 			int     filblock = (foff + i * PAGE_SIZE) / bsize;
143526f9a767SRodney W. Grimes 			struct buf *fbp;
143626f9a767SRodney W. Grimes 
143726f9a767SRodney W. Grimes 			s = splbio();
143805f0fdd2SPoul-Henning Kamp 			fbp = incore(vp, filblock);
143905f0fdd2SPoul-Henning Kamp 			if (fbp) {
144026f9a767SRodney W. Grimes 				fbp = getblk(vp, filblock, fbp->b_bufsize, 0, 0);
1441bbc0ec52SDavid Greenman 				if (fbp->b_flags & B_DELWRI) {
1442bbc0ec52SDavid Greenman 					if (fbp->b_bufsize <= PAGE_SIZE)
1443bbc0ec52SDavid Greenman 						fbp->b_flags &= ~B_DELWRI;
1444bbc0ec52SDavid Greenman 					else {
1445bbc0ec52SDavid Greenman 						bwrite(fbp);
1446bbc0ec52SDavid Greenman 						fbp = getblk(vp, filblock,
1447bbc0ec52SDavid Greenman 							     fbp->b_bufsize, 0, 0);
1448bbc0ec52SDavid Greenman 					}
1449bbc0ec52SDavid Greenman 				}
145026f9a767SRodney W. Grimes 				fbp->b_flags |= B_INVAL;
145126f9a767SRodney W. Grimes 				brelse(fbp);
145226f9a767SRodney W. Grimes 			}
145326f9a767SRodney W. Grimes 			splx(s);
145426f9a767SRodney W. Grimes 		}
14558e58bf68SDavid Greenman #ifdef NOTYET
14568e58bf68SDavid Greenman 	}
14578e58bf68SDavid Greenman #endif
145826f9a767SRodney W. Grimes 
145926f9a767SRodney W. Grimes 
146026f9a767SRodney W. Grimes 	VHOLD(vp);
146126f9a767SRodney W. Grimes 	/* build a minimal buffer header */
146226f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY | B_WRITE | B_CALL;
146326f9a767SRodney W. Grimes 	bp->b_iodone = vnode_pager_iodone;
146426f9a767SRodney W. Grimes 	/* B_PHYS is not set, but it is nice to fill this in */
146526f9a767SRodney W. Grimes 	bp->b_proc = curproc;
146626f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
146726f9a767SRodney W. Grimes 
146826f9a767SRodney W. Grimes 	if (bp->b_rcred != NOCRED)
146926f9a767SRodney W. Grimes 		crhold(bp->b_rcred);
147026f9a767SRodney W. Grimes 	if (bp->b_wcred != NOCRED)
147126f9a767SRodney W. Grimes 		crhold(bp->b_wcred);
147226f9a767SRodney W. Grimes 	bp->b_blkno = reqaddr / DEV_BSIZE;
147326f9a767SRodney W. Grimes 	bgetvp(dp, bp);
147426f9a767SRodney W. Grimes 	++dp->v_numoutput;
147526f9a767SRodney W. Grimes 
147626f9a767SRodney W. Grimes 	/* for NFS */
147726f9a767SRodney W. Grimes 	bp->b_dirtyoff = 0;
147826f9a767SRodney W. Grimes 	bp->b_dirtyend = size;
147926f9a767SRodney W. Grimes 
148026f9a767SRodney W. Grimes 	bp->b_bcount = size;
148126f9a767SRodney W. Grimes 	bp->b_bufsize = size;
148226f9a767SRodney W. Grimes 
1483976e77fcSDavid Greenman 	cnt.v_vnodeout++;
1484976e77fcSDavid Greenman 	cnt.v_vnodepgsout += count;
1485976e77fcSDavid Greenman 
148626f9a767SRodney W. Grimes 	/* do the output */
148726f9a767SRodney W. Grimes 	VOP_STRATEGY(bp);
148826f9a767SRodney W. Grimes 
148926f9a767SRodney W. Grimes 	s = splbio();
149026f9a767SRodney W. Grimes 
149126f9a767SRodney W. Grimes 	/* we definitely need to be at splbio here */
149226f9a767SRodney W. Grimes 
149326f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
149426f9a767SRodney W. Grimes 		tsleep((caddr_t) bp, PVM, "vnwrite", 0);
149526f9a767SRodney W. Grimes 	}
149626f9a767SRodney W. Grimes 	splx(s);
149726f9a767SRodney W. Grimes 
149826f9a767SRodney W. Grimes 	if ((bp->b_flags & B_ERROR) != 0)
149926f9a767SRodney W. Grimes 		error = EIO;
150026f9a767SRodney W. Grimes 
150116f62314SDavid Greenman 	pmap_qremove( kva, count);
150226f9a767SRodney W. Grimes 
150326f9a767SRodney W. Grimes 	/*
150426f9a767SRodney W. Grimes 	 * free the buffer header back to the swap buffer pool
150526f9a767SRodney W. Grimes 	 */
150626f9a767SRodney W. Grimes 	relpbuf(bp);
150726f9a767SRodney W. Grimes 	HOLDRELE(vp);
150826f9a767SRodney W. Grimes 
150926f9a767SRodney W. Grimes 	if (!error) {
151026f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
151126f9a767SRodney W. Grimes 			pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
151226f9a767SRodney W. Grimes 			m[i]->flags |= PG_CLEAN;
151326f9a767SRodney W. Grimes 			m[i]->flags &= ~PG_LAUNDRY;
151426f9a767SRodney W. Grimes 			rtvals[i] = VM_PAGER_OK;
151526f9a767SRodney W. Grimes 		}
151626f9a767SRodney W. Grimes 	} else if (count != 1) {
151726f9a767SRodney W. Grimes 		error = 0;
151826f9a767SRodney W. Grimes 		count = 1;
151926f9a767SRodney W. Grimes 		goto retryoutput;
152026f9a767SRodney W. Grimes 	}
152126f9a767SRodney W. Grimes 	if (error) {
1522a83c285cSDavid Greenman 		printf("vnode_pager_output: I/O write error\n");
152326f9a767SRodney W. Grimes 	}
1524a83c285cSDavid Greenman 	return (error ? VM_PAGER_ERROR: VM_PAGER_OK);
152526f9a767SRodney W. Grimes }
1526