linux-bk/mm/swap.c
<<
>>
Prefs
   1/*
   2 *  linux/mm/swap.c
   3 *
   4 *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   5 */
   6
   7/*
   8 * This file contains the default values for the opereation of the
   9 * Linux VM subsystem. Fine-tuning documentation can be found in
  10 * linux/Documentation/sysctl/vm.txt.
  11 * Started 18.12.91
  12 * Swap aging added 23.2.95, Stephen Tweedie.
  13 * Buffermem limits added 12.3.98, Rik van Riel.
  14 */
  15
  16#include <linux/mm.h>
  17#include <linux/kernel_stat.h>
  18#include <linux/swap.h>
  19#include <linux/pagemap.h>
  20#include <linux/pagevec.h>
  21#include <linux/init.h>
  22#include <linux/mm_inline.h>
  23#include <linux/buffer_head.h>
  24#include <linux/prefetch.h>
  25
  26/* How many pages do we try to swap or page in/out together? */
  27int page_cluster;
  28
  29/*
  30 * FIXME: speed this up?
  31 */
  32void activate_page(struct page *page)
  33{
  34        struct zone *zone = page_zone(page);
  35
  36        spin_lock_irq(&zone->lru_lock);
  37        if (PageLRU(page) && !PageActive(page)) {
  38                del_page_from_inactive_list(zone, page);
  39                SetPageActive(page);
  40                add_page_to_active_list(zone, page);
  41                KERNEL_STAT_INC(pgactivate);
  42        }
  43        spin_unlock_irq(&zone->lru_lock);
  44}
  45
  46/**
  47 * lru_cache_add: add a page to the page lists
  48 * @page: the page to add
  49 */
  50static struct pagevec lru_add_pvecs[NR_CPUS];
  51
  52void lru_cache_add(struct page *page)
  53{
  54        struct pagevec *pvec = &lru_add_pvecs[get_cpu()];
  55
  56        page_cache_get(page);
  57        if (!pagevec_add(pvec, page))
  58                __pagevec_lru_add(pvec);
  59        put_cpu();
  60}
  61
  62void lru_add_drain(void)
  63{
  64        struct pagevec *pvec = &lru_add_pvecs[get_cpu()];
  65
  66        if (pagevec_count(pvec))
  67                __pagevec_lru_add(pvec);
  68        put_cpu();
  69}
  70
  71/*
  72 * This path almost never happens - pages are normally freed via pagevecs.
  73 */
  74void __page_cache_release(struct page *page)
  75{
  76        unsigned long flags;
  77        struct zone *zone = page_zone(page);
  78
  79        spin_lock_irqsave(&zone->lru_lock, flags);
  80        if (TestClearPageLRU(page))
  81                del_page_from_lru(zone, page);
  82        if (page_count(page) != 0)
  83                page = NULL;
  84        spin_unlock_irqrestore(&zone->lru_lock, flags);
  85        if (page)
  86                __free_pages_ok(page, 0);
  87}
  88
  89/*
  90 * Batched page_cache_release().  Decrement the reference count on all the
  91 * passed pages.  If it fell to zero then remove the page from the LRU and
  92 * free it.
  93 *
  94 * Avoid taking zone->lru_lock if possible, but if it is taken, retain it
  95 * for the remainder of the operation.
  96 *
  97 * The locking in this function is against shrink_cache(): we recheck the
  98 * page count inside the lock to see whether shrink_cache grabbed the page
  99 * via the LRU.  If it did, give up: shrink_cache will free it.
 100 */
 101void release_pages(struct page **pages, int nr)
 102{
 103        int i;
 104        struct pagevec pages_to_free;
 105        struct zone *zone = NULL;
 106
 107        pagevec_init(&pages_to_free);
 108        for (i = 0; i < nr; i++) {
 109                struct page *page = pages[i];
 110                struct zone *pagezone;
 111
 112                if (PageReserved(page) || !put_page_testzero(page))
 113                        continue;
 114
 115                pagezone = page_zone(page);
 116                if (pagezone != zone) {
 117                        if (zone)
 118                                spin_unlock_irq(&zone->lru_lock);
 119                        zone = pagezone;
 120                        spin_lock_irq(&zone->lru_lock);
 121                }
 122                if (TestClearPageLRU(page))
 123                        del_page_from_lru(zone, page);
 124                if (page_count(page) == 0) {
 125                        if (!pagevec_add(&pages_to_free, page)) {
 126                                spin_unlock_irq(&zone->lru_lock);
 127                                __pagevec_free(&pages_to_free);
 128                                pagevec_init(&pages_to_free);
 129                                zone = NULL;    /* No lock is held */
 130                        }
 131                }
 132        }
 133        if (zone)
 134                spin_unlock_irq(&zone->lru_lock);
 135
 136        pagevec_free(&pages_to_free);
 137}
 138
 139void __pagevec_release(struct pagevec *pvec)
 140{
 141        release_pages(pvec->pages, pagevec_count(pvec));
 142        pagevec_init(pvec);
 143}
 144
 145/*
 146 * pagevec_release() for pages which are known to not be on the LRU
 147 *
 148 * This function reinitialises the caller's pagevec.
 149 */
 150void __pagevec_release_nonlru(struct pagevec *pvec)
 151{
 152        int i;
 153        struct pagevec pages_to_free;
 154
 155        pagevec_init(&pages_to_free);
 156        for (i = 0; i < pagevec_count(pvec); i++) {
 157                struct page *page = pvec->pages[i];
 158
 159                BUG_ON(PageLRU(page));
 160                if (put_page_testzero(page))
 161                        pagevec_add(&pages_to_free, page);
 162        }
 163        pagevec_free(&pages_to_free);
 164        pagevec_init(pvec);
 165}
 166
 167/*
 168 * Move all the inactive pages to the head of the inactive list and release
 169 * them.  Reinitialises the caller's pagevec.
 170 */
 171void pagevec_deactivate_inactive(struct pagevec *pvec)
 172{
 173        int i;
 174        struct zone *zone = NULL;
 175
 176        if (pagevec_count(pvec) == 0)
 177                return;
 178        for (i = 0; i < pagevec_count(pvec); i++) {
 179                struct page *page = pvec->pages[i];
 180                struct zone *pagezone = page_zone(page);
 181
 182                if (pagezone != zone) {
 183                        if (zone)
 184                                spin_unlock_irq(&zone->lru_lock);
 185                        zone = pagezone;
 186                        spin_lock_irq(&zone->lru_lock);
 187                }
 188                if (!PageActive(page) && PageLRU(page))
 189                        list_move(&page->lru, &pagezone->inactive_list);
 190        }
 191        if (zone)
 192                spin_unlock_irq(&zone->lru_lock);
 193        __pagevec_release(pvec);
 194}
 195
 196/*
 197 * Add the passed pages to the inactive_list, then drop the caller's refcount
 198 * on them.  Reinitialises the caller's pagevec.
 199 */
 200void __pagevec_lru_add(struct pagevec *pvec)
 201{
 202        int i;
 203        struct zone *zone = NULL;
 204
 205        for (i = 0; i < pagevec_count(pvec); i++) {
 206                struct page *page = pvec->pages[i];
 207                struct zone *pagezone = page_zone(page);
 208
 209                if (pagezone != zone) {
 210                        if (zone)
 211                                spin_unlock_irq(&zone->lru_lock);
 212                        zone = pagezone;
 213                        spin_lock_irq(&zone->lru_lock);
 214                }
 215                if (TestSetPageLRU(page))
 216                        BUG();
 217                add_page_to_inactive_list(zone, page);
 218        }
 219        if (zone)
 220                spin_unlock_irq(&zone->lru_lock);
 221        pagevec_release(pvec);
 222}
 223
 224/*
 225 * Try to drop buffers from the pages in a pagevec
 226 */
 227void pagevec_strip(struct pagevec *pvec)
 228{
 229        int i;
 230
 231        for (i = 0; i < pagevec_count(pvec); i++) {
 232                struct page *page = pvec->pages[i];
 233
 234                if (PagePrivate(page) && !TestSetPageLocked(page)) {
 235                        try_to_release_page(page, 0);
 236                        unlock_page(page);
 237                }
 238        }
 239}
 240
 241/*
 242 * Perform any setup for the swap system
 243 */
 244void __init swap_setup(void)
 245{
 246        unsigned long megs = num_physpages >> (20 - PAGE_SHIFT);
 247
 248        /* Use a smaller cluster for small-memory machines */
 249        if (megs < 16)
 250                page_cluster = 2;
 251        else
 252                page_cluster = 3;
 253        /*
 254         * Right now other parts of the system means that we
 255         * _really_ don't want to cluster much more
 256         */
 257}
 258
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.