The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/vm/vm_contig.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    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  *
    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_page.c     7.4 (Berkeley) 5/7/91
   37  * $FreeBSD: releng/5.1/sys/vm/vm_contig.c 113955 2003-04-24 04:31:25Z alc $
   38  */
   39 
   40 /*
   41  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
   42  * All rights reserved.
   43  *
   44  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
   45  *
   46  * Permission to use, copy, modify and distribute this software and
   47  * its documentation is hereby granted, provided that both the copyright
   48  * notice and this permission notice appear in all copies of the
   49  * software, derivative works or modified versions, and any portions
   50  * thereof, and that both notices appear in supporting documentation.
   51  *
   52  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   53  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
   54  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   55  *
   56  * Carnegie Mellon requests users of this software to return to
   57  *
   58  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   59  *  School of Computer Science
   60  *  Carnegie Mellon University
   61  *  Pittsburgh PA 15213-3890
   62  *
   63  * any improvements or extensions that they make and grant Carnegie the
   64  * rights to redistribute these changes.
   65  */
   66 
   67 #include <sys/param.h>
   68 #include <sys/systm.h>
   69 #include <sys/lock.h>
   70 #include <sys/malloc.h>
   71 #include <sys/mutex.h>
   72 #include <sys/proc.h>
   73 #include <sys/vmmeter.h>
   74 #include <sys/vnode.h>
   75 
   76 #include <vm/vm.h>
   77 #include <vm/vm_param.h>
   78 #include <vm/vm_kern.h>
   79 #include <vm/pmap.h>
   80 #include <vm/vm_map.h>
   81 #include <vm/vm_object.h>
   82 #include <vm/vm_page.h>
   83 #include <vm/vm_pageout.h>
   84 #include <vm/vm_pager.h>
   85 #include <vm/vm_extern.h>
   86 
   87 static int
   88 vm_contig_launder(int queue)
   89 {
   90         vm_object_t object;
   91         vm_page_t m, m_tmp, next;
   92 
   93         for (m = TAILQ_FIRST(&vm_page_queues[queue].pl); m != NULL; m = next) {
   94                 next = TAILQ_NEXT(m, pageq);
   95                 KASSERT(m->queue == queue,
   96                     ("vm_contig_launder: page %p's queue is not %d", m, queue));
   97                 if (vm_page_sleep_if_busy(m, TRUE, "vpctw0")) {
   98                         vm_page_lock_queues();
   99                         return (TRUE);
  100                 }
  101                 vm_page_test_dirty(m);
  102                 if (m->dirty) {
  103                         object = m->object;
  104                         if (object->type == OBJT_VNODE) {
  105                                 vm_page_unlock_queues();
  106                                 vn_lock(object->handle,
  107                                     LK_EXCLUSIVE | LK_RETRY, curthread);
  108                                 VM_OBJECT_LOCK(object);
  109                                 vm_object_page_clean(object, 0, 0, OBJPC_SYNC);
  110                                 VM_OBJECT_UNLOCK(object);
  111                                 VOP_UNLOCK(object->handle, 0, curthread);
  112                                 vm_page_lock_queues();
  113                                 return (TRUE);
  114                         } else if (object->type == OBJT_SWAP ||
  115                                    object->type == OBJT_DEFAULT) {
  116                                 m_tmp = m;
  117                                 vm_pageout_flush(&m_tmp, 1, 0, FALSE);
  118                                 return (TRUE);
  119                         }
  120                 } else if (m->busy == 0 && m->hold_count == 0)
  121                         vm_page_cache(m);
  122         }
  123         return (FALSE);
  124 }
  125 
  126 /*
  127  * This interface is for merging with malloc() someday.
  128  * Even if we never implement compaction so that contiguous allocation
  129  * works after initialization time, malloc()'s data structures are good
  130  * for statistics and for allocations of less than a page.
  131  */
  132 static void *
  133 contigmalloc1(
  134         unsigned long size,     /* should be size_t here and for malloc() */
  135         struct malloc_type *type,
  136         int flags,
  137         vm_paddr_t low,
  138         vm_paddr_t high,
  139         unsigned long alignment,
  140         unsigned long boundary,
  141         vm_map_t map)
  142 {
  143         int i, s, start;
  144         vm_paddr_t phys;
  145         vm_offset_t addr, tmp_addr;
  146         int pass;
  147         vm_page_t pga = vm_page_array;
  148 
  149         size = round_page(size);
  150         if (size == 0)
  151                 panic("contigmalloc1: size must not be 0");
  152         if ((alignment & (alignment - 1)) != 0)
  153                 panic("contigmalloc1: alignment must be a power of 2");
  154         if ((boundary & (boundary - 1)) != 0)
  155                 panic("contigmalloc1: boundary must be a power of 2");
  156 
  157         start = 0;
  158         for (pass = 0; pass <= 1; pass++) {
  159                 s = splvm();
  160                 vm_page_lock_queues();
  161 again:
  162                 /*
  163                  * Find first page in array that is free, within range, aligned, and
  164                  * such that the boundary won't be crossed.
  165                  */
  166                 for (i = start; i < cnt.v_page_count; i++) {
  167                         int pqtype;
  168                         phys = VM_PAGE_TO_PHYS(&pga[i]);
  169                         pqtype = pga[i].queue - pga[i].pc;
  170                         if (((pqtype == PQ_FREE) || (pqtype == PQ_CACHE)) &&
  171                             (phys >= low) && (phys < high) &&
  172                             ((phys & (alignment - 1)) == 0) &&
  173                             (((phys ^ (phys + size - 1)) & ~(boundary - 1)) == 0))
  174                                 break;
  175                 }
  176 
  177                 /*
  178                  * If the above failed or we will exceed the upper bound, fail.
  179                  */
  180                 if ((i == cnt.v_page_count) ||
  181                         ((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) {
  182 again1:
  183                         if (vm_contig_launder(PQ_INACTIVE))
  184                                 goto again1;
  185                         if (vm_contig_launder(PQ_ACTIVE))
  186                                 goto again1;
  187                         vm_page_unlock_queues();
  188                         splx(s);
  189                         continue;
  190                 }
  191                 start = i;
  192 
  193                 /*
  194                  * Check successive pages for contiguous and free.
  195                  */
  196                 for (i = start + 1; i < (start + size / PAGE_SIZE); i++) {
  197                         int pqtype;
  198                         pqtype = pga[i].queue - pga[i].pc;
  199                         if ((VM_PAGE_TO_PHYS(&pga[i]) !=
  200                             (VM_PAGE_TO_PHYS(&pga[i - 1]) + PAGE_SIZE)) ||
  201                             ((pqtype != PQ_FREE) && (pqtype != PQ_CACHE))) {
  202                                 start++;
  203                                 goto again;
  204                         }
  205                 }
  206                 for (i = start; i < (start + size / PAGE_SIZE); i++) {
  207                         vm_page_t m = &pga[i];
  208 
  209                         if ((m->queue - m->pc) == PQ_CACHE) {
  210                                 vm_page_busy(m);
  211                                 vm_page_free(m);
  212                         }
  213                         mtx_lock_spin(&vm_page_queue_free_mtx);
  214                         vm_pageq_remove_nowakeup(m);
  215                         m->valid = VM_PAGE_BITS_ALL;
  216                         if (m->flags & PG_ZERO)
  217                                 vm_page_zero_count--;
  218                         m->flags = 0;
  219                         KASSERT(m->dirty == 0, ("contigmalloc1: page %p was dirty", m));
  220                         m->wire_count = 0;
  221                         m->busy = 0;
  222                         m->object = NULL;
  223                         mtx_unlock_spin(&vm_page_queue_free_mtx);
  224                 }
  225                 vm_page_unlock_queues();
  226                 /*
  227                  * We've found a contiguous chunk that meets are requirements.
  228                  * Allocate kernel VM, unfree and assign the physical pages to it and
  229                  * return kernel VM pointer.
  230                  */
  231                 vm_map_lock(map);
  232                 if (vm_map_findspace(map, vm_map_min(map), size, &addr) !=
  233                     KERN_SUCCESS) {
  234                         /*
  235                          * XXX We almost never run out of kernel virtual
  236                          * space, so we don't make the allocated memory
  237                          * above available.
  238                          */
  239                         vm_map_unlock(map);
  240                         splx(s);
  241                         return (NULL);
  242                 }
  243                 vm_object_reference(kernel_object);
  244                 vm_map_insert(map, kernel_object, addr - VM_MIN_KERNEL_ADDRESS,
  245                     addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, 0);
  246                 vm_map_unlock(map);
  247 
  248                 tmp_addr = addr;
  249                 VM_OBJECT_LOCK(kernel_object);
  250                 for (i = start; i < (start + size / PAGE_SIZE); i++) {
  251                         vm_page_t m = &pga[i];
  252                         vm_page_insert(m, kernel_object,
  253                                 OFF_TO_IDX(tmp_addr - VM_MIN_KERNEL_ADDRESS));
  254                         tmp_addr += PAGE_SIZE;
  255                 }
  256                 VM_OBJECT_UNLOCK(kernel_object);
  257                 vm_map_wire(map, addr, addr + size, FALSE);
  258 
  259                 splx(s);
  260                 return ((void *)addr);
  261         }
  262         return NULL;
  263 }
  264 
  265 void *
  266 contigmalloc(
  267         unsigned long size,     /* should be size_t here and for malloc() */
  268         struct malloc_type *type,
  269         int flags,
  270         vm_paddr_t low,
  271         vm_paddr_t high,
  272         unsigned long alignment,
  273         unsigned long boundary)
  274 {
  275         void * ret;
  276 
  277         GIANT_REQUIRED;
  278         ret = contigmalloc1(size, type, flags, low, high, alignment, boundary,
  279                              kernel_map);
  280         return (ret);
  281 
  282 }
  283 
  284 void
  285 contigfree(void *addr, unsigned long size, struct malloc_type *type)
  286 {
  287         GIANT_REQUIRED;
  288         kmem_free(kernel_map, (vm_offset_t)addr, size);
  289 }
  290 
  291 vm_offset_t
  292 vm_page_alloc_contig(
  293         vm_offset_t size,
  294         vm_paddr_t low,
  295         vm_paddr_t high,
  296         vm_offset_t alignment)
  297 {
  298         vm_offset_t ret;
  299 
  300         GIANT_REQUIRED;
  301         ret = ((vm_offset_t)contigmalloc1(size, M_DEVBUF, M_NOWAIT, low, high,
  302                                           alignment, 0ul, kernel_map));
  303         return (ret);
  304 
  305 }
  306 

Cache object: 640587561af4f74d37bdd3da11b5a248


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.