1 /* 2 * Copyright (c) 2003 Hiten Pandya <hmp@backplane.com>. 3 * All rights reserved. 4 * 5 * Copyright (c) 1991 Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * The Mach Operating System project at Carnegie-Mellon University. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * from: @(#)vm_page.c 7.4 (Berkeley) 5/7/91 40 * $DragonFly: src/sys/vm/vm_contig.c,v 1.6 2004/03/01 06:33:24 dillon Exp $ 41 */ 42 43 /* 44 * Copyright (c) 1987, 1990 Carnegie-Mellon University. 45 * All rights reserved. 46 * 47 * Authors: Avadis Tevanian, Jr., Michael Wayne Young 48 * 49 * Permission to use, copy, modify and distribute this software and 50 * its documentation is hereby granted, provided that both the copyright 51 * notice and this permission notice appear in all copies of the 52 * software, derivative works or modified versions, and any portions 53 * thereof, and that both notices appear in supporting documentation. 54 * 55 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 56 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 57 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 58 * 59 * Carnegie Mellon requests users of this software to return to 60 * 61 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 62 * School of Computer Science 63 * Carnegie Mellon University 64 * Pittsburgh PA 15213-3890 65 * 66 * any improvements or extensions that they make and grant Carnegie the 67 * rights to redistribute these changes. 68 */ 69 70 /* 71 * Contiguous memory allocation API. 72 */ 73 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/malloc.h> 77 #include <sys/proc.h> 78 #include <sys/lock.h> 79 #include <sys/vmmeter.h> 80 #include <sys/vnode.h> 81 82 #include <vm/vm.h> 83 #include <vm/vm_param.h> 84 #include <vm/vm_kern.h> 85 #include <vm/pmap.h> 86 #include <vm/vm_map.h> 87 #include <vm/vm_object.h> 88 #include <vm/vm_page.h> 89 #include <vm/vm_pageout.h> 90 #include <vm/vm_pager.h> 91 #include <vm/vm_extern.h> 92 #include <vm/vm_page2.h> 93 94 /* 95 * vm_contig_pg_clean: 96 * 97 * Do a thorough cleanup of the specified 'queue', which can be either 98 * PQ_ACTIVE or PQ_INACTIVE by doing a walkthrough. If the page is not 99 * marked dirty, it is shoved into the page cache, provided no one has 100 * currently aqcuired it, otherwise localized action per object type 101 * is taken for cleanup: 102 * 103 * In the OBJT_VNODE case, the whole page range is cleaned up 104 * using the vm_object_page_clean() routine, by specyfing a 105 * start and end of '0'. 106 * 107 * Otherwise if the object is of any other type, the generic 108 * pageout (daemon) flush routine is invoked. 109 */ 110 static int 111 vm_contig_pg_clean(int queue) 112 { 113 vm_object_t object; 114 vm_page_t m, m_tmp, next; 115 116 for (m = TAILQ_FIRST(&vm_page_queues[queue].pl); m != NULL; m = next) { 117 KASSERT(m->queue == queue, 118 ("vm_contig_clean: page %p's queue is not %d", m, queue)); 119 120 next = TAILQ_NEXT(m, pageq); 121 122 if (vm_page_sleep_busy(m, TRUE, "vpctw0")) 123 return (TRUE); 124 125 vm_page_test_dirty(m); 126 if (m->dirty) { 127 object = m->object; 128 if (object->type == OBJT_VNODE) { 129 vn_lock(object->handle, NULL, 130 LK_EXCLUSIVE | LK_RETRY, curthread); 131 vm_object_page_clean(object, 0, 0, OBJPC_SYNC); 132 VOP_UNLOCK(object->handle, NULL, 0, curthread); 133 return (TRUE); 134 } else if (object->type == OBJT_SWAP || 135 object->type == OBJT_DEFAULT) { 136 m_tmp = m; 137 vm_pageout_flush(&m_tmp, 1, 0); 138 return (TRUE); 139 } 140 } 141 142 if ((m->dirty == 0) && (m->busy == 0) && (m->hold_count == 0)) 143 vm_page_cache(m); 144 } 145 146 return (FALSE); 147 } 148 149 /* 150 * vm_contig_pg_alloc: 151 * 152 * Allocate contiguous pages from the VM. This function does not 153 * map the allocated pages into the kernel map, otherwise it is 154 * impossible to make large allocations (i.e. >2G). 155 * 156 * Malloc()'s data structures have been used for collection of 157 * statistics and for allocations of less than a page. 158 * 159 */ 160 int 161 vm_contig_pg_alloc( 162 unsigned long size, 163 vm_paddr_t low, 164 vm_paddr_t high, 165 unsigned long alignment, 166 unsigned long boundary) 167 { 168 int i, s, start, pass; 169 vm_offset_t phys; 170 vm_page_t pga = vm_page_array; 171 172 size = round_page(size); 173 if (size == 0) 174 panic("vm_contig_pg_alloc: size must not be 0"); 175 if ((alignment & (alignment - 1)) != 0) 176 panic("vm_contig_pg_alloc: alignment must be a power of 2"); 177 if ((boundary & (boundary - 1)) != 0) 178 panic("vm_contig_pg_alloc: boundary must be a power of 2"); 179 180 start = 0; 181 for (pass = 0; pass <= 1; pass++) { 182 s = splvm(); 183 again: 184 /* 185 * Find first page in array that is free, within range, aligned, and 186 * such that the boundary won't be crossed. 187 */ 188 for (i = start; i < vmstats.v_page_count; i++) { 189 int pqtype; 190 phys = VM_PAGE_TO_PHYS(&pga[i]); 191 pqtype = pga[i].queue - pga[i].pc; 192 if (((pqtype == PQ_FREE) || (pqtype == PQ_CACHE)) && 193 (phys >= low) && (phys < high) && 194 ((phys & (alignment - 1)) == 0) && 195 (((phys ^ (phys + size - 1)) & ~(boundary - 1)) == 0)) 196 break; 197 } 198 199 /* 200 * If we cannot find the page in the given range, or we have 201 * crossed the boundary, call the vm_contig_pg_clean() function 202 * for flushing out the queues, and returning it back to 203 * normal state. 204 */ 205 if ((i == vmstats.v_page_count) || 206 ((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) { 207 208 again1: 209 if (vm_contig_pg_clean(PQ_INACTIVE)) 210 goto again1; 211 if (vm_contig_pg_clean(PQ_ACTIVE)) 212 goto again1; 213 214 splx(s); 215 continue; /* next pass */ 216 } 217 start = i; 218 219 /* 220 * Check successive pages for contiguous and free. 221 */ 222 for (i = start + 1; i < (start + size / PAGE_SIZE); i++) { 223 int pqtype; 224 pqtype = pga[i].queue - pga[i].pc; 225 if ((VM_PAGE_TO_PHYS(&pga[i]) != 226 (VM_PAGE_TO_PHYS(&pga[i - 1]) + PAGE_SIZE)) || 227 ((pqtype != PQ_FREE) && (pqtype != PQ_CACHE))) { 228 start++; 229 goto again; 230 } 231 } 232 233 for (i = start; i < (start + size / PAGE_SIZE); i++) { 234 int pqtype; 235 vm_page_t m = &pga[i]; 236 237 pqtype = m->queue - m->pc; 238 if (pqtype == PQ_CACHE) { 239 vm_page_busy(m); 240 vm_page_free(m); 241 } 242 vm_page_unqueue_nowakeup(m); 243 m->valid = VM_PAGE_BITS_ALL; 244 if (m->flags & PG_ZERO) 245 vm_page_zero_count--; 246 /* Don't clear the PG_ZERO flag, we'll need it later. */ 247 m->flags &= PG_ZERO; 248 KASSERT(m->dirty == 0, 249 ("vm_contig_pg_alloc: page %p was dirty", m)); 250 m->wire_count = 0; 251 m->busy = 0; 252 m->object = NULL; 253 } 254 255 /* 256 * Our job is done, return the index page of vm_page_array. 257 */ 258 259 splx(s); 260 return (start); /* aka &pga[start] */ 261 } 262 263 /* 264 * Failed. 265 */ 266 splx(s); 267 return (-1); 268 } 269 270 /* 271 * vm_contig_pg_free: 272 * 273 * Remove pages previously allocated by vm_contig_pg_alloc, and 274 * assume all references to the pages have been removed, and that 275 * it is OK to add them back to the free list. 276 */ 277 void 278 vm_contig_pg_free(int start, u_long size) 279 { 280 vm_page_t pga = vm_page_array; 281 int i; 282 283 size = round_page(size); 284 if (size == 0) 285 panic("vm_contig_pg_free: size must not be 0"); 286 287 for (i = start; i < (start + size / PAGE_SIZE); i++) { 288 vm_page_free(&pga[i]); 289 } 290 } 291 292 /* 293 * vm_contig_pg_kmap: 294 * 295 * Map previously allocated (vm_contig_pg_alloc) range of pages from 296 * vm_page_array[] into the KVA. Once mapped, the pages are part of 297 * the Kernel, and are to free'ed with kmem_free(kernel_map, addr, size). 298 */ 299 vm_offset_t 300 vm_contig_pg_kmap(int start, u_long size, vm_map_t map, int flags) 301 { 302 vm_offset_t addr, tmp_addr; 303 vm_page_t pga = vm_page_array; 304 int i, s, count; 305 306 size = round_page(size); 307 if (size == 0) 308 panic("vm_contig_pg_kmap: size must not be 0"); 309 310 s = splvm(); /* XXX: is this really needed? */ 311 312 /* 313 * We've found a contiguous chunk that meets our requirements. 314 * Allocate KVM, and assign phys pages and return a kernel VM 315 * pointer. 316 */ 317 count = vm_map_entry_reserve(MAP_RESERVE_COUNT); 318 vm_map_lock(map); 319 if (vm_map_findspace(map, vm_map_min(map), size, 1, &addr) != 320 KERN_SUCCESS) { 321 /* 322 * XXX We almost never run out of kernel virtual 323 * space, so we don't make the allocated memory 324 * above available. 325 */ 326 vm_map_unlock(map); 327 vm_map_entry_release(count); 328 splx(s); 329 return (0); 330 } 331 vm_object_reference(kernel_object); 332 vm_map_insert(map, &count, 333 kernel_object, addr - VM_MIN_KERNEL_ADDRESS, 334 addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, 0); 335 vm_map_unlock(map); 336 vm_map_entry_release(count); 337 338 tmp_addr = addr; 339 for (i = start; i < (start + size / PAGE_SIZE); i++) { 340 vm_page_t m = &pga[i]; 341 vm_page_insert(m, kernel_object, 342 OFF_TO_IDX(tmp_addr - VM_MIN_KERNEL_ADDRESS)); 343 if ((flags & M_ZERO) && !(m->flags & PG_ZERO)) 344 pmap_zero_page(VM_PAGE_TO_PHYS(m)); 345 m->flags = 0; 346 tmp_addr += PAGE_SIZE; 347 } 348 vm_map_wire(map, addr, addr + size, 0); 349 350 splx(s); 351 return (addr); 352 } 353 354 void * 355 contigmalloc( 356 unsigned long size, /* should be size_t here and for malloc() */ 357 struct malloc_type *type, 358 int flags, 359 vm_paddr_t low, 360 vm_paddr_t high, 361 unsigned long alignment, 362 unsigned long boundary) 363 { 364 return contigmalloc_map(size, type, flags, low, high, alignment, 365 boundary, kernel_map); 366 } 367 368 void * 369 contigmalloc_map( 370 unsigned long size, /* should be size_t here and for malloc() */ 371 struct malloc_type *type, 372 int flags, 373 vm_paddr_t low, 374 vm_paddr_t high, 375 unsigned long alignment, 376 unsigned long boundary, 377 vm_map_t map) 378 { 379 int index; 380 void *rv; 381 382 index = vm_contig_pg_alloc(size, low, high, alignment, boundary); 383 if (index < 0) { 384 printf("contigmalloc_map: failed in index < 0 case!"); 385 return NULL; 386 } 387 388 rv = (void *) vm_contig_pg_kmap(index, size, map, flags); 389 if (!rv) 390 vm_contig_pg_free(index, size); 391 392 return rv; 393 } 394 395 void 396 contigfree(void *addr, unsigned long size, struct malloc_type *type) 397 { 398 kmem_free(kernel_map, (vm_offset_t)addr, size); 399 } 400 401 vm_offset_t 402 vm_page_alloc_contig( 403 vm_offset_t size, 404 vm_paddr_t low, 405 vm_paddr_t high, 406 vm_offset_t alignment) 407 { 408 return ((vm_offset_t)contigmalloc_map(size, M_DEVBUF, M_NOWAIT, low, 409 high, alignment, 0ul, kernel_map)); 410 } 411