vm_pager.c revision 33108
1/*
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * The Mach Operating System project at Carnegie-Mellon University.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	from: @(#)vm_pager.c	8.6 (Berkeley) 1/12/94
37 *
38 *
39 * Copyright (c) 1987, 1990 Carnegie-Mellon University.
40 * All rights reserved.
41 *
42 * Authors: Avadis Tevanian, Jr., Michael Wayne Young
43 *
44 * Permission to use, copy, modify and distribute this software and
45 * its documentation is hereby granted, provided that both the copyright
46 * notice and this permission notice appear in all copies of the
47 * software, derivative works or modified versions, and any portions
48 * thereof, and that both notices appear in supporting documentation.
49 *
50 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53 *
54 * Carnegie Mellon requests users of this software to return to
55 *
56 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
57 *  School of Computer Science
58 *  Carnegie Mellon University
59 *  Pittsburgh PA 15213-3890
60 *
61 * any improvements or extensions that they make and grant Carnegie the
62 * rights to redistribute these changes.
63 *
64 * $Id: vm_pager.c,v 1.32 1998/01/24 02:01:46 dyson Exp $
65 */
66
67/*
68 *	Paging space routine stubs.  Emulates a matchmaker-like interface
69 *	for builtin pagers.
70 */
71
72#include "opt_diagnostic.h"
73
74#include <sys/param.h>
75#include <sys/systm.h>
76#include <sys/buf.h>
77#include <sys/ucred.h>
78#include <sys/malloc.h>
79
80#include <vm/vm.h>
81#include <vm/vm_param.h>
82#include <vm/vm_prot.h>
83#include <vm/vm_object.h>
84#include <vm/vm_page.h>
85#include <vm/vm_pager.h>
86#include <vm/vm_extern.h>
87
88MALLOC_DEFINE(M_VMPGDATA, "VM pgdata", "XXX: VM pager private data");
89
90extern struct pagerops defaultpagerops;
91extern struct pagerops swappagerops;
92extern struct pagerops vnodepagerops;
93extern struct pagerops devicepagerops;
94
95static struct pagerops *pagertab[] = {
96	&defaultpagerops,	/* OBJT_DEFAULT */
97	&swappagerops,		/* OBJT_SWAP */
98	&vnodepagerops,		/* OBJT_VNODE */
99	&devicepagerops,	/* OBJT_DEVICE */
100};
101static int npagers = sizeof(pagertab) / sizeof(pagertab[0]);
102
103/*
104 * Kernel address space for mapping pages.
105 * Used by pagers where KVAs are needed for IO.
106 *
107 * XXX needs to be large enough to support the number of pending async
108 * cleaning requests (NPENDINGIO == 64) * the maximum swap cluster size
109 * (MAXPHYS == 64k) if you want to get the most efficiency.
110 */
111#define PAGER_MAP_SIZE	(8 * 1024 * 1024)
112
113int pager_map_size = PAGER_MAP_SIZE;
114vm_map_t pager_map;
115static int bswneeded;
116static vm_offset_t swapbkva;		/* swap buffers kva */
117
118void
119vm_pager_init()
120{
121	struct pagerops **pgops;
122
123	/*
124	 * Initialize known pagers
125	 */
126	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
127		if (pgops && ((*pgops)->pgo_init != NULL))
128			(*(*pgops)->pgo_init) ();
129}
130
131void
132vm_pager_bufferinit()
133{
134	struct buf *bp;
135	int i;
136
137	bp = swbuf;
138	/*
139	 * Now set up swap and physical I/O buffer headers.
140	 */
141	for (i = 0; i < nswbuf; i++, bp++) {
142		TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
143		bp->b_rcred = bp->b_wcred = NOCRED;
144		bp->b_vnbufs.le_next = NOLIST;
145	}
146
147	swapbkva = kmem_alloc_pageable(pager_map, nswbuf * MAXPHYS);
148	if (!swapbkva)
149		panic("Not enough pager_map VM space for physical buffers");
150}
151
152/*
153 * Allocate an instance of a pager of the given type.
154 * Size, protection and offset parameters are passed in for pagers that
155 * need to perform page-level validation (e.g. the device pager).
156 */
157vm_object_t
158vm_pager_allocate(objtype_t type, void *handle, vm_size_t size, vm_prot_t prot,
159		  vm_ooffset_t off)
160{
161	struct pagerops *ops;
162
163	ops = pagertab[type];
164	if (ops)
165		return ((*ops->pgo_alloc) (handle, size, prot, off));
166	return (NULL);
167}
168
169void
170vm_pager_deallocate(object)
171	vm_object_t object;
172{
173	(*pagertab[object->type]->pgo_dealloc) (object);
174}
175
176
177int
178vm_pager_get_pages(object, m, count, reqpage)
179	vm_object_t object;
180	vm_page_t *m;
181	int count;
182	int reqpage;
183{
184	return ((*pagertab[object->type]->pgo_getpages)(object, m, count, reqpage));
185}
186
187int
188vm_pager_put_pages(object, m, count, sync, rtvals)
189	vm_object_t object;
190	vm_page_t *m;
191	int count;
192	boolean_t sync;
193	int *rtvals;
194{
195	return ((*pagertab[object->type]->pgo_putpages)(object, m, count, sync, rtvals));
196}
197
198boolean_t
199vm_pager_has_page(object, offset, before, after)
200	vm_object_t object;
201	vm_pindex_t offset;
202	int *before;
203	int *after;
204{
205	return ((*pagertab[object->type]->pgo_haspage) (object, offset, before, after));
206}
207
208/*
209 * Called by pageout daemon before going back to sleep.
210 * Gives pagers a chance to clean up any completed async pageing operations.
211 */
212void
213vm_pager_sync()
214{
215	struct pagerops **pgops;
216
217	for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++)
218		if (pgops && ((*pgops)->pgo_sync != NULL))
219			(*(*pgops)->pgo_sync) ();
220}
221
222vm_offset_t
223vm_pager_map_page(m)
224	vm_page_t m;
225{
226	vm_offset_t kva;
227
228	kva = kmem_alloc_wait(pager_map, PAGE_SIZE);
229	pmap_kenter(kva, VM_PAGE_TO_PHYS(m));
230	return (kva);
231}
232
233void
234vm_pager_unmap_page(kva)
235	vm_offset_t kva;
236{
237	pmap_kremove(kva);
238	kmem_free_wakeup(pager_map, kva, PAGE_SIZE);
239}
240
241vm_object_t
242vm_pager_object_lookup(pg_list, handle)
243	register struct pagerlst *pg_list;
244	void *handle;
245{
246	register vm_object_t object;
247
248	for (object = TAILQ_FIRST(pg_list); object != NULL; object = TAILQ_NEXT(object,pager_object_list))
249		if (object->handle == handle)
250			return (object);
251	return (NULL);
252}
253
254/*
255 * initialize a physical buffer
256 */
257
258static void
259initpbuf(struct buf *bp) {
260	bzero(bp, sizeof *bp);
261	bp->b_rcred = NOCRED;
262	bp->b_wcred = NOCRED;
263	bp->b_qindex = QUEUE_NONE;
264	bp->b_data = (caddr_t) (MAXPHYS * (bp - swbuf)) + swapbkva;
265	bp->b_kvabase = bp->b_data;
266	bp->b_kvasize = MAXPHYS;
267	bp->b_vnbufs.le_next = NOLIST;
268}
269
270/*
271 * allocate a physical buffer
272 */
273struct buf *
274getpbuf()
275{
276	int s;
277	struct buf *bp;
278
279	s = splbio();
280	/* get a bp from the swap buffer header pool */
281	while ((bp = TAILQ_FIRST(&bswlist)) == NULL) {
282		bswneeded = 1;
283		tsleep(&bswneeded, PVM, "wswbuf", 0);
284	}
285	TAILQ_REMOVE(&bswlist, bp, b_freelist);
286	splx(s);
287
288	initpbuf(bp);
289	return bp;
290}
291
292/*
293 * allocate a physical buffer, if one is available
294 */
295struct buf *
296trypbuf()
297{
298	int s;
299	struct buf *bp;
300
301	s = splbio();
302	if ((bp = TAILQ_FIRST(&bswlist)) == NULL) {
303		splx(s);
304		return NULL;
305	}
306	TAILQ_REMOVE(&bswlist, bp, b_freelist);
307	splx(s);
308
309	initpbuf(bp);
310
311	return bp;
312}
313
314/*
315 * release a physical buffer
316 */
317void
318relpbuf(bp)
319	struct buf *bp;
320{
321	int s;
322
323	s = splbio();
324
325	if (bp->b_rcred != NOCRED) {
326		crfree(bp->b_rcred);
327		bp->b_rcred = NOCRED;
328	}
329	if (bp->b_wcred != NOCRED) {
330		crfree(bp->b_wcred);
331		bp->b_wcred = NOCRED;
332	}
333	if (bp->b_vp)
334		pbrelvp(bp);
335
336	if (bp->b_flags & B_WANTED)
337		wakeup(bp);
338
339	TAILQ_INSERT_HEAD(&bswlist, bp, b_freelist);
340
341	if (bswneeded) {
342		bswneeded = 0;
343		wakeup(&bswneeded);
344	}
345	splx(s);
346}
347