device_pager.c (8876) | device_pager.c (9507) |
---|---|
1/* 2 * Copyright (c) 1990 University of Utah. 3 * Copyright (c) 1991, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. --- 22 unchanged lines hidden (view full) --- 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)device_pager.c 8.1 (Berkeley) 6/11/93 | 1/* 2 * Copyright (c) 1990 University of Utah. 3 * Copyright (c) 1991, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. --- 22 unchanged lines hidden (view full) --- 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)device_pager.c 8.1 (Berkeley) 6/11/93 |
39 * $Id: device_pager.c,v 1.10 1995/05/18 02:59:18 davidg Exp $ | 39 * $Id: device_pager.c,v 1.11 1995/05/30 08:15:46 rgrimes Exp $ |
40 */ 41 | 40 */ 41 |
42/* 43 * Page to/from special files. 44 */ 45 | |
46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/conf.h> 49#include <sys/mman.h> 50#include <sys/malloc.h> 51#include <sys/proc.h> 52 53#include <vm/vm.h> 54#include <vm/vm_kern.h> 55#include <vm/vm_page.h> | 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/conf.h> 45#include <sys/mman.h> 46#include <sys/malloc.h> 47#include <sys/proc.h> 48 49#include <vm/vm.h> 50#include <vm/vm_kern.h> 51#include <vm/vm_page.h> |
52#include <vm/vm_pager.h> |
|
56#include <vm/device_pager.h> 57 | 53#include <vm/device_pager.h> 54 |
58struct pagerlst dev_pager_list; /* list of managed devices */ 59struct pglist dev_pager_fakelist; /* list of available vm_page_t's */ | 55struct pagerlst dev_pager_object_list; /* list of device pager objects */ 56TAILQ_HEAD(, vm_page) dev_pager_fakelist; /* list of available vm_page_t's */ |
60 | 57 |
61#ifdef DEBUG 62int dpagerdebug; 63 64#define DDB_FOLLOW 0x01 65#define DDB_INIT 0x02 66#define DDB_ALLOC 0x04 67#define DDB_FAIL 0x08 68#endif 69 70static vm_pager_t dev_pager_alloc __P((void *, vm_size_t, vm_prot_t, vm_offset_t)); 71static void dev_pager_dealloc __P((vm_pager_t)); 72static int dev_pager_getpage __P((vm_pager_t, vm_page_t, boolean_t)); 73static boolean_t dev_pager_haspage __P((vm_pager_t, vm_offset_t)); 74static void dev_pager_init __P((void)); 75static int dev_pager_putpage __P((vm_pager_t, vm_page_t, boolean_t)); | |
76static vm_page_t dev_pager_getfake __P((vm_offset_t)); 77static void dev_pager_putfake __P((vm_page_t)); 78 | 58static vm_page_t dev_pager_getfake __P((vm_offset_t)); 59static void dev_pager_putfake __P((vm_page_t)); 60 |
61static int dev_pager_alloc_lock, dev_pager_alloc_lock_want; 62 |
|
79struct pagerops devicepagerops = { 80 dev_pager_init, 81 dev_pager_alloc, 82 dev_pager_dealloc, | 63struct pagerops devicepagerops = { 64 dev_pager_init, 65 dev_pager_alloc, 66 dev_pager_dealloc, |
83 dev_pager_getpage, 84 0, 85 dev_pager_putpage, 86 0, 87 dev_pager_haspage | 67 dev_pager_getpages, 68 dev_pager_putpages, 69 dev_pager_haspage, 70 NULL |
88}; 89 | 71}; 72 |
90static void | 73void |
91dev_pager_init() 92{ | 74dev_pager_init() 75{ |
93#ifdef DEBUG 94 if (dpagerdebug & DDB_FOLLOW) 95 printf("dev_pager_init()\n"); 96#endif 97 TAILQ_INIT(&dev_pager_list); | 76 TAILQ_INIT(&dev_pager_object_list); |
98 TAILQ_INIT(&dev_pager_fakelist); 99} 100 | 77 TAILQ_INIT(&dev_pager_fakelist); 78} 79 |
101static vm_pager_t | 80vm_object_t |
102dev_pager_alloc(handle, size, prot, foff) 103 void *handle; 104 vm_size_t size; 105 vm_prot_t prot; 106 vm_offset_t foff; 107{ 108 dev_t dev; | 81dev_pager_alloc(handle, size, prot, foff) 82 void *handle; 83 vm_size_t size; 84 vm_prot_t prot; 85 vm_offset_t foff; 86{ 87 dev_t dev; |
109 vm_pager_t pager; | |
110 int (*mapfunc) (); 111 vm_object_t object; | 88 int (*mapfunc) (); 89 vm_object_t object; |
112 dev_pager_t devp; | |
113 unsigned int npages, off; 114 | 90 unsigned int npages, off; 91 |
115#ifdef DEBUG 116 if (dpagerdebug & DDB_FOLLOW) 117 printf("dev_pager_alloc(%x, %x, %x, %x)\n", 118 handle, size, prot, foff); 119#endif 120#ifdef DIAGNOSTIC | |
121 /* | 92 /* |
122 * Pageout to device, should never happen. 123 */ 124 if (handle == NULL) 125 panic("dev_pager_alloc called"); 126#endif 127 128 /* | |
129 * Make sure this device can be mapped. 130 */ 131 dev = (dev_t) (u_long) handle; 132 mapfunc = cdevsw[major(dev)].d_mmap; 133 if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop) 134 return (NULL); 135 136 /* --- 9 unchanged lines hidden (view full) --- 146 * XXX assumes VM_PROT_* == PROT_* 147 */ 148 npages = atop(round_page(size)); 149 for (off = foff; npages--; off += PAGE_SIZE) 150 if ((*mapfunc) (dev, off, (int) prot) == -1) 151 return (NULL); 152 153 /* | 93 * Make sure this device can be mapped. 94 */ 95 dev = (dev_t) (u_long) handle; 96 mapfunc = cdevsw[major(dev)].d_mmap; 97 if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop) 98 return (NULL); 99 100 /* --- 9 unchanged lines hidden (view full) --- 110 * XXX assumes VM_PROT_* == PROT_* 111 */ 112 npages = atop(round_page(size)); 113 for (off = foff; npages--; off += PAGE_SIZE) 114 if ((*mapfunc) (dev, off, (int) prot) == -1) 115 return (NULL); 116 117 /* |
118 * Lock to prevent object creation race contion. 119 */ 120 while (dev_pager_alloc_lock) { 121 dev_pager_alloc_lock_want++; 122 tsleep(&dev_pager_alloc_lock, PVM, "dvpall", 0); 123 dev_pager_alloc_lock_want--; 124 } 125 dev_pager_alloc_lock = 1; 126 127 /* |
|
154 * Look up pager, creating as necessary. 155 */ | 128 * Look up pager, creating as necessary. 129 */ |
156top: 157 pager = vm_pager_lookup(&dev_pager_list, handle); 158 if (pager == NULL) { | 130 object = vm_pager_object_lookup(&dev_pager_object_list, handle); 131 if (object == NULL) { |
159 /* | 132 /* |
160 * Allocate and initialize pager structs 161 */ 162 pager = (vm_pager_t) malloc(sizeof *pager, M_VMPAGER, M_WAITOK); 163 if (pager == NULL) 164 return (NULL); 165 devp = (dev_pager_t) malloc(sizeof *devp, M_VMPGDATA, M_WAITOK); 166 if (devp == NULL) { 167 free((caddr_t) pager, M_VMPAGER); 168 return (NULL); 169 } 170 pager->pg_handle = handle; 171 pager->pg_ops = &devicepagerops; 172 pager->pg_type = PG_DEVICE; 173 pager->pg_data = (caddr_t) devp; 174 TAILQ_INIT(&devp->devp_pglist); 175 /* | |
176 * Allocate object and associate it with the pager. 177 */ | 133 * Allocate object and associate it with the pager. 134 */ |
178 object = devp->devp_object = vm_object_allocate(foff + size); 179 object->flags &= ~OBJ_INTERNAL; 180 vm_object_enter(object, pager); 181 object->pager = pager; 182 /* 183 * Finally, put it on the managed list so other can find it. 184 * First we re-lookup in case someone else beat us to this 185 * point (due to blocking in the various mallocs). If so, we 186 * free everything and start over. 187 */ 188 if (vm_pager_lookup(&dev_pager_list, handle)) { 189 free((caddr_t) devp, M_VMPGDATA); 190 free((caddr_t) pager, M_VMPAGER); 191 goto top; 192 } 193 TAILQ_INSERT_TAIL(&dev_pager_list, pager, pg_list); 194#ifdef DEBUG 195 if (dpagerdebug & DDB_ALLOC) { 196 printf("dev_pager_alloc: pager %x devp %x object %x\n", 197 pager, devp, object); 198 vm_object_print(object, FALSE); 199 } 200#endif | 135 object = vm_object_allocate(OBJT_DEVICE, foff + size); 136 object->handle = handle; 137 TAILQ_INIT(&object->un_pager.devp.devp_pglist); 138 TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list); |
201 } else { 202 /* 203 * Gain a reference to the object. 204 */ | 139 } else { 140 /* 141 * Gain a reference to the object. 142 */ |
205 object = vm_object_lookup(pager); | 143 vm_object_reference(object); |
206 if (foff + size > object->size) 207 object->size = foff + size; | 144 if (foff + size > object->size) 145 object->size = foff + size; |
208#ifdef DIAGNOSTIC 209 devp = (dev_pager_t) pager->pg_data; 210 if (object != devp->devp_object) 211 panic("dev_pager_setup: bad object"); 212#endif | |
213 } | 146 } |
214 return (pager); | 147 148 dev_pager_alloc_lock = 0; 149 if (dev_pager_alloc_lock_want) 150 wakeup(&dev_pager_alloc_lock); 151 152 return (object); |
215} 216 | 153} 154 |
217static void 218dev_pager_dealloc(pager) 219 vm_pager_t pager; 220{ 221 dev_pager_t devp; | 155void 156dev_pager_dealloc(object) |
222 vm_object_t object; | 157 vm_object_t object; |
158{ |
|
223 vm_page_t m; 224 | 159 vm_page_t m; 160 |
225#ifdef DEBUG 226 if (dpagerdebug & DDB_FOLLOW) 227 printf("dev_pager_dealloc(%x)\n", pager); 228#endif 229 TAILQ_REMOVE(&dev_pager_list, pager, pg_list); | 161 TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list); |
230 /* | 162 /* |
231 * Get the object. Note: cannot use vm_object_lookup since object has 232 * already been removed from the hash chain. 233 */ 234 devp = (dev_pager_t) pager->pg_data; 235 object = devp->devp_object; 236#ifdef DEBUG 237 if (dpagerdebug & DDB_ALLOC) 238 printf("dev_pager_dealloc: devp %x object %x\n", devp, object); 239#endif 240 /* | |
241 * Free up our fake pages. 242 */ | 163 * Free up our fake pages. 164 */ |
243 while ((m = devp->devp_pglist.tqh_first) != 0) { 244 TAILQ_REMOVE(&devp->devp_pglist, m, pageq); | 165 while ((m = object->un_pager.devp.devp_pglist.tqh_first) != 0) { 166 TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m, pageq); |
245 dev_pager_putfake(m); 246 } | 167 dev_pager_putfake(m); 168 } |
247 free((caddr_t) devp, M_VMPGDATA); 248 free((caddr_t) pager, M_VMPAGER); | |
249} 250 | 169} 170 |
251static int 252dev_pager_getpage(pager, m, sync) 253 vm_pager_t pager; 254 vm_page_t m; 255 boolean_t sync; | 171int 172dev_pager_getpages(object, m, count, reqpage) 173 vm_object_t object; 174 vm_page_t *m; 175 int count; 176 int reqpage; |
256{ | 177{ |
257 register vm_object_t object; | |
258 vm_offset_t offset, paddr; 259 vm_page_t page; 260 dev_t dev; | 178 vm_offset_t offset, paddr; 179 vm_page_t page; 180 dev_t dev; |
261 int s; | 181 int i, s; |
262 int (*mapfunc) (), prot; 263 | 182 int (*mapfunc) (), prot; 183 |
264#ifdef DEBUG 265 if (dpagerdebug & DDB_FOLLOW) 266 printf("dev_pager_getpage(%x, %x)\n", pager, m); 267#endif 268 269 object = m->object; 270 dev = (dev_t) (u_long) pager->pg_handle; 271 offset = m->offset + object->paging_offset; | 184 dev = (dev_t) (u_long) object->handle; 185 offset = m[reqpage]->offset + object->paging_offset; |
272 prot = PROT_READ; /* XXX should pass in? */ 273 mapfunc = cdevsw[major(dev)].d_mmap; 274 275 if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop) 276 panic("dev_pager_getpage: no map function"); 277 278 paddr = pmap_phys_address((*mapfunc) ((dev_t) dev, (int) offset, prot)); 279#ifdef DIAGNOSTIC 280 if (paddr == -1) 281 panic("dev_pager_getpage: map function returns error"); 282#endif 283 /* | 186 prot = PROT_READ; /* XXX should pass in? */ 187 mapfunc = cdevsw[major(dev)].d_mmap; 188 189 if (mapfunc == NULL || mapfunc == enodev || mapfunc == nullop) 190 panic("dev_pager_getpage: no map function"); 191 192 paddr = pmap_phys_address((*mapfunc) ((dev_t) dev, (int) offset, prot)); 193#ifdef DIAGNOSTIC 194 if (paddr == -1) 195 panic("dev_pager_getpage: map function returns error"); 196#endif 197 /* |
284 * Replace the passed in page with our own fake page and free up the 285 * original. | 198 * Replace the passed in reqpage page with our own fake page and free up the 199 * all of the original pages. |
286 */ 287 page = dev_pager_getfake(paddr); | 200 */ 201 page = dev_pager_getfake(paddr); |
288 TAILQ_INSERT_TAIL(&((dev_pager_t) pager->pg_data)->devp_pglist, 289 page, pageq); 290 vm_object_lock(object); 291 vm_page_lock_queues(); 292 PAGE_WAKEUP(m); 293 vm_page_free(m); 294 vm_page_unlock_queues(); | 202 TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq); 203 for (i = 0; i < count; i++) { 204 PAGE_WAKEUP(m[i]); 205 vm_page_free(m[i]); 206 } |
295 s = splhigh(); 296 vm_page_insert(page, object, offset); 297 splx(s); | 207 s = splhigh(); 208 vm_page_insert(page, object, offset); 209 splx(s); |
298 vm_object_unlock(object); | |
299 300 return (VM_PAGER_OK); 301} 302 | 210 211 return (VM_PAGER_OK); 212} 213 |
303static int 304dev_pager_putpage(pager, m, sync) 305 vm_pager_t pager; 306 vm_page_t m; | 214int 215dev_pager_putpages(object, m, count, sync, rtvals) 216 vm_object_t object; 217 vm_page_t *m; 218 int count; |
307 boolean_t sync; | 219 boolean_t sync; |
220 int *rtvals; |
|
308{ | 221{ |
309#ifdef DEBUG 310 if (dpagerdebug & DDB_FOLLOW) 311 printf("dev_pager_putpage(%x, %x)\n", pager, m); 312#endif 313 if (pager == NULL) 314 return 0; | |
315 panic("dev_pager_putpage called"); 316} 317 | 222 panic("dev_pager_putpage called"); 223} 224 |
318static boolean_t 319dev_pager_haspage(pager, offset) 320 vm_pager_t pager; | 225boolean_t 226dev_pager_haspage(object, offset, before, after) 227 vm_object_t object; |
321 vm_offset_t offset; | 228 vm_offset_t offset; |
229 int *before; 230 int *after; |
|
322{ | 231{ |
323#ifdef DEBUG 324 if (dpagerdebug & DDB_FOLLOW) 325 printf("dev_pager_haspage(%x, %x)\n", pager, offset); 326#endif | 232 if (before != NULL) 233 *before = 0; 234 if (after != NULL) 235 *after = 0; |
327 return (TRUE); 328} 329 330static vm_page_t 331dev_pager_getfake(paddr) 332 vm_offset_t paddr; 333{ 334 vm_page_t m; --- 5 unchanged lines hidden (view full) --- 340 TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq); 341 m++; 342 } 343 } 344 m = dev_pager_fakelist.tqh_first; 345 TAILQ_REMOVE(&dev_pager_fakelist, m, pageq); 346 347 m->flags = PG_BUSY | PG_FICTITIOUS; | 236 return (TRUE); 237} 238 239static vm_page_t 240dev_pager_getfake(paddr) 241 vm_offset_t paddr; 242{ 243 vm_page_t m; --- 5 unchanged lines hidden (view full) --- 249 TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq); 250 m++; 251 } 252 } 253 m = dev_pager_fakelist.tqh_first; 254 TAILQ_REMOVE(&dev_pager_fakelist, m, pageq); 255 256 m->flags = PG_BUSY | PG_FICTITIOUS; |
348 m->dirty = 0; | |
349 m->valid = VM_PAGE_BITS_ALL; | 257 m->valid = VM_PAGE_BITS_ALL; |
258 m->dirty = 0; |
|
350 m->busy = 0; 351 m->bmapped = 0; 352 353 m->wire_count = 1; 354 m->phys_addr = paddr; 355 356 return (m); 357} 358 359static void 360dev_pager_putfake(m) 361 vm_page_t m; 362{ | 259 m->busy = 0; 260 m->bmapped = 0; 261 262 m->wire_count = 1; 263 m->phys_addr = paddr; 264 265 return (m); 266} 267 268static void 269dev_pager_putfake(m) 270 vm_page_t m; 271{ |
363#ifdef DIAGNOSTIC | |
364 if (!(m->flags & PG_FICTITIOUS)) 365 panic("dev_pager_putfake: bad page"); | 272 if (!(m->flags & PG_FICTITIOUS)) 273 panic("dev_pager_putfake: bad page"); |
366#endif | |
367 TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq); 368} | 274 TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq); 275} |