Annotation of Gnu-Mach/vm/vm_page.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Copyright (c) 2010-2014 Richard Braun.
                      3:  *
                      4:  * This program is free software: you can redistribute it and/or modify
                      5:  * it under the terms of the GNU General Public License as published by
                      6:  * the Free Software Foundation, either version 2 of the License, or
                      7:  * (at your option) any later version.
                      8:  *
                      9:  * This program is distributed in the hope that it will be useful,
                     10:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     12:  * GNU General Public License for more details.
                     13:  *
                     14:  * You should have received a copy of the GNU General Public License
                     15:  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     16:  *
                     17:  *
                     18:  * This implementation uses the binary buddy system to manage its heap.
                     19:  * Descriptions of the buddy system can be found in the following works :
                     20:  * - "UNIX Internals: The New Frontiers", by Uresh Vahalia.
                     21:  * - "Dynamic Storage Allocation: A Survey and Critical Review",
                     22:  *    by Paul R. Wilson, Mark S. Johnstone, Michael Neely, and David Boles.
                     23:  *
                     24:  * In addition, this allocator uses per-CPU pools of pages for order 0
                     25:  * (i.e. single page) allocations. These pools act as caches (but are named
                     26:  * differently to avoid confusion with CPU caches) that reduce contention on
                     27:  * multiprocessor systems. When a pool is empty and cannot provide a page,
                     28:  * it is filled by transferring multiple pages from the backend buddy system.
                     29:  * The symmetric case is handled likewise.
1.1.1.2 ! root       30:  *
        !            31:  * TODO Limit number of dirty pages, block allocations above a top limit.
1.1       root       32:  */
                     33: 
                     34: #include <string.h>
                     35: #include <kern/assert.h>
1.1.1.2 ! root       36: #include <kern/counters.h>
1.1       root       37: #include <kern/cpu_number.h>
                     38: #include <kern/debug.h>
                     39: #include <kern/list.h>
                     40: #include <kern/lock.h>
                     41: #include <kern/macros.h>
                     42: #include <kern/printf.h>
                     43: #include <kern/thread.h>
                     44: #include <mach/vm_param.h>
                     45: #include <machine/pmap.h>
                     46: #include <sys/types.h>
                     47: #include <vm/vm_page.h>
1.1.1.2 ! root       48: #include <vm/vm_pageout.h>
        !            49: 
        !            50: #define DEBUG 0
1.1       root       51: 
                     52: #define __init
                     53: #define __initdata
                     54: #define __read_mostly
                     55: 
                     56: #define thread_pin()
                     57: #define thread_unpin()
                     58: 
                     59: /*
                     60:  * Number of free block lists per segment.
                     61:  */
                     62: #define VM_PAGE_NR_FREE_LISTS 11
                     63: 
                     64: /*
                     65:  * The size of a CPU pool is computed by dividing the number of pages in its
                     66:  * containing segment by this value.
                     67:  */
                     68: #define VM_PAGE_CPU_POOL_RATIO 1024
                     69: 
                     70: /*
                     71:  * Maximum number of pages in a CPU pool.
                     72:  */
                     73: #define VM_PAGE_CPU_POOL_MAX_SIZE 128
                     74: 
                     75: /*
                     76:  * The transfer size of a CPU pool is computed by dividing the pool size by
                     77:  * this value.
                     78:  */
                     79: #define VM_PAGE_CPU_POOL_TRANSFER_RATIO 2
                     80: 
                     81: /*
                     82:  * Per-processor cache of pages.
                     83:  */
                     84: struct vm_page_cpu_pool {
                     85:     simple_lock_data_t lock;
                     86:     int size;
                     87:     int transfer_size;
                     88:     int nr_pages;
                     89:     struct list pages;
                     90: } __aligned(CPU_L1_SIZE);
                     91: 
                     92: /*
                     93:  * Special order value for pages that aren't in a free list. Such pages are
                     94:  * either allocated, or part of a free block of pages but not the head page.
                     95:  */
                     96: #define VM_PAGE_ORDER_UNLISTED ((unsigned short)-1)
                     97: 
                     98: /*
                     99:  * Doubly-linked list of free blocks.
                    100:  */
                    101: struct vm_page_free_list {
                    102:     unsigned long size;
                    103:     struct list blocks;
                    104: };
                    105: 
                    106: /*
1.1.1.2 ! root      107:  * XXX Because of a potential deadlock involving the default pager (see
        !           108:  * vm_map_lock()), it's currently impossible to reliably determine the
        !           109:  * minimum number of free pages required for successful pageout. Since
        !           110:  * that process is dependent on the amount of physical memory, we scale
        !           111:  * the minimum number of free pages from it, in the hope that memory
        !           112:  * exhaustion happens as rarely as possible...
        !           113:  */
        !           114: 
        !           115: /*
        !           116:  * Ratio used to compute the minimum number of pages in a segment.
        !           117:  */
        !           118: #define VM_PAGE_SEG_THRESHOLD_MIN_NUM   5
        !           119: #define VM_PAGE_SEG_THRESHOLD_MIN_DENOM 100
        !           120: 
        !           121: /*
        !           122:  * Number of pages reserved for privileged allocations in a segment.
        !           123:  */
        !           124: #define VM_PAGE_SEG_THRESHOLD_MIN 500
        !           125: 
        !           126: /*
        !           127:  * Ratio used to compute the threshold below which pageout is started.
        !           128:  */
        !           129: #define VM_PAGE_SEG_THRESHOLD_LOW_NUM   6
        !           130: #define VM_PAGE_SEG_THRESHOLD_LOW_DENOM 100
        !           131: 
        !           132: /*
        !           133:  * Minimum value the low threshold can have for a segment.
        !           134:  */
        !           135: #define VM_PAGE_SEG_THRESHOLD_LOW 600
        !           136: 
        !           137: #if VM_PAGE_SEG_THRESHOLD_LOW <= VM_PAGE_SEG_THRESHOLD_MIN
        !           138: #error VM_PAGE_SEG_THRESHOLD_LOW invalid
        !           139: #endif /* VM_PAGE_SEG_THRESHOLD_LOW >= VM_PAGE_SEG_THRESHOLD_MIN */
        !           140: 
        !           141: /*
        !           142:  * Ratio used to compute the threshold above which pageout is stopped.
        !           143:  */
        !           144: #define VM_PAGE_SEG_THRESHOLD_HIGH_NUM      10
        !           145: #define VM_PAGE_SEG_THRESHOLD_HIGH_DENOM    100
        !           146: 
        !           147: /*
        !           148:  * Minimum value the high threshold can have for a segment.
        !           149:  */
        !           150: #define VM_PAGE_SEG_THRESHOLD_HIGH 1000
        !           151: 
        !           152: #if VM_PAGE_SEG_THRESHOLD_HIGH <= VM_PAGE_SEG_THRESHOLD_LOW
        !           153: #error VM_PAGE_SEG_THRESHOLD_HIGH invalid
        !           154: #endif /* VM_PAGE_SEG_THRESHOLD_HIGH <= VM_PAGE_SEG_THRESHOLD_LOW */
        !           155: 
        !           156: /*
        !           157:  * Minimum number of pages allowed for a segment.
        !           158:  */
        !           159: #define VM_PAGE_SEG_MIN_PAGES 2000
        !           160: 
        !           161: #if VM_PAGE_SEG_MIN_PAGES <= VM_PAGE_SEG_THRESHOLD_HIGH
        !           162: #error VM_PAGE_SEG_MIN_PAGES invalid
        !           163: #endif /* VM_PAGE_SEG_MIN_PAGES <= VM_PAGE_SEG_THRESHOLD_HIGH */
        !           164: 
        !           165: /*
        !           166:  * Ratio used to compute the threshold of active pages beyond which
        !           167:  * to refill the inactive queue.
        !           168:  */
        !           169: #define VM_PAGE_HIGH_ACTIVE_PAGE_NUM    1
        !           170: #define VM_PAGE_HIGH_ACTIVE_PAGE_DENOM  3
        !           171: 
        !           172: /*
        !           173:  * Page cache queue.
        !           174:  *
        !           175:  * XXX The current implementation hardcodes a preference to evict external
        !           176:  * pages first and keep internal ones as much as possible. This is because
        !           177:  * the Hurd default pager implementation suffers from bugs that can easily
        !           178:  * cause the system to freeze.
        !           179:  */
        !           180: struct vm_page_queue {
        !           181:     struct list internal_pages;
        !           182:     struct list external_pages;
        !           183: };
        !           184: 
        !           185: /*
1.1       root      186:  * Segment name buffer size.
                    187:  */
                    188: #define VM_PAGE_NAME_SIZE 16
                    189: 
                    190: /*
                    191:  * Segment of contiguous memory.
1.1.1.2 ! root      192:  *
        !           193:  * XXX Per-segment locking is probably useless, since one or both of the
        !           194:  * page queues lock and the free page queue lock is held on any access.
        !           195:  * However it should first be made clear which lock protects access to
        !           196:  * which members of a segment.
1.1       root      197:  */
                    198: struct vm_page_seg {
                    199:     struct vm_page_cpu_pool cpu_pools[NCPUS];
                    200: 
                    201:     phys_addr_t start;
                    202:     phys_addr_t end;
                    203:     struct vm_page *pages;
                    204:     struct vm_page *pages_end;
                    205:     simple_lock_data_t lock;
                    206:     struct vm_page_free_list free_lists[VM_PAGE_NR_FREE_LISTS];
                    207:     unsigned long nr_free_pages;
1.1.1.2 ! root      208: 
        !           209:     /* Free memory thresholds */
        !           210:     unsigned long min_free_pages; /* Privileged allocations only */
        !           211:     unsigned long low_free_pages; /* Pageout daemon starts scanning */
        !           212:     unsigned long high_free_pages; /* Pageout daemon stops scanning,
        !           213:                                       unprivileged allocations resume */
        !           214: 
        !           215:     /* Page cache related data */
        !           216:     struct vm_page_queue active_pages;
        !           217:     unsigned long nr_active_pages;
        !           218:     unsigned long high_active_pages;
        !           219:     struct vm_page_queue inactive_pages;
        !           220:     unsigned long nr_inactive_pages;
1.1       root      221: };
                    222: 
                    223: /*
                    224:  * Bootstrap information about a segment.
                    225:  */
                    226: struct vm_page_boot_seg {
                    227:     phys_addr_t start;
                    228:     phys_addr_t end;
1.1.1.2 ! root      229:     boolean_t heap_present;
1.1       root      230:     phys_addr_t avail_start;
                    231:     phys_addr_t avail_end;
                    232: };
                    233: 
                    234: static int vm_page_is_ready __read_mostly;
                    235: 
                    236: /*
                    237:  * Segment table.
                    238:  *
                    239:  * The system supports a maximum of 4 segments :
                    240:  *  - DMA: suitable for DMA
                    241:  *  - DMA32: suitable for DMA when devices support 32-bits addressing
                    242:  *  - DIRECTMAP: direct physical mapping, allows direct access from
                    243:  *    the kernel with a simple offset translation
                    244:  *  - HIGHMEM: must be mapped before it can be accessed
                    245:  *
                    246:  * Segments are ordered by priority, 0 being the lowest priority. Their
                    247:  * relative priorities are DMA < DMA32 < DIRECTMAP < HIGHMEM. Some segments
                    248:  * may actually be aliases for others, e.g. if DMA is always possible from
                    249:  * the direct physical mapping, DMA and DMA32 are aliases for DIRECTMAP,
                    250:  * in which case the segment table contains DIRECTMAP and HIGHMEM only.
                    251:  */
                    252: static struct vm_page_seg vm_page_segs[VM_PAGE_MAX_SEGS];
                    253: 
                    254: /*
                    255:  * Bootstrap segment table.
                    256:  */
                    257: static struct vm_page_boot_seg vm_page_boot_segs[VM_PAGE_MAX_SEGS] __initdata;
                    258: 
                    259: /*
                    260:  * Number of loaded segments.
                    261:  */
                    262: static unsigned int vm_page_segs_size __read_mostly;
                    263: 
1.1.1.2 ! root      264: /*
        !           265:  * If true, unprivileged allocations are blocked, disregarding any other
        !           266:  * condition.
        !           267:  *
        !           268:  * This variable is also used to resume clients once pages are available.
        !           269:  *
        !           270:  * The free page queue lock must be held when accessing this variable.
        !           271:  */
        !           272: static boolean_t vm_page_alloc_paused;
        !           273: 
1.1       root      274: static void __init
                    275: vm_page_init_pa(struct vm_page *page, unsigned short seg_index, phys_addr_t pa)
                    276: {
                    277:     memset(page, 0, sizeof(*page));
                    278:     vm_page_init(page); /* vm_resident members */
                    279:     page->type = VM_PT_RESERVED;
                    280:     page->seg_index = seg_index;
                    281:     page->order = VM_PAGE_ORDER_UNLISTED;
                    282:     page->priv = NULL;
                    283:     page->phys_addr = pa;
                    284: }
                    285: 
                    286: void
                    287: vm_page_set_type(struct vm_page *page, unsigned int order, unsigned short type)
                    288: {
                    289:     unsigned int i, nr_pages;
                    290: 
                    291:     nr_pages = 1 << order;
                    292: 
                    293:     for (i = 0; i < nr_pages; i++)
                    294:         page[i].type = type;
                    295: }
                    296: 
1.1.1.2 ! root      297: static boolean_t
        !           298: vm_page_pageable(const struct vm_page *page)
        !           299: {
        !           300:     return (page->object != NULL)
        !           301:            && (page->wire_count == 0)
        !           302:            && (page->active || page->inactive);
        !           303: }
        !           304: 
        !           305: static boolean_t
        !           306: vm_page_can_move(const struct vm_page *page)
        !           307: {
        !           308:     /*
        !           309:      * This function is called on pages pulled from the page queues,
        !           310:      * implying they're pageable, which is why the wire count isn't
        !           311:      * checked here.
        !           312:      */
        !           313: 
        !           314:     return !page->busy
        !           315:            && !page->wanted
        !           316:            && !page->absent
        !           317:            && page->object->alive;
        !           318: }
        !           319: 
        !           320: static void
        !           321: vm_page_remove_mappings(struct vm_page *page)
        !           322: {
        !           323:     page->busy = TRUE;
        !           324:     pmap_page_protect(page->phys_addr, VM_PROT_NONE);
        !           325: 
        !           326:     if (!page->dirty) {
        !           327:         page->dirty = pmap_is_modified(page->phys_addr);
        !           328:     }
        !           329: }
        !           330: 
1.1       root      331: static void __init
                    332: vm_page_free_list_init(struct vm_page_free_list *free_list)
                    333: {
                    334:     free_list->size = 0;
                    335:     list_init(&free_list->blocks);
                    336: }
                    337: 
                    338: static inline void
                    339: vm_page_free_list_insert(struct vm_page_free_list *free_list,
                    340:                          struct vm_page *page)
                    341: {
                    342:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
                    343: 
                    344:     free_list->size++;
                    345:     list_insert_head(&free_list->blocks, &page->node);
                    346: }
                    347: 
                    348: static inline void
                    349: vm_page_free_list_remove(struct vm_page_free_list *free_list,
                    350:                          struct vm_page *page)
                    351: {
                    352:     assert(page->order != VM_PAGE_ORDER_UNLISTED);
                    353: 
                    354:     free_list->size--;
                    355:     list_remove(&page->node);
                    356: }
                    357: 
                    358: static struct vm_page *
                    359: vm_page_seg_alloc_from_buddy(struct vm_page_seg *seg, unsigned int order)
                    360: {
                    361:     struct vm_page_free_list *free_list = free_list;
                    362:     struct vm_page *page, *buddy;
                    363:     unsigned int i;
                    364: 
                    365:     assert(order < VM_PAGE_NR_FREE_LISTS);
                    366: 
1.1.1.2 ! root      367:     if (vm_page_alloc_paused && current_thread()
        !           368:         && !current_thread()->vm_privilege) {
        !           369:         return NULL;
        !           370:     } else if (seg->nr_free_pages <= seg->low_free_pages) {
        !           371:         vm_pageout_start();
        !           372: 
        !           373:         if ((seg->nr_free_pages <= seg->min_free_pages)
        !           374:             && current_thread() && !current_thread()->vm_privilege) {
        !           375:             vm_page_alloc_paused = TRUE;
        !           376:             return NULL;
        !           377:         }
        !           378:     }
        !           379: 
1.1       root      380:     for (i = order; i < VM_PAGE_NR_FREE_LISTS; i++) {
                    381:         free_list = &seg->free_lists[i];
                    382: 
                    383:         if (free_list->size != 0)
                    384:             break;
                    385:     }
                    386: 
                    387:     if (i == VM_PAGE_NR_FREE_LISTS)
                    388:         return NULL;
                    389: 
                    390:     page = list_first_entry(&free_list->blocks, struct vm_page, node);
                    391:     vm_page_free_list_remove(free_list, page);
                    392:     page->order = VM_PAGE_ORDER_UNLISTED;
                    393: 
                    394:     while (i > order) {
                    395:         i--;
                    396:         buddy = &page[1 << i];
                    397:         vm_page_free_list_insert(&seg->free_lists[i], buddy);
                    398:         buddy->order = i;
                    399:     }
                    400: 
                    401:     seg->nr_free_pages -= (1 << order);
1.1.1.2 ! root      402: 
        !           403:     if (seg->nr_free_pages < seg->min_free_pages) {
        !           404:         vm_page_alloc_paused = TRUE;
        !           405:     }
        !           406: 
1.1       root      407:     return page;
                    408: }
                    409: 
                    410: static void
                    411: vm_page_seg_free_to_buddy(struct vm_page_seg *seg, struct vm_page *page,
                    412:                           unsigned int order)
                    413: {
                    414:     struct vm_page *buddy;
                    415:     phys_addr_t pa, buddy_pa;
                    416:     unsigned int nr_pages;
                    417: 
                    418:     assert(page >= seg->pages);
                    419:     assert(page < seg->pages_end);
                    420:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
                    421:     assert(order < VM_PAGE_NR_FREE_LISTS);
                    422: 
                    423:     nr_pages = (1 << order);
                    424:     pa = page->phys_addr;
                    425: 
                    426:     while (order < (VM_PAGE_NR_FREE_LISTS - 1)) {
                    427:         buddy_pa = pa ^ vm_page_ptoa(1 << order);
                    428: 
                    429:         if ((buddy_pa < seg->start) || (buddy_pa >= seg->end))
                    430:             break;
                    431: 
                    432:         buddy = &seg->pages[vm_page_atop(buddy_pa - seg->start)];
                    433: 
                    434:         if (buddy->order != order)
                    435:             break;
                    436: 
                    437:         vm_page_free_list_remove(&seg->free_lists[order], buddy);
                    438:         buddy->order = VM_PAGE_ORDER_UNLISTED;
                    439:         order++;
                    440:         pa &= -vm_page_ptoa(1 << order);
                    441:         page = &seg->pages[vm_page_atop(pa - seg->start)];
                    442:     }
                    443: 
                    444:     vm_page_free_list_insert(&seg->free_lists[order], page);
                    445:     page->order = order;
                    446:     seg->nr_free_pages += nr_pages;
                    447: }
                    448: 
                    449: static void __init
                    450: vm_page_cpu_pool_init(struct vm_page_cpu_pool *cpu_pool, int size)
                    451: {
                    452:     simple_lock_init(&cpu_pool->lock);
                    453:     cpu_pool->size = size;
                    454:     cpu_pool->transfer_size = (size + VM_PAGE_CPU_POOL_TRANSFER_RATIO - 1)
                    455:                               / VM_PAGE_CPU_POOL_TRANSFER_RATIO;
                    456:     cpu_pool->nr_pages = 0;
                    457:     list_init(&cpu_pool->pages);
                    458: }
                    459: 
                    460: static inline struct vm_page_cpu_pool *
                    461: vm_page_cpu_pool_get(struct vm_page_seg *seg)
                    462: {
                    463:     return &seg->cpu_pools[cpu_number()];
                    464: }
                    465: 
                    466: static inline struct vm_page *
                    467: vm_page_cpu_pool_pop(struct vm_page_cpu_pool *cpu_pool)
                    468: {
                    469:     struct vm_page *page;
                    470: 
                    471:     assert(cpu_pool->nr_pages != 0);
                    472:     cpu_pool->nr_pages--;
                    473:     page = list_first_entry(&cpu_pool->pages, struct vm_page, node);
                    474:     list_remove(&page->node);
                    475:     return page;
                    476: }
                    477: 
                    478: static inline void
                    479: vm_page_cpu_pool_push(struct vm_page_cpu_pool *cpu_pool, struct vm_page *page)
                    480: {
                    481:     assert(cpu_pool->nr_pages < cpu_pool->size);
                    482:     cpu_pool->nr_pages++;
                    483:     list_insert_head(&cpu_pool->pages, &page->node);
                    484: }
                    485: 
                    486: static int
                    487: vm_page_cpu_pool_fill(struct vm_page_cpu_pool *cpu_pool,
                    488:                       struct vm_page_seg *seg)
                    489: {
                    490:     struct vm_page *page;
                    491:     int i;
                    492: 
                    493:     assert(cpu_pool->nr_pages == 0);
                    494: 
                    495:     simple_lock(&seg->lock);
                    496: 
                    497:     for (i = 0; i < cpu_pool->transfer_size; i++) {
                    498:         page = vm_page_seg_alloc_from_buddy(seg, 0);
                    499: 
                    500:         if (page == NULL)
                    501:             break;
                    502: 
                    503:         vm_page_cpu_pool_push(cpu_pool, page);
                    504:     }
                    505: 
                    506:     simple_unlock(&seg->lock);
                    507: 
                    508:     return i;
                    509: }
                    510: 
                    511: static void
                    512: vm_page_cpu_pool_drain(struct vm_page_cpu_pool *cpu_pool,
                    513:                        struct vm_page_seg *seg)
                    514: {
                    515:     struct vm_page *page;
                    516:     int i;
                    517: 
                    518:     assert(cpu_pool->nr_pages == cpu_pool->size);
                    519: 
                    520:     simple_lock(&seg->lock);
                    521: 
                    522:     for (i = cpu_pool->transfer_size; i > 0; i--) {
                    523:         page = vm_page_cpu_pool_pop(cpu_pool);
                    524:         vm_page_seg_free_to_buddy(seg, page, 0);
                    525:     }
                    526: 
                    527:     simple_unlock(&seg->lock);
                    528: }
                    529: 
1.1.1.2 ! root      530: static void
        !           531: vm_page_queue_init(struct vm_page_queue *queue)
        !           532: {
        !           533:     list_init(&queue->internal_pages);
        !           534:     list_init(&queue->external_pages);
        !           535: }
        !           536: 
        !           537: static void
        !           538: vm_page_queue_push(struct vm_page_queue *queue, struct vm_page *page)
        !           539: {
        !           540:     if (page->external) {
        !           541:         list_insert_tail(&queue->external_pages, &page->node);
        !           542:     } else {
        !           543:         list_insert_tail(&queue->internal_pages, &page->node);
        !           544:     }
        !           545: }
        !           546: 
        !           547: static void
        !           548: vm_page_queue_remove(struct vm_page_queue *queue, struct vm_page *page)
        !           549: {
        !           550:     (void)queue;
        !           551:     list_remove(&page->node);
        !           552: }
        !           553: 
        !           554: static struct vm_page *
        !           555: vm_page_queue_first(struct vm_page_queue *queue, boolean_t external_only)
        !           556: {
        !           557:     struct vm_page *page;
        !           558: 
        !           559:     if (!list_empty(&queue->external_pages)) {
        !           560:         page = list_first_entry(&queue->external_pages, struct vm_page, node);
        !           561:         return page;
        !           562:     }
        !           563: 
        !           564:     if (!external_only && !list_empty(&queue->internal_pages)) {
        !           565:         page = list_first_entry(&queue->internal_pages, struct vm_page, node);
        !           566:         return page;
        !           567:     }
        !           568: 
        !           569:     return NULL;
        !           570: }
        !           571: 
        !           572: static struct vm_page_seg *
        !           573: vm_page_seg_get(unsigned short index)
        !           574: {
        !           575:     assert(index < vm_page_segs_size);
        !           576:     return &vm_page_segs[index];
        !           577: }
        !           578: 
        !           579: static unsigned int
        !           580: vm_page_seg_index(const struct vm_page_seg *seg)
        !           581: {
        !           582:     unsigned int index;
        !           583: 
        !           584:     index = seg - vm_page_segs;
        !           585:     assert(index < vm_page_segs_size);
        !           586:     return index;
        !           587: }
        !           588: 
1.1       root      589: static phys_addr_t __init
                    590: vm_page_seg_size(struct vm_page_seg *seg)
                    591: {
                    592:     return seg->end - seg->start;
                    593: }
                    594: 
                    595: static int __init
                    596: vm_page_seg_compute_pool_size(struct vm_page_seg *seg)
                    597: {
                    598:     phys_addr_t size;
                    599: 
                    600:     size = vm_page_atop(vm_page_seg_size(seg)) / VM_PAGE_CPU_POOL_RATIO;
                    601: 
                    602:     if (size == 0)
                    603:         size = 1;
                    604:     else if (size > VM_PAGE_CPU_POOL_MAX_SIZE)
                    605:         size = VM_PAGE_CPU_POOL_MAX_SIZE;
                    606: 
                    607:     return size;
                    608: }
                    609: 
                    610: static void __init
1.1.1.2 ! root      611: vm_page_seg_compute_pageout_thresholds(struct vm_page_seg *seg)
        !           612: {
        !           613:     unsigned long nr_pages;
        !           614: 
        !           615:     nr_pages = vm_page_atop(vm_page_seg_size(seg));
        !           616: 
        !           617:     if (nr_pages < VM_PAGE_SEG_MIN_PAGES) {
        !           618:         panic("vm_page: segment too small");
        !           619:     }
        !           620: 
        !           621:     seg->min_free_pages = nr_pages * VM_PAGE_SEG_THRESHOLD_MIN_NUM
        !           622:                           / VM_PAGE_SEG_THRESHOLD_MIN_DENOM;
        !           623: 
        !           624:     if (seg->min_free_pages < VM_PAGE_SEG_THRESHOLD_MIN) {
        !           625:         seg->min_free_pages = VM_PAGE_SEG_THRESHOLD_MIN;
        !           626:     }
        !           627: 
        !           628:     seg->low_free_pages = nr_pages * VM_PAGE_SEG_THRESHOLD_LOW_NUM
        !           629:                           / VM_PAGE_SEG_THRESHOLD_LOW_DENOM;
        !           630: 
        !           631:     if (seg->low_free_pages < VM_PAGE_SEG_THRESHOLD_LOW) {
        !           632:         seg->low_free_pages = VM_PAGE_SEG_THRESHOLD_LOW;
        !           633:     }
        !           634: 
        !           635:     seg->high_free_pages = nr_pages * VM_PAGE_SEG_THRESHOLD_HIGH_NUM
        !           636:                            / VM_PAGE_SEG_THRESHOLD_HIGH_DENOM;
        !           637: 
        !           638:     if (seg->high_free_pages < VM_PAGE_SEG_THRESHOLD_HIGH) {
        !           639:         seg->high_free_pages = VM_PAGE_SEG_THRESHOLD_HIGH;
        !           640:     }
        !           641: }
        !           642: 
        !           643: static void __init
1.1       root      644: vm_page_seg_init(struct vm_page_seg *seg, phys_addr_t start, phys_addr_t end,
                    645:                  struct vm_page *pages)
                    646: {
                    647:     phys_addr_t pa;
                    648:     int pool_size;
                    649:     unsigned int i;
                    650: 
                    651:     seg->start = start;
                    652:     seg->end = end;
                    653:     pool_size = vm_page_seg_compute_pool_size(seg);
                    654: 
                    655:     for (i = 0; i < ARRAY_SIZE(seg->cpu_pools); i++)
                    656:         vm_page_cpu_pool_init(&seg->cpu_pools[i], pool_size);
                    657: 
                    658:     seg->pages = pages;
                    659:     seg->pages_end = pages + vm_page_atop(vm_page_seg_size(seg));
                    660:     simple_lock_init(&seg->lock);
                    661: 
                    662:     for (i = 0; i < ARRAY_SIZE(seg->free_lists); i++)
                    663:         vm_page_free_list_init(&seg->free_lists[i]);
                    664: 
                    665:     seg->nr_free_pages = 0;
1.1.1.2 ! root      666: 
        !           667:     vm_page_seg_compute_pageout_thresholds(seg);
        !           668: 
        !           669:     vm_page_queue_init(&seg->active_pages);
        !           670:     seg->nr_active_pages = 0;
        !           671:     vm_page_queue_init(&seg->inactive_pages);
        !           672:     seg->nr_inactive_pages = 0;
        !           673: 
        !           674:     i = vm_page_seg_index(seg);
1.1       root      675: 
                    676:     for (pa = seg->start; pa < seg->end; pa += PAGE_SIZE)
                    677:         vm_page_init_pa(&pages[vm_page_atop(pa - seg->start)], i, pa);
                    678: }
                    679: 
                    680: static struct vm_page *
                    681: vm_page_seg_alloc(struct vm_page_seg *seg, unsigned int order,
                    682:                   unsigned short type)
                    683: {
                    684:     struct vm_page_cpu_pool *cpu_pool;
                    685:     struct vm_page *page;
                    686:     int filled;
                    687: 
                    688:     assert(order < VM_PAGE_NR_FREE_LISTS);
                    689: 
                    690:     if (order == 0) {
                    691:         thread_pin();
                    692:         cpu_pool = vm_page_cpu_pool_get(seg);
                    693:         simple_lock(&cpu_pool->lock);
                    694: 
                    695:         if (cpu_pool->nr_pages == 0) {
                    696:             filled = vm_page_cpu_pool_fill(cpu_pool, seg);
                    697: 
                    698:             if (!filled) {
                    699:                 simple_unlock(&cpu_pool->lock);
                    700:                 thread_unpin();
                    701:                 return NULL;
                    702:             }
                    703:         }
                    704: 
                    705:         page = vm_page_cpu_pool_pop(cpu_pool);
                    706:         simple_unlock(&cpu_pool->lock);
                    707:         thread_unpin();
                    708:     } else {
                    709:         simple_lock(&seg->lock);
                    710:         page = vm_page_seg_alloc_from_buddy(seg, order);
                    711:         simple_unlock(&seg->lock);
                    712: 
                    713:         if (page == NULL)
                    714:             return NULL;
                    715:     }
                    716: 
                    717:     assert(page->type == VM_PT_FREE);
                    718:     vm_page_set_type(page, order, type);
                    719:     return page;
                    720: }
                    721: 
                    722: static void
                    723: vm_page_seg_free(struct vm_page_seg *seg, struct vm_page *page,
                    724:                  unsigned int order)
                    725: {
                    726:     struct vm_page_cpu_pool *cpu_pool;
                    727: 
                    728:     assert(page->type != VM_PT_FREE);
                    729:     assert(order < VM_PAGE_NR_FREE_LISTS);
                    730: 
                    731:     vm_page_set_type(page, order, VM_PT_FREE);
                    732: 
                    733:     if (order == 0) {
                    734:         thread_pin();
                    735:         cpu_pool = vm_page_cpu_pool_get(seg);
                    736:         simple_lock(&cpu_pool->lock);
                    737: 
                    738:         if (cpu_pool->nr_pages == cpu_pool->size)
                    739:             vm_page_cpu_pool_drain(cpu_pool, seg);
                    740: 
                    741:         vm_page_cpu_pool_push(cpu_pool, page);
                    742:         simple_unlock(&cpu_pool->lock);
                    743:         thread_unpin();
                    744:     } else {
                    745:         simple_lock(&seg->lock);
                    746:         vm_page_seg_free_to_buddy(seg, page, order);
                    747:         simple_unlock(&seg->lock);
                    748:     }
                    749: }
                    750: 
1.1.1.2 ! root      751: static void
        !           752: vm_page_seg_add_active_page(struct vm_page_seg *seg, struct vm_page *page)
1.1       root      753: {
1.1.1.2 ! root      754:     assert(page->object != NULL);
        !           755:     assert(page->seg_index == vm_page_seg_index(seg));
        !           756:     assert(page->type != VM_PT_FREE);
        !           757:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
        !           758:     assert(!page->free && !page->active && !page->inactive);
        !           759:     page->active = TRUE;
        !           760:     page->reference = TRUE;
        !           761:     vm_page_queue_push(&seg->active_pages, page);
        !           762:     seg->nr_active_pages++;
        !           763:     vm_page_active_count++;
        !           764: }
1.1       root      765: 
1.1.1.2 ! root      766: static void
        !           767: vm_page_seg_remove_active_page(struct vm_page_seg *seg, struct vm_page *page)
        !           768: {
        !           769:     assert(page->object != NULL);
        !           770:     assert(page->seg_index == vm_page_seg_index(seg));
        !           771:     assert(page->type != VM_PT_FREE);
        !           772:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
        !           773:     assert(!page->free && page->active && !page->inactive);
        !           774:     page->active = FALSE;
        !           775:     vm_page_queue_remove(&seg->active_pages, page);
        !           776:     seg->nr_active_pages--;
        !           777:     vm_page_active_count--;
        !           778: }
1.1       root      779: 
1.1.1.2 ! root      780: static void
        !           781: vm_page_seg_add_inactive_page(struct vm_page_seg *seg, struct vm_page *page)
        !           782: {
        !           783:     assert(page->object != NULL);
        !           784:     assert(page->seg_index == vm_page_seg_index(seg));
        !           785:     assert(page->type != VM_PT_FREE);
        !           786:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
        !           787:     assert(!page->free && !page->active && !page->inactive);
        !           788:     page->inactive = TRUE;
        !           789:     vm_page_queue_push(&seg->inactive_pages, page);
        !           790:     seg->nr_inactive_pages++;
        !           791:     vm_page_inactive_count++;
1.1       root      792: }
                    793: 
1.1.1.2 ! root      794: static void
        !           795: vm_page_seg_remove_inactive_page(struct vm_page_seg *seg, struct vm_page *page)
1.1       root      796: {
1.1.1.2 ! root      797:     assert(page->object != NULL);
        !           798:     assert(page->seg_index == vm_page_seg_index(seg));
        !           799:     assert(page->type != VM_PT_FREE);
        !           800:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
        !           801:     assert(!page->free && !page->active && page->inactive);
        !           802:     page->inactive = FALSE;
        !           803:     vm_page_queue_remove(&seg->inactive_pages, page);
        !           804:     seg->nr_inactive_pages--;
        !           805:     vm_page_inactive_count--;
1.1       root      806: }
                    807: 
1.1.1.2 ! root      808: /*
        !           809:  * Attempt to pull an active page.
        !           810:  *
        !           811:  * If successful, the object containing the page is locked.
        !           812:  */
        !           813: static struct vm_page *
        !           814: vm_page_seg_pull_active_page(struct vm_page_seg *seg, boolean_t external_only)
1.1       root      815: {
1.1.1.2 ! root      816:     struct vm_page *page, *first;
        !           817:     boolean_t locked;
1.1       root      818: 
1.1.1.2 ! root      819:     first = NULL;
        !           820: 
        !           821:     for (;;) {
        !           822:         page = vm_page_queue_first(&seg->active_pages, external_only);
        !           823: 
        !           824:         if (page == NULL) {
        !           825:             break;
        !           826:         } else if (first == NULL) {
        !           827:             first = page;
        !           828:         } else if (first == page) {
        !           829:             break;
        !           830:         }
        !           831: 
        !           832:         vm_page_seg_remove_active_page(seg, page);
        !           833:         locked = vm_object_lock_try(page->object);
        !           834: 
        !           835:         if (!locked) {
        !           836:             vm_page_seg_add_active_page(seg, page);
        !           837:             continue;
        !           838:         }
        !           839: 
        !           840:         if (!vm_page_can_move(page)) {
        !           841:             vm_page_seg_add_active_page(seg, page);
        !           842:             vm_object_unlock(page->object);
        !           843:             continue;
        !           844:         }
        !           845: 
        !           846:         return page;
1.1       root      847:     }
                    848: 
1.1.1.2 ! root      849:     return NULL;
1.1       root      850: }
                    851: 
1.1.1.2 ! root      852: /*
        !           853:  * Attempt to pull an inactive page.
        !           854:  *
        !           855:  * If successful, the object containing the page is locked.
        !           856:  *
        !           857:  * XXX See vm_page_seg_pull_active_page (duplicated code).
        !           858:  */
        !           859: static struct vm_page *
        !           860: vm_page_seg_pull_inactive_page(struct vm_page_seg *seg, boolean_t external_only)
1.1       root      861: {
1.1.1.2 ! root      862:     struct vm_page *page, *first;
        !           863:     boolean_t locked;
1.1       root      864: 
1.1.1.2 ! root      865:     first = NULL;
1.1       root      866: 
1.1.1.2 ! root      867:     for (;;) {
        !           868:         page = vm_page_queue_first(&seg->inactive_pages, external_only);
1.1       root      869: 
1.1.1.2 ! root      870:         if (page == NULL) {
        !           871:             break;
        !           872:         } else if (first == NULL) {
        !           873:             first = page;
        !           874:         } else if (first == page) {
        !           875:             break;
        !           876:         }
1.1       root      877: 
1.1.1.2 ! root      878:         vm_page_seg_remove_inactive_page(seg, page);
        !           879:         locked = vm_object_lock_try(page->object);
        !           880: 
        !           881:         if (!locked) {
        !           882:             vm_page_seg_add_inactive_page(seg, page);
        !           883:             continue;
        !           884:         }
        !           885: 
        !           886:         if (!vm_page_can_move(page)) {
        !           887:             vm_page_seg_add_inactive_page(seg, page);
        !           888:             vm_object_unlock(page->object);
1.1       root      889:             continue;
1.1.1.2 ! root      890:         }
1.1       root      891: 
1.1.1.2 ! root      892:         return page;
1.1       root      893:     }
1.1.1.2 ! root      894: 
        !           895:     return NULL;
1.1       root      896: }
                    897: 
1.1.1.2 ! root      898: /*
        !           899:  * Attempt to pull a page cache page.
        !           900:  *
        !           901:  * If successful, the object containing the page is locked.
        !           902:  */
        !           903: static struct vm_page *
        !           904: vm_page_seg_pull_cache_page(struct vm_page_seg *seg,
        !           905:                             boolean_t external_only,
        !           906:                             boolean_t *was_active)
1.1       root      907: {
1.1.1.2 ! root      908:     struct vm_page *page;
        !           909: 
        !           910:     page = vm_page_seg_pull_inactive_page(seg, external_only);
        !           911: 
        !           912:     if (page != NULL) {
        !           913:         *was_active = FALSE;
        !           914:         return page;
        !           915:     }
        !           916: 
        !           917:     page = vm_page_seg_pull_active_page(seg, external_only);
        !           918: 
        !           919:     if (page != NULL) {
        !           920:         *was_active = TRUE;
        !           921:         return page;
        !           922:     }
        !           923: 
        !           924:     return NULL;
1.1       root      925: }
                    926: 
1.1.1.2 ! root      927: static boolean_t
        !           928: vm_page_seg_page_available(const struct vm_page_seg *seg)
1.1       root      929: {
1.1.1.2 ! root      930:     return (seg->nr_free_pages > seg->high_free_pages);
1.1       root      931: }
                    932: 
1.1.1.2 ! root      933: static boolean_t
        !           934: vm_page_seg_usable(const struct vm_page_seg *seg)
1.1       root      935: {
1.1.1.2 ! root      936:     if ((seg->nr_active_pages + seg->nr_inactive_pages) == 0) {
        !           937:         /* Nothing to page out, assume segment is usable */
        !           938:         return TRUE;
1.1       root      939:     }
                    940: 
1.1.1.2 ! root      941:     return (seg->nr_free_pages >= seg->high_free_pages);
1.1       root      942: }
                    943: 
1.1.1.2 ! root      944: static void
        !           945: vm_page_seg_double_lock(struct vm_page_seg *seg1, struct vm_page_seg *seg2)
        !           946: {
        !           947:     assert(seg1 != seg2);
        !           948: 
        !           949:     if (seg1 < seg2) {
        !           950:         simple_lock(&seg1->lock);
        !           951:         simple_lock(&seg2->lock);
        !           952:     } else {
        !           953:         simple_lock(&seg2->lock);
        !           954:         simple_lock(&seg1->lock);
        !           955:     }
        !           956: }
        !           957: 
        !           958: static void
        !           959: vm_page_seg_double_unlock(struct vm_page_seg *seg1, struct vm_page_seg *seg2)
        !           960: {
        !           961:     simple_unlock(&seg1->lock);
        !           962:     simple_unlock(&seg2->lock);
        !           963: }
        !           964: 
        !           965: /*
        !           966:  * Attempt to balance a segment by moving one page to another segment.
        !           967:  *
        !           968:  * Return TRUE if a page was actually moved.
        !           969:  */
        !           970: static boolean_t
        !           971: vm_page_seg_balance_page(struct vm_page_seg *seg,
        !           972:                          struct vm_page_seg *remote_seg)
        !           973: {
        !           974:     struct vm_page *src, *dest;
        !           975:     vm_object_t object;
        !           976:     vm_offset_t offset;
        !           977:     boolean_t was_active;
        !           978: 
        !           979:     vm_page_lock_queues();
        !           980:     simple_lock(&vm_page_queue_free_lock);
        !           981:     vm_page_seg_double_lock(seg, remote_seg);
        !           982: 
        !           983:     if (vm_page_seg_usable(seg)
        !           984:         || !vm_page_seg_page_available(remote_seg)) {
        !           985:         goto error;
        !           986:     }
        !           987: 
        !           988:     src = vm_page_seg_pull_cache_page(seg, FALSE, &was_active);
        !           989: 
        !           990:     if (src == NULL) {
        !           991:         goto error;
        !           992:     }
        !           993: 
        !           994:     assert(src->object != NULL);
        !           995:     assert(!src->fictitious && !src->private);
        !           996:     assert(src->wire_count == 0);
        !           997:     assert(src->type != VM_PT_FREE);
        !           998:     assert(src->order == VM_PAGE_ORDER_UNLISTED);
        !           999: 
        !          1000:     dest = vm_page_seg_alloc_from_buddy(remote_seg, 0);
        !          1001:     assert(dest != NULL);
        !          1002: 
        !          1003:     vm_page_seg_double_unlock(seg, remote_seg);
        !          1004:     simple_unlock(&vm_page_queue_free_lock);
        !          1005: 
        !          1006:     if (!was_active && !src->reference && pmap_is_referenced(src->phys_addr)) {
        !          1007:         src->reference = TRUE;
        !          1008:     }
        !          1009: 
        !          1010:     object = src->object;
        !          1011:     offset = src->offset;
        !          1012:     vm_page_remove(src);
        !          1013: 
        !          1014:     vm_page_remove_mappings(src);
        !          1015: 
        !          1016:     vm_page_set_type(dest, 0, src->type);
        !          1017:     memcpy(&dest->vm_page_header, &src->vm_page_header,
        !          1018:            sizeof(*dest) - VM_PAGE_HEADER_SIZE);
        !          1019:     vm_page_copy(src, dest);
        !          1020: 
        !          1021:     if (!src->dirty) {
        !          1022:         pmap_clear_modify(dest->phys_addr);
        !          1023:     }
        !          1024: 
        !          1025:     dest->busy = FALSE;
        !          1026: 
        !          1027:     simple_lock(&vm_page_queue_free_lock);
        !          1028:     vm_page_init(src);
        !          1029:     src->free = TRUE;
        !          1030:     simple_lock(&seg->lock);
        !          1031:     vm_page_set_type(src, 0, VM_PT_FREE);
        !          1032:     vm_page_seg_free_to_buddy(seg, src, 0);
        !          1033:     simple_unlock(&seg->lock);
        !          1034:     simple_unlock(&vm_page_queue_free_lock);
        !          1035: 
        !          1036:     vm_page_insert(dest, object, offset);
        !          1037:     vm_object_unlock(object);
        !          1038: 
        !          1039:     if (was_active) {
        !          1040:         vm_page_activate(dest);
        !          1041:     } else {
        !          1042:         vm_page_deactivate(dest);
        !          1043:     }
        !          1044: 
        !          1045:     vm_page_unlock_queues();
        !          1046: 
        !          1047:     return TRUE;
        !          1048: 
        !          1049: error:
        !          1050:     vm_page_seg_double_unlock(seg, remote_seg);
        !          1051:     simple_unlock(&vm_page_queue_free_lock);
        !          1052:     vm_page_unlock_queues();
        !          1053:     return FALSE;
        !          1054: }
        !          1055: 
        !          1056: static boolean_t
        !          1057: vm_page_seg_balance(struct vm_page_seg *seg)
        !          1058: {
        !          1059:     struct vm_page_seg *remote_seg;
        !          1060:     unsigned int i;
        !          1061:     boolean_t balanced;
        !          1062: 
        !          1063:     /*
        !          1064:      * It's important here that pages are moved to lower priority
        !          1065:      * segments first.
        !          1066:      */
        !          1067: 
        !          1068:     for (i = vm_page_segs_size - 1; i < vm_page_segs_size; i--) {
        !          1069:         remote_seg = vm_page_seg_get(i);
        !          1070: 
        !          1071:         if (remote_seg == seg) {
        !          1072:             continue;
        !          1073:         }
        !          1074: 
        !          1075:         balanced = vm_page_seg_balance_page(seg, remote_seg);
        !          1076: 
        !          1077:         if (balanced) {
        !          1078:             return TRUE;
        !          1079:         }
        !          1080:     }
        !          1081: 
        !          1082:     return FALSE;
        !          1083: }
        !          1084: 
        !          1085: static boolean_t
        !          1086: vm_page_seg_evict(struct vm_page_seg *seg, boolean_t external_only,
        !          1087:                   boolean_t alloc_paused)
        !          1088: {
        !          1089:     struct vm_page *page;
        !          1090:     boolean_t reclaim, laundry;
        !          1091:     vm_object_t object;
        !          1092:     boolean_t was_active;
        !          1093: 
        !          1094:     page = NULL;
        !          1095:     object = NULL;
        !          1096:     laundry = FALSE;
        !          1097: 
        !          1098: restart:
        !          1099:     vm_page_lock_queues();
        !          1100:     simple_lock(&seg->lock);
        !          1101: 
        !          1102:     if (page != NULL) {
        !          1103:         vm_object_lock(page->object);
        !          1104:     } else {
        !          1105:         page = vm_page_seg_pull_cache_page(seg, external_only, &was_active);
        !          1106: 
        !          1107:         if (page == NULL) {
        !          1108:             goto out;
        !          1109:         }
        !          1110:     }
        !          1111: 
        !          1112:     assert(page->object != NULL);
        !          1113:     assert(!page->fictitious && !page->private);
        !          1114:     assert(page->wire_count == 0);
        !          1115:     assert(page->type != VM_PT_FREE);
        !          1116:     assert(page->order == VM_PAGE_ORDER_UNLISTED);
        !          1117: 
        !          1118:     object = page->object;
        !          1119: 
        !          1120:     if (!was_active
        !          1121:         && (page->reference || pmap_is_referenced(page->phys_addr))) {
        !          1122:         vm_page_seg_add_active_page(seg, page);
        !          1123:         simple_unlock(&seg->lock);
        !          1124:         vm_object_unlock(object);
        !          1125:         vm_stat.reactivations++;
        !          1126:         current_task()->reactivations++;
        !          1127:         vm_page_unlock_queues();
        !          1128:         page = NULL;
        !          1129:         goto restart;
        !          1130:     }
        !          1131: 
        !          1132:     vm_page_remove_mappings(page);
        !          1133: 
        !          1134:     if (!page->dirty && !page->precious) {
        !          1135:         reclaim = TRUE;
        !          1136:         goto out;
        !          1137:     }
        !          1138: 
        !          1139:     reclaim = FALSE;
        !          1140: 
        !          1141:     /*
        !          1142:      * If we are very low on memory, then we can't rely on an external
        !          1143:      * pager to clean a dirty page, because external pagers are not
        !          1144:      * vm-privileged.
        !          1145:      *
        !          1146:      * The laundry bit tells vm_pageout_setup not to do any special
        !          1147:      * processing of this page since it's immediately going to be
        !          1148:      * double paged out to the default pager. The laundry bit is
        !          1149:      * reset and the page is inserted into an internal object by
        !          1150:      * vm_pageout_setup before the double paging pass.
        !          1151:      */
        !          1152: 
        !          1153:     assert(!page->laundry);
        !          1154:     assert(!(laundry && page->external));
        !          1155: 
        !          1156:     if (object->internal || !alloc_paused) {
        !          1157:         laundry = FALSE;
        !          1158:     } else {
        !          1159:         laundry = page->laundry = TRUE;
        !          1160:     }
        !          1161: 
        !          1162: out:
        !          1163:     simple_unlock(&seg->lock);
        !          1164: 
        !          1165:     if (object == NULL) {
        !          1166:         vm_page_unlock_queues();
        !          1167:         return FALSE;
        !          1168:     }
        !          1169: 
        !          1170:     if (reclaim) {
        !          1171:         vm_page_free(page);
        !          1172:         vm_page_unlock_queues();
        !          1173: 
        !          1174:         if (vm_object_collectable(object)) {
        !          1175:             vm_object_collect(object);
        !          1176:         } else {
        !          1177:             vm_object_unlock(object);
        !          1178:         }
        !          1179: 
        !          1180:         return TRUE;
        !          1181:     }
        !          1182: 
        !          1183:     vm_page_unlock_queues();
        !          1184: 
        !          1185:     /*
        !          1186:      * If there is no memory object for the page, create one and hand it
        !          1187:      * to the default pager. First try to collapse, so we don't create
        !          1188:      * one unnecessarily.
        !          1189:      */
        !          1190: 
        !          1191:     if (!object->pager_initialized) {
        !          1192:         vm_object_collapse(object);
        !          1193:     }
        !          1194: 
        !          1195:     if (!object->pager_initialized) {
        !          1196:         vm_object_pager_create(object);
        !          1197:     }
        !          1198: 
        !          1199:     if (!object->pager_initialized) {
        !          1200:         panic("vm_page_seg_evict");
        !          1201:     }
        !          1202: 
        !          1203:     vm_pageout_page(page, FALSE, TRUE); /* flush it */
        !          1204:     vm_object_unlock(object);
        !          1205: 
        !          1206:     if (laundry) {
        !          1207:         goto restart;
        !          1208:     }
        !          1209: 
        !          1210:     return TRUE;
        !          1211: }
        !          1212: 
        !          1213: static void
        !          1214: vm_page_seg_compute_high_active_page(struct vm_page_seg *seg)
        !          1215: {
        !          1216:     unsigned long nr_pages;
        !          1217: 
        !          1218:     nr_pages = seg->nr_active_pages + seg->nr_inactive_pages;
        !          1219:     seg->high_active_pages = nr_pages * VM_PAGE_HIGH_ACTIVE_PAGE_NUM
        !          1220:                              / VM_PAGE_HIGH_ACTIVE_PAGE_DENOM;
        !          1221: }
        !          1222: 
        !          1223: static void
        !          1224: vm_page_seg_refill_inactive(struct vm_page_seg *seg)
        !          1225: {
        !          1226:     struct vm_page *page;
        !          1227: 
        !          1228:     simple_lock(&seg->lock);
        !          1229: 
        !          1230:     vm_page_seg_compute_high_active_page(seg);
        !          1231: 
        !          1232:     while (seg->nr_active_pages > seg->high_active_pages) {
        !          1233:         page = vm_page_seg_pull_active_page(seg, FALSE);
        !          1234: 
        !          1235:         if (page == NULL) {
        !          1236:             break;
        !          1237:         }
        !          1238: 
        !          1239:         page->reference = FALSE;
        !          1240:         pmap_clear_reference(page->phys_addr);
        !          1241:         vm_page_seg_add_inactive_page(seg, page);
        !          1242:         vm_object_unlock(page->object);
        !          1243:     }
        !          1244: 
        !          1245:     simple_unlock(&seg->lock);
        !          1246: }
        !          1247: 
        !          1248: void __init
        !          1249: vm_page_load(unsigned int seg_index, phys_addr_t start, phys_addr_t end)
        !          1250: {
        !          1251:     struct vm_page_boot_seg *seg;
        !          1252: 
        !          1253:     assert(seg_index < ARRAY_SIZE(vm_page_boot_segs));
        !          1254:     assert(vm_page_aligned(start));
        !          1255:     assert(vm_page_aligned(end));
        !          1256:     assert(start < end);
        !          1257:     assert(vm_page_segs_size < ARRAY_SIZE(vm_page_boot_segs));
        !          1258: 
        !          1259:     seg = &vm_page_boot_segs[seg_index];
        !          1260:     seg->start = start;
        !          1261:     seg->end = end;
        !          1262:     seg->heap_present = FALSE;
        !          1263: 
        !          1264: #if DEBUG
        !          1265:     printf("vm_page: load: %s: %llx:%llx\n",
        !          1266:            vm_page_seg_name(seg_index),
        !          1267:            (unsigned long long)start, (unsigned long long)end);
        !          1268: #endif
        !          1269: 
        !          1270:     vm_page_segs_size++;
        !          1271: }
        !          1272: 
        !          1273: void
        !          1274: vm_page_load_heap(unsigned int seg_index, phys_addr_t start, phys_addr_t end)
        !          1275: {
        !          1276:     struct vm_page_boot_seg *seg;
        !          1277: 
        !          1278:     assert(seg_index < ARRAY_SIZE(vm_page_boot_segs));
        !          1279:     assert(vm_page_aligned(start));
        !          1280:     assert(vm_page_aligned(end));
        !          1281: 
        !          1282:     seg = &vm_page_boot_segs[seg_index];
        !          1283: 
        !          1284:     assert(seg->start <= start);
        !          1285:     assert(end <= seg-> end);
        !          1286: 
        !          1287:     seg->avail_start = start;
        !          1288:     seg->avail_end = end;
        !          1289:     seg->heap_present = TRUE;
        !          1290: 
        !          1291: #if DEBUG
        !          1292:     printf("vm_page: heap: %s: %llx:%llx\n",
        !          1293:            vm_page_seg_name(seg_index),
        !          1294:            (unsigned long long)start, (unsigned long long)end);
        !          1295: #endif
        !          1296: }
        !          1297: 
        !          1298: int
        !          1299: vm_page_ready(void)
        !          1300: {
        !          1301:     return vm_page_is_ready;
        !          1302: }
        !          1303: 
        !          1304: static unsigned int
        !          1305: vm_page_select_alloc_seg(unsigned int selector)
        !          1306: {
        !          1307:     unsigned int seg_index;
        !          1308: 
        !          1309:     switch (selector) {
        !          1310:     case VM_PAGE_SEL_DMA:
        !          1311:         seg_index = VM_PAGE_SEG_DMA;
        !          1312:         break;
        !          1313:     case VM_PAGE_SEL_DMA32:
        !          1314:         seg_index = VM_PAGE_SEG_DMA32;
        !          1315:         break;
        !          1316:     case VM_PAGE_SEL_DIRECTMAP:
        !          1317:         seg_index = VM_PAGE_SEG_DIRECTMAP;
        !          1318:         break;
        !          1319:     case VM_PAGE_SEL_HIGHMEM:
        !          1320:         seg_index = VM_PAGE_SEG_HIGHMEM;
        !          1321:         break;
        !          1322:     default:
        !          1323:         panic("vm_page: invalid selector");
        !          1324:     }
        !          1325: 
        !          1326:     return MIN(vm_page_segs_size - 1, seg_index);
        !          1327: }
        !          1328: 
        !          1329: static int __init
        !          1330: vm_page_boot_seg_loaded(const struct vm_page_boot_seg *seg)
        !          1331: {
        !          1332:     return (seg->end != 0);
        !          1333: }
        !          1334: 
        !          1335: static void __init
        !          1336: vm_page_check_boot_segs(void)
        !          1337: {
        !          1338:     unsigned int i;
        !          1339:     int expect_loaded;
        !          1340: 
        !          1341:     if (vm_page_segs_size == 0)
        !          1342:         panic("vm_page: no physical memory loaded");
        !          1343: 
        !          1344:     for (i = 0; i < ARRAY_SIZE(vm_page_boot_segs); i++) {
        !          1345:         expect_loaded = (i < vm_page_segs_size);
        !          1346: 
        !          1347:         if (vm_page_boot_seg_loaded(&vm_page_boot_segs[i]) == expect_loaded)
        !          1348:             continue;
        !          1349: 
        !          1350:         panic("vm_page: invalid boot segment table");
        !          1351:     }
        !          1352: }
        !          1353: 
        !          1354: static phys_addr_t __init
        !          1355: vm_page_boot_seg_size(struct vm_page_boot_seg *seg)
        !          1356: {
        !          1357:     return seg->end - seg->start;
        !          1358: }
        !          1359: 
        !          1360: static phys_addr_t __init
        !          1361: vm_page_boot_seg_avail_size(struct vm_page_boot_seg *seg)
        !          1362: {
        !          1363:     return seg->avail_end - seg->avail_start;
        !          1364: }
        !          1365: 
        !          1366: unsigned long __init
        !          1367: vm_page_bootalloc(size_t size)
        !          1368: {
        !          1369:     struct vm_page_boot_seg *seg;
        !          1370:     phys_addr_t pa;
        !          1371:     unsigned int i;
        !          1372: 
        !          1373:     for (i = vm_page_select_alloc_seg(VM_PAGE_SEL_DIRECTMAP);
        !          1374:          i < vm_page_segs_size;
        !          1375:          i--) {
        !          1376:         seg = &vm_page_boot_segs[i];
        !          1377: 
        !          1378:         if (size <= vm_page_boot_seg_avail_size(seg)) {
        !          1379:             pa = seg->avail_start;
        !          1380:             seg->avail_start += vm_page_round(size);
        !          1381:             return pa;
        !          1382:         }
        !          1383:     }
        !          1384: 
        !          1385:     panic("vm_page: no physical memory available");
        !          1386: }
        !          1387: 
        !          1388: void __init
        !          1389: vm_page_setup(void)
1.1       root     1390: {
                   1391:     struct vm_page_boot_seg *boot_seg;
                   1392:     struct vm_page_seg *seg;
                   1393:     struct vm_page *table, *page, *end;
                   1394:     size_t nr_pages, table_size;
                   1395:     unsigned long va;
                   1396:     unsigned int i;
                   1397:     phys_addr_t pa;
                   1398: 
                   1399:     vm_page_check_boot_segs();
                   1400: 
                   1401:     /*
                   1402:      * Compute the page table size.
                   1403:      */
                   1404:     nr_pages = 0;
                   1405: 
                   1406:     for (i = 0; i < vm_page_segs_size; i++)
                   1407:         nr_pages += vm_page_atop(vm_page_boot_seg_size(&vm_page_boot_segs[i]));
                   1408: 
                   1409:     table_size = vm_page_round(nr_pages * sizeof(struct vm_page));
                   1410:     printf("vm_page: page table size: %lu entries (%luk)\n", nr_pages,
                   1411:            table_size >> 10);
                   1412:     table = (struct vm_page *)pmap_steal_memory(table_size);
                   1413:     va = (unsigned long)table;
                   1414: 
                   1415:     /*
                   1416:      * Initialize the segments, associating them to the page table. When
                   1417:      * the segments are initialized, all their pages are set allocated.
                   1418:      * Pages are then released, which populates the free lists.
                   1419:      */
                   1420:     for (i = 0; i < vm_page_segs_size; i++) {
                   1421:         seg = &vm_page_segs[i];
                   1422:         boot_seg = &vm_page_boot_segs[i];
                   1423:         vm_page_seg_init(seg, boot_seg->start, boot_seg->end, table);
                   1424:         page = seg->pages + vm_page_atop(boot_seg->avail_start
                   1425:                                          - boot_seg->start);
                   1426:         end = seg->pages + vm_page_atop(boot_seg->avail_end
                   1427:                                         - boot_seg->start);
                   1428: 
                   1429:         while (page < end) {
                   1430:             page->type = VM_PT_FREE;
                   1431:             vm_page_seg_free_to_buddy(seg, page, 0);
                   1432:             page++;
                   1433:         }
                   1434: 
                   1435:         table += vm_page_atop(vm_page_seg_size(seg));
                   1436:     }
                   1437: 
                   1438:     while (va < (unsigned long)table) {
                   1439:         pa = pmap_extract(kernel_pmap, va);
                   1440:         page = vm_page_lookup_pa(pa);
                   1441:         assert((page != NULL) && (page->type == VM_PT_RESERVED));
                   1442:         page->type = VM_PT_TABLE;
                   1443:         va += PAGE_SIZE;
                   1444:     }
                   1445: 
                   1446:     vm_page_is_ready = 1;
                   1447: }
                   1448: 
                   1449: void __init
                   1450: vm_page_manage(struct vm_page *page)
                   1451: {
                   1452:     assert(page->seg_index < ARRAY_SIZE(vm_page_segs));
                   1453:     assert(page->type == VM_PT_RESERVED);
                   1454: 
                   1455:     vm_page_set_type(page, 0, VM_PT_FREE);
                   1456:     vm_page_seg_free_to_buddy(&vm_page_segs[page->seg_index], page, 0);
                   1457: }
                   1458: 
                   1459: struct vm_page *
                   1460: vm_page_lookup_pa(phys_addr_t pa)
                   1461: {
                   1462:     struct vm_page_seg *seg;
                   1463:     unsigned int i;
                   1464: 
1.1.1.2 ! root     1465:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1466:         seg = &vm_page_segs[i];
        !          1467: 
        !          1468:         if ((pa >= seg->start) && (pa < seg->end))
        !          1469:             return &seg->pages[vm_page_atop(pa - seg->start)];
        !          1470:     }
        !          1471: 
        !          1472:     return NULL;
        !          1473: }
        !          1474: 
        !          1475: static struct vm_page_seg *
        !          1476: vm_page_lookup_seg(const struct vm_page *page)
        !          1477: {
        !          1478:     struct vm_page_seg *seg;
        !          1479:     unsigned int i;
        !          1480: 
        !          1481:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1482:         seg = &vm_page_segs[i];
        !          1483: 
        !          1484:         if ((page->phys_addr >= seg->start) && (page->phys_addr < seg->end)) {
        !          1485:             return seg;
        !          1486:         }
        !          1487:     }
        !          1488: 
        !          1489:     return NULL;
        !          1490: }
        !          1491: 
        !          1492: void vm_page_check(const struct vm_page *page)
        !          1493: {
        !          1494:     if (page->fictitious) {
        !          1495:         if (page->private) {
        !          1496:             panic("vm_page: page both fictitious and private");
        !          1497:         }
        !          1498: 
        !          1499:         if (page->phys_addr != vm_page_fictitious_addr) {
        !          1500:             panic("vm_page: invalid fictitious page");
        !          1501:         }
        !          1502:     } else {
        !          1503:         struct vm_page_seg *seg;
        !          1504: 
        !          1505:         if (page->phys_addr == vm_page_fictitious_addr) {
        !          1506:             panic("vm_page: real page has fictitious address");
        !          1507:         }
1.1       root     1508: 
1.1.1.2 ! root     1509:         seg = vm_page_lookup_seg(page);
1.1       root     1510: 
1.1.1.2 ! root     1511:         if (seg == NULL) {
        !          1512:             if (!page->private) {
        !          1513:                 panic("vm_page: page claims it's managed but not in any segment");
        !          1514:             }
        !          1515:         } else {
        !          1516:             if (page->private) {
        !          1517:                 struct vm_page *real_page;
        !          1518: 
        !          1519:                 if (vm_page_pageable(page)) {
        !          1520:                     panic("vm_page: private page is pageable");
        !          1521:                 }
        !          1522: 
        !          1523:                 real_page = vm_page_lookup_pa(page->phys_addr);
        !          1524: 
        !          1525:                 if (vm_page_pageable(real_page)) {
        !          1526:                     panic("vm_page: page underlying private page is pageable");
        !          1527:                 }
        !          1528: 
        !          1529:                 if ((real_page->type == VM_PT_FREE)
        !          1530:                     || (real_page->order != VM_PAGE_ORDER_UNLISTED)) {
        !          1531:                     panic("vm_page: page underlying private pagei is free");
        !          1532:                 }
        !          1533:             } else {
        !          1534:                 unsigned int index;
        !          1535: 
        !          1536:                 index = vm_page_seg_index(seg);
        !          1537: 
        !          1538:                 if (index != page->seg_index) {
        !          1539:                     panic("vm_page: page segment mismatch");
        !          1540:                 }
        !          1541:             }
        !          1542:         }
        !          1543:     }
1.1       root     1544: }
                   1545: 
                   1546: struct vm_page *
                   1547: vm_page_alloc_pa(unsigned int order, unsigned int selector, unsigned short type)
                   1548: {
                   1549:     struct vm_page *page;
                   1550:     unsigned int i;
                   1551: 
                   1552:     for (i = vm_page_select_alloc_seg(selector); i < vm_page_segs_size; i--) {
                   1553:         page = vm_page_seg_alloc(&vm_page_segs[i], order, type);
                   1554: 
                   1555:         if (page != NULL)
                   1556:             return page;
                   1557:     }
                   1558: 
1.1.1.2 ! root     1559:     if (!current_thread() || current_thread()->vm_privilege)
        !          1560:         panic("vm_page: privileged thread unable to allocate page");
1.1       root     1561: 
                   1562:     return NULL;
                   1563: }
                   1564: 
                   1565: void
                   1566: vm_page_free_pa(struct vm_page *page, unsigned int order)
                   1567: {
                   1568:     assert(page != NULL);
                   1569:     assert(page->seg_index < ARRAY_SIZE(vm_page_segs));
                   1570: 
                   1571:     vm_page_seg_free(&vm_page_segs[page->seg_index], page, order);
                   1572: }
                   1573: 
                   1574: const char *
                   1575: vm_page_seg_name(unsigned int seg_index)
                   1576: {
                   1577:     /* Don't use a switch statement since segments can be aliased */
                   1578:     if (seg_index == VM_PAGE_SEG_HIGHMEM)
                   1579:         return "HIGHMEM";
                   1580:     else if (seg_index == VM_PAGE_SEG_DIRECTMAP)
                   1581:         return "DIRECTMAP";
                   1582:     else if (seg_index == VM_PAGE_SEG_DMA32)
                   1583:         return "DMA32";
                   1584:     else if (seg_index == VM_PAGE_SEG_DMA)
                   1585:         return "DMA";
                   1586:     else
                   1587:         panic("vm_page: invalid segment index");
                   1588: }
                   1589: 
                   1590: void
                   1591: vm_page_info_all(void)
                   1592: {
                   1593:     struct vm_page_seg *seg;
                   1594:     unsigned long pages;
                   1595:     unsigned int i;
                   1596: 
                   1597:     for (i = 0; i < vm_page_segs_size; i++) {
                   1598:         seg = &vm_page_segs[i];
                   1599:         pages = (unsigned long)(seg->pages_end - seg->pages);
                   1600:         printf("vm_page: %s: pages: %lu (%luM), free: %lu (%luM)\n",
                   1601:                vm_page_seg_name(i), pages, pages >> (20 - PAGE_SHIFT),
                   1602:                seg->nr_free_pages, seg->nr_free_pages >> (20 - PAGE_SHIFT));
1.1.1.2 ! root     1603:         printf("vm_page: %s: min:%lu low:%lu high:%lu\n",
        !          1604:                vm_page_seg_name(vm_page_seg_index(seg)),
        !          1605:                seg->min_free_pages, seg->low_free_pages, seg->high_free_pages);
        !          1606:     }
        !          1607: }
        !          1608: 
        !          1609: phys_addr_t
        !          1610: vm_page_seg_end(unsigned int selector)
        !          1611: {
        !          1612:     return vm_page_segs[vm_page_select_alloc_seg(selector)].end;
        !          1613: }
        !          1614: 
        !          1615: static unsigned long
        !          1616: vm_page_boot_table_size(void)
        !          1617: {
        !          1618:     unsigned long nr_pages;
        !          1619:     unsigned int i;
        !          1620: 
        !          1621:     nr_pages = 0;
        !          1622: 
        !          1623:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1624:         nr_pages += vm_page_atop(vm_page_boot_seg_size(&vm_page_boot_segs[i]));
        !          1625:     }
        !          1626: 
        !          1627:     return nr_pages;
        !          1628: }
        !          1629: 
        !          1630: unsigned long
        !          1631: vm_page_table_size(void)
        !          1632: {
        !          1633:     unsigned long nr_pages;
        !          1634:     unsigned int i;
        !          1635: 
        !          1636:     if (!vm_page_is_ready) {
        !          1637:         return vm_page_boot_table_size();
        !          1638:     }
        !          1639: 
        !          1640:     nr_pages = 0;
        !          1641: 
        !          1642:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1643:         nr_pages += vm_page_atop(vm_page_seg_size(&vm_page_segs[i]));
        !          1644:     }
        !          1645: 
        !          1646:     return nr_pages;
        !          1647: }
        !          1648: 
        !          1649: unsigned long
        !          1650: vm_page_table_index(phys_addr_t pa)
        !          1651: {
        !          1652:     struct vm_page_seg *seg;
        !          1653:     unsigned long index;
        !          1654:     unsigned int i;
        !          1655: 
        !          1656:     index = 0;
        !          1657: 
        !          1658:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1659:         seg = &vm_page_segs[i];
        !          1660: 
        !          1661:         if ((pa >= seg->start) && (pa < seg->end)) {
        !          1662:             return index + vm_page_atop(pa - seg->start);
        !          1663:         }
        !          1664: 
        !          1665:         index += vm_page_atop(vm_page_seg_size(seg));
1.1       root     1666:     }
1.1.1.2 ! root     1667: 
        !          1668:     panic("vm_page: invalid physical address");
1.1       root     1669: }
                   1670: 
                   1671: phys_addr_t
                   1672: vm_page_mem_size(void)
                   1673: {
                   1674:     phys_addr_t total;
                   1675:     unsigned int i;
                   1676: 
                   1677:     total = 0;
                   1678: 
                   1679:     for (i = 0; i < vm_page_segs_size; i++) {
                   1680:         total += vm_page_seg_size(&vm_page_segs[i]);
                   1681:     }
                   1682: 
                   1683:     return total;
                   1684: }
                   1685: 
                   1686: unsigned long
                   1687: vm_page_mem_free(void)
                   1688: {
                   1689:     unsigned long total;
                   1690:     unsigned int i;
                   1691: 
                   1692:     total = 0;
                   1693: 
                   1694:     for (i = 0; i < vm_page_segs_size; i++) {
                   1695:         total += vm_page_segs[i].nr_free_pages;
                   1696:     }
                   1697: 
                   1698:     return total;
                   1699: }
1.1.1.2 ! root     1700: 
        !          1701: /*
        !          1702:  * Mark this page as wired down by yet another map, removing it
        !          1703:  * from paging queues as necessary.
        !          1704:  *
        !          1705:  * The page's object and the page queues must be locked.
        !          1706:  */
        !          1707: void
        !          1708: vm_page_wire(struct vm_page *page)
        !          1709: {
        !          1710:     VM_PAGE_CHECK(page);
        !          1711: 
        !          1712:     if (page->wire_count == 0) {
        !          1713:         vm_page_queues_remove(page);
        !          1714: 
        !          1715:         if (!page->private && !page->fictitious) {
        !          1716:             vm_page_wire_count++;
        !          1717:         }
        !          1718:     }
        !          1719: 
        !          1720:     page->wire_count++;
        !          1721: }
        !          1722: 
        !          1723: /*
        !          1724:  * Release one wiring of this page, potentially enabling it to be paged again.
        !          1725:  *
        !          1726:  * The page's object and the page queues must be locked.
        !          1727:  */
        !          1728: void
        !          1729: vm_page_unwire(struct vm_page *page)
        !          1730: {
        !          1731:     struct vm_page_seg *seg;
        !          1732: 
        !          1733:     VM_PAGE_CHECK(page);
        !          1734: 
        !          1735:     assert(page->wire_count != 0);
        !          1736:     page->wire_count--;
        !          1737: 
        !          1738:     if ((page->wire_count != 0)
        !          1739:         || page->fictitious
        !          1740:         || page->private) {
        !          1741:         return;
        !          1742:     }
        !          1743: 
        !          1744:     seg = vm_page_seg_get(page->seg_index);
        !          1745: 
        !          1746:     simple_lock(&seg->lock);
        !          1747:     vm_page_seg_add_active_page(seg, page);
        !          1748:     simple_unlock(&seg->lock);
        !          1749: 
        !          1750:     vm_page_wire_count--;
        !          1751: }
        !          1752: 
        !          1753: /*
        !          1754:  * Returns the given page to the inactive list, indicating that
        !          1755:  * no physical maps have access to this page.
        !          1756:  * [Used by the physical mapping system.]
        !          1757:  *
        !          1758:  * The page queues must be locked.
        !          1759:  */
        !          1760: void
        !          1761: vm_page_deactivate(struct vm_page *page)
        !          1762: {
        !          1763:     struct vm_page_seg *seg;
        !          1764: 
        !          1765:     VM_PAGE_CHECK(page);
        !          1766: 
        !          1767:     /*
        !          1768:      * This page is no longer very interesting.  If it was
        !          1769:      * interesting (active or inactive/referenced), then we
        !          1770:      * clear the reference bit and (re)enter it in the
        !          1771:      * inactive queue.  Note wired pages should not have
        !          1772:      * their reference bit cleared.
        !          1773:      */
        !          1774: 
        !          1775:     if (page->active || (page->inactive && page->reference)) {
        !          1776:         if (!page->fictitious && !page->private && !page->absent) {
        !          1777:             pmap_clear_reference(page->phys_addr);
        !          1778:         }
        !          1779: 
        !          1780:         page->reference = FALSE;
        !          1781:         vm_page_queues_remove(page);
        !          1782:     }
        !          1783: 
        !          1784:     if ((page->wire_count == 0) && !page->fictitious
        !          1785:         && !page->private && !page->inactive) {
        !          1786:         seg = vm_page_seg_get(page->seg_index);
        !          1787: 
        !          1788:         simple_lock(&seg->lock);
        !          1789:         vm_page_seg_add_inactive_page(seg, page);
        !          1790:         simple_unlock(&seg->lock);
        !          1791:     }
        !          1792: }
        !          1793: 
        !          1794: /*
        !          1795:  * Put the specified page on the active list (if appropriate).
        !          1796:  *
        !          1797:  * The page queues must be locked.
        !          1798:  */
        !          1799: void
        !          1800: vm_page_activate(struct vm_page *page)
        !          1801: {
        !          1802:     struct vm_page_seg *seg;
        !          1803: 
        !          1804:     VM_PAGE_CHECK(page);
        !          1805: 
        !          1806:     /*
        !          1807:      * Unconditionally remove so that, even if the page was already
        !          1808:      * active, it gets back to the end of the active queue.
        !          1809:      */
        !          1810:     vm_page_queues_remove(page);
        !          1811: 
        !          1812:     if ((page->wire_count == 0) && !page->fictitious && !page->private) {
        !          1813:         seg = vm_page_seg_get(page->seg_index);
        !          1814: 
        !          1815:         if (page->active)
        !          1816:             panic("vm_page_activate: already active");
        !          1817: 
        !          1818:         simple_lock(&seg->lock);
        !          1819:         vm_page_seg_add_active_page(seg, page);
        !          1820:         simple_unlock(&seg->lock);
        !          1821:     }
        !          1822: }
        !          1823: 
        !          1824: void
        !          1825: vm_page_queues_remove(struct vm_page *page)
        !          1826: {
        !          1827:     struct vm_page_seg *seg;
        !          1828: 
        !          1829:     assert(!page->active || !page->inactive);
        !          1830: 
        !          1831:     if (!page->active && !page->inactive) {
        !          1832:         return;
        !          1833:     }
        !          1834: 
        !          1835:     seg = vm_page_seg_get(page->seg_index);
        !          1836: 
        !          1837:     simple_lock(&seg->lock);
        !          1838: 
        !          1839:     if (page->active) {
        !          1840:         vm_page_seg_remove_active_page(seg, page);
        !          1841:     } else {
        !          1842:         vm_page_seg_remove_inactive_page(seg, page);
        !          1843:     }
        !          1844: 
        !          1845:     simple_unlock(&seg->lock);
        !          1846: }
        !          1847: 
        !          1848: /*
        !          1849:  * Check whether segments are all usable for unprivileged allocations.
        !          1850:  *
        !          1851:  * If all segments are usable, resume pending unprivileged allocations
        !          1852:  * and return TRUE.
        !          1853:  *
        !          1854:  * This function acquires vm_page_queue_free_lock, which is held on return.
        !          1855:  */
        !          1856: static boolean_t
        !          1857: vm_page_check_usable(void)
        !          1858: {
        !          1859:     struct vm_page_seg *seg;
        !          1860:     boolean_t usable;
        !          1861:     unsigned int i;
        !          1862: 
        !          1863:     simple_lock(&vm_page_queue_free_lock);
        !          1864: 
        !          1865:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1866:         seg = vm_page_seg_get(i);
        !          1867: 
        !          1868:         simple_lock(&seg->lock);
        !          1869:         usable = vm_page_seg_usable(seg);
        !          1870:         simple_unlock(&seg->lock);
        !          1871: 
        !          1872:         if (!usable) {
        !          1873:             return FALSE;
        !          1874:         }
        !          1875:     }
        !          1876: 
        !          1877:     vm_page_external_laundry_count = -1;
        !          1878:     vm_page_alloc_paused = FALSE;
        !          1879:     thread_wakeup(&vm_page_alloc_paused);
        !          1880:     return TRUE;
        !          1881: }
        !          1882: 
        !          1883: static boolean_t
        !          1884: vm_page_may_balance(void)
        !          1885: {
        !          1886:     struct vm_page_seg *seg;
        !          1887:     boolean_t page_available;
        !          1888:     unsigned int i;
        !          1889: 
        !          1890:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1891:         seg = vm_page_seg_get(i);
        !          1892: 
        !          1893:         simple_lock(&seg->lock);
        !          1894:         page_available = vm_page_seg_page_available(seg);
        !          1895:         simple_unlock(&seg->lock);
        !          1896: 
        !          1897:         if (page_available) {
        !          1898:             return TRUE;
        !          1899:         }
        !          1900:     }
        !          1901: 
        !          1902:     return FALSE;
        !          1903: }
        !          1904: 
        !          1905: static boolean_t
        !          1906: vm_page_balance_once(void)
        !          1907: {
        !          1908:     boolean_t balanced;
        !          1909:     unsigned int i;
        !          1910: 
        !          1911:     /*
        !          1912:      * It's important here that pages are moved from higher priority
        !          1913:      * segments first.
        !          1914:      */
        !          1915: 
        !          1916:     for (i = 0; i < vm_page_segs_size; i++) {
        !          1917:         balanced = vm_page_seg_balance(vm_page_seg_get(i));
        !          1918: 
        !          1919:         if (balanced) {
        !          1920:             return TRUE;
        !          1921:         }
        !          1922:     }
        !          1923: 
        !          1924:     return FALSE;
        !          1925: }
        !          1926: 
        !          1927: boolean_t
        !          1928: vm_page_balance(void)
        !          1929: {
        !          1930:     boolean_t balanced;
        !          1931: 
        !          1932:     while (vm_page_may_balance()) {
        !          1933:         balanced = vm_page_balance_once();
        !          1934: 
        !          1935:         if (!balanced) {
        !          1936:             break;
        !          1937:         }
        !          1938:     }
        !          1939: 
        !          1940:     return vm_page_check_usable();
        !          1941: }
        !          1942: 
        !          1943: static boolean_t
        !          1944: vm_page_evict_once(boolean_t external_only, boolean_t alloc_paused)
        !          1945: {
        !          1946:     boolean_t evicted;
        !          1947:     unsigned int i;
        !          1948: 
        !          1949:     /*
        !          1950:      * It's important here that pages are evicted from lower priority
        !          1951:      * segments first.
        !          1952:      */
        !          1953: 
        !          1954:     for (i = vm_page_segs_size - 1; i < vm_page_segs_size; i--) {
        !          1955:         evicted = vm_page_seg_evict(vm_page_seg_get(i),
        !          1956:                                     external_only, alloc_paused);
        !          1957: 
        !          1958:         if (evicted) {
        !          1959:             return TRUE;
        !          1960:         }
        !          1961:     }
        !          1962: 
        !          1963:     return FALSE;
        !          1964: }
        !          1965: 
        !          1966: #define VM_PAGE_MAX_LAUNDRY   5
        !          1967: #define VM_PAGE_MAX_EVICTIONS 5
        !          1968: 
        !          1969: boolean_t
        !          1970: vm_page_evict(boolean_t *should_wait)
        !          1971: {
        !          1972:     boolean_t pause, evicted, external_only, alloc_paused;
        !          1973:     unsigned int i;
        !          1974: 
        !          1975:     *should_wait = TRUE;
        !          1976:     external_only = TRUE;
        !          1977: 
        !          1978:     simple_lock(&vm_page_queue_free_lock);
        !          1979:     vm_page_external_laundry_count = 0;
        !          1980:     alloc_paused = vm_page_alloc_paused;
        !          1981:     simple_unlock(&vm_page_queue_free_lock);
        !          1982: 
        !          1983: again:
        !          1984:     vm_page_lock_queues();
        !          1985:     pause = (vm_page_laundry_count >= VM_PAGE_MAX_LAUNDRY);
        !          1986:     vm_page_unlock_queues();
        !          1987: 
        !          1988:     if (pause) {
        !          1989:         simple_lock(&vm_page_queue_free_lock);
        !          1990:         return FALSE;
        !          1991:     }
        !          1992: 
        !          1993:     for (i = 0; i < VM_PAGE_MAX_EVICTIONS; i++) {
        !          1994:         evicted = vm_page_evict_once(external_only, alloc_paused);
        !          1995: 
        !          1996:         if (!evicted) {
        !          1997:             break;
        !          1998:         }
        !          1999:     }
        !          2000: 
        !          2001:     simple_lock(&vm_page_queue_free_lock);
        !          2002: 
        !          2003:     /*
        !          2004:      * Keep in mind eviction may not cause pageouts, since non-precious
        !          2005:      * clean pages are simply released.
        !          2006:      */
        !          2007:     if ((vm_page_laundry_count == 0) && (vm_page_external_laundry_count == 0)) {
        !          2008:         /*
        !          2009:          * No pageout, but some clean pages were freed. Start a complete
        !          2010:          * scan again without waiting.
        !          2011:          */
        !          2012:         if (evicted) {
        !          2013:             *should_wait = FALSE;
        !          2014:             return FALSE;
        !          2015:         }
        !          2016: 
        !          2017:         /*
        !          2018:          * Eviction failed, consider pages from internal objects on the
        !          2019:          * next attempt.
        !          2020:          */
        !          2021:         if (external_only) {
        !          2022:             simple_unlock(&vm_page_queue_free_lock);
        !          2023:             external_only = FALSE;
        !          2024:             goto again;
        !          2025:         }
        !          2026: 
        !          2027:         /*
        !          2028:          * TODO Find out what could cause this and how to deal with it.
        !          2029:          * This will likely require an out-of-memory killer.
        !          2030:          */
        !          2031:         panic("vm_page: unable to recycle any page");
        !          2032:     }
        !          2033: 
        !          2034:     simple_unlock(&vm_page_queue_free_lock);
        !          2035: 
        !          2036:     return vm_page_check_usable();
        !          2037: }
        !          2038: 
        !          2039: void
        !          2040: vm_page_refill_inactive(void)
        !          2041: {
        !          2042:     unsigned int i;
        !          2043: 
        !          2044:     vm_page_lock_queues();
        !          2045: 
        !          2046:     for (i = 0; i < vm_page_segs_size; i++) {
        !          2047:         vm_page_seg_refill_inactive(vm_page_seg_get(i));
        !          2048:     }
        !          2049: 
        !          2050:     vm_page_unlock_queues();
        !          2051: }
        !          2052: 
        !          2053: void
        !          2054: vm_page_wait(void (*continuation)(void))
        !          2055: {
        !          2056:     assert(!current_thread()->vm_privilege);
        !          2057: 
        !          2058:     simple_lock(&vm_page_queue_free_lock);
        !          2059: 
        !          2060:     if (!vm_page_alloc_paused) {
        !          2061:         simple_unlock(&vm_page_queue_free_lock);
        !          2062:         return;
        !          2063:     }
        !          2064: 
        !          2065:     assert_wait(&vm_page_alloc_paused, FALSE);
        !          2066: 
        !          2067:     simple_unlock(&vm_page_queue_free_lock);
        !          2068: 
        !          2069:     if (continuation != 0) {
        !          2070:         counter(c_vm_page_wait_block_user++);
        !          2071:         thread_block(continuation);
        !          2072:     } else {
        !          2073:         counter(c_vm_page_wait_block_kernel++);
        !          2074:         thread_block((void (*)(void)) 0);
        !          2075:     }
        !          2076: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.