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/device_pager.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) 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.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the University of
   21  *      California, Berkeley and its contributors.
   22  * 4. Neither the name of the University nor the names of its contributors
   23  *    may be used to endorse or promote products derived from this software
   24  *    without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   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  * $FreeBSD: src/sys/vm/device_pager.c,v 1.23.2.1 1999/09/05 08:24:15 peter Exp $
   40  */
   41 
   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 #include <sys/queue.h>
   49 
   50 #include <vm/vm.h>
   51 #include <vm/vm_param.h>
   52 #include <vm/vm_prot.h>
   53 #include <vm/vm_kern.h>
   54 #include <vm/vm_object.h>
   55 #include <vm/vm_page.h>
   56 #include <vm/vm_pager.h>
   57 #include <vm/device_pager.h>
   58 
   59 static void dev_pager_init __P((void));
   60 static vm_object_t dev_pager_alloc __P((void *, vm_size_t, vm_prot_t,
   61                 vm_ooffset_t));
   62 static void dev_pager_dealloc __P((vm_object_t));
   63 static int dev_pager_getpages __P((vm_object_t, vm_page_t *, int, int));
   64 static int dev_pager_putpages __P((vm_object_t, vm_page_t *, int, 
   65                 boolean_t, int *));
   66 static boolean_t dev_pager_haspage __P((vm_object_t, vm_pindex_t, int *,
   67                 int *));
   68 
   69 /* list of device pager objects */
   70 static struct pagerlst dev_pager_object_list;
   71 
   72 /* list of available vm_page_t's */
   73 static TAILQ_HEAD(, vm_page) dev_pager_fakelist;
   74 
   75 static vm_page_t dev_pager_getfake __P((vm_offset_t));
   76 static void dev_pager_putfake __P((vm_page_t));
   77 
   78 static int dev_pager_alloc_lock, dev_pager_alloc_lock_want;
   79 
   80 struct pagerops devicepagerops = {
   81         dev_pager_init,
   82         dev_pager_alloc,
   83         dev_pager_dealloc,
   84         dev_pager_getpages,
   85         dev_pager_putpages,
   86         dev_pager_haspage,
   87         NULL
   88 };
   89 
   90 static void
   91 dev_pager_init()
   92 {
   93         TAILQ_INIT(&dev_pager_object_list);
   94         TAILQ_INIT(&dev_pager_fakelist);
   95 }
   96 
   97 static vm_object_t
   98 dev_pager_alloc(handle, size, prot, foff)
   99         void *handle;
  100         vm_size_t size;
  101         vm_prot_t prot;
  102         vm_ooffset_t foff;
  103 {
  104         dev_t dev;
  105         d_mmap_t *mapfunc;
  106         vm_object_t object;
  107         unsigned int npages, off;
  108 
  109         /*
  110          * Make sure this device can be mapped.
  111          */
  112         dev = (dev_t) (u_long) handle;
  113         mapfunc = cdevsw[major(dev)]->d_mmap;
  114         if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop) {
  115                 printf("obsolete map function %p\n", (void *)mapfunc);
  116                 return (NULL);
  117         }
  118 
  119         /*
  120          * Offset should be page aligned.
  121          */
  122         if (foff & PAGE_MASK)
  123                 return (NULL);
  124 
  125         /*
  126          * Check that the specified range of the device allows the desired
  127          * protection.
  128          *
  129          * XXX assumes VM_PROT_* == PROT_*
  130          */
  131         npages = size;
  132         for (off = foff; npages--; off += PAGE_SIZE)
  133                 if ((*mapfunc) (dev, off, (int) prot) == -1)
  134                         return (NULL);
  135 
  136         /*
  137          * Lock to prevent object creation race contion.
  138          */
  139         while (dev_pager_alloc_lock) {
  140                 dev_pager_alloc_lock_want++;
  141                 tsleep(&dev_pager_alloc_lock, PVM, "dvpall", 0);
  142                 dev_pager_alloc_lock_want--;
  143         }
  144         dev_pager_alloc_lock = 1;
  145 
  146         /*
  147          * Look up pager, creating as necessary.
  148          */
  149         object = vm_pager_object_lookup(&dev_pager_object_list, handle);
  150         if (object == NULL) {
  151                 /*
  152                  * Allocate object and associate it with the pager.
  153                  */
  154                 object = vm_object_allocate(OBJT_DEVICE,
  155                         OFF_TO_IDX(foff) + size);
  156                 object->handle = handle;
  157                 TAILQ_INIT(&object->un_pager.devp.devp_pglist);
  158                 TAILQ_INSERT_TAIL(&dev_pager_object_list, object, pager_object_list);
  159         } else {
  160                 /*
  161                  * Gain a reference to the object.
  162                  */
  163                 vm_object_reference(object);
  164                 if (OFF_TO_IDX(foff) + size > object->size)
  165                         object->size = OFF_TO_IDX(foff) + size;
  166         }
  167 
  168         dev_pager_alloc_lock = 0;
  169         if (dev_pager_alloc_lock_want)
  170                 wakeup(&dev_pager_alloc_lock);
  171 
  172         return (object);
  173 }
  174 
  175 static void
  176 dev_pager_dealloc(object)
  177         vm_object_t object;
  178 {
  179         vm_page_t m;
  180 
  181         TAILQ_REMOVE(&dev_pager_object_list, object, pager_object_list);
  182         /*
  183          * Free up our fake pages.
  184          */
  185         while ((m = TAILQ_FIRST(&object->un_pager.devp.devp_pglist)) != 0) {
  186                 TAILQ_REMOVE(&object->un_pager.devp.devp_pglist, m, pageq);
  187                 dev_pager_putfake(m);
  188         }
  189 }
  190 
  191 static int
  192 dev_pager_getpages(object, m, count, reqpage)
  193         vm_object_t object;
  194         vm_page_t *m;
  195         int count;
  196         int reqpage;
  197 {
  198         vm_offset_t offset;
  199         vm_offset_t paddr;
  200         vm_page_t page;
  201         dev_t dev;
  202         int i, s;
  203         d_mmap_t *mapfunc;
  204         int prot;
  205 
  206         dev = (dev_t) (u_long) object->handle;
  207         offset = m[reqpage]->pindex + OFF_TO_IDX(object->paging_offset);
  208         prot = PROT_READ;       /* XXX should pass in? */
  209         mapfunc = cdevsw[major(dev)]->d_mmap;
  210 
  211         if (mapfunc == NULL || mapfunc == (d_mmap_t *)nullop)
  212                 panic("dev_pager_getpage: no map function");
  213 
  214         paddr = pmap_phys_address((*mapfunc) ((dev_t) dev, (int) offset << PAGE_SHIFT, prot));
  215 #ifdef DIAGNOSTIC
  216         if (paddr == -1)
  217                 panic("dev_pager_getpage: map function returns error");
  218 #endif
  219         /*
  220          * Replace the passed in reqpage page with our own fake page and free up the
  221          * all of the original pages.
  222          */
  223         page = dev_pager_getfake(paddr);
  224         TAILQ_INSERT_TAIL(&object->un_pager.devp.devp_pglist, page, pageq);
  225         for (i = 0; i < count; i++) {
  226                 PAGE_WAKEUP(m[i]);
  227                 vm_page_free(m[i]);
  228         }
  229         s = splhigh();
  230         vm_page_insert(page, object, offset);
  231         splx(s);
  232 
  233         return (VM_PAGER_OK);
  234 }
  235 
  236 static int
  237 dev_pager_putpages(object, m, count, sync, rtvals)
  238         vm_object_t object;
  239         vm_page_t *m;
  240         int count;
  241         boolean_t sync;
  242         int *rtvals;
  243 {
  244         panic("dev_pager_putpage called");
  245 }
  246 
  247 static boolean_t
  248 dev_pager_haspage(object, pindex, before, after)
  249         vm_object_t object;
  250         vm_pindex_t pindex;
  251         int *before;
  252         int *after;
  253 {
  254         if (before != NULL)
  255                 *before = 0;
  256         if (after != NULL)
  257                 *after = 0;
  258         return (TRUE);
  259 }
  260 
  261 static vm_page_t
  262 dev_pager_getfake(paddr)
  263         vm_offset_t paddr;
  264 {
  265         vm_page_t m;
  266         int i;
  267 
  268         if (TAILQ_FIRST(&dev_pager_fakelist) == NULL) {
  269                 m = (vm_page_t) malloc(PAGE_SIZE * 2, M_VMPGDATA, M_WAITOK);
  270                 for (i = (PAGE_SIZE * 2) / sizeof(*m); i > 0; i--) {
  271                         TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq);
  272                         m++;
  273                 }
  274         }
  275         m = TAILQ_FIRST(&dev_pager_fakelist);
  276         TAILQ_REMOVE(&dev_pager_fakelist, m, pageq);
  277 
  278         m->flags = PG_BUSY | PG_FICTITIOUS;
  279         m->valid = VM_PAGE_BITS_ALL;
  280         m->dirty = 0;
  281         m->busy = 0;
  282         m->queue = PQ_NONE;
  283 
  284         m->wire_count = 1;
  285         m->hold_count = 0;
  286         m->phys_addr = paddr;
  287 
  288         return (m);
  289 }
  290 
  291 static void
  292 dev_pager_putfake(m)
  293         vm_page_t m;
  294 {
  295         if (!(m->flags & PG_FICTITIOUS))
  296                 panic("dev_pager_putfake: bad page");
  297         TAILQ_INSERT_TAIL(&dev_pager_fakelist, m, pageq);
  298 }

Cache object: bfa591d0d1fbcff3b07c21fdc9f917e7


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