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/uvm/uvm_mremap.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 /*      $NetBSD: uvm_mremap.c,v 1.12 2008/06/17 16:17:21 tsutsui Exp $  */
    2 
    3 /*-
    4  * Copyright (c)2006 YAMAMOTO Takashi,
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __KERNEL_RCSID(0, "$NetBSD: uvm_mremap.c,v 1.12 2008/06/17 16:17:21 tsutsui Exp $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/mman.h>
   34 #include <sys/sched.h>
   35 #include <sys/syscallargs.h>
   36 #include <sys/proc.h>
   37 #include <sys/atomic.h>
   38 
   39 #include <uvm/uvm.h>
   40 
   41 static int
   42 uvm_mapent_extend(struct vm_map *map, vaddr_t endva, vsize_t size)
   43 {
   44         struct vm_map_entry *entry;
   45         struct vm_map_entry *reserved_entry;
   46         struct uvm_object *uobj;
   47         int error = 0;
   48 
   49         vm_map_lock(map);
   50         if (!uvm_map_lookup_entry(map, endva, &reserved_entry)) {
   51                 error = ENOENT;
   52                 goto done;
   53         }
   54         if (reserved_entry->start != endva ||
   55             reserved_entry->end != endva + size ||
   56             reserved_entry->object.uvm_obj != NULL ||
   57             reserved_entry->aref.ar_amap != NULL) {
   58                 error = EINVAL;
   59                 goto done;
   60         }
   61         entry = reserved_entry->prev;
   62         KASSERT(&map->header != entry);
   63         if (entry->end != endva) {
   64                 error = EINVAL;
   65                 goto done;
   66         }
   67 
   68         /*
   69          * now, make reserved_entry compatible with entry, and then
   70          * try to merge.
   71          */
   72 
   73         uobj = entry->object.uvm_obj;
   74         if (uobj) {
   75                 voff_t offset = entry->offset;
   76                 voff_t newoffset;
   77                 
   78                 newoffset = offset + entry->end - entry->start;
   79                 if (newoffset <= offset) {
   80                         error = E2BIG; /* XXX */
   81                         goto done;
   82                 }
   83                 mutex_enter(&uobj->vmobjlock);
   84                 KASSERT(uobj->uo_refs > 0);
   85                 atomic_inc_uint(&uobj->uo_refs);
   86                 mutex_exit(&uobj->vmobjlock);
   87                 reserved_entry->object.uvm_obj = uobj;
   88                 reserved_entry->offset = newoffset;
   89         }
   90         reserved_entry->etype = entry->etype;
   91         if (UVM_ET_ISCOPYONWRITE(entry)) {
   92                 reserved_entry->etype |= UVM_ET_NEEDSCOPY;
   93         }
   94         reserved_entry->flags &= ~UVM_MAP_NOMERGE;
   95         reserved_entry->protection = entry->protection;
   96         reserved_entry->max_protection = entry->max_protection;
   97         reserved_entry->inheritance = entry->inheritance;
   98         reserved_entry->advice = entry->advice;
   99         reserved_entry->wired_count = 0; /* XXX should inherit? */
  100         uvm_mapent_trymerge(map, reserved_entry, 0);
  101 done:
  102         vm_map_unlock(map);
  103 
  104         return error;
  105 }
  106 
  107 /*
  108  * uvm_mremap: move and/or resize existing mappings.
  109  */
  110 
  111 int
  112 uvm_mremap(struct vm_map *oldmap, vaddr_t oldva, vsize_t oldsize,
  113     struct vm_map *newmap, vaddr_t *newvap, vsize_t newsize,
  114     struct proc *newproc, int flags)
  115 {
  116         vaddr_t dstva;
  117         vsize_t movesize;
  118         vaddr_t newva;
  119         vaddr_t align = 0;
  120         int error = 0;
  121         const bool fixed = (flags & MAP_FIXED) != 0;
  122 
  123         if (fixed) {
  124                 newva = *newvap;
  125         } else {
  126                 newva = 0;
  127         }
  128         if ((oldva & PAGE_MASK) != 0 ||
  129             (newva & PAGE_MASK) != 0 ||
  130             (oldsize & PAGE_MASK) != 0 ||
  131             (newsize & PAGE_MASK) != 0) {
  132                 return EINVAL;
  133         }
  134         /* XXX zero-size should be allowed? */
  135         if (oldva + oldsize <= oldva || newva + newsize <= newva) {
  136                 return EINVAL;
  137         }
  138 
  139         /*
  140          * Try to see if any requested alignment can even be attemped.
  141          * Make sure we can express the alignment (asking for a >= 4GB
  142          * alignment on an ILP32 architecure make no sense) and the
  143          * alignment is at least for a page sized quanitiy.  If the
  144          * request was for a fixed mapping, make sure supplied address
  145          * adheres to the request alignment.
  146          */
  147         align = (flags & MAP_ALIGNMENT_MASK) >> MAP_ALIGNMENT_SHIFT;
  148         if (align) {
  149                 if (align >= sizeof(vaddr_t) * NBBY)
  150                         return(EINVAL);
  151                 align = 1L << align;
  152                 if (align < PAGE_SIZE)
  153                         return(EINVAL);
  154                 if (align >= vm_map_max(oldmap))
  155                         return(ENOMEM);
  156                 if (flags & MAP_FIXED) {
  157                         if ((*newvap & (align-1)) != 0)
  158                                 return(EINVAL);
  159                         align = 0;
  160                 }
  161         }
  162 
  163         /*
  164          * check the easy cases first.
  165          */
  166 
  167         if ((!fixed || newva == oldva) && newmap == oldmap &&
  168             (align == 0 || (oldva & (align - 1)) == 0)) {
  169                 vaddr_t va;
  170 
  171                 if (newsize == oldsize) {
  172                         newva = oldva;
  173                         goto done;
  174                 }
  175                 if (newsize < oldsize) {
  176                         uvm_unmap(oldmap, oldva + newsize, oldva + oldsize);
  177                         newva = oldva;
  178                         goto done;
  179                 }
  180                 va = oldva + oldsize;
  181                 if (uvm_map_reserve(oldmap, newsize - oldsize, 0, 0, &va,
  182                     UVM_FLAG_FIXED)) {
  183                         newva = oldva;
  184                         goto extend;
  185                 }
  186                 if (fixed) {
  187                         return ENOMEM;
  188                 }
  189         }
  190 
  191         /*
  192          * we need to move mappings.
  193          */
  194 
  195         if (!fixed) {
  196                 KASSERT(&newproc->p_vmspace->vm_map == newmap);
  197                 newva = newproc->p_emul->e_vm_default_addr(newproc,
  198                     (vaddr_t)newproc->p_vmspace->vm_daddr, newsize);
  199         }
  200         dstva = newva;
  201         if (!uvm_map_reserve(newmap, newsize, oldva, align, &dstva, 
  202             fixed ? UVM_FLAG_FIXED : 0)) {
  203                 return ENOMEM;
  204         }
  205         KASSERT(!fixed || dstva == newva);
  206         newva = dstva;
  207         movesize = MIN(oldsize, newsize);
  208         error = uvm_map_extract(oldmap, oldva, movesize, newmap, &dstva,
  209             UVM_EXTRACT_RESERVED);
  210         KASSERT(dstva == newva);
  211         if (error != 0) {
  212                 /* undo uvm_map_reserve */
  213                 uvm_unmap(newmap, newva, newva + newsize);
  214                 return error;
  215         }
  216         if (newsize > oldsize) {
  217 extend:
  218                 error = uvm_mapent_extend(newmap, newva + oldsize,
  219                     newsize - oldsize);
  220                 if (error != 0) {
  221                         /* undo uvm_map_reserve and uvm_map_extract */
  222                         uvm_unmap(newmap, newva, newva + newsize);
  223                         return error;
  224                 }
  225         }
  226 
  227         /*
  228          * now we won't fail.  remove original entries.
  229          */
  230 
  231         if (oldva != newva || oldmap != newmap) {
  232                 uvm_unmap(oldmap, oldva, oldva + oldsize);
  233         }
  234 done:
  235         *newvap = newva;
  236         return 0;
  237 }
  238 
  239 /*
  240  * sys_mremap: mremap system call.
  241  */
  242 
  243 int
  244 sys_mremap(struct lwp *l, const struct sys_mremap_args *uap, register_t *retval)
  245 {
  246         /* {
  247                 syscallarg(void *) old_address;
  248                 syscallarg(size_t) old_size;
  249                 syscallarg(void *) new_address;
  250                 syscallarg(size_t) new_size;
  251                 syscallarg(int) flags;
  252         } */
  253 
  254         struct proc *p;
  255         struct vm_map *map;
  256         vaddr_t oldva;
  257         vaddr_t newva;
  258         size_t oldsize;
  259         size_t newsize;
  260         int flags;
  261         int error;
  262 
  263         flags = SCARG(uap, flags);
  264         oldva = (vaddr_t)SCARG(uap, old_address);
  265         oldsize = (vsize_t)(SCARG(uap, old_size));
  266         newva = (vaddr_t)SCARG(uap, new_address);
  267         newsize = (vsize_t)(SCARG(uap, new_size));
  268 
  269         if ((flags & ~(MAP_FIXED | MAP_ALIGNMENT_MASK)) != 0) {
  270                 error = EINVAL;
  271                 goto done;
  272         }
  273 
  274         oldsize = round_page(oldsize);
  275         newsize = round_page(newsize);
  276 
  277         p = l->l_proc;
  278         map = &p->p_vmspace->vm_map;
  279         error = uvm_mremap(map, oldva, oldsize, map, &newva, newsize, p,
  280             flags);
  281 
  282 done:
  283         *retval = (error != 0) ? 0 : (register_t)newva;
  284         return error;
  285 
  286 }

Cache object: 19e226ef46c7cebbf087b6b492721757


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