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.0/sys/vm/vm_contig.c 101304 2002-08-04 07:07:34Z 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_page_clean(object, 0, 0, OBJPC_SYNC);
  109                                 VOP_UNLOCK(object->handle, 0, curthread);
  110                                 vm_page_lock_queues();
  111                                 return (TRUE);
  112                         } else if (object->type == OBJT_SWAP ||
  113                                    object->type == OBJT_DEFAULT) {
  114                                 m_tmp = m;
  115                                 vm_pageout_flush(&m_tmp, 1, 0);
  116                                 return (TRUE);
  117                         }
  118                 } else if (m->busy == 0 && m->hold_count == 0)
  119                         vm_page_cache(m);
  120         }
  121         return (FALSE);
  122 }
  123 
  124 /*
  125  * This interface is for merging with malloc() someday.
  126  * Even if we never implement compaction so that contiguous allocation
  127  * works after initialization time, malloc()'s data structures are good
  128  * for statistics and for allocations of less than a page.
  129  */
  130 static void *
  131 contigmalloc1(
  132         unsigned long size,     /* should be size_t here and for malloc() */
  133         struct malloc_type *type,
  134         int flags,
  135         unsigned long low,
  136         unsigned long high,
  137         unsigned long alignment,
  138         unsigned long boundary,
  139         vm_map_t map)
  140 {
  141         int i, s, start;
  142         vm_offset_t addr, phys, tmp_addr;
  143         int pass;
  144         vm_page_t pga = vm_page_array;
  145 
  146         size = round_page(size);
  147         if (size == 0)
  148                 panic("contigmalloc1: size must not be 0");
  149         if ((alignment & (alignment - 1)) != 0)
  150                 panic("contigmalloc1: alignment must be a power of 2");
  151         if ((boundary & (boundary - 1)) != 0)
  152                 panic("contigmalloc1: boundary must be a power of 2");
  153 
  154         start = 0;
  155         for (pass = 0; pass <= 1; pass++) {
  156                 s = splvm();
  157                 vm_page_lock_queues();
  158 again:
  159                 /*
  160                  * Find first page in array that is free, within range, aligned, and
  161                  * such that the boundary won't be crossed.
  162                  */
  163                 for (i = start; i < cnt.v_page_count; i++) {
  164                         int pqtype;
  165                         phys = VM_PAGE_TO_PHYS(&pga[i]);
  166                         pqtype = pga[i].queue - pga[i].pc;
  167                         if (((pqtype == PQ_FREE) || (pqtype == PQ_CACHE)) &&
  168                             (phys >= low) && (phys < high) &&
  169                             ((phys & (alignment - 1)) == 0) &&
  170                             (((phys ^ (phys + size - 1)) & ~(boundary - 1)) == 0))
  171                                 break;
  172                 }
  173 
  174                 /*
  175                  * If the above failed or we will exceed the upper bound, fail.
  176                  */
  177                 if ((i == cnt.v_page_count) ||
  178                         ((VM_PAGE_TO_PHYS(&pga[i]) + size) > high)) {
  179 again1:
  180                         if (vm_contig_launder(PQ_INACTIVE))
  181                                 goto again1;
  182                         if (vm_contig_launder(PQ_ACTIVE))
  183                                 goto again1;
  184                         vm_page_unlock_queues();
  185                         splx(s);
  186                         continue;
  187                 }
  188                 start = i;
  189 
  190                 /*
  191                  * Check successive pages for contiguous and free.
  192                  */
  193                 for (i = start + 1; i < (start + size / PAGE_SIZE); i++) {
  194                         int pqtype;
  195                         pqtype = pga[i].queue - pga[i].pc;
  196                         if ((VM_PAGE_TO_PHYS(&pga[i]) !=
  197                             (VM_PAGE_TO_PHYS(&pga[i - 1]) + PAGE_SIZE)) ||
  198                             ((pqtype != PQ_FREE) && (pqtype != PQ_CACHE))) {
  199                                 start++;
  200                                 goto again;
  201                         }
  202                 }
  203                 for (i = start; i < (start + size / PAGE_SIZE); i++) {
  204                         vm_page_t m = &pga[i];
  205 
  206                         if ((m->queue - m->pc) == PQ_CACHE) {
  207                                 vm_page_busy(m);
  208                                 vm_page_free(m);
  209                         }
  210                         mtx_lock_spin(&vm_page_queue_free_mtx);
  211                         vm_pageq_remove_nowakeup(m);
  212                         m->valid = VM_PAGE_BITS_ALL;
  213                         if (m->flags & PG_ZERO)
  214                                 vm_page_zero_count--;
  215                         m->flags = 0;
  216                         KASSERT(m->dirty == 0, ("contigmalloc1: page %p was dirty", m));
  217                         m->wire_count = 0;
  218                         m->busy = 0;
  219                         m->object = NULL;
  220                         mtx_unlock_spin(&vm_page_queue_free_mtx);
  221                 }
  222                 vm_page_unlock_queues();
  223                 /*
  224                  * We've found a contiguous chunk that meets are requirements.
  225                  * Allocate kernel VM, unfree and assign the physical pages to it and
  226                  * return kernel VM pointer.
  227                  */
  228                 vm_map_lock(map);
  229                 if (vm_map_findspace(map, vm_map_min(map), size, &addr) !=
  230                     KERN_SUCCESS) {
  231                         /*
  232                          * XXX We almost never run out of kernel virtual
  233                          * space, so we don't make the allocated memory
  234                          * above available.
  235                          */
  236                         vm_map_unlock(map);
  237                         splx(s);
  238                         return (NULL);
  239                 }
  240                 vm_object_reference(kernel_object);
  241                 vm_map_insert(map, kernel_object, addr - VM_MIN_KERNEL_ADDRESS,
  242                     addr, addr + size, VM_PROT_ALL, VM_PROT_ALL, 0);
  243                 vm_map_unlock(map);
  244 
  245                 tmp_addr = addr;
  246                 for (i = start; i < (start + size / PAGE_SIZE); i++) {
  247                         vm_page_t m = &pga[i];
  248                         vm_page_insert(m, kernel_object,
  249                                 OFF_TO_IDX(tmp_addr - VM_MIN_KERNEL_ADDRESS));
  250                         tmp_addr += PAGE_SIZE;
  251                 }
  252                 vm_map_wire(map, addr, addr + size, FALSE);
  253 
  254                 splx(s);
  255                 return ((void *)addr);
  256         }
  257         return NULL;
  258 }
  259 
  260 void *
  261 contigmalloc(
  262         unsigned long size,     /* should be size_t here and for malloc() */
  263         struct malloc_type *type,
  264         int flags,
  265         unsigned long low,
  266         unsigned long high,
  267         unsigned long alignment,
  268         unsigned long boundary)
  269 {
  270         void * ret;
  271 
  272         GIANT_REQUIRED;
  273         ret = contigmalloc1(size, type, flags, low, high, alignment, boundary,
  274                              kernel_map);
  275         return (ret);
  276 
  277 }
  278 
  279 void
  280 contigfree(void *addr, unsigned long size, struct malloc_type *type)
  281 {
  282         GIANT_REQUIRED;
  283         kmem_free(kernel_map, (vm_offset_t)addr, size);
  284 }
  285 
  286 vm_offset_t
  287 vm_page_alloc_contig(
  288         vm_offset_t size,
  289         vm_offset_t low,
  290         vm_offset_t high,
  291         vm_offset_t alignment)
  292 {
  293         vm_offset_t ret;
  294 
  295         GIANT_REQUIRED;
  296         ret = ((vm_offset_t)contigmalloc1(size, M_DEVBUF, M_NOWAIT, low, high,
  297                                           alignment, 0ul, kernel_map));
  298         return (ret);
  299 
  300 }
  301 

Cache object: 33c27fa719161eb60f3a85176e3aece2


[ 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.