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/mm/highmem.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  * High memory handling common code and variables.
    3  *
    4  * (C) 1999 Andrea Arcangeli, SuSE GmbH, andrea@suse.de
    5  *          Gerhard Wichert, Siemens AG, Gerhard.Wichert@pdb.siemens.de
    6  *
    7  *
    8  * Redesigned the x86 32-bit VM architecture to deal with
    9  * 64-bit physical space. With current x86 CPUs this
   10  * means up to 64 Gigabytes physical RAM.
   11  *
   12  * Rewrote high memory support to move the page cache into
   13  * high memory. Implemented permanent (schedulable) kmaps
   14  * based on Linus' idea.
   15  *
   16  * Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
   17  */
   18 
   19 #include <linux/mm.h>
   20 #include <linux/export.h>
   21 #include <linux/swap.h>
   22 #include <linux/bio.h>
   23 #include <linux/pagemap.h>
   24 #include <linux/mempool.h>
   25 #include <linux/blkdev.h>
   26 #include <linux/init.h>
   27 #include <linux/hash.h>
   28 #include <linux/highmem.h>
   29 #include <linux/kgdb.h>
   30 #include <asm/tlbflush.h>
   31 
   32 
   33 #if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32)
   34 DEFINE_PER_CPU(int, __kmap_atomic_idx);
   35 #endif
   36 
   37 /*
   38  * Virtual_count is not a pure "count".
   39  *  0 means that it is not mapped, and has not been mapped
   40  *    since a TLB flush - it is usable.
   41  *  1 means that there are no users, but it has been mapped
   42  *    since the last TLB flush - so we can't use it.
   43  *  n means that there are (n-1) current users of it.
   44  */
   45 #ifdef CONFIG_HIGHMEM
   46 
   47 unsigned long totalhigh_pages __read_mostly;
   48 EXPORT_SYMBOL(totalhigh_pages);
   49 
   50 
   51 EXPORT_PER_CPU_SYMBOL(__kmap_atomic_idx);
   52 
   53 unsigned int nr_free_highpages (void)
   54 {
   55         pg_data_t *pgdat;
   56         unsigned int pages = 0;
   57 
   58         for_each_online_pgdat(pgdat) {
   59                 pages += zone_page_state(&pgdat->node_zones[ZONE_HIGHMEM],
   60                         NR_FREE_PAGES);
   61                 if (zone_movable_is_highmem())
   62                         pages += zone_page_state(
   63                                         &pgdat->node_zones[ZONE_MOVABLE],
   64                                         NR_FREE_PAGES);
   65         }
   66 
   67         return pages;
   68 }
   69 
   70 static int pkmap_count[LAST_PKMAP];
   71 static unsigned int last_pkmap_nr;
   72 static  __cacheline_aligned_in_smp DEFINE_SPINLOCK(kmap_lock);
   73 
   74 pte_t * pkmap_page_table;
   75 
   76 static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
   77 
   78 /*
   79  * Most architectures have no use for kmap_high_get(), so let's abstract
   80  * the disabling of IRQ out of the locking in that case to save on a
   81  * potential useless overhead.
   82  */
   83 #ifdef ARCH_NEEDS_KMAP_HIGH_GET
   84 #define lock_kmap()             spin_lock_irq(&kmap_lock)
   85 #define unlock_kmap()           spin_unlock_irq(&kmap_lock)
   86 #define lock_kmap_any(flags)    spin_lock_irqsave(&kmap_lock, flags)
   87 #define unlock_kmap_any(flags)  spin_unlock_irqrestore(&kmap_lock, flags)
   88 #else
   89 #define lock_kmap()             spin_lock(&kmap_lock)
   90 #define unlock_kmap()           spin_unlock(&kmap_lock)
   91 #define lock_kmap_any(flags)    \
   92                 do { spin_lock(&kmap_lock); (void)(flags); } while (0)
   93 #define unlock_kmap_any(flags)  \
   94                 do { spin_unlock(&kmap_lock); (void)(flags); } while (0)
   95 #endif
   96 
   97 struct page *kmap_to_page(void *vaddr)
   98 {
   99         unsigned long addr = (unsigned long)vaddr;
  100 
  101         if (addr >= PKMAP_ADDR(0) && addr < PKMAP_ADDR(LAST_PKMAP)) {
  102                 int i = PKMAP_NR(addr);
  103                 return pte_page(pkmap_page_table[i]);
  104         }
  105 
  106         return virt_to_page(addr);
  107 }
  108 EXPORT_SYMBOL(kmap_to_page);
  109 
  110 static void flush_all_zero_pkmaps(void)
  111 {
  112         int i;
  113         int need_flush = 0;
  114 
  115         flush_cache_kmaps();
  116 
  117         for (i = 0; i < LAST_PKMAP; i++) {
  118                 struct page *page;
  119 
  120                 /*
  121                  * zero means we don't have anything to do,
  122                  * >1 means that it is still in use. Only
  123                  * a count of 1 means that it is free but
  124                  * needs to be unmapped
  125                  */
  126                 if (pkmap_count[i] != 1)
  127                         continue;
  128                 pkmap_count[i] = 0;
  129 
  130                 /* sanity check */
  131                 BUG_ON(pte_none(pkmap_page_table[i]));
  132 
  133                 /*
  134                  * Don't need an atomic fetch-and-clear op here;
  135                  * no-one has the page mapped, and cannot get at
  136                  * its virtual address (and hence PTE) without first
  137                  * getting the kmap_lock (which is held here).
  138                  * So no dangers, even with speculative execution.
  139                  */
  140                 page = pte_page(pkmap_page_table[i]);
  141                 pte_clear(&init_mm, PKMAP_ADDR(i), &pkmap_page_table[i]);
  142 
  143                 set_page_address(page, NULL);
  144                 need_flush = 1;
  145         }
  146         if (need_flush)
  147                 flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
  148 }
  149 
  150 /**
  151  * kmap_flush_unused - flush all unused kmap mappings in order to remove stray mappings
  152  */
  153 void kmap_flush_unused(void)
  154 {
  155         lock_kmap();
  156         flush_all_zero_pkmaps();
  157         unlock_kmap();
  158 }
  159 
  160 static inline unsigned long map_new_virtual(struct page *page)
  161 {
  162         unsigned long vaddr;
  163         int count;
  164 
  165 start:
  166         count = LAST_PKMAP;
  167         /* Find an empty entry */
  168         for (;;) {
  169                 last_pkmap_nr = (last_pkmap_nr + 1) & LAST_PKMAP_MASK;
  170                 if (!last_pkmap_nr) {
  171                         flush_all_zero_pkmaps();
  172                         count = LAST_PKMAP;
  173                 }
  174                 if (!pkmap_count[last_pkmap_nr])
  175                         break;  /* Found a usable entry */
  176                 if (--count)
  177                         continue;
  178 
  179                 /*
  180                  * Sleep for somebody else to unmap their entries
  181                  */
  182                 {
  183                         DECLARE_WAITQUEUE(wait, current);
  184 
  185                         __set_current_state(TASK_UNINTERRUPTIBLE);
  186                         add_wait_queue(&pkmap_map_wait, &wait);
  187                         unlock_kmap();
  188                         schedule();
  189                         remove_wait_queue(&pkmap_map_wait, &wait);
  190                         lock_kmap();
  191 
  192                         /* Somebody else might have mapped it while we slept */
  193                         if (page_address(page))
  194                                 return (unsigned long)page_address(page);
  195 
  196                         /* Re-start */
  197                         goto start;
  198                 }
  199         }
  200         vaddr = PKMAP_ADDR(last_pkmap_nr);
  201         set_pte_at(&init_mm, vaddr,
  202                    &(pkmap_page_table[last_pkmap_nr]), mk_pte(page, kmap_prot));
  203 
  204         pkmap_count[last_pkmap_nr] = 1;
  205         set_page_address(page, (void *)vaddr);
  206 
  207         return vaddr;
  208 }
  209 
  210 /**
  211  * kmap_high - map a highmem page into memory
  212  * @page: &struct page to map
  213  *
  214  * Returns the page's virtual memory address.
  215  *
  216  * We cannot call this from interrupts, as it may block.
  217  */
  218 void *kmap_high(struct page *page)
  219 {
  220         unsigned long vaddr;
  221 
  222         /*
  223          * For highmem pages, we can't trust "virtual" until
  224          * after we have the lock.
  225          */
  226         lock_kmap();
  227         vaddr = (unsigned long)page_address(page);
  228         if (!vaddr)
  229                 vaddr = map_new_virtual(page);
  230         pkmap_count[PKMAP_NR(vaddr)]++;
  231         BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 2);
  232         unlock_kmap();
  233         return (void*) vaddr;
  234 }
  235 
  236 EXPORT_SYMBOL(kmap_high);
  237 
  238 #ifdef ARCH_NEEDS_KMAP_HIGH_GET
  239 /**
  240  * kmap_high_get - pin a highmem page into memory
  241  * @page: &struct page to pin
  242  *
  243  * Returns the page's current virtual memory address, or NULL if no mapping
  244  * exists.  If and only if a non null address is returned then a
  245  * matching call to kunmap_high() is necessary.
  246  *
  247  * This can be called from any context.
  248  */
  249 void *kmap_high_get(struct page *page)
  250 {
  251         unsigned long vaddr, flags;
  252 
  253         lock_kmap_any(flags);
  254         vaddr = (unsigned long)page_address(page);
  255         if (vaddr) {
  256                 BUG_ON(pkmap_count[PKMAP_NR(vaddr)] < 1);
  257                 pkmap_count[PKMAP_NR(vaddr)]++;
  258         }
  259         unlock_kmap_any(flags);
  260         return (void*) vaddr;
  261 }
  262 #endif
  263 
  264 /**
  265  * kunmap_high - unmap a highmem page into memory
  266  * @page: &struct page to unmap
  267  *
  268  * If ARCH_NEEDS_KMAP_HIGH_GET is not defined then this may be called
  269  * only from user context.
  270  */
  271 void kunmap_high(struct page *page)
  272 {
  273         unsigned long vaddr;
  274         unsigned long nr;
  275         unsigned long flags;
  276         int need_wakeup;
  277 
  278         lock_kmap_any(flags);
  279         vaddr = (unsigned long)page_address(page);
  280         BUG_ON(!vaddr);
  281         nr = PKMAP_NR(vaddr);
  282 
  283         /*
  284          * A count must never go down to zero
  285          * without a TLB flush!
  286          */
  287         need_wakeup = 0;
  288         switch (--pkmap_count[nr]) {
  289         case 0:
  290                 BUG();
  291         case 1:
  292                 /*
  293                  * Avoid an unnecessary wake_up() function call.
  294                  * The common case is pkmap_count[] == 1, but
  295                  * no waiters.
  296                  * The tasks queued in the wait-queue are guarded
  297                  * by both the lock in the wait-queue-head and by
  298                  * the kmap_lock.  As the kmap_lock is held here,
  299                  * no need for the wait-queue-head's lock.  Simply
  300                  * test if the queue is empty.
  301                  */
  302                 need_wakeup = waitqueue_active(&pkmap_map_wait);
  303         }
  304         unlock_kmap_any(flags);
  305 
  306         /* do wake-up, if needed, race-free outside of the spin lock */
  307         if (need_wakeup)
  308                 wake_up(&pkmap_map_wait);
  309 }
  310 
  311 EXPORT_SYMBOL(kunmap_high);
  312 #endif
  313 
  314 #if defined(HASHED_PAGE_VIRTUAL)
  315 
  316 #define PA_HASH_ORDER   7
  317 
  318 /*
  319  * Describes one page->virtual association
  320  */
  321 struct page_address_map {
  322         struct page *page;
  323         void *virtual;
  324         struct list_head list;
  325 };
  326 
  327 static struct page_address_map page_address_maps[LAST_PKMAP];
  328 
  329 /*
  330  * Hash table bucket
  331  */
  332 static struct page_address_slot {
  333         struct list_head lh;                    /* List of page_address_maps */
  334         spinlock_t lock;                        /* Protect this bucket's list */
  335 } ____cacheline_aligned_in_smp page_address_htable[1<<PA_HASH_ORDER];
  336 
  337 static struct page_address_slot *page_slot(const struct page *page)
  338 {
  339         return &page_address_htable[hash_ptr(page, PA_HASH_ORDER)];
  340 }
  341 
  342 /**
  343  * page_address - get the mapped virtual address of a page
  344  * @page: &struct page to get the virtual address of
  345  *
  346  * Returns the page's virtual address.
  347  */
  348 void *page_address(const struct page *page)
  349 {
  350         unsigned long flags;
  351         void *ret;
  352         struct page_address_slot *pas;
  353 
  354         if (!PageHighMem(page))
  355                 return lowmem_page_address(page);
  356 
  357         pas = page_slot(page);
  358         ret = NULL;
  359         spin_lock_irqsave(&pas->lock, flags);
  360         if (!list_empty(&pas->lh)) {
  361                 struct page_address_map *pam;
  362 
  363                 list_for_each_entry(pam, &pas->lh, list) {
  364                         if (pam->page == page) {
  365                                 ret = pam->virtual;
  366                                 goto done;
  367                         }
  368                 }
  369         }
  370 done:
  371         spin_unlock_irqrestore(&pas->lock, flags);
  372         return ret;
  373 }
  374 
  375 EXPORT_SYMBOL(page_address);
  376 
  377 /**
  378  * set_page_address - set a page's virtual address
  379  * @page: &struct page to set
  380  * @virtual: virtual address to use
  381  */
  382 void set_page_address(struct page *page, void *virtual)
  383 {
  384         unsigned long flags;
  385         struct page_address_slot *pas;
  386         struct page_address_map *pam;
  387 
  388         BUG_ON(!PageHighMem(page));
  389 
  390         pas = page_slot(page);
  391         if (virtual) {          /* Add */
  392                 pam = &page_address_maps[PKMAP_NR((unsigned long)virtual)];
  393                 pam->page = page;
  394                 pam->virtual = virtual;
  395 
  396                 spin_lock_irqsave(&pas->lock, flags);
  397                 list_add_tail(&pam->list, &pas->lh);
  398                 spin_unlock_irqrestore(&pas->lock, flags);
  399         } else {                /* Remove */
  400                 spin_lock_irqsave(&pas->lock, flags);
  401                 list_for_each_entry(pam, &pas->lh, list) {
  402                         if (pam->page == page) {
  403                                 list_del(&pam->list);
  404                                 spin_unlock_irqrestore(&pas->lock, flags);
  405                                 goto done;
  406                         }
  407                 }
  408                 spin_unlock_irqrestore(&pas->lock, flags);
  409         }
  410 done:
  411         return;
  412 }
  413 
  414 void __init page_address_init(void)
  415 {
  416         int i;
  417 
  418         for (i = 0; i < ARRAY_SIZE(page_address_htable); i++) {
  419                 INIT_LIST_HEAD(&page_address_htable[i].lh);
  420                 spin_lock_init(&page_address_htable[i].lock);
  421         }
  422 }
  423 
  424 #endif  /* defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) */

Cache object: 2adf95d9c05de1070b4d766d32ac41b6


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