Commit | Line | Data |
---|---|---|
175f072e | 1 | /* |
175f072e KM |
2 | * Copyright (c) 1991 Regents of the University of California. |
3 | * 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 | * | |
0e24ad83 | 8 | * %sccs.include.redist.c% |
175f072e | 9 | * |
1692aa9f | 10 | * @(#)vm_pager.c 7.8 (Berkeley) %G% |
0e24ad83 KM |
11 | * |
12 | * | |
13 | * Copyright (c) 1987, 1990 Carnegie-Mellon University. | |
14 | * All rights reserved. | |
15 | * | |
16 | * Authors: Avadis Tevanian, Jr., Michael Wayne Young | |
17 | * | |
18 | * Permission to use, copy, modify and distribute this software and | |
19 | * its documentation is hereby granted, provided that both the copyright | |
20 | * notice and this permission notice appear in all copies of the | |
21 | * software, derivative works or modified versions, and any portions | |
22 | * thereof, and that both notices appear in supporting documentation. | |
23 | * | |
24 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
25 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND | |
26 | * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
27 | * | |
28 | * Carnegie Mellon requests users of this software to return to | |
29 | * | |
30 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
31 | * School of Computer Science | |
32 | * Carnegie Mellon University | |
33 | * Pittsburgh PA 15213-3890 | |
34 | * | |
35 | * any improvements or extensions that they make and grant Carnegie the | |
36 | * rights to redistribute these changes. | |
175f072e KM |
37 | */ |
38 | ||
39 | /* | |
40 | * Paging space routine stubs. Emulates a matchmaker-like interface | |
41 | * for builtin pagers. | |
42 | */ | |
43 | ||
1692aa9f KB |
44 | #include <sys/param.h> |
45 | #include <sys/systm.h> | |
46 | #include <sys/malloc.h> | |
175f072e | 47 | |
1692aa9f KB |
48 | #include <vm/vm.h> |
49 | #include <vm/vm_page.h> | |
50 | #include <vm/vm_kern.h> | |
175f072e | 51 | |
175f072e KM |
52 | #include "swappager.h" |
53 | #if NSWAPPAGER > 0 | |
54 | extern struct pagerops swappagerops; | |
5a2135db | 55 | #define swappagerops_p &swappagerops |
175f072e | 56 | #endif |
5a2135db | 57 | |
175f072e KM |
58 | #include "vnodepager.h" |
59 | #if NVNODEPAGER > 0 | |
60 | extern struct pagerops vnodepagerops; | |
5a2135db | 61 | #define vnodepagerops_p &vnodepagerops |
175f072e | 62 | #endif |
5a2135db | 63 | |
175f072e KM |
64 | #include "devpager.h" |
65 | #if NDEVPAGER > 0 | |
66 | extern struct pagerops devicepagerops; | |
5a2135db | 67 | #define devicepagerops_p &devicepagerops |
175f072e KM |
68 | #endif |
69 | ||
70 | struct pagerops *pagertab[] = { | |
1f245e77 | 71 | #if NSWAPPAGER > 0 |
5a2135db | 72 | swappagerops_p, /* PG_SWAP */ |
1f245e77 KM |
73 | #endif |
74 | #if NVNODEPAGER > 0 | |
5a2135db | 75 | vnodepagerops_p, /* PG_VNODE */ |
1f245e77 KM |
76 | #endif |
77 | #if NDEVPAGER > 0 | |
5a2135db | 78 | devicepagerops_p, /* PG_DEV */ |
1f245e77 | 79 | #endif |
175f072e KM |
80 | }; |
81 | int npagers = sizeof (pagertab) / sizeof (pagertab[0]); | |
82 | ||
ffe0d082 | 83 | struct pagerops *dfltpagerops = NULL; /* default pager */ |
175f072e KM |
84 | |
85 | /* | |
86 | * Kernel address space for mapping pages. | |
87 | * Used by pagers where KVAs are needed for IO. | |
88 | */ | |
89 | #define PAGER_MAP_SIZE (256 * PAGE_SIZE) | |
90 | vm_map_t pager_map; | |
11371b93 | 91 | vm_offset_t pager_sva, pager_eva; |
175f072e KM |
92 | |
93 | void | |
94 | vm_pager_init() | |
95 | { | |
175f072e KM |
96 | struct pagerops **pgops; |
97 | ||
98 | /* | |
99 | * Allocate a kernel submap for tracking get/put page mappings | |
100 | */ | |
11371b93 | 101 | pager_map = kmem_suballoc(kernel_map, &pager_sva, &pager_eva, |
175f072e KM |
102 | PAGER_MAP_SIZE, FALSE); |
103 | /* | |
104 | * Initialize known pagers | |
105 | */ | |
106 | for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) | |
107 | (*(*pgops)->pgo_init)(); | |
ffe0d082 | 108 | if (dfltpagerops == NULL) |
175f072e KM |
109 | panic("no default pager"); |
110 | } | |
111 | ||
112 | /* | |
113 | * Allocate an instance of a pager of the given type. | |
114 | */ | |
115 | vm_pager_t | |
116 | vm_pager_allocate(type, handle, size, prot) | |
117 | int type; | |
118 | caddr_t handle; | |
119 | vm_size_t size; | |
120 | vm_prot_t prot; | |
121 | { | |
122 | vm_pager_t pager; | |
123 | struct pagerops *ops; | |
124 | ||
125 | ops = (type == PG_DFLT) ? dfltpagerops : pagertab[type]; | |
126 | return((*ops->pgo_alloc)(handle, size, prot)); | |
127 | } | |
128 | ||
129 | void | |
130 | vm_pager_deallocate(pager) | |
131 | vm_pager_t pager; | |
132 | { | |
ffe0d082 | 133 | if (pager == NULL) |
175f072e KM |
134 | panic("vm_pager_deallocate: null pager"); |
135 | ||
136 | VM_PAGER_DEALLOC(pager); | |
137 | } | |
138 | ||
1692aa9f | 139 | int |
175f072e KM |
140 | vm_pager_get(pager, m, sync) |
141 | vm_pager_t pager; | |
142 | vm_page_t m; | |
143 | boolean_t sync; | |
144 | { | |
145 | extern boolean_t vm_page_zero_fill(); | |
146 | ||
ffe0d082 | 147 | if (pager == NULL) |
175f072e KM |
148 | return(vm_page_zero_fill(m) ? VM_PAGER_OK : VM_PAGER_FAIL); |
149 | return(VM_PAGER_GET(pager, m, sync)); | |
150 | } | |
151 | ||
1692aa9f | 152 | int |
175f072e KM |
153 | vm_pager_put(pager, m, sync) |
154 | vm_pager_t pager; | |
155 | vm_page_t m; | |
156 | boolean_t sync; | |
157 | { | |
ffe0d082 | 158 | if (pager == NULL) |
175f072e KM |
159 | panic("vm_pager_put: null pager"); |
160 | return(VM_PAGER_PUT(pager, m, sync)); | |
161 | } | |
162 | ||
163 | boolean_t | |
164 | vm_pager_has_page(pager, offset) | |
165 | vm_pager_t pager; | |
166 | vm_offset_t offset; | |
167 | { | |
ffe0d082 | 168 | if (pager == NULL) |
175f072e KM |
169 | panic("vm_pager_has_page"); |
170 | return(VM_PAGER_HASPAGE(pager, offset)); | |
171 | } | |
172 | ||
173 | /* | |
174 | * Called by pageout daemon before going back to sleep. | |
175 | * Gives pagers a chance to clean up any completed async pageing operations. | |
176 | */ | |
177 | void | |
178 | vm_pager_sync() | |
179 | { | |
180 | struct pagerops **pgops; | |
181 | ||
182 | for (pgops = pagertab; pgops < &pagertab[npagers]; pgops++) | |
ffe0d082 | 183 | (*(*pgops)->pgo_putpage)(NULL, NULL, FALSE); |
175f072e KM |
184 | } |
185 | ||
186 | vm_offset_t | |
187 | vm_pager_map_page(m) | |
188 | vm_page_t m; | |
189 | { | |
190 | vm_offset_t kva; | |
191 | ||
11371b93 MH |
192 | #ifdef DEBUG |
193 | if (!m->busy || m->active) | |
194 | panic("vm_pager_map_page: page active or not busy"); | |
195 | if (m->pagerowned) | |
196 | printf("vm_pager_map_page: page %x already in pager\n", m); | |
197 | #endif | |
175f072e | 198 | kva = kmem_alloc_wait(pager_map, PAGE_SIZE); |
11371b93 MH |
199 | #ifdef DEBUG |
200 | m->pagerowned = 1; | |
201 | #endif | |
175f072e KM |
202 | pmap_enter(vm_map_pmap(pager_map), kva, VM_PAGE_TO_PHYS(m), |
203 | VM_PROT_DEFAULT, TRUE); | |
175f072e KM |
204 | return(kva); |
205 | } | |
206 | ||
207 | void | |
208 | vm_pager_unmap_page(kva) | |
209 | vm_offset_t kva; | |
210 | { | |
11371b93 MH |
211 | #ifdef DEBUG |
212 | vm_page_t m; | |
213 | ||
214 | m = PHYS_TO_VM_PAGE(pmap_extract(vm_map_pmap(pager_map), kva)); | |
175f072e | 215 | #endif |
11371b93 | 216 | pmap_remove(vm_map_pmap(pager_map), kva, kva + PAGE_SIZE); |
175f072e | 217 | kmem_free_wakeup(pager_map, kva, PAGE_SIZE); |
11371b93 MH |
218 | #ifdef DEBUG |
219 | if (m->pagerowned) | |
220 | m->pagerowned = 0; | |
221 | else | |
222 | printf("vm_pager_unmap_page: page %x(%x/%x) not owned\n", | |
223 | m, kva, VM_PAGE_TO_PHYS(m)); | |
224 | #endif | |
175f072e KM |
225 | } |
226 | ||
227 | vm_pager_t | |
228 | vm_pager_lookup(list, handle) | |
229 | register queue_head_t *list; | |
230 | caddr_t handle; | |
231 | { | |
232 | register vm_pager_t pager; | |
233 | ||
234 | pager = (vm_pager_t) queue_first(list); | |
235 | while (!queue_end(list, (queue_entry_t)pager)) { | |
236 | if (pager->pg_handle == handle) | |
237 | return(pager); | |
238 | pager = (vm_pager_t) queue_next(&pager->pg_list); | |
239 | } | |
ffe0d082 | 240 | return(NULL); |
175f072e KM |
241 | } |
242 | ||
243 | /* | |
244 | * This routine gains a reference to the object. | |
245 | * Explicit deallocation is necessary. | |
246 | */ | |
1692aa9f | 247 | int |
175f072e KM |
248 | pager_cache(object, should_cache) |
249 | vm_object_t object; | |
250 | boolean_t should_cache; | |
251 | { | |
ffe0d082 | 252 | if (object == NULL) |
175f072e KM |
253 | return(KERN_INVALID_ARGUMENT); |
254 | ||
255 | vm_object_cache_lock(); | |
256 | vm_object_lock(object); | |
a9e495d8 KM |
257 | if (should_cache) |
258 | object->flags |= OBJ_CANPERSIST; | |
259 | else | |
260 | object->flags &= ~OBJ_CANPERSIST; | |
175f072e KM |
261 | vm_object_unlock(object); |
262 | vm_object_cache_unlock(); | |
263 | ||
264 | vm_object_deallocate(object); | |
265 | ||
266 | return(KERN_SUCCESS); | |
267 | } |