vnode_pager.c revision 10669
1/*
2 * Copyright (c) 1990 University of Utah.
3 * Copyright (c) 1991 The Regents of the University of California.
4 * All rights reserved.
5 * Copyright (c) 1993, 1994 John S. Dyson
6 * Copyright (c) 1995, David Greenman
7 *
8 * This code is derived from software contributed to Berkeley by
9 * the Systems Programming Group of the University of Utah Computer
10 * Science Department.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *	This product includes software developed by the University of
23 *	California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *	from: @(#)vnode_pager.c	7.5 (Berkeley) 4/20/91
41 *	$Id: vnode_pager.c,v 1.47 1995/09/06 05:37:41 dyson Exp $
42 */
43
44/*
45 * Page to/from files (vnodes).
46 */
47
48/*
49 * TODO:
50 *	Implement VOP_GETPAGES/PUTPAGES interface for filesystems. Will
51 *	greatly re-simplify the vnode_pager.
52 */
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/kernel.h>
57#include <sys/proc.h>
58#include <sys/malloc.h>
59#include <sys/vnode.h>
60#include <sys/uio.h>
61#include <sys/mount.h>
62#include <sys/buf.h>
63
64#include <vm/vm.h>
65#include <vm/vm_page.h>
66#include <vm/vm_pager.h>
67#include <vm/vnode_pager.h>
68
69struct pagerops vnodepagerops = {
70	NULL,
71	vnode_pager_alloc,
72	vnode_pager_dealloc,
73	vnode_pager_getpages,
74	vnode_pager_putpages,
75	vnode_pager_haspage,
76	NULL
77};
78
79static int vnode_pager_leaf_getpages();
80
81static int vnode_pager_leaf_putpages();
82/*
83 * Allocate (or lookup) pager for a vnode.
84 * Handle is a vnode pointer.
85 */
86vm_object_t
87vnode_pager_alloc(handle, size, prot, offset)
88	void *handle;
89	vm_size_t size;
90	vm_prot_t prot;
91	vm_offset_t offset;
92{
93	vm_object_t object;
94	struct vnode *vp;
95
96	/*
97	 * Pageout to vnode, no can do yet.
98	 */
99	if (handle == NULL)
100		return (NULL);
101
102	vp = (struct vnode *) handle;
103
104	/*
105	 * Prevent race condition when allocating the object. This
106	 * can happen with NFS vnodes since the nfsnode isn't locked.
107	 */
108	while (vp->v_flag & VOLOCK) {
109		vp->v_flag |= VOWANT;
110		tsleep(vp, PVM, "vnpobj", 0);
111	}
112	vp->v_flag |= VOLOCK;
113
114	/*
115	 * If the object is being terminated, wait for it to
116	 * go away.
117	 */
118	while (((object = vp->v_object) != NULL) && (object->flags & OBJ_DEAD)) {
119		tsleep(object, PVM, "vadead", 0);
120	}
121
122	if (object == NULL) {
123		/*
124		 * And an object of the appropriate size
125		 */
126		object = vm_object_allocate(OBJT_VNODE, round_page(size));
127		object->flags = OBJ_CANPERSIST;
128
129		/*
130		 * Hold a reference to the vnode and initialize object data.
131		 */
132		VREF(vp);
133		object->un_pager.vnp.vnp_size = size;
134
135		object->handle = handle;
136		vp->v_object = object;
137	} else {
138		/*
139		 * vm_object_reference() will remove the object from the cache if
140		 * found and gain a reference to the object.
141		 */
142		vm_object_reference(object);
143	}
144
145	if (vp->v_type == VREG)
146		vp->v_flag |= VVMIO;
147
148	vp->v_flag &= ~VOLOCK;
149	if (vp->v_flag & VOWANT) {
150		vp->v_flag &= ~VOWANT;
151		wakeup(vp);
152	}
153	return (object);
154}
155
156void
157vnode_pager_dealloc(object)
158	vm_object_t object;
159{
160	register struct vnode *vp = object->handle;
161
162	if (vp == NULL)
163		panic("vnode_pager_dealloc: pager already dealloced");
164
165	if (object->paging_in_progress) {
166		int s = splbio();
167		while (object->paging_in_progress) {
168			object->flags |= OBJ_PIPWNT;
169			tsleep(object, PVM, "vnpdea", 0);
170		}
171		splx(s);
172	}
173
174	object->handle = NULL;
175
176	vp->v_object = NULL;
177	vp->v_flag &= ~(VTEXT | VVMIO);
178	vp->v_flag |= VAGE;
179	vrele(vp);
180}
181
182boolean_t
183vnode_pager_haspage(object, offset, before, after)
184	vm_object_t object;
185	vm_offset_t offset;
186	int *before;
187	int *after;
188{
189	struct vnode *vp = object->handle;
190	daddr_t bn;
191	int err, run;
192	daddr_t reqblock;
193	int poff;
194	int bsize = vp->v_mount->mnt_stat.f_iosize;
195	int pagesperblock;
196
197	/*
198	 * If filesystem no longer mounted or offset beyond end of file we do
199	 * not have the page.
200	 */
201	if ((vp->v_mount == NULL) || (offset >= object->un_pager.vnp.vnp_size))
202		return FALSE;
203
204	pagesperblock = bsize / PAGE_SIZE;
205	reqblock = offset / bsize;
206	err = VOP_BMAP(vp, reqblock, (struct vnode **) 0, &bn,
207		after, before);
208	if (err)
209		return TRUE;
210	if (((long) bn) < 0)
211		return FALSE;
212	poff = (offset - (reqblock * bsize)) / PAGE_SIZE;
213	if (before) {
214		*before *= pagesperblock;
215		*before += poff;
216	}
217	if (after) {
218		int numafter;
219		*after *= pagesperblock;
220		numafter = pagesperblock - (poff + 1);
221		if (offset + numafter * PAGE_SIZE > object->un_pager.vnp.vnp_size) {
222			numafter = (object->un_pager.vnp.vnp_size - offset)/PAGE_SIZE;
223		}
224		*after += numafter;
225	}
226	return TRUE;
227}
228
229/*
230 * Lets the VM system know about a change in size for a file.
231 * We adjust our own internal size and flush any cached pages in
232 * the associated object that are affected by the size change.
233 *
234 * Note: this routine may be invoked as a result of a pager put
235 * operation (possibly at object termination time), so we must be careful.
236 */
237void
238vnode_pager_setsize(vp, nsize)
239	struct vnode *vp;
240	u_long nsize;
241{
242	vm_object_t object = vp->v_object;
243
244	if (object == NULL)
245		return;
246
247	/*
248	 * Hasn't changed size
249	 */
250	if (nsize == object->un_pager.vnp.vnp_size)
251		return;
252
253	/*
254	 * File has shrunk. Toss any cached pages beyond the new EOF.
255	 */
256	if (nsize < object->un_pager.vnp.vnp_size) {
257		if (round_page((vm_offset_t) nsize) < object->un_pager.vnp.vnp_size) {
258			vm_object_page_remove(object,
259			    round_page((vm_offset_t) nsize), object->un_pager.vnp.vnp_size, FALSE);
260		}
261		/*
262		 * this gets rid of garbage at the end of a page that is now
263		 * only partially backed by the vnode...
264		 */
265		if (nsize & PAGE_MASK) {
266			vm_offset_t kva;
267			vm_page_t m;
268
269			m = vm_page_lookup(object, trunc_page((vm_offset_t) nsize));
270			if (m) {
271				kva = vm_pager_map_page(m);
272				bzero((caddr_t) kva + (nsize & PAGE_MASK),
273				    round_page(nsize) - nsize);
274				vm_pager_unmap_page(kva);
275			}
276		}
277	}
278	object->un_pager.vnp.vnp_size = (vm_offset_t) nsize;
279	object->size = round_page(nsize);
280}
281
282void
283vnode_pager_umount(mp)
284	register struct mount *mp;
285{
286	struct vnode *vp, *nvp;
287
288loop:
289	for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) {
290		/*
291		 * Vnode can be reclaimed by getnewvnode() while we
292		 * traverse the list.
293		 */
294		if (vp->v_mount != mp)
295			goto loop;
296
297		/*
298		 * Save the next pointer now since uncaching may terminate the
299		 * object and render vnode invalid
300		 */
301		nvp = vp->v_mntvnodes.le_next;
302
303		if (vp->v_object != NULL) {
304			VOP_LOCK(vp);
305			vnode_pager_uncache(vp);
306			VOP_UNLOCK(vp);
307		}
308	}
309}
310
311/*
312 * Remove vnode associated object from the object cache.
313 * This routine must be called with the vnode locked.
314 *
315 * XXX unlock the vnode.
316 * We must do this since uncaching the object may result in its
317 * destruction which may initiate paging activity which may necessitate
318 * re-locking the vnode.
319 */
320void
321vnode_pager_uncache(vp)
322	struct vnode *vp;
323{
324	vm_object_t object;
325
326	/*
327	 * Not a mapped vnode
328	 */
329	object = vp->v_object;
330	if (object == NULL)
331		return;
332
333	vm_object_reference(object);
334	VOP_UNLOCK(vp);
335	pager_cache(object, FALSE);
336	VOP_LOCK(vp);
337	return;
338}
339
340
341void
342vnode_pager_freepage(m)
343	vm_page_t m;
344{
345	PAGE_WAKEUP(m);
346	vm_page_free(m);
347}
348
349/*
350 * calculate the linear (byte) disk address of specified virtual
351 * file address
352 */
353vm_offset_t
354vnode_pager_addr(vp, address, run)
355	struct vnode *vp;
356	vm_offset_t address;
357	int *run;
358{
359	int rtaddress;
360	int bsize;
361	vm_offset_t block;
362	struct vnode *rtvp;
363	int err;
364	int vblock, voffset;
365
366	if ((int) address < 0)
367		return -1;
368
369	bsize = vp->v_mount->mnt_stat.f_iosize;
370	vblock = address / bsize;
371	voffset = address % bsize;
372
373	err = VOP_BMAP(vp, vblock, &rtvp, &block, run, NULL);
374
375	if (err || (block == -1))
376		rtaddress = -1;
377	else {
378		rtaddress = block + voffset / DEV_BSIZE;
379		if( run) {
380			*run += 1;
381			*run *= bsize/PAGE_SIZE;
382			*run -= voffset/PAGE_SIZE;
383		}
384	}
385
386	return rtaddress;
387}
388
389/*
390 * interrupt routine for I/O completion
391 */
392void
393vnode_pager_iodone(bp)
394	struct buf *bp;
395{
396	bp->b_flags |= B_DONE;
397	wakeup(bp);
398}
399
400/*
401 * small block file system vnode pager input
402 */
403int
404vnode_pager_input_smlfs(object, m)
405	vm_object_t object;
406	vm_page_t m;
407{
408	int i;
409	int s;
410	struct vnode *dp, *vp;
411	struct buf *bp;
412	vm_offset_t kva;
413	int fileaddr;
414	vm_offset_t bsize;
415	int error = 0;
416
417	vp = object->handle;
418	bsize = vp->v_mount->mnt_stat.f_iosize;
419
420
421	VOP_BMAP(vp, 0, &dp, 0, NULL, NULL);
422
423	kva = vm_pager_map_page(m);
424
425	for (i = 0; i < PAGE_SIZE / bsize; i++) {
426
427		if ((vm_page_bits(m->offset + i * bsize, bsize) & m->valid))
428			continue;
429
430		fileaddr = vnode_pager_addr(vp, m->offset + i * bsize, (int *)0);
431		if (fileaddr != -1) {
432			bp = getpbuf();
433
434			/* build a minimal buffer header */
435			bp->b_flags = B_BUSY | B_READ | B_CALL;
436			bp->b_iodone = vnode_pager_iodone;
437			bp->b_proc = curproc;
438			bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
439			if (bp->b_rcred != NOCRED)
440				crhold(bp->b_rcred);
441			if (bp->b_wcred != NOCRED)
442				crhold(bp->b_wcred);
443			bp->b_un.b_addr = (caddr_t) kva + i * bsize;
444			bp->b_blkno = fileaddr;
445			pbgetvp(dp, bp);
446			bp->b_bcount = bsize;
447			bp->b_bufsize = bsize;
448
449			/* do the input */
450			VOP_STRATEGY(bp);
451
452			/* we definitely need to be at splbio here */
453
454			s = splbio();
455			while ((bp->b_flags & B_DONE) == 0) {
456				tsleep(bp, PVM, "vnsrd", 0);
457			}
458			splx(s);
459			if ((bp->b_flags & B_ERROR) != 0)
460				error = EIO;
461
462			/*
463			 * free the buffer header back to the swap buffer pool
464			 */
465			relpbuf(bp);
466			if (error)
467				break;
468
469			vm_page_set_validclean(m, (i * bsize) & (PAGE_SIZE-1), bsize);
470		} else {
471			vm_page_set_validclean(m, (i * bsize) & (PAGE_SIZE-1), bsize);
472			bzero((caddr_t) kva + i * bsize, bsize);
473		}
474	}
475	vm_pager_unmap_page(kva);
476	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
477	m->flags &= ~PG_ZERO;
478	if (error) {
479		return VM_PAGER_ERROR;
480	}
481	return VM_PAGER_OK;
482
483}
484
485
486/*
487 * old style vnode pager output routine
488 */
489int
490vnode_pager_input_old(object, m)
491	vm_object_t object;
492	vm_page_t m;
493{
494	struct uio auio;
495	struct iovec aiov;
496	int error;
497	int size;
498	vm_offset_t kva;
499
500	error = 0;
501
502	/*
503	 * Return failure if beyond current EOF
504	 */
505	if (m->offset >= object->un_pager.vnp.vnp_size) {
506		return VM_PAGER_BAD;
507	} else {
508		size = PAGE_SIZE;
509		if (m->offset + size > object->un_pager.vnp.vnp_size)
510			size = object->un_pager.vnp.vnp_size - m->offset;
511
512		/*
513		 * Allocate a kernel virtual address and initialize so that
514		 * we can use VOP_READ/WRITE routines.
515		 */
516		kva = vm_pager_map_page(m);
517
518		aiov.iov_base = (caddr_t) kva;
519		aiov.iov_len = size;
520		auio.uio_iov = &aiov;
521		auio.uio_iovcnt = 1;
522		auio.uio_offset = m->offset;
523		auio.uio_segflg = UIO_SYSSPACE;
524		auio.uio_rw = UIO_READ;
525		auio.uio_resid = size;
526		auio.uio_procp = (struct proc *) 0;
527
528		error = VOP_READ(object->handle, &auio, 0, curproc->p_ucred);
529		if (!error) {
530			register int count = size - auio.uio_resid;
531
532			if (count == 0)
533				error = EINVAL;
534			else if (count != PAGE_SIZE)
535				bzero((caddr_t) kva + count, PAGE_SIZE - count);
536		}
537		vm_pager_unmap_page(kva);
538	}
539	pmap_clear_modify(VM_PAGE_TO_PHYS(m));
540	m->dirty = 0;
541	m->flags &= ~PG_ZERO;
542	return error ? VM_PAGER_ERROR : VM_PAGER_OK;
543}
544
545/*
546 * generic vnode pager input routine
547 */
548
549int
550vnode_pager_getpages(object, m, count, reqpage)
551	vm_object_t object;
552	vm_page_t *m;
553	int count;
554	int reqpage;
555{
556	int rtval;
557	struct vnode *vp;
558	vp = object->handle;
559	rtval = VOP_GETPAGES(vp, m, count, reqpage);
560	if (rtval == EOPNOTSUPP)
561		return vnode_pager_leaf_getpages(object, m, count, reqpage);
562	else
563		return rtval;
564}
565
566static int
567vnode_pager_leaf_getpages(object, m, count, reqpage)
568	vm_object_t object;
569	vm_page_t *m;
570	int count;
571	int reqpage;
572{
573	vm_offset_t kva, foff;
574	int i, size, bsize, first, firstaddr;
575	struct vnode *dp, *vp;
576	int runpg;
577	int runend;
578	struct buf *bp;
579	int s;
580	int error = 0;
581
582	vp = object->handle;
583	bsize = vp->v_mount->mnt_stat.f_iosize;
584
585	/* get the UNDERLYING device for the file with VOP_BMAP() */
586
587	/*
588	 * originally, we did not check for an error return value -- assuming
589	 * an fs always has a bmap entry point -- that assumption is wrong!!!
590	 */
591	foff = m[reqpage]->offset;
592
593	/*
594	 * if we can't bmap, use old VOP code
595	 */
596	if (VOP_BMAP(vp, 0, &dp, 0, NULL, NULL)) {
597		for (i = 0; i < count; i++) {
598			if (i != reqpage) {
599				vnode_pager_freepage(m[i]);
600			}
601		}
602		cnt.v_vnodein++;
603		cnt.v_vnodepgsin++;
604		return vnode_pager_input_old(object, m[reqpage]);
605
606		/*
607		 * if the blocksize is smaller than a page size, then use
608		 * special small filesystem code.  NFS sometimes has a small
609		 * blocksize, but it can handle large reads itself.
610		 */
611	} else if ((PAGE_SIZE / bsize) > 1 &&
612	    (vp->v_mount->mnt_stat.f_type != MOUNT_NFS)) {
613
614		for (i = 0; i < count; i++) {
615			if (i != reqpage) {
616				vnode_pager_freepage(m[i]);
617			}
618		}
619		cnt.v_vnodein++;
620		cnt.v_vnodepgsin++;
621		return vnode_pager_input_smlfs(object, m[reqpage]);
622	}
623	/*
624	 * if ANY DEV_BSIZE blocks are valid on a large filesystem block
625	 * then, the entire page is valid --
626	 */
627	if (m[reqpage]->valid) {
628		m[reqpage]->valid = VM_PAGE_BITS_ALL;
629		for (i = 0; i < count; i++) {
630			if (i != reqpage)
631				vnode_pager_freepage(m[i]);
632		}
633		return VM_PAGER_OK;
634	}
635
636	/*
637	 * here on direct device I/O
638	 */
639
640	firstaddr = -1;
641	/*
642	 * calculate the run that includes the required page
643	 */
644	for(first = 0, i = 0; i < count; i = runend) {
645		firstaddr = vnode_pager_addr(vp, m[i]->offset, &runpg);
646		if (firstaddr == -1) {
647			if (i == reqpage && foff < object->un_pager.vnp.vnp_size) {
648				panic("vnode_pager_putpages: unexpected missing page: firstaddr: %d, foff: %ld, vnp_size: %d",
649			   	 firstaddr, foff, object->un_pager.vnp.vnp_size);
650			}
651			vnode_pager_freepage(m[i]);
652			runend = i + 1;
653			first = runend;
654			continue;
655		}
656		runend = i + runpg;
657		if (runend <= reqpage) {
658			int j;
659			for (j = i; j < runend; j++) {
660				vnode_pager_freepage(m[j]);
661			}
662		} else {
663			if (runpg < (count - first)) {
664				for (i = first + runpg; i < count; i++)
665					vnode_pager_freepage(m[i]);
666				count = first + runpg;
667			}
668			break;
669		}
670		first = runend;
671	}
672
673	/*
674	 * the first and last page have been calculated now, move input pages
675	 * to be zero based...
676	 */
677	if (first != 0) {
678		for (i = first; i < count; i++) {
679			m[i - first] = m[i];
680		}
681		count -= first;
682		reqpage -= first;
683	}
684
685	/*
686	 * calculate the file virtual address for the transfer
687	 */
688	foff = m[0]->offset;
689
690	/*
691	 * calculate the size of the transfer
692	 */
693	size = count * PAGE_SIZE;
694	if ((foff + size) > object->un_pager.vnp.vnp_size)
695		size = object->un_pager.vnp.vnp_size - foff;
696
697	/*
698	 * round up physical size for real devices
699	 */
700	if (dp->v_type == VBLK || dp->v_type == VCHR)
701		size = (size + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
702
703	bp = getpbuf();
704	kva = (vm_offset_t) bp->b_data;
705
706	/*
707	 * and map the pages to be read into the kva
708	 */
709	pmap_qenter(kva, m, count);
710
711	/* build a minimal buffer header */
712	bp->b_flags = B_BUSY | B_READ | B_CALL;
713	bp->b_iodone = vnode_pager_iodone;
714	/* B_PHYS is not set, but it is nice to fill this in */
715	bp->b_proc = curproc;
716	bp->b_rcred = bp->b_wcred = bp->b_proc->p_ucred;
717	if (bp->b_rcred != NOCRED)
718		crhold(bp->b_rcred);
719	if (bp->b_wcred != NOCRED)
720		crhold(bp->b_wcred);
721	bp->b_blkno = firstaddr;
722	pbgetvp(dp, bp);
723	bp->b_bcount = size;
724	bp->b_bufsize = size;
725
726	cnt.v_vnodein++;
727	cnt.v_vnodepgsin += count;
728
729	/* do the input */
730	VOP_STRATEGY(bp);
731
732	s = splbio();
733	/* we definitely need to be at splbio here */
734
735	while ((bp->b_flags & B_DONE) == 0) {
736		tsleep(bp, PVM, "vnread", 0);
737	}
738	splx(s);
739	if ((bp->b_flags & B_ERROR) != 0)
740		error = EIO;
741
742	if (!error) {
743		if (size != count * PAGE_SIZE)
744			bzero((caddr_t) kva + size, PAGE_SIZE * count - size);
745	}
746	pmap_qremove(kva, count);
747
748	/*
749	 * free the buffer header back to the swap buffer pool
750	 */
751	relpbuf(bp);
752
753	for (i = 0; i < count; i++) {
754		pmap_clear_modify(VM_PAGE_TO_PHYS(m[i]));
755		m[i]->dirty = 0;
756		m[i]->valid = VM_PAGE_BITS_ALL;
757		m[i]->flags &= ~PG_ZERO;
758		if (i != reqpage) {
759
760			/*
761			 * whether or not to leave the page activated is up in
762			 * the air, but we should put the page on a page queue
763			 * somewhere. (it already is in the object). Result:
764			 * It appears that emperical results show that
765			 * deactivating pages is best.
766			 */
767
768			/*
769			 * just in case someone was asking for this page we
770			 * now tell them that it is ok to use
771			 */
772			if (!error) {
773				vm_page_deactivate(m[i]);
774				PAGE_WAKEUP(m[i]);
775			} else {
776				vnode_pager_freepage(m[i]);
777			}
778		}
779	}
780	if (error) {
781		printf("vnode_pager_getpages: I/O read error\n");
782	}
783	return (error ? VM_PAGER_ERROR : VM_PAGER_OK);
784}
785
786int
787vnode_pager_putpages(object, m, count, sync, rtvals)
788	vm_object_t object;
789	vm_page_t *m;
790	int count;
791	boolean_t sync;
792	int *rtvals;
793{
794	int rtval;
795	struct vnode *vp;
796	vp = object->handle;
797	rtval = VOP_PUTPAGES(vp, m, count, sync, rtvals);
798	if (rtval == EOPNOTSUPP)
799		return vnode_pager_leaf_putpages(object, m, count, sync, rtvals);
800	else
801		return rtval;
802}
803
804/*
805 * generic vnode pager output routine
806 */
807static int
808vnode_pager_leaf_putpages(object, m, count, sync, rtvals)
809	vm_object_t object;
810	vm_page_t *m;
811	int count;
812	boolean_t sync;
813	int *rtvals;
814{
815	int i;
816
817	struct vnode *vp;
818	int maxsize, ncount;
819	struct uio auio;
820	struct iovec aiov;
821	int error;
822
823	vp = object->handle;;
824	for (i = 0; i < count; i++)
825		rtvals[i] = VM_PAGER_AGAIN;
826
827	if ((int) m[0]->offset < 0) {
828		printf("vnode_pager_putpages: attempt to write meta-data!!! -- 0x%x(%x)\n", m[0]->offset, m[0]->dirty);
829		rtvals[0] = VM_PAGER_BAD;
830		return VM_PAGER_BAD;
831	}
832
833	maxsize = count * PAGE_SIZE;
834	ncount = count;
835
836	if (maxsize + m[0]->offset > object->un_pager.vnp.vnp_size) {
837		if (object->un_pager.vnp.vnp_size > m[0]->offset)
838			maxsize = object->un_pager.vnp.vnp_size - m[0]->offset;
839		else
840			maxsize = 0;
841		ncount = (maxsize + PAGE_SIZE - 1) / PAGE_SIZE;
842		if (ncount < count) {
843			for (i = ncount; i < count; i++) {
844				rtvals[i] = VM_PAGER_BAD;
845			}
846			if (ncount == 0) {
847				printf("vnode_pager_putpages: write past end of file: %d, %d\n",
848					m[0]->offset, object->un_pager.vnp.vnp_size);
849				return rtvals[0];
850			}
851		}
852	}
853
854	for (i = 0; i < count; i++) {
855		m[i]->busy++;
856		m[i]->flags &= ~PG_BUSY;
857	}
858
859	aiov.iov_base = (caddr_t) 0;
860	aiov.iov_len = maxsize;
861	auio.uio_iov = &aiov;
862	auio.uio_iovcnt = 1;
863	auio.uio_offset = m[0]->offset;
864	auio.uio_segflg = UIO_NOCOPY;
865	auio.uio_rw = UIO_WRITE;
866	auio.uio_resid = maxsize;
867	auio.uio_procp = (struct proc *) 0;
868	error = VOP_WRITE(vp, &auio, IO_VMIO, curproc->p_ucred);
869	cnt.v_vnodeout++;
870	cnt.v_vnodepgsout += ncount;
871
872	if (error) {
873		printf("vnode_pager_putpages: I/O error %d\n", error);
874	}
875	if (auio.uio_resid) {
876		printf("vnode_pager_putpages: residual I/O %d at %d\n", auio.uio_resid, m[0]->offset);
877	}
878	for (i = 0; i < count; i++) {
879		m[i]->busy--;
880		if (i < ncount) {
881			rtvals[i] = VM_PAGER_OK;
882		}
883		if ((m[i]->busy == 0) && (m[i]->flags & PG_WANTED))
884			wakeup(m[i]);
885	}
886	return rtvals[0];
887}
888
889struct vnode *
890vnode_pager_lock(object)
891	vm_object_t object;
892{
893	for (; object != NULL; object = object->backing_object) {
894		if (object->type != OBJT_VNODE)
895			continue;
896
897		VOP_LOCK(object->handle);
898		return object->handle;
899	}
900	return NULL;
901}
902