phys_pager.c revision 63973
1/*
2 * Copyright (c) 2000 Peter Wemm
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 * $FreeBSD: head/sys/vm/phys_pager.c 63973 2000-07-28 22:03:08Z peter $
26 */
27
28#include <sys/param.h>
29#include <sys/systm.h>
30#include <sys/linker_set.h>
31#include <sys/conf.h>
32#include <sys/mman.h>
33#include <sys/sysctl.h>
34
35#include <vm/vm.h>
36#include <vm/vm_object.h>
37#include <vm/vm_page.h>
38#include <vm/vm_pager.h>
39#include <vm/vm_zone.h>
40
41/* list of device pager objects */
42static struct pagerlst phys_pager_object_list;
43
44static int phys_pager_alloc_lock, phys_pager_alloc_lock_want;
45
46static void
47phys_pager_init(void)
48{
49
50	TAILQ_INIT(&phys_pager_object_list);
51}
52
53static vm_object_t
54phys_pager_alloc(void *handle, vm_ooffset_t size, vm_prot_t prot,
55		 vm_ooffset_t foff)
56{
57	vm_object_t object;
58
59	/*
60	 * Offset should be page aligned.
61	 */
62	if (foff & PAGE_MASK)
63		return (NULL);
64
65	size = round_page(size);
66
67	/*
68	 * Lock to prevent object creation race condition.
69	 */
70	while (phys_pager_alloc_lock) {
71		phys_pager_alloc_lock_want++;
72		tsleep(&phys_pager_alloc_lock, PVM, "ppall", 0);
73		phys_pager_alloc_lock_want--;
74	}
75	phys_pager_alloc_lock = 1;
76
77	/*
78	 * Look up pager, creating as necessary.
79	 */
80	object = vm_pager_object_lookup(&phys_pager_object_list, handle);
81	if (object == NULL) {
82		/*
83		 * Allocate object and associate it with the pager.
84		 */
85		object = vm_object_allocate(OBJT_PHYS,
86			OFF_TO_IDX(foff + size));
87		object->handle = handle;
88		TAILQ_INSERT_TAIL(&phys_pager_object_list, object,
89		    pager_object_list);
90	} else {
91		/*
92		 * Gain a reference to the object.
93		 */
94		vm_object_reference(object);
95		if (OFF_TO_IDX(foff + size) > object->size)
96			object->size = OFF_TO_IDX(foff + size);
97	}
98
99	phys_pager_alloc_lock = 0;
100	if (phys_pager_alloc_lock_want)
101		wakeup(&phys_pager_alloc_lock);
102
103	return (object);
104}
105
106static void
107phys_pager_dealloc(vm_object_t object)
108{
109
110	TAILQ_REMOVE(&phys_pager_object_list, object, pager_object_list);
111}
112
113static int
114phys_pager_getpages(vm_object_t object, vm_page_t *m, int count, int reqpage)
115{
116	int i, s;
117
118	s = splvm();
119	/*
120	 * Fill as many pages as vm_fault has allocated for us.
121	 */
122	for (i = 0; i < count; i++) {
123		if ((m[i]->flags & PG_ZERO) == 0)
124			vm_page_zero_fill(m[i]);
125		vm_page_flag_set(m[i], PG_ZERO);
126		/* Switch off pv_entries */
127		vm_page_unmanage(m[i]);
128		m[i]->valid = VM_PAGE_BITS_ALL;
129		m[i]->dirty = 0;
130		/* The requested page must remain busy, the others not. */
131		if (reqpage != i) {
132			vm_page_flag_clear(m[i], PG_BUSY);
133			m[i]->busy = 0;
134		}
135	}
136	splx(s);
137
138	return (VM_PAGER_OK);
139}
140
141static void
142phys_pager_putpages(vm_object_t object, vm_page_t *m, int count, boolean_t sync,
143		    int *rtvals)
144{
145
146	panic("phys_pager_putpage called");
147}
148
149/*
150 * Implement a pretty aggressive clustered getpages strategy.  Hint that
151 * everything in an entire 4MB window should be prefaulted at once.
152 *
153 * XXX 4MB (1024 slots per page table page) is convenient for x86,
154 * but may not be for other arches.
155 */
156#ifndef PHYSCLUSTER
157#define PHYSCLUSTER 1024
158#endif
159static boolean_t
160phys_pager_haspage(vm_object_t object, vm_pindex_t pindex, int *before,
161		   int *after)
162{
163	vm_pindex_t base, end;
164
165	base = pindex & (~(PHYSCLUSTER - 1));
166	end = base + (PHYSCLUSTER - 1);
167	if (before != NULL)
168		*before = pindex - base;
169	if (after != NULL)
170		*after = end - pindex;
171	return (TRUE);
172}
173
174struct pagerops physpagerops = {
175	phys_pager_init,
176	phys_pager_alloc,
177	phys_pager_dealloc,
178	phys_pager_getpages,
179	phys_pager_putpages,
180	phys_pager_haspage,
181	NULL
182};
183