xref: /freebsd/sys/vm/vnode_pager.c (revision 0d94caffcad13f94e28da90c9e945749e0659463)
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
400d94caffSDavid Greenman  *	$Id: vnode_pager.c,v 1.18 1994/11/24 14:43:22 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 /*
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>
710d94caffSDavid Greenman #include <sys/kernel.h>
72df8bae1dSRodney W. Grimes #include <sys/proc.h>
73df8bae1dSRodney W. Grimes #include <sys/malloc.h>
74df8bae1dSRodney W. Grimes #include <sys/vnode.h>
75df8bae1dSRodney W. Grimes #include <sys/uio.h>
76df8bae1dSRodney W. Grimes #include <sys/mount.h>
77df8bae1dSRodney W. Grimes 
78df8bae1dSRodney W. Grimes #include <vm/vm.h>
79df8bae1dSRodney W. Grimes #include <vm/vm_page.h>
80df8bae1dSRodney W. Grimes #include <vm/vnode_pager.h>
81df8bae1dSRodney W. Grimes 
8226f9a767SRodney W. Grimes #include <sys/buf.h>
8326f9a767SRodney W. Grimes #include <miscfs/specfs/specdev.h>
84df8bae1dSRodney W. Grimes 
8526f9a767SRodney W. Grimes int vnode_pager_putmulti();
86df8bae1dSRodney W. Grimes 
8726f9a767SRodney W. Grimes void vnode_pager_init();
8826f9a767SRodney W. Grimes vm_pager_t vnode_pager_alloc(caddr_t, vm_offset_t, vm_prot_t, vm_offset_t);
8926f9a767SRodney W. Grimes void vnode_pager_dealloc();
9026f9a767SRodney W. Grimes int vnode_pager_getpage();
9126f9a767SRodney W. Grimes int vnode_pager_getmulti();
9226f9a767SRodney W. Grimes int vnode_pager_putpage();
9326f9a767SRodney W. Grimes boolean_t vnode_pager_haspage();
94df8bae1dSRodney W. Grimes 
95df8bae1dSRodney W. Grimes struct pagerops vnodepagerops = {
96df8bae1dSRodney W. Grimes 	vnode_pager_init,
97df8bae1dSRodney W. Grimes 	vnode_pager_alloc,
98df8bae1dSRodney W. Grimes 	vnode_pager_dealloc,
99df8bae1dSRodney W. Grimes 	vnode_pager_getpage,
10026f9a767SRodney W. Grimes 	vnode_pager_getmulti,
101df8bae1dSRodney W. Grimes 	vnode_pager_putpage,
10226f9a767SRodney W. Grimes 	vnode_pager_putmulti,
10326f9a767SRodney W. Grimes 	vnode_pager_haspage
104df8bae1dSRodney W. Grimes };
105df8bae1dSRodney W. Grimes 
10616f62314SDavid Greenman 
10716f62314SDavid Greenman 
10826f9a767SRodney W. Grimes static int vnode_pager_input(vn_pager_t vnp, vm_page_t * m, int count, int reqpage);
10926f9a767SRodney W. Grimes static int vnode_pager_output(vn_pager_t vnp, vm_page_t * m, int count, int *rtvals);
11026f9a767SRodney W. Grimes 
11126f9a767SRodney W. Grimes extern vm_map_t pager_map;
11226f9a767SRodney W. Grimes 
11326f9a767SRodney W. Grimes struct pagerlst vnode_pager_list;	/* list of managed vnodes */
11426f9a767SRodney W. Grimes 
11526f9a767SRodney W. Grimes #define MAXBP (PAGE_SIZE/DEV_BSIZE);
11626f9a767SRodney W. Grimes 
11726f9a767SRodney W. Grimes void
118df8bae1dSRodney W. Grimes vnode_pager_init()
119df8bae1dSRodney W. Grimes {
120df8bae1dSRodney W. Grimes 	TAILQ_INIT(&vnode_pager_list);
121df8bae1dSRodney W. Grimes }
122df8bae1dSRodney W. Grimes 
123df8bae1dSRodney W. Grimes /*
124df8bae1dSRodney W. Grimes  * Allocate (or lookup) pager for a vnode.
125df8bae1dSRodney W. Grimes  * Handle is a vnode pointer.
126df8bae1dSRodney W. Grimes  */
12726f9a767SRodney W. Grimes vm_pager_t
12826f9a767SRodney W. Grimes vnode_pager_alloc(handle, size, prot, offset)
129df8bae1dSRodney W. Grimes 	caddr_t handle;
130df8bae1dSRodney W. Grimes 	vm_size_t size;
131df8bae1dSRodney W. Grimes 	vm_prot_t prot;
13226f9a767SRodney W. Grimes 	vm_offset_t offset;
133df8bae1dSRodney W. Grimes {
134df8bae1dSRodney W. Grimes 	register vm_pager_t pager;
135df8bae1dSRodney W. Grimes 	register vn_pager_t vnp;
1360d94caffSDavid Greenman 	vm_object_t object, tobject;
137df8bae1dSRodney W. Grimes 	struct vattr vattr;
138df8bae1dSRodney W. Grimes 	struct vnode *vp;
139df8bae1dSRodney W. Grimes 	struct proc *p = curproc;	/* XXX */
1400d94caffSDavid Greenman 	int rtval;
141df8bae1dSRodney W. Grimes 
142df8bae1dSRodney W. Grimes 	/*
143df8bae1dSRodney W. Grimes 	 * Pageout to vnode, no can do yet.
144df8bae1dSRodney W. Grimes 	 */
145df8bae1dSRodney W. Grimes 	if (handle == NULL)
146df8bae1dSRodney W. Grimes 		return (NULL);
147df8bae1dSRodney W. Grimes 
148df8bae1dSRodney W. Grimes 	/*
149bbc0ec52SDavid Greenman 	 * Vnodes keep a pointer to any associated pager so no need to lookup
150bbc0ec52SDavid Greenman 	 * with vm_pager_lookup.
151df8bae1dSRodney W. Grimes 	 */
152df8bae1dSRodney W. Grimes 	vp = (struct vnode *) handle;
1530d94caffSDavid Greenman 	while ((object = (vm_object_t) vp->v_vmdata) && (object->flags & OBJ_DEAD))
1540d94caffSDavid Greenman 		tsleep((caddr_t) object, PVM, "vadead", 0);
1550d94caffSDavid Greenman 
1568e58bf68SDavid Greenman 	pager = NULL;
1578e58bf68SDavid Greenman 	if (object != NULL)
1588e58bf68SDavid Greenman 		pager = object->pager;
159df8bae1dSRodney W. Grimes 	if (pager == NULL) {
160bbc0ec52SDavid Greenman 
161df8bae1dSRodney W. Grimes 		/*
162df8bae1dSRodney W. Grimes 		 * Allocate pager structures
163df8bae1dSRodney W. Grimes 		 */
164df8bae1dSRodney W. Grimes 		pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK);
165df8bae1dSRodney W. Grimes 		if (pager == NULL)
166df8bae1dSRodney W. Grimes 			return (NULL);
167df8bae1dSRodney W. Grimes 		vnp = (vn_pager_t) malloc(sizeof *vnp, M_VMPGDATA, M_WAITOK);
168df8bae1dSRodney W. Grimes 		if (vnp == NULL) {
169df8bae1dSRodney W. Grimes 			free((caddr_t) pager, M_VMPAGER);
170df8bae1dSRodney W. Grimes 			return (NULL);
171df8bae1dSRodney W. Grimes 		}
172df8bae1dSRodney W. Grimes 		/*
173df8bae1dSRodney W. Grimes 		 * And an object of the appropriate size
174df8bae1dSRodney W. Grimes 		 */
1750d94caffSDavid Greenman 		if ((rtval = VOP_GETATTR(vp, &vattr, p->p_ucred, p)) == 0) {
176df8bae1dSRodney W. Grimes 			object = vm_object_allocate(round_page(vattr.va_size));
177df8bae1dSRodney W. Grimes 			vm_object_enter(object, pager);
178df8bae1dSRodney W. Grimes 			vm_object_setpager(object, pager, 0, TRUE);
179df8bae1dSRodney W. Grimes 		} else {
1800d94caffSDavid Greenman 			printf("Error in getattr: %d\n", rtval);
181df8bae1dSRodney W. Grimes 			free((caddr_t) vnp, M_VMPGDATA);
182df8bae1dSRodney W. Grimes 			free((caddr_t) pager, M_VMPAGER);
183df8bae1dSRodney W. Grimes 			return (NULL);
184df8bae1dSRodney W. Grimes 		}
185bbc0ec52SDavid Greenman 
186df8bae1dSRodney W. Grimes 		/*
187df8bae1dSRodney W. Grimes 		 * Hold a reference to the vnode and initialize pager data.
188df8bae1dSRodney W. Grimes 		 */
189df8bae1dSRodney W. Grimes 		VREF(vp);
190df8bae1dSRodney W. Grimes 		vnp->vnp_flags = 0;
191df8bae1dSRodney W. Grimes 		vnp->vnp_vp = vp;
192df8bae1dSRodney W. Grimes 		vnp->vnp_size = vattr.va_size;
19326f9a767SRodney W. Grimes 
194df8bae1dSRodney W. Grimes 		TAILQ_INSERT_TAIL(&vnode_pager_list, pager, pg_list);
195df8bae1dSRodney W. Grimes 		pager->pg_handle = handle;
196df8bae1dSRodney W. Grimes 		pager->pg_type = PG_VNODE;
197df8bae1dSRodney W. Grimes 		pager->pg_ops = &vnodepagerops;
19826f9a767SRodney W. Grimes 		pager->pg_data = (caddr_t) vnp;
1998e58bf68SDavid Greenman 		vp->v_vmdata = (caddr_t) object;
200df8bae1dSRodney W. Grimes 	} else {
201bbc0ec52SDavid Greenman 
202df8bae1dSRodney W. Grimes 		/*
203bbc0ec52SDavid Greenman 		 * vm_object_lookup() will remove the object from the cache if
204bbc0ec52SDavid Greenman 		 * found and also gain a reference to the object.
205df8bae1dSRodney W. Grimes 		 */
2068e58bf68SDavid Greenman 		(void) vm_object_lookup(pager);
207df8bae1dSRodney W. Grimes 	}
208df8bae1dSRodney W. Grimes 	return (pager);
209df8bae1dSRodney W. Grimes }
210df8bae1dSRodney W. Grimes 
21126f9a767SRodney W. Grimes void
212df8bae1dSRodney W. Grimes vnode_pager_dealloc(pager)
213df8bae1dSRodney W. Grimes 	vm_pager_t pager;
214df8bae1dSRodney W. Grimes {
215df8bae1dSRodney W. Grimes 	register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
216df8bae1dSRodney W. Grimes 	register struct vnode *vp;
2170d94caffSDavid Greenman 	vm_object_t object;
218df8bae1dSRodney W. Grimes 
21905f0fdd2SPoul-Henning Kamp 	vp = vnp->vnp_vp;
22005f0fdd2SPoul-Henning Kamp 	if (vp) {
2210d94caffSDavid Greenman 		int s = splbio();
2220d94caffSDavid Greenman 
2230d94caffSDavid Greenman 		object = (vm_object_t) vp->v_vmdata;
2240d94caffSDavid Greenman 		if (object) {
2250d94caffSDavid Greenman 			while (object->paging_in_progress) {
2260d94caffSDavid Greenman 				tsleep(object, PVM, "vnpdea", 0);
2270d94caffSDavid Greenman 			}
2280d94caffSDavid Greenman 		}
2290d94caffSDavid Greenman 		splx(s);
2300d94caffSDavid Greenman 
231df8bae1dSRodney W. Grimes 		vp->v_vmdata = NULL;
2328e58bf68SDavid Greenman 		vp->v_flag &= ~(VTEXT | VVMIO);
233df8bae1dSRodney W. Grimes 		vrele(vp);
234df8bae1dSRodney W. Grimes 	}
235df8bae1dSRodney W. Grimes 	TAILQ_REMOVE(&vnode_pager_list, pager, pg_list);
236df8bae1dSRodney W. Grimes 	free((caddr_t) vnp, M_VMPGDATA);
237df8bae1dSRodney W. Grimes 	free((caddr_t) pager, M_VMPAGER);
238df8bae1dSRodney W. Grimes }
239df8bae1dSRodney W. Grimes 
24026f9a767SRodney W. Grimes int
24126f9a767SRodney W. Grimes vnode_pager_getmulti(pager, m, count, reqpage, sync)
242df8bae1dSRodney W. Grimes 	vm_pager_t pager;
24326f9a767SRodney W. Grimes 	vm_page_t *m;
24426f9a767SRodney W. Grimes 	int count;
24526f9a767SRodney W. Grimes 	int reqpage;
246df8bae1dSRodney W. Grimes 	boolean_t sync;
247df8bae1dSRodney W. Grimes {
248df8bae1dSRodney W. Grimes 
24926f9a767SRodney W. Grimes 	return vnode_pager_input((vn_pager_t) pager->pg_data, m, count, reqpage);
250df8bae1dSRodney W. Grimes }
251df8bae1dSRodney W. Grimes 
25226f9a767SRodney W. Grimes int
25326f9a767SRodney W. Grimes vnode_pager_getpage(pager, m, sync)
254df8bae1dSRodney W. Grimes 	vm_pager_t pager;
25526f9a767SRodney W. Grimes 	vm_page_t m;
25626f9a767SRodney W. Grimes 	boolean_t sync;
25726f9a767SRodney W. Grimes {
25826f9a767SRodney W. Grimes 
25926f9a767SRodney W. Grimes 	vm_page_t marray[1];
260bbc0ec52SDavid Greenman 
26126f9a767SRodney W. Grimes 	if (pager == NULL)
26226f9a767SRodney W. Grimes 		return FALSE;
26326f9a767SRodney W. Grimes 	marray[0] = m;
26426f9a767SRodney W. Grimes 
26526f9a767SRodney W. Grimes 	return vnode_pager_input((vn_pager_t) pager->pg_data, marray, 1, 0);
26626f9a767SRodney W. Grimes }
26726f9a767SRodney W. Grimes 
26826f9a767SRodney W. Grimes boolean_t
26926f9a767SRodney W. Grimes vnode_pager_putpage(pager, m, sync)
27026f9a767SRodney W. Grimes 	vm_pager_t pager;
27126f9a767SRodney W. Grimes 	vm_page_t m;
272df8bae1dSRodney W. Grimes 	boolean_t sync;
273df8bae1dSRodney W. Grimes {
27426f9a767SRodney W. Grimes 	vm_page_t marray[1];
27526f9a767SRodney W. Grimes 	int rtvals[1];
276df8bae1dSRodney W. Grimes 
277df8bae1dSRodney W. Grimes 	if (pager == NULL)
27826f9a767SRodney W. Grimes 		return FALSE;
27926f9a767SRodney W. Grimes 	marray[0] = m;
28026f9a767SRodney W. Grimes 	vnode_pager_output((vn_pager_t) pager->pg_data, marray, 1, rtvals);
28126f9a767SRodney W. Grimes 	return rtvals[0];
282df8bae1dSRodney W. Grimes }
283df8bae1dSRodney W. Grimes 
28426f9a767SRodney W. Grimes int
28526f9a767SRodney W. Grimes vnode_pager_putmulti(pager, m, c, sync, rtvals)
28626f9a767SRodney W. Grimes 	vm_pager_t pager;
28726f9a767SRodney W. Grimes 	vm_page_t *m;
28826f9a767SRodney W. Grimes 	int c;
28926f9a767SRodney W. Grimes 	boolean_t sync;
29026f9a767SRodney W. Grimes 	int *rtvals;
29126f9a767SRodney W. Grimes {
29226f9a767SRodney W. Grimes 	return vnode_pager_output((vn_pager_t) pager->pg_data, m, c, rtvals);
29326f9a767SRodney W. Grimes }
29426f9a767SRodney W. Grimes 
29526f9a767SRodney W. Grimes 
29626f9a767SRodney W. Grimes boolean_t
297df8bae1dSRodney W. Grimes vnode_pager_haspage(pager, offset)
298df8bae1dSRodney W. Grimes 	vm_pager_t pager;
299df8bae1dSRodney W. Grimes 	vm_offset_t offset;
300df8bae1dSRodney W. Grimes {
301df8bae1dSRodney W. Grimes 	register vn_pager_t vnp = (vn_pager_t) pager->pg_data;
3024abc71c0SDavid Greenman 	register struct vnode *vp = vnp->vnp_vp;
303df8bae1dSRodney W. Grimes 	daddr_t bn;
304df8bae1dSRodney W. Grimes 	int err;
305317205caSDavid Greenman 	daddr_t block;
306df8bae1dSRodney W. Grimes 
307df8bae1dSRodney W. Grimes 	/*
3080d94caffSDavid Greenman 	 * If filesystem no longer mounted or offset beyond end of file we do
3090d94caffSDavid Greenman 	 * not have the page.
310df8bae1dSRodney W. Grimes 	 */
3114abc71c0SDavid Greenman 	if ((vp->v_mount == NULL) || (offset >= vnp->vnp_size))
3124abc71c0SDavid Greenman 		return FALSE;
313df8bae1dSRodney W. Grimes 
3144abc71c0SDavid Greenman 	block = offset / vp->v_mount->mnt_stat.f_iosize;
3154abc71c0SDavid Greenman 	if (incore(vp, block))
316317205caSDavid Greenman 		return TRUE;
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 	 */
350df8bae1dSRodney W. Grimes 	if (vp == NULL || vp->v_type != VREG || vp->v_vmdata == NULL)
351df8bae1dSRodney W. Grimes 		return;
352bbc0ec52SDavid Greenman 
353df8bae1dSRodney W. Grimes 	/*
354df8bae1dSRodney W. Grimes 	 * Hasn't changed size
355df8bae1dSRodney W. Grimes 	 */
3568e58bf68SDavid Greenman 	object = (vm_object_t) vp->v_vmdata;
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 	 * No object. This can happen during object termination since
367bbc0ec52SDavid Greenman 	 * vm_object_page_clean is called after the object has been removed
368bbc0ec52SDavid Greenman 	 * from the hash table, and clean may cause vnode write operations
369bbc0ec52SDavid Greenman 	 * which can wind up back here.
370df8bae1dSRodney W. Grimes 	 */
371df8bae1dSRodney W. Grimes 	object = vm_object_lookup(pager);
372df8bae1dSRodney W. Grimes 	if (object == NULL)
373df8bae1dSRodney W. Grimes 		return;
374df8bae1dSRodney W. Grimes 
375df8bae1dSRodney W. Grimes 	/*
376bbc0ec52SDavid Greenman 	 * File has shrunk. Toss any cached pages beyond the new EOF.
377df8bae1dSRodney W. Grimes 	 */
378bbc0ec52SDavid Greenman 	if (nsize < vnp->vnp_size) {
3790d94caffSDavid Greenman 		if (round_page((vm_offset_t) nsize) < vnp->vnp_size) {
380df8bae1dSRodney W. Grimes 			vm_object_lock(object);
381df8bae1dSRodney W. Grimes 			vm_object_page_remove(object,
382bbc0ec52SDavid Greenman 			    round_page((vm_offset_t) nsize), vnp->vnp_size);
383bbc0ec52SDavid Greenman 			vm_object_unlock(object);
3840d94caffSDavid Greenman 		}
385bbc0ec52SDavid Greenman 		/*
386bbc0ec52SDavid Greenman 		 * this gets rid of garbage at the end of a page that is now
387bbc0ec52SDavid Greenman 		 * only partially backed by the vnode...
388bbc0ec52SDavid Greenman 		 */
389bbc0ec52SDavid Greenman 		if (nsize & PAGE_MASK) {
390bbc0ec52SDavid Greenman 			vm_offset_t kva;
391bbc0ec52SDavid Greenman 			vm_page_t m;
392bbc0ec52SDavid Greenman 
393bbc0ec52SDavid Greenman 			m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize));
394bbc0ec52SDavid Greenman 			if (m) {
395bbc0ec52SDavid Greenman 				kva = vm_pager_map_page(m);
396bbc0ec52SDavid Greenman 				bzero((caddr_t) kva + (nsize & PAGE_MASK),
397bbc0ec52SDavid Greenman 				    round_page(nsize) - nsize);
398bbc0ec52SDavid Greenman 				vm_pager_unmap_page(kva);
399bbc0ec52SDavid Greenman 			}
400bbc0ec52SDavid Greenman 		}
401bbc0ec52SDavid Greenman 	}
402df8bae1dSRodney W. Grimes 	vnp->vnp_size = (vm_offset_t) nsize;
403bbc0ec52SDavid Greenman 	object->size = round_page(nsize);
404bbc0ec52SDavid Greenman 
405df8bae1dSRodney W. Grimes 	vm_object_deallocate(object);
406df8bae1dSRodney W. Grimes }
407df8bae1dSRodney W. Grimes 
408df8bae1dSRodney W. Grimes void
409df8bae1dSRodney W. Grimes vnode_pager_umount(mp)
410df8bae1dSRodney W. Grimes 	register struct mount *mp;
411df8bae1dSRodney W. Grimes {
412df8bae1dSRodney W. Grimes 	register vm_pager_t pager, npager;
413df8bae1dSRodney W. Grimes 	struct vnode *vp;
414df8bae1dSRodney W. Grimes 
41526f9a767SRodney W. Grimes 	pager = vnode_pager_list.tqh_first;
41626f9a767SRodney W. Grimes 	while (pager) {
417bbc0ec52SDavid Greenman 
418df8bae1dSRodney W. Grimes 		/*
419bbc0ec52SDavid Greenman 		 * Save the next pointer now since uncaching may terminate the
420bbc0ec52SDavid Greenman 		 * object and render pager invalid
421df8bae1dSRodney W. Grimes 		 */
422df8bae1dSRodney W. Grimes 		vp = ((vn_pager_t) pager->pg_data)->vnp_vp;
42326f9a767SRodney W. Grimes 		npager = pager->pg_list.tqe_next;
42426f9a767SRodney W. Grimes 		if (mp == (struct mount *) 0 || vp->v_mount == mp)
425df8bae1dSRodney W. Grimes 			(void) vnode_pager_uncache(vp);
42626f9a767SRodney W. Grimes 		pager = npager;
427df8bae1dSRodney W. Grimes 	}
428df8bae1dSRodney W. Grimes }
429df8bae1dSRodney W. Grimes 
430df8bae1dSRodney W. Grimes /*
431df8bae1dSRodney W. Grimes  * Remove vnode associated object from the object cache.
432df8bae1dSRodney W. Grimes  *
43326f9a767SRodney W. Grimes  * Note: this routine may be invoked as a result of a pager put
43426f9a767SRodney W. Grimes  * operation (possibly at object termination time), so we must be careful.
43526f9a767SRodney W. Grimes  */
43626f9a767SRodney W. Grimes boolean_t
43726f9a767SRodney W. Grimes vnode_pager_uncache(vp)
43826f9a767SRodney W. Grimes 	register struct vnode *vp;
43926f9a767SRodney W. Grimes {
44026f9a767SRodney W. Grimes 	register vm_object_t object;
44126f9a767SRodney W. Grimes 	boolean_t uncached, locked;
44226f9a767SRodney W. Grimes 	vm_pager_t pager;
44326f9a767SRodney W. Grimes 
44426f9a767SRodney W. Grimes 	/*
44526f9a767SRodney W. Grimes 	 * Not a mapped vnode
44626f9a767SRodney W. Grimes 	 */
4478e58bf68SDavid Greenman 	object = (vm_object_t) vp->v_vmdata;
4488e58bf68SDavid Greenman 	if (object == NULL)
4498e58bf68SDavid Greenman 		return (TRUE);
4500d94caffSDavid Greenman 
4518e58bf68SDavid Greenman 	pager = object->pager;
45226f9a767SRodney W. Grimes 	if (pager == NULL)
45326f9a767SRodney W. Grimes 		return (TRUE);
454bbc0ec52SDavid Greenman 
45526f9a767SRodney W. Grimes 	/*
456bbc0ec52SDavid Greenman 	 * Unlock the vnode if it is currently locked. We do this since
457bbc0ec52SDavid Greenman 	 * uncaching the object may result in its destruction which may
458bbc0ec52SDavid Greenman 	 * initiate paging activity which may necessitate locking the vnode.
45926f9a767SRodney W. Grimes 	 */
46026f9a767SRodney W. Grimes 	locked = VOP_ISLOCKED(vp);
46126f9a767SRodney W. Grimes 	if (locked)
46226f9a767SRodney W. Grimes 		VOP_UNLOCK(vp);
463bbc0ec52SDavid Greenman 
46426f9a767SRodney W. Grimes 	/*
465bbc0ec52SDavid Greenman 	 * Must use vm_object_lookup() as it actually removes the object from
466bbc0ec52SDavid Greenman 	 * the cache list.
46726f9a767SRodney W. Grimes 	 */
46826f9a767SRodney W. Grimes 	object = vm_object_lookup(pager);
46926f9a767SRodney W. Grimes 	if (object) {
47026f9a767SRodney W. Grimes 		uncached = (object->ref_count <= 1);
47126f9a767SRodney W. Grimes 		pager_cache(object, FALSE);
47226f9a767SRodney W. Grimes 	} else
47326f9a767SRodney W. Grimes 		uncached = TRUE;
47426f9a767SRodney W. Grimes 	if (locked)
47526f9a767SRodney W. Grimes 		VOP_LOCK(vp);
47626f9a767SRodney W. Grimes 	return (uncached);
47726f9a767SRodney W. Grimes }
478df8bae1dSRodney W. Grimes 
47926f9a767SRodney W. Grimes 
48026f9a767SRodney W. Grimes void
48126f9a767SRodney W. Grimes vnode_pager_freepage(m)
48226f9a767SRodney W. Grimes 	vm_page_t m;
483df8bae1dSRodney W. Grimes {
48426f9a767SRodney W. Grimes 	PAGE_WAKEUP(m);
48526f9a767SRodney W. Grimes 	vm_page_free(m);
48626f9a767SRodney W. Grimes }
48726f9a767SRodney W. Grimes 
48826f9a767SRodney W. Grimes /*
48926f9a767SRodney W. Grimes  * calculate the linear (byte) disk address of specified virtual
49026f9a767SRodney W. Grimes  * file address
49126f9a767SRodney W. Grimes  */
49226f9a767SRodney W. Grimes vm_offset_t
49326f9a767SRodney W. Grimes vnode_pager_addr(vp, address)
49426f9a767SRodney W. Grimes 	struct vnode *vp;
49526f9a767SRodney W. Grimes 	vm_offset_t address;
49626f9a767SRodney W. Grimes {
49726f9a767SRodney W. Grimes 	int rtaddress;
49826f9a767SRodney W. Grimes 	int bsize;
49926f9a767SRodney W. Grimes 	vm_offset_t block;
50026f9a767SRodney W. Grimes 	struct vnode *rtvp;
50126f9a767SRodney W. Grimes 	int err;
50226f9a767SRodney W. Grimes 	int vblock, voffset;
50326f9a767SRodney W. Grimes 
5040d94caffSDavid Greenman 	if ((int) address < 0)
5050d94caffSDavid Greenman 		return -1;
5060d94caffSDavid Greenman 
50726f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
50826f9a767SRodney W. Grimes 	vblock = address / bsize;
50926f9a767SRodney W. Grimes 	voffset = address % bsize;
51026f9a767SRodney W. Grimes 
51126f9a767SRodney W. Grimes 	err = VOP_BMAP(vp, vblock, &rtvp, &block, 0);
51226f9a767SRodney W. Grimes 
51326f9a767SRodney W. Grimes 	if (err)
51426f9a767SRodney W. Grimes 		rtaddress = -1;
51526f9a767SRodney W. Grimes 	else
51626f9a767SRodney W. Grimes 		rtaddress = block * DEV_BSIZE + voffset;
51726f9a767SRodney W. Grimes 
51826f9a767SRodney W. Grimes 	return rtaddress;
51926f9a767SRodney W. Grimes }
52026f9a767SRodney W. Grimes 
52126f9a767SRodney W. Grimes /*
52226f9a767SRodney W. Grimes  * interrupt routine for I/O completion
52326f9a767SRodney W. Grimes  */
52426f9a767SRodney W. Grimes void
52526f9a767SRodney W. Grimes vnode_pager_iodone(bp)
52626f9a767SRodney W. Grimes 	struct buf *bp;
52726f9a767SRodney W. Grimes {
52826f9a767SRodney W. Grimes 	bp->b_flags |= B_DONE;
52926f9a767SRodney W. Grimes 	wakeup((caddr_t) bp);
53016f62314SDavid Greenman 	if (bp->b_flags & B_ASYNC) {
53116f62314SDavid Greenman 		vm_offset_t paddr;
53216f62314SDavid Greenman 		vm_page_t m;
53316f62314SDavid Greenman 		vm_object_t obj = 0;
53416f62314SDavid Greenman 		int i;
53516f62314SDavid Greenman 		int npages;
53616f62314SDavid Greenman 
53716f62314SDavid Greenman 		paddr = (vm_offset_t) bp->b_data;
53816f62314SDavid Greenman 		if (bp->b_bufsize != bp->b_bcount)
53916f62314SDavid Greenman 			bzero(bp->b_data + bp->b_bcount,
54016f62314SDavid Greenman 			    bp->b_bufsize - bp->b_bcount);
54116f62314SDavid Greenman 
54216f62314SDavid Greenman 		npages = (bp->b_bufsize + PAGE_SIZE - 1) / PAGE_SIZE;
54316f62314SDavid Greenman 		for (i = 0; i < npages; i++) {
54416f62314SDavid Greenman 			m = PHYS_TO_VM_PAGE(pmap_kextract(paddr + i * PAGE_SIZE));
54516f62314SDavid Greenman 			obj = m->object;
54616f62314SDavid Greenman 			if (m) {
5470d94caffSDavid Greenman 				m->dirty = 0;
5480d94caffSDavid Greenman 				m->valid = VM_PAGE_BITS_ALL;
5490d94caffSDavid Greenman 				if (m->flags & PG_WANTED)
5500d94caffSDavid Greenman 					m->flags |= PG_REFERENCED;
55116f62314SDavid Greenman 				PAGE_WAKEUP(m);
55216f62314SDavid Greenman 			} else {
55316f62314SDavid Greenman 				panic("vnode_pager_iodone: page is gone!!!");
55416f62314SDavid Greenman 			}
55516f62314SDavid Greenman 		}
556a481f200SDavid Greenman 		pmap_qremove(paddr, npages);
55716f62314SDavid Greenman 		if (obj) {
55816f62314SDavid Greenman 			--obj->paging_in_progress;
55916f62314SDavid Greenman 			if (obj->paging_in_progress == 0)
56016f62314SDavid Greenman 				wakeup((caddr_t) obj);
56116f62314SDavid Greenman 		} else {
56216f62314SDavid Greenman 			panic("vnode_pager_iodone: object is gone???");
56316f62314SDavid Greenman 		}
56416f62314SDavid Greenman 		relpbuf(bp);
56516f62314SDavid Greenman 	}
56626f9a767SRodney W. Grimes }
56726f9a767SRodney W. Grimes 
56826f9a767SRodney W. Grimes /*
56926f9a767SRodney W. Grimes  * small block file system vnode pager input
57026f9a767SRodney W. Grimes  */
57126f9a767SRodney W. Grimes int
57226f9a767SRodney W. Grimes vnode_pager_input_smlfs(vnp, m)
57326f9a767SRodney W. Grimes 	vn_pager_t vnp;
57426f9a767SRodney W. Grimes 	vm_page_t m;
57526f9a767SRodney W. Grimes {
57626f9a767SRodney W. Grimes 	int i;
57726f9a767SRodney W. Grimes 	int s;
57826f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
57926f9a767SRodney W. Grimes 	struct buf *bp;
58026f9a767SRodney W. Grimes 	vm_offset_t kva;
58126f9a767SRodney W. Grimes 	int fileaddr;
58226f9a767SRodney W. Grimes 	int block;
58326f9a767SRodney W. Grimes 	vm_offset_t bsize;
58426f9a767SRodney W. Grimes 	int error = 0;
58526f9a767SRodney W. Grimes 
58626f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
58726f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
58826f9a767SRodney W. Grimes 
5890d94caffSDavid Greenman 	VOP_BMAP(vp, 0, &dp, 0, 0);
59026f9a767SRodney W. Grimes 
59126f9a767SRodney W. Grimes 	kva = vm_pager_map_page(m);
59226f9a767SRodney W. Grimes 
59326f9a767SRodney W. Grimes 	for (i = 0; i < PAGE_SIZE / bsize; i++) {
594bbc0ec52SDavid Greenman 
5950d94caffSDavid Greenman 		if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid))
59626f9a767SRodney W. Grimes 			continue;
59726f9a767SRodney W. Grimes 
5980d94caffSDavid Greenman 		fileaddr = vnode_pager_addr(vp, m->offset + i * bsize);
59926f9a767SRodney W. Grimes 		if (fileaddr != -1) {
60026f9a767SRodney W. Grimes 			bp = getpbuf();
60126f9a767SRodney W. Grimes 
60226f9a767SRodney W. Grimes 			/* build a minimal buffer header */
60326f9a767SRodney W. Grimes 			bp->b_flags = B_BUSY | B_READ | B_CALL;
60426f9a767SRodney W. Grimes 			bp->b_iodone = vnode_pager_iodone;
60526f9a767SRodney W. Grimes 			bp->b_proc = curproc;
60626f9a767SRodney W. Grimes 			bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
60726f9a767SRodney W. Grimes 			if (bp->b_rcred != NOCRED)
60826f9a767SRodney W. Grimes 				crhold(bp->b_rcred);
60926f9a767SRodney W. Grimes 			if (bp->b_wcred != NOCRED)
61026f9a767SRodney W. Grimes 				crhold(bp->b_wcred);
61126f9a767SRodney W. Grimes 			bp->b_un.b_addr = (caddr_t) kva + i * bsize;
61226f9a767SRodney W. Grimes 			bp->b_blkno = fileaddr / DEV_BSIZE;
6130d94caffSDavid Greenman 			pbgetvp(dp, bp);
61426f9a767SRodney W. Grimes 			bp->b_bcount = bsize;
61526f9a767SRodney W. Grimes 			bp->b_bufsize = bsize;
61626f9a767SRodney W. Grimes 
61726f9a767SRodney W. Grimes 			/* do the input */
61826f9a767SRodney W. Grimes 			VOP_STRATEGY(bp);
61926f9a767SRodney W. Grimes 
62026f9a767SRodney W. Grimes 			/* we definitely need to be at splbio here */
62126f9a767SRodney W. Grimes 
62226f9a767SRodney W. Grimes 			s = splbio();
62326f9a767SRodney W. Grimes 			while ((bp->b_flags & B_DONE) == 0) {
62426f9a767SRodney W. Grimes 				tsleep((caddr_t) bp, PVM, "vnsrd", 0);
62526f9a767SRodney W. Grimes 			}
62626f9a767SRodney W. Grimes 			splx(s);
62726f9a767SRodney W. Grimes 			if ((bp->b_flags & B_ERROR) != 0)
62826f9a767SRodney W. Grimes 				error = EIO;
62926f9a767SRodney W. Grimes 
63026f9a767SRodney W. Grimes 			/*
63126f9a767SRodney W. Grimes 			 * free the buffer header back to the swap buffer pool
63226f9a767SRodney W. Grimes 			 */
63326f9a767SRodney W. Grimes 			relpbuf(bp);
63426f9a767SRodney W. Grimes 			HOLDRELE(vp);
63526f9a767SRodney W. Grimes 			if (error)
63626f9a767SRodney W. Grimes 				break;
6370d94caffSDavid Greenman 
6380d94caffSDavid Greenman 			vm_page_set_clean(m, i * bsize, bsize);
6390d94caffSDavid Greenman 			vm_page_set_valid(m, i * bsize, bsize);
64026f9a767SRodney W. Grimes 		} else {
6410d94caffSDavid Greenman 			vm_page_set_clean(m, i * bsize, bsize);
64226f9a767SRodney W. Grimes 			bzero((caddr_t) kva + i * bsize, bsize);
64326f9a767SRodney W. Grimes 		}
64426f9a767SRodney W. Grimes nextblock:
64526f9a767SRodney W. Grimes 	}
64626f9a767SRodney W. Grimes 	vm_pager_unmap_page(kva);
6470d94caffSDavid Greenman 	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
64826f9a767SRodney W. Grimes 	if (error) {
649a83c285cSDavid Greenman 		return VM_PAGER_ERROR;
65026f9a767SRodney W. Grimes 	}
65126f9a767SRodney W. Grimes 	return VM_PAGER_OK;
65226f9a767SRodney W. Grimes 
65326f9a767SRodney W. Grimes }
65426f9a767SRodney W. Grimes 
65526f9a767SRodney W. Grimes 
65626f9a767SRodney W. Grimes /*
65726f9a767SRodney W. Grimes  * old style vnode pager output routine
65826f9a767SRodney W. Grimes  */
65926f9a767SRodney W. Grimes int
66026f9a767SRodney W. Grimes vnode_pager_input_old(vnp, m)
66126f9a767SRodney W. Grimes 	vn_pager_t vnp;
66226f9a767SRodney W. Grimes 	vm_page_t m;
66326f9a767SRodney W. Grimes {
664df8bae1dSRodney W. Grimes 	struct uio auio;
665df8bae1dSRodney W. Grimes 	struct iovec aiov;
66626f9a767SRodney W. Grimes 	int error;
66726f9a767SRodney W. Grimes 	int size;
66826f9a767SRodney W. Grimes 	vm_offset_t kva;
669df8bae1dSRodney W. Grimes 
67026f9a767SRodney W. Grimes 	error = 0;
671bbc0ec52SDavid Greenman 
672df8bae1dSRodney W. Grimes 	/*
67326f9a767SRodney W. Grimes 	 * Return failure if beyond current EOF
67426f9a767SRodney W. Grimes 	 */
6750d94caffSDavid Greenman 	if (m->offset >= vnp->vnp_size) {
67626f9a767SRodney W. Grimes 		return VM_PAGER_BAD;
67726f9a767SRodney W. Grimes 	} else {
67826f9a767SRodney W. Grimes 		size = PAGE_SIZE;
6790d94caffSDavid Greenman 		if (m->offset + size > vnp->vnp_size)
6800d94caffSDavid Greenman 			size = vnp->vnp_size - m->offset;
68126f9a767SRodney W. Grimes 		/*
682df8bae1dSRodney W. Grimes 		 * Allocate a kernel virtual address and initialize so that
683df8bae1dSRodney W. Grimes 		 * we can use VOP_READ/WRITE routines.
684df8bae1dSRodney W. Grimes 		 */
68526f9a767SRodney W. Grimes 		kva = vm_pager_map_page(m);
686df8bae1dSRodney W. Grimes 		aiov.iov_base = (caddr_t) kva;
687df8bae1dSRodney W. Grimes 		aiov.iov_len = size;
688df8bae1dSRodney W. Grimes 		auio.uio_iov = &aiov;
689df8bae1dSRodney W. Grimes 		auio.uio_iovcnt = 1;
6900d94caffSDavid Greenman 		auio.uio_offset = m->offset;
691df8bae1dSRodney W. Grimes 		auio.uio_segflg = UIO_SYSSPACE;
69226f9a767SRodney W. Grimes 		auio.uio_rw = UIO_READ;
693df8bae1dSRodney W. Grimes 		auio.uio_resid = size;
694df8bae1dSRodney W. Grimes 		auio.uio_procp = (struct proc *) 0;
69526f9a767SRodney W. Grimes 
69626f9a767SRodney W. Grimes 		error = VOP_READ(vnp->vnp_vp, &auio, 0, curproc->p_ucred);
697df8bae1dSRodney W. Grimes 		if (!error) {
698df8bae1dSRodney W. Grimes 			register int count = size - auio.uio_resid;
699df8bae1dSRodney W. Grimes 
700df8bae1dSRodney W. Grimes 			if (count == 0)
701df8bae1dSRodney W. Grimes 				error = EINVAL;
70226f9a767SRodney W. Grimes 			else if (count != PAGE_SIZE)
70326f9a767SRodney W. Grimes 				bzero((caddr_t) kva + count, PAGE_SIZE - count);
704df8bae1dSRodney W. Grimes 		}
70526f9a767SRodney W. Grimes 		vm_pager_unmap_page(kva);
706df8bae1dSRodney W. Grimes 	}
70726f9a767SRodney W. Grimes 	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
7080d94caffSDavid Greenman 	m->dirty = 0;
709a83c285cSDavid Greenman 	return error ? VM_PAGER_ERROR : VM_PAGER_OK;
71026f9a767SRodney W. Grimes }
71126f9a767SRodney W. Grimes 
71226f9a767SRodney W. Grimes /*
71326f9a767SRodney W. Grimes  * generic vnode pager input routine
71426f9a767SRodney W. Grimes  */
71526f9a767SRodney W. Grimes int
71626f9a767SRodney W. Grimes vnode_pager_input(vnp, m, count, reqpage)
71726f9a767SRodney W. Grimes 	register vn_pager_t vnp;
71826f9a767SRodney W. Grimes 	vm_page_t *m;
71926f9a767SRodney W. Grimes 	int count, reqpage;
72026f9a767SRodney W. Grimes {
72105f0fdd2SPoul-Henning Kamp 	int i;
72226f9a767SRodney W. Grimes 	vm_offset_t kva, foff;
72316f62314SDavid Greenman 	int size, sizea;
72426f9a767SRodney W. Grimes 	vm_object_t object;
72526f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
72626f9a767SRodney W. Grimes 	int bsize;
72726f9a767SRodney W. Grimes 
72826f9a767SRodney W. Grimes 	int first, last;
72926f9a767SRodney W. Grimes 	int reqaddr, firstaddr;
73026f9a767SRodney W. Grimes 	int block, offset;
73126f9a767SRodney W. Grimes 
73216f62314SDavid Greenman 	struct buf *bp, *bpa;
73316f62314SDavid Greenman 	int counta;
73426f9a767SRodney W. Grimes 	int s;
73526f9a767SRodney W. Grimes 	int failflag;
73626f9a767SRodney W. Grimes 
73726f9a767SRodney W. Grimes 	int error = 0;
73826f9a767SRodney W. Grimes 
739bbc0ec52SDavid Greenman 	object = m[reqpage]->object;	/* all vm_page_t items are in same
740bbc0ec52SDavid Greenman 					 * object */
74126f9a767SRodney W. Grimes 
74226f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
74326f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
74426f9a767SRodney W. Grimes 
74526f9a767SRodney W. Grimes 	/* get the UNDERLYING device for the file with VOP_BMAP() */
746bbc0ec52SDavid Greenman 
74726f9a767SRodney W. Grimes 	/*
748bbc0ec52SDavid Greenman 	 * originally, we did not check for an error return value -- assuming
749bbc0ec52SDavid Greenman 	 * an fs always has a bmap entry point -- that assumption is wrong!!!
75026f9a767SRodney W. Grimes 	 */
7510d94caffSDavid Greenman 	foff = m[reqpage]->offset;
752bbc0ec52SDavid Greenman 
75326f9a767SRodney W. Grimes 	/*
75416f62314SDavid Greenman 	 * if we can't bmap, use old VOP code
75526f9a767SRodney W. Grimes 	 */
7560d94caffSDavid Greenman 	if (VOP_BMAP(vp, 0, &dp, 0, 0)) {
75726f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
75826f9a767SRodney W. Grimes 			if (i != reqpage) {
75926f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
76026f9a767SRodney W. Grimes 			}
76126f9a767SRodney W. Grimes 		}
762976e77fcSDavid Greenman 		cnt.v_vnodein++;
763976e77fcSDavid Greenman 		cnt.v_vnodepgsin++;
76426f9a767SRodney W. Grimes 		return vnode_pager_input_old(vnp, m[reqpage]);
765bbc0ec52SDavid Greenman 
76626f9a767SRodney W. Grimes 		/*
76726f9a767SRodney W. Grimes 		 * if the blocksize is smaller than a page size, then use
76826f9a767SRodney W. Grimes 		 * special small filesystem code.  NFS sometimes has a small
76926f9a767SRodney W. Grimes 		 * blocksize, but it can handle large reads itself.
77026f9a767SRodney W. Grimes 		 */
77126f9a767SRodney W. Grimes 	} else if ((PAGE_SIZE / bsize) > 1 &&
77226f9a767SRodney W. Grimes 	    (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
77326f9a767SRodney W. Grimes 
77426f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
77526f9a767SRodney W. Grimes 			if (i != reqpage) {
77626f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
77726f9a767SRodney W. Grimes 			}
77826f9a767SRodney W. Grimes 		}
779976e77fcSDavid Greenman 		cnt.v_vnodein++;
780976e77fcSDavid Greenman 		cnt.v_vnodepgsin++;
78126f9a767SRodney W. Grimes 		return vnode_pager_input_smlfs(vnp, m[reqpage]);
78226f9a767SRodney W. Grimes 	}
78326f9a767SRodney W. Grimes 	/*
7840d94caffSDavid Greenman 	 * if ANY DEV_BSIZE blocks are valid on a large filesystem block
7850d94caffSDavid Greenman 	 * then, the entire page is valid --
7860d94caffSDavid Greenman 	 */
7870d94caffSDavid Greenman 	if (m[reqpage]->valid) {
7880d94caffSDavid Greenman 		m[reqpage]->valid = VM_PAGE_BITS_ALL;
7890d94caffSDavid Greenman 		for (i = 0; i < count; i++) {
7900d94caffSDavid Greenman 			if (i != reqpage)
7910d94caffSDavid Greenman 				vnode_pager_freepage(m[i]);
7920d94caffSDavid Greenman 		}
7930d94caffSDavid Greenman 		return VM_PAGER_OK;
7940d94caffSDavid Greenman 	}
7950d94caffSDavid Greenman 	/*
79626f9a767SRodney W. Grimes 	 * here on direct device I/O
79726f9a767SRodney W. Grimes 	 */
79826f9a767SRodney W. Grimes 
79926f9a767SRodney W. Grimes 	reqaddr = vnode_pager_addr(vp, foff);
8000d94caffSDavid Greenman 	if (reqaddr == -1 && foff < vnp->vnp_size) {
8010d94caffSDavid Greenman 		printf("reqaddr: %d, foff: %d, vnp_size: %d\n",
8020d94caffSDavid Greenman 		    reqaddr, foff, vnp->vnp_size);
8030d94caffSDavid Greenman 		Debugger("");
8040d94caffSDavid Greenman 	}
80526f9a767SRodney W. Grimes 	s = splbio();
806bbc0ec52SDavid Greenman 
80726f9a767SRodney W. Grimes 	/*
808bbc0ec52SDavid Greenman 	 * Make sure that our I/O request is contiguous. Scan backward and
809bbc0ec52SDavid Greenman 	 * stop for the first discontiguous entry or stop for a page being in
810bbc0ec52SDavid Greenman 	 * buffer cache.
81126f9a767SRodney W. Grimes 	 */
81226f9a767SRodney W. Grimes 	failflag = 0;
81326f9a767SRodney W. Grimes 	first = reqpage;
81426f9a767SRodney W. Grimes 	for (i = reqpage - 1; i >= 0; --i) {
81526f9a767SRodney W. Grimes 		if (failflag ||
8160d94caffSDavid Greenman 		    (vnode_pager_addr(vp, m[i]->offset))
81726f9a767SRodney W. Grimes 		    != reqaddr + (i - reqpage) * PAGE_SIZE) {
81826f9a767SRodney W. Grimes 			vnode_pager_freepage(m[i]);
81926f9a767SRodney W. Grimes 			failflag = 1;
82026f9a767SRodney W. Grimes 		} else {
82126f9a767SRodney W. Grimes 			first = i;
82226f9a767SRodney W. Grimes 		}
82326f9a767SRodney W. Grimes 	}
82426f9a767SRodney W. Grimes 
82526f9a767SRodney W. Grimes 	/*
826bbc0ec52SDavid Greenman 	 * Scan forward and stop for the first non-contiguous entry or stop
827bbc0ec52SDavid Greenman 	 * for a page being in buffer cache.
82826f9a767SRodney W. Grimes 	 */
82926f9a767SRodney W. Grimes 	failflag = 0;
83026f9a767SRodney W. Grimes 	last = reqpage + 1;
83126f9a767SRodney W. Grimes 	for (i = reqpage + 1; i < count; i++) {
83226f9a767SRodney W. Grimes 		if (failflag ||
8330d94caffSDavid Greenman 		    (vnode_pager_addr(vp, m[i]->offset))
83426f9a767SRodney W. Grimes 		    != reqaddr + (i - reqpage) * PAGE_SIZE) {
83526f9a767SRodney W. Grimes 			vnode_pager_freepage(m[i]);
83626f9a767SRodney W. Grimes 			failflag = 1;
83726f9a767SRodney W. Grimes 		} else {
83826f9a767SRodney W. Grimes 			last = i + 1;
83926f9a767SRodney W. Grimes 		}
84026f9a767SRodney W. Grimes 	}
84126f9a767SRodney W. Grimes 	splx(s);
84226f9a767SRodney W. Grimes 
84326f9a767SRodney W. Grimes 	/*
844bbc0ec52SDavid Greenman 	 * the first and last page have been calculated now, move input pages
845bbc0ec52SDavid Greenman 	 * to be zero based...
84626f9a767SRodney W. Grimes 	 */
84726f9a767SRodney W. Grimes 	count = last;
84826f9a767SRodney W. Grimes 	if (first != 0) {
84926f9a767SRodney W. Grimes 		for (i = first; i < count; i++) {
85026f9a767SRodney W. Grimes 			m[i - first] = m[i];
85126f9a767SRodney W. Grimes 		}
85226f9a767SRodney W. Grimes 		count -= first;
85326f9a767SRodney W. Grimes 		reqpage -= first;
85426f9a767SRodney W. Grimes 	}
85526f9a767SRodney W. Grimes 	/*
85626f9a767SRodney W. Grimes 	 * calculate the file virtual address for the transfer
85726f9a767SRodney W. Grimes 	 */
8580d94caffSDavid Greenman 	foff = m[0]->offset;
859bbc0ec52SDavid Greenman 
86026f9a767SRodney W. Grimes 	/*
86126f9a767SRodney W. Grimes 	 * and get the disk physical address (in bytes)
86226f9a767SRodney W. Grimes 	 */
86326f9a767SRodney W. Grimes 	firstaddr = vnode_pager_addr(vp, foff);
86426f9a767SRodney W. Grimes 
86526f9a767SRodney W. Grimes 	/*
86626f9a767SRodney W. Grimes 	 * calculate the size of the transfer
86726f9a767SRodney W. Grimes 	 */
86826f9a767SRodney W. Grimes 	size = count * PAGE_SIZE;
86926f9a767SRodney W. Grimes 	if ((foff + size) > vnp->vnp_size)
87026f9a767SRodney W. Grimes 		size = vnp->vnp_size - foff;
87126f9a767SRodney W. Grimes 
87226f9a767SRodney W. Grimes 	/*
87326f9a767SRodney W. Grimes 	 * round up physical size for real devices
87426f9a767SRodney W. Grimes 	 */
87526f9a767SRodney W. Grimes 	if (dp->v_type == VBLK || dp->v_type == VCHR)
87626f9a767SRodney W. Grimes 		size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
87726f9a767SRodney W. Grimes 
87816f62314SDavid Greenman 	counta = 0;
87916f62314SDavid Greenman 	if (count * PAGE_SIZE > bsize)
88016f62314SDavid Greenman 		counta = (count - reqpage) - 1;
88116f62314SDavid Greenman 	bpa = 0;
88216f62314SDavid Greenman 	sizea = 0;
88316f62314SDavid Greenman 	if (counta) {
88416f62314SDavid Greenman 		bpa = getpbuf();
88516f62314SDavid Greenman 		count -= counta;
88616f62314SDavid Greenman 		sizea = size - count * PAGE_SIZE;
88716f62314SDavid Greenman 		size = count * PAGE_SIZE;
88816f62314SDavid Greenman 	}
88916f62314SDavid Greenman 	bp = getpbuf();
89016f62314SDavid Greenman 	kva = (vm_offset_t) bp->b_data;
89116f62314SDavid Greenman 
89226f9a767SRodney W. Grimes 	/*
89326f9a767SRodney W. Grimes 	 * and map the pages to be read into the kva
89426f9a767SRodney W. Grimes 	 */
89516f62314SDavid Greenman 	pmap_qenter(kva, m, count);
89626f9a767SRodney W. Grimes 
89726f9a767SRodney W. Grimes 	/* build a minimal buffer header */
89826f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY | B_READ | B_CALL;
89926f9a767SRodney W. Grimes 	bp->b_iodone = vnode_pager_iodone;
90026f9a767SRodney W. Grimes 	/* B_PHYS is not set, but it is nice to fill this in */
90126f9a767SRodney W. Grimes 	bp->b_proc = curproc;
90226f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
90326f9a767SRodney W. Grimes 	if (bp->b_rcred != NOCRED)
90426f9a767SRodney W. Grimes 		crhold(bp->b_rcred);
90526f9a767SRodney W. Grimes 	if (bp->b_wcred != NOCRED)
90626f9a767SRodney W. Grimes 		crhold(bp->b_wcred);
90726f9a767SRodney W. Grimes 	bp->b_blkno = firstaddr / DEV_BSIZE;
9080d94caffSDavid Greenman 	pbgetvp(dp, bp);
90926f9a767SRodney W. Grimes 	bp->b_bcount = size;
91026f9a767SRodney W. Grimes 	bp->b_bufsize = size;
91126f9a767SRodney W. Grimes 
912976e77fcSDavid Greenman 	cnt.v_vnodein++;
913976e77fcSDavid Greenman 	cnt.v_vnodepgsin += count;
914976e77fcSDavid Greenman 
91526f9a767SRodney W. Grimes 	/* do the input */
91626f9a767SRodney W. Grimes 	VOP_STRATEGY(bp);
917976e77fcSDavid Greenman 
91816f62314SDavid Greenman 	if (counta) {
91916f62314SDavid Greenman 		for (i = 0; i < counta; i++) {
92016f62314SDavid Greenman 			vm_page_deactivate(m[count + i]);
92116f62314SDavid Greenman 		}
922c87801feSDavid Greenman 		pmap_qenter((vm_offset_t) bpa->b_data, &m[count], counta);
92316f62314SDavid Greenman 		++m[count]->object->paging_in_progress;
92416f62314SDavid Greenman 		bpa->b_flags = B_BUSY | B_READ | B_CALL | B_ASYNC;
92516f62314SDavid Greenman 		bpa->b_iodone = vnode_pager_iodone;
92616f62314SDavid Greenman 		/* B_PHYS is not set, but it is nice to fill this in */
92716f62314SDavid Greenman 		bpa->b_proc = curproc;
92816f62314SDavid Greenman 		bpa->b_rcred = bpa->b_wcred = bpa->b_proc->p_ucred;
92916f62314SDavid Greenman 		if (bpa->b_rcred != NOCRED)
93016f62314SDavid Greenman 			crhold(bpa->b_rcred);
93116f62314SDavid Greenman 		if (bpa->b_wcred != NOCRED)
93216f62314SDavid Greenman 			crhold(bpa->b_wcred);
93316f62314SDavid Greenman 		bpa->b_blkno = (firstaddr + count * PAGE_SIZE) / DEV_BSIZE;
9340d94caffSDavid Greenman 		pbgetvp(dp, bpa);
93516f62314SDavid Greenman 		bpa->b_bcount = sizea;
93616f62314SDavid Greenman 		bpa->b_bufsize = counta * PAGE_SIZE;
93716f62314SDavid Greenman 
938976e77fcSDavid Greenman 		cnt.v_vnodepgsin += counta;
93916f62314SDavid Greenman 		VOP_STRATEGY(bpa);
94016f62314SDavid Greenman 	}
94126f9a767SRodney W. Grimes 	s = splbio();
94226f9a767SRodney W. Grimes 	/* we definitely need to be at splbio here */
94326f9a767SRodney W. Grimes 
94426f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
94526f9a767SRodney W. Grimes 		tsleep((caddr_t) bp, PVM, "vnread", 0);
94626f9a767SRodney W. Grimes 	}
94726f9a767SRodney W. Grimes 	splx(s);
94826f9a767SRodney W. Grimes 	if ((bp->b_flags & B_ERROR) != 0)
94926f9a767SRodney W. Grimes 		error = EIO;
95026f9a767SRodney W. Grimes 
95126f9a767SRodney W. Grimes 	if (!error) {
95226f9a767SRodney W. Grimes 		if (size != count * PAGE_SIZE)
95326f9a767SRodney W. Grimes 			bzero((caddr_t) kva + size, PAGE_SIZE * count - size);
95426f9a767SRodney W. Grimes 	}
95516f62314SDavid Greenman 	pmap_qremove(kva, count);
95626f9a767SRodney W. Grimes 
95726f9a767SRodney W. Grimes 	/*
95826f9a767SRodney W. Grimes 	 * free the buffer header back to the swap buffer pool
95926f9a767SRodney W. Grimes 	 */
96026f9a767SRodney W. Grimes 	relpbuf(bp);
96126f9a767SRodney W. Grimes 	HOLDRELE(vp);
96226f9a767SRodney W. Grimes 
96326f9a767SRodney W. Grimes finishup:
96426f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
965fff93ab6SDavid Greenman 		pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
9660d94caffSDavid Greenman 		m[i]->dirty = 0;
9670d94caffSDavid Greenman 		m[i]->valid = VM_PAGE_BITS_ALL;
96826f9a767SRodney W. Grimes 		if (i != reqpage) {
969bbc0ec52SDavid Greenman 
97026f9a767SRodney W. Grimes 			/*
971bbc0ec52SDavid Greenman 			 * whether or not to leave the page activated is up in
972bbc0ec52SDavid Greenman 			 * the air, but we should put the page on a page queue
973bbc0ec52SDavid Greenman 			 * somewhere. (it already is in the object). Result:
974bbc0ec52SDavid Greenman 			 * It appears that emperical results show that
975bbc0ec52SDavid Greenman 			 * deactivating pages is best.
97626f9a767SRodney W. Grimes 			 */
977bbc0ec52SDavid Greenman 
97826f9a767SRodney W. Grimes 			/*
979bbc0ec52SDavid Greenman 			 * just in case someone was asking for this page we
980bbc0ec52SDavid Greenman 			 * now tell them that it is ok to use
98126f9a767SRodney W. Grimes 			 */
98226f9a767SRodney W. Grimes 			if (!error) {
9830d94caffSDavid Greenman 				if (i != reqpage - 1)
98426f9a767SRodney W. Grimes 					vm_page_deactivate(m[i]);
9850d94caffSDavid Greenman 				else
9860d94caffSDavid Greenman 					vm_page_activate(m[i]);
98726f9a767SRodney W. Grimes 				PAGE_WAKEUP(m[i]);
98826f9a767SRodney W. Grimes 			} else {
98926f9a767SRodney W. Grimes 				vnode_pager_freepage(m[i]);
99026f9a767SRodney W. Grimes 			}
99126f9a767SRodney W. Grimes 		}
99226f9a767SRodney W. Grimes 	}
99326f9a767SRodney W. Grimes 	if (error) {
994a83c285cSDavid Greenman 		printf("vnode_pager_input: I/O read error\n");
99526f9a767SRodney W. Grimes 	}
996a83c285cSDavid Greenman 	return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
99726f9a767SRodney W. Grimes }
99826f9a767SRodney W. Grimes 
99926f9a767SRodney W. Grimes /*
100026f9a767SRodney W. Grimes  * old-style vnode pager output routine
100126f9a767SRodney W. Grimes  */
100226f9a767SRodney W. Grimes int
100326f9a767SRodney W. Grimes vnode_pager_output_old(vnp, m)
100426f9a767SRodney W. Grimes 	register vn_pager_t vnp;
100526f9a767SRodney W. Grimes 	vm_page_t m;
100626f9a767SRodney W. Grimes {
10070d94caffSDavid Greenman 	vm_offset_t kva, kva2;
100826f9a767SRodney W. Grimes 	vm_offset_t size;
100926f9a767SRodney W. Grimes 	struct iovec aiov;
101026f9a767SRodney W. Grimes 	struct uio auio;
101126f9a767SRodney W. Grimes 	struct vnode *vp;
101226f9a767SRodney W. Grimes 	int error;
101326f9a767SRodney W. Grimes 
101426f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
1015bbc0ec52SDavid Greenman 
101626f9a767SRodney W. Grimes 	/*
10170d94caffSDavid Greenman 	 * Dont return failure if beyond current EOF placate the VM system.
101826f9a767SRodney W. Grimes 	 */
10190d94caffSDavid Greenman 	if (m->offset >= vnp->vnp_size) {
10200d94caffSDavid Greenman 		return VM_PAGER_OK;
102126f9a767SRodney W. Grimes 	} else {
102226f9a767SRodney W. Grimes 		size = PAGE_SIZE;
10230d94caffSDavid Greenman 		if (m->offset + size > vnp->vnp_size)
10240d94caffSDavid Greenman 			size = vnp->vnp_size - m->offset;
10250d94caffSDavid Greenman 
10260d94caffSDavid Greenman 		kva2 = kmem_alloc(pager_map, PAGE_SIZE);
102726f9a767SRodney W. Grimes 		/*
102826f9a767SRodney W. Grimes 		 * Allocate a kernel virtual address and initialize so that
102926f9a767SRodney W. Grimes 		 * we can use VOP_WRITE routines.
103026f9a767SRodney W. Grimes 		 */
103126f9a767SRodney W. Grimes 		kva = vm_pager_map_page(m);
10320d94caffSDavid Greenman 		bcopy((caddr_t) kva, (caddr_t) kva2, size);
10330d94caffSDavid Greenman 		vm_pager_unmap_page(kva);
10340d94caffSDavid Greenman 		pmap_clear_modify(VM_PAGE_TO_PHYS(m));
10350d94caffSDavid Greenman 		PAGE_WAKEUP(m);
10360d94caffSDavid Greenman 
10370d94caffSDavid Greenman 		aiov.iov_base = (caddr_t) kva2;
103826f9a767SRodney W. Grimes 		aiov.iov_len = size;
103926f9a767SRodney W. Grimes 		auio.uio_iov = &aiov;
104026f9a767SRodney W. Grimes 		auio.uio_iovcnt = 1;
10410d94caffSDavid Greenman 		auio.uio_offset = m->offset;
104226f9a767SRodney W. Grimes 		auio.uio_segflg = UIO_SYSSPACE;
104326f9a767SRodney W. Grimes 		auio.uio_rw = UIO_WRITE;
104426f9a767SRodney W. Grimes 		auio.uio_resid = size;
104526f9a767SRodney W. Grimes 		auio.uio_procp = (struct proc *) 0;
104626f9a767SRodney W. Grimes 
104726f9a767SRodney W. Grimes 		error = VOP_WRITE(vp, &auio, 0, curproc->p_ucred);
104826f9a767SRodney W. Grimes 
10490d94caffSDavid Greenman 		kmem_free_wakeup(pager_map, kva2, PAGE_SIZE);
105026f9a767SRodney W. Grimes 		if (!error) {
105126f9a767SRodney W. Grimes 			if ((size - auio.uio_resid) == 0) {
105226f9a767SRodney W. Grimes 				error = EINVAL;
105326f9a767SRodney W. Grimes 			}
105426f9a767SRodney W. Grimes 		}
1055a83c285cSDavid Greenman 		return error ? VM_PAGER_ERROR : VM_PAGER_OK;
105626f9a767SRodney W. Grimes 	}
105726f9a767SRodney W. Grimes }
105826f9a767SRodney W. Grimes 
105926f9a767SRodney W. Grimes /*
106026f9a767SRodney W. Grimes  * vnode pager output on a small-block file system
106126f9a767SRodney W. Grimes  */
106226f9a767SRodney W. Grimes int
106326f9a767SRodney W. Grimes vnode_pager_output_smlfs(vnp, m)
106426f9a767SRodney W. Grimes 	vn_pager_t vnp;
106526f9a767SRodney W. Grimes 	vm_page_t m;
106626f9a767SRodney W. Grimes {
106726f9a767SRodney W. Grimes 	int i;
106826f9a767SRodney W. Grimes 	int s;
106926f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
107026f9a767SRodney W. Grimes 	struct buf *bp;
107126f9a767SRodney W. Grimes 	vm_offset_t kva;
107226f9a767SRodney W. Grimes 	int fileaddr;
107326f9a767SRodney W. Grimes 	vm_offset_t bsize;
107426f9a767SRodney W. Grimes 	int error = 0;
107526f9a767SRodney W. Grimes 
107626f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
107726f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
107826f9a767SRodney W. Grimes 
10790d94caffSDavid Greenman 	VOP_BMAP(vp, 0, &dp, 0, 0);
108026f9a767SRodney W. Grimes 	kva = vm_pager_map_page(m);
108126f9a767SRodney W. Grimes 	for (i = 0; !error && i < (PAGE_SIZE / bsize); i++) {
1082bbc0ec52SDavid Greenman 
10830d94caffSDavid Greenman 		if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid & m->dirty) == 0)
10840d94caffSDavid Greenman 			continue;
108526f9a767SRodney W. Grimes 		/*
108626f9a767SRodney W. Grimes 		 * calculate logical block and offset
108726f9a767SRodney W. Grimes 		 */
10880d94caffSDavid Greenman 		fileaddr = vnode_pager_addr(vp, m->offset + i * bsize);
108926f9a767SRodney W. Grimes 		if (fileaddr != -1) {
109026f9a767SRodney W. Grimes 
109126f9a767SRodney W. Grimes 			bp = getpbuf();
109226f9a767SRodney W. Grimes 
109326f9a767SRodney W. Grimes 			/* build a minimal buffer header */
109426f9a767SRodney W. Grimes 			bp->b_flags = B_BUSY | B_CALL | B_WRITE;
109526f9a767SRodney W. Grimes 			bp->b_iodone = vnode_pager_iodone;
109626f9a767SRodney W. Grimes 			bp->b_proc = curproc;
109726f9a767SRodney W. Grimes 			bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
109826f9a767SRodney W. Grimes 			if (bp->b_rcred != NOCRED)
109926f9a767SRodney W. Grimes 				crhold(bp->b_rcred);
110026f9a767SRodney W. Grimes 			if (bp->b_wcred != NOCRED)
110126f9a767SRodney W. Grimes 				crhold(bp->b_wcred);
110226f9a767SRodney W. Grimes 			bp->b_un.b_addr = (caddr_t) kva + i * bsize;
110326f9a767SRodney W. Grimes 			bp->b_blkno = fileaddr / DEV_BSIZE;
11040d94caffSDavid Greenman 			pbgetvp(dp, bp);
110526f9a767SRodney W. Grimes 			++dp->v_numoutput;
110626f9a767SRodney W. Grimes 			/* for NFS */
110726f9a767SRodney W. Grimes 			bp->b_dirtyoff = 0;
110826f9a767SRodney W. Grimes 			bp->b_dirtyend = bsize;
110926f9a767SRodney W. Grimes 			bp->b_bcount = bsize;
111026f9a767SRodney W. Grimes 			bp->b_bufsize = bsize;
111126f9a767SRodney W. Grimes 
111226f9a767SRodney W. Grimes 			/* do the input */
111326f9a767SRodney W. Grimes 			VOP_STRATEGY(bp);
111426f9a767SRodney W. Grimes 
111526f9a767SRodney W. Grimes 			/* we definitely need to be at splbio here */
111626f9a767SRodney W. Grimes 
111726f9a767SRodney W. Grimes 			s = splbio();
111826f9a767SRodney W. Grimes 			while ((bp->b_flags & B_DONE) == 0) {
111926f9a767SRodney W. Grimes 				tsleep((caddr_t) bp, PVM, "vnswrt", 0);
112026f9a767SRodney W. Grimes 			}
112126f9a767SRodney W. Grimes 			splx(s);
112226f9a767SRodney W. Grimes 			if ((bp->b_flags & B_ERROR) != 0)
112326f9a767SRodney W. Grimes 				error = EIO;
112426f9a767SRodney W. Grimes 
11250d94caffSDavid Greenman 			vm_page_set_clean(m, i * bsize, bsize);
112626f9a767SRodney W. Grimes 			/*
112726f9a767SRodney W. Grimes 			 * free the buffer header back to the swap buffer pool
112826f9a767SRodney W. Grimes 			 */
112926f9a767SRodney W. Grimes 			relpbuf(bp);
113026f9a767SRodney W. Grimes 			HOLDRELE(vp);
113126f9a767SRodney W. Grimes 		}
113226f9a767SRodney W. Grimes 	}
113326f9a767SRodney W. Grimes 	vm_pager_unmap_page(kva);
113426f9a767SRodney W. Grimes 	if (error)
1135a83c285cSDavid Greenman 		return VM_PAGER_ERROR;
113626f9a767SRodney W. Grimes 	else
113726f9a767SRodney W. Grimes 		return VM_PAGER_OK;
113826f9a767SRodney W. Grimes }
113926f9a767SRodney W. Grimes 
114026f9a767SRodney W. Grimes /*
114126f9a767SRodney W. Grimes  * generic vnode pager output routine
114226f9a767SRodney W. Grimes  */
114326f9a767SRodney W. Grimes int
114426f9a767SRodney W. Grimes vnode_pager_output(vnp, m, count, rtvals)
114526f9a767SRodney W. Grimes 	vn_pager_t vnp;
114626f9a767SRodney W. Grimes 	vm_page_t *m;
114726f9a767SRodney W. Grimes 	int count;
114826f9a767SRodney W. Grimes 	int *rtvals;
114926f9a767SRodney W. Grimes {
115026f9a767SRodney W. Grimes 	int i, j;
115126f9a767SRodney W. Grimes 	vm_offset_t kva, foff;
115226f9a767SRodney W. Grimes 	int size;
115326f9a767SRodney W. Grimes 	vm_object_t object;
115426f9a767SRodney W. Grimes 	struct vnode *dp, *vp;
115526f9a767SRodney W. Grimes 	struct buf *bp;
115626f9a767SRodney W. Grimes 	vm_offset_t reqaddr;
115726f9a767SRodney W. Grimes 	int bsize;
115826f9a767SRodney W. Grimes 	int s;
11590d94caffSDavid Greenman 	daddr_t block;
11600d94caffSDavid Greenman 	struct timeval tv;
116126f9a767SRodney W. Grimes 
116226f9a767SRodney W. Grimes 	int error = 0;
116326f9a767SRodney W. Grimes 
116426f9a767SRodney W. Grimes retryoutput:
116526f9a767SRodney W. Grimes 	object = m[0]->object;	/* all vm_page_t items are in same object */
116626f9a767SRodney W. Grimes 
116726f9a767SRodney W. Grimes 	vp = vnp->vnp_vp;
11684abc71c0SDavid Greenman 
11694abc71c0SDavid Greenman 	/*
11704abc71c0SDavid Greenman 	 * Make sure underlying filesystem is still mounted.
11714abc71c0SDavid Greenman 	 */
11724abc71c0SDavid Greenman 	if (vp->v_mount == NULL)
11734abc71c0SDavid Greenman 		return VM_PAGER_FAIL;
11744abc71c0SDavid Greenman 
117526f9a767SRodney W. Grimes 	bsize = vp->v_mount->mnt_stat.f_iosize;
117626f9a767SRodney W. Grimes 
117726f9a767SRodney W. Grimes 	for (i = 0; i < count; i++)
117826f9a767SRodney W. Grimes 		rtvals[i] = VM_PAGER_AGAIN;
117926f9a767SRodney W. Grimes 
11800d94caffSDavid Greenman 	if ((int) m[0]->offset < 0) {
11810d94caffSDavid Greenman 		printf("vnode_pager_output: attempt to write meta-data!!! -- 0x%x\n", m[0]->offset);
11820d94caffSDavid Greenman 		m[0]->dirty = 0;
11830d94caffSDavid Greenman 		rtvals[0] = VM_PAGER_OK;
11840d94caffSDavid Greenman 		return VM_PAGER_OK;
11850d94caffSDavid Greenman 	}
118626f9a767SRodney W. Grimes 	/*
1187bbc0ec52SDavid Greenman 	 * if the filesystem does not have a bmap, then use the old code
118826f9a767SRodney W. Grimes 	 */
11890d94caffSDavid Greenman 	if (VOP_BMAP(vp, (m[0]->offset / bsize), &dp, &block, 0) ||
11900d94caffSDavid Greenman 	    (block == -1)) {
119126f9a767SRodney W. Grimes 
119226f9a767SRodney W. Grimes 		rtvals[0] = vnode_pager_output_old(vnp, m[0]);
119326f9a767SRodney W. Grimes 
11940d94caffSDavid Greenman 		m[0]->dirty = 0;
1195976e77fcSDavid Greenman 		cnt.v_vnodeout++;
1196976e77fcSDavid Greenman 		cnt.v_vnodepgsout++;
119726f9a767SRodney W. Grimes 		return rtvals[0];
119826f9a767SRodney W. Grimes 	}
11990d94caffSDavid Greenman 	tv = time;
12000d94caffSDavid Greenman 	VOP_UPDATE(vp, &tv, &tv, 0);
120126f9a767SRodney W. Grimes 
120226f9a767SRodney W. Grimes 	/*
1203bbc0ec52SDavid Greenman 	 * if the filesystem has a small blocksize, then use the small block
1204bbc0ec52SDavid Greenman 	 * filesystem output code
120526f9a767SRodney W. Grimes 	 */
120626f9a767SRodney W. Grimes 	if ((bsize < PAGE_SIZE) &&
120726f9a767SRodney W. Grimes 	    (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
120826f9a767SRodney W. Grimes 
120926f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
121026f9a767SRodney W. Grimes 			rtvals[i] = vnode_pager_output_smlfs(vnp, m[i]);
121126f9a767SRodney W. Grimes 			if (rtvals[i] == VM_PAGER_OK) {
121226f9a767SRodney W. Grimes 				pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
121326f9a767SRodney W. Grimes 			}
121426f9a767SRodney W. Grimes 		}
1215976e77fcSDavid Greenman 		cnt.v_vnodeout++;
1216976e77fcSDavid Greenman 		cnt.v_vnodepgsout += count;
121726f9a767SRodney W. Grimes 		return rtvals[0];
121826f9a767SRodney W. Grimes 	}
121926f9a767SRodney W. Grimes 	for (i = 0; i < count; i++) {
12200d94caffSDavid Greenman 		foff = m[i]->offset;
122126f9a767SRodney W. Grimes 		if (foff >= vnp->vnp_size) {
122226f9a767SRodney W. Grimes 			for (j = i; j < count; j++)
122326f9a767SRodney W. Grimes 				rtvals[j] = VM_PAGER_BAD;
122426f9a767SRodney W. Grimes 			count = i;
122526f9a767SRodney W. Grimes 			break;
122626f9a767SRodney W. Grimes 		}
122726f9a767SRodney W. Grimes 	}
122826f9a767SRodney W. Grimes 	if (count == 0) {
122926f9a767SRodney W. Grimes 		return rtvals[0];
123026f9a767SRodney W. Grimes 	}
12310d94caffSDavid Greenman 	foff = m[0]->offset;
123226f9a767SRodney W. Grimes 	reqaddr = vnode_pager_addr(vp, foff);
1233bbc0ec52SDavid Greenman 
123426f9a767SRodney W. Grimes 	/*
1235bbc0ec52SDavid Greenman 	 * Scan forward and stop for the first non-contiguous entry or stop
1236bbc0ec52SDavid Greenman 	 * for a page being in buffer cache.
123726f9a767SRodney W. Grimes 	 */
123826f9a767SRodney W. Grimes 	for (i = 1; i < count; i++) {
12390d94caffSDavid Greenman 		if (vnode_pager_addr(vp, m[i]->offset)
124026f9a767SRodney W. Grimes 		    != reqaddr + i * PAGE_SIZE) {
124126f9a767SRodney W. Grimes 			count = i;
124226f9a767SRodney W. Grimes 			break;
124326f9a767SRodney W. Grimes 		}
124426f9a767SRodney W. Grimes 	}
124526f9a767SRodney W. Grimes 
124626f9a767SRodney W. Grimes 	/*
124726f9a767SRodney W. Grimes 	 * calculate the size of the transfer
124826f9a767SRodney W. Grimes 	 */
124926f9a767SRodney W. Grimes 	size = count * PAGE_SIZE;
125026f9a767SRodney W. Grimes 	if ((foff + size) > vnp->vnp_size)
125126f9a767SRodney W. Grimes 		size = vnp->vnp_size - foff;
125226f9a767SRodney W. Grimes 
125326f9a767SRodney W. Grimes 	/*
125426f9a767SRodney W. Grimes 	 * round up physical size for real devices
125526f9a767SRodney W. Grimes 	 */
125626f9a767SRodney W. Grimes 	if (dp->v_type == VBLK || dp->v_type == VCHR)
125726f9a767SRodney W. Grimes 		size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
125826f9a767SRodney W. Grimes 
125916f62314SDavid Greenman 	bp = getpbuf();
126016f62314SDavid Greenman 	kva = (vm_offset_t) bp->b_data;
126126f9a767SRodney W. Grimes 	/*
126226f9a767SRodney W. Grimes 	 * and map the pages to be read into the kva
126326f9a767SRodney W. Grimes 	 */
126416f62314SDavid Greenman 	pmap_qenter(kva, m, count);
1265bbc0ec52SDavid Greenman 
126626f9a767SRodney W. Grimes 	/* build a minimal buffer header */
126726f9a767SRodney W. Grimes 	bp->b_flags = B_BUSY | B_WRITE | B_CALL;
126826f9a767SRodney W. Grimes 	bp->b_iodone = vnode_pager_iodone;
126926f9a767SRodney W. Grimes 	/* B_PHYS is not set, but it is nice to fill this in */
127026f9a767SRodney W. Grimes 	bp->b_proc = curproc;
127126f9a767SRodney W. Grimes 	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
127226f9a767SRodney W. Grimes 
127326f9a767SRodney W. Grimes 	if (bp->b_rcred != NOCRED)
127426f9a767SRodney W. Grimes 		crhold(bp->b_rcred);
127526f9a767SRodney W. Grimes 	if (bp->b_wcred != NOCRED)
127626f9a767SRodney W. Grimes 		crhold(bp->b_wcred);
127726f9a767SRodney W. Grimes 	bp->b_blkno = reqaddr / DEV_BSIZE;
12780d94caffSDavid Greenman 	pbgetvp(dp, bp);
127926f9a767SRodney W. Grimes 	++dp->v_numoutput;
128026f9a767SRodney W. Grimes 
128126f9a767SRodney W. Grimes 	/* for NFS */
128226f9a767SRodney W. Grimes 	bp->b_dirtyoff = 0;
128326f9a767SRodney W. Grimes 	bp->b_dirtyend = size;
128426f9a767SRodney W. Grimes 
128526f9a767SRodney W. Grimes 	bp->b_bcount = size;
128626f9a767SRodney W. Grimes 	bp->b_bufsize = size;
128726f9a767SRodney W. Grimes 
1288976e77fcSDavid Greenman 	cnt.v_vnodeout++;
1289976e77fcSDavid Greenman 	cnt.v_vnodepgsout += count;
1290976e77fcSDavid Greenman 
129126f9a767SRodney W. Grimes 	/* do the output */
129226f9a767SRodney W. Grimes 	VOP_STRATEGY(bp);
129326f9a767SRodney W. Grimes 
129426f9a767SRodney W. Grimes 	s = splbio();
129526f9a767SRodney W. Grimes 
129626f9a767SRodney W. Grimes 	/* we definitely need to be at splbio here */
129726f9a767SRodney W. Grimes 
129826f9a767SRodney W. Grimes 	while ((bp->b_flags & B_DONE) == 0) {
129926f9a767SRodney W. Grimes 		tsleep((caddr_t) bp, PVM, "vnwrite", 0);
130026f9a767SRodney W. Grimes 	}
130126f9a767SRodney W. Grimes 	splx(s);
130226f9a767SRodney W. Grimes 
130326f9a767SRodney W. Grimes 	if ((bp->b_flags & B_ERROR) != 0)
130426f9a767SRodney W. Grimes 		error = EIO;
130526f9a767SRodney W. Grimes 
130616f62314SDavid Greenman 	pmap_qremove(kva, count);
130726f9a767SRodney W. Grimes 
130826f9a767SRodney W. Grimes 	/*
130926f9a767SRodney W. Grimes 	 * free the buffer header back to the swap buffer pool
131026f9a767SRodney W. Grimes 	 */
131126f9a767SRodney W. Grimes 	relpbuf(bp);
131226f9a767SRodney W. Grimes 	HOLDRELE(vp);
131326f9a767SRodney W. Grimes 
131426f9a767SRodney W. Grimes 	if (!error) {
131526f9a767SRodney W. Grimes 		for (i = 0; i < count; i++) {
131626f9a767SRodney W. Grimes 			pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
13170d94caffSDavid Greenman 			m[i]->dirty = 0;
131826f9a767SRodney W. Grimes 			rtvals[i] = VM_PAGER_OK;
131926f9a767SRodney W. Grimes 		}
132026f9a767SRodney W. Grimes 	} else if (count != 1) {
132126f9a767SRodney W. Grimes 		error = 0;
132226f9a767SRodney W. Grimes 		count = 1;
132326f9a767SRodney W. Grimes 		goto retryoutput;
132426f9a767SRodney W. Grimes 	}
132526f9a767SRodney W. Grimes 	if (error) {
1326a83c285cSDavid Greenman 		printf("vnode_pager_output: I/O write error\n");
132726f9a767SRodney W. Grimes 	}
1328a83c285cSDavid Greenman 	return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
132926f9a767SRodney W. Grimes }
1330