Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | /* * linux/mm/swap.c * * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds */ /* * This file contains the default values for the opereation of the * Linux VM subsystem. Fine-tuning documentation can be found in * linux/Documentation/sysctl/vm.txt. * Started 18.12.91 * Swap aging added 23.2.95, Stephen Tweedie. * Buffermem limits added 12.3.98, Rik van Riel. */ #include <linux/mm.h> #include <linux/kernel_stat.h> #include <linux/swap.h> #include <linux/swapctl.h> #include <linux/pagemap.h> #include <linux/init.h> #include <asm/dma.h> #include <asm/uaccess.h> /* for copy_to/from_user */ #include <asm/pgtable.h> /* * We identify three levels of free memory. We never let free mem * fall below the freepages.min except for atomic allocations. We * start background swapping if we fall below freepages.high free * pages, and we begin intensive swapping below freepages.low. * * Actual initialization is done in mm/page_alloc.c or * arch/sparc(64)/mm/init.c. */ freepages_t freepages = { 0, /* freepages.min */ 0, /* freepages.low */ 0 /* freepages.high */ }; /* How many pages do we try to swap or page in/out together? */ int page_cluster; /* * This variable contains the amount of page steals the system * is doing, averaged over a minute. We use this to determine how * many inactive pages we should have. * * In reclaim_page and __alloc_pages: memory_pressure++ * In __free_pages_ok: memory_pressure-- * In recalculate_vm_stats the value is decayed (once a second) */ int memory_pressure; /* We track the number of pages currently being asynchronously swapped out, so that we don't try to swap TOO many pages out at once */ atomic_t nr_async_pages = ATOMIC_INIT(0); buffer_mem_t buffer_mem = { 2, /* minimum percent buffer */ 10, /* borrow percent buffer */ 60 /* maximum percent buffer */ }; buffer_mem_t page_cache = { 2, /* minimum percent page cache */ 15, /* borrow percent page cache */ 75 /* maximum */ }; pager_daemon_t pager_daemon = { 512, /* base number for calculating the number of tries */ SWAP_CLUSTER_MAX, /* minimum number of tries */ 8, /* do swap I/O in clusters of this size */ }; /** * age_page_{up,down} - page aging helper functions * @page - the page we want to age * @nolock - are we already holding the pagelist_lru_lock? * * If the page is on one of the lists (active, inactive_dirty or * inactive_clean), we will grab the pagelist_lru_lock as needed. * If you're already holding the lock, call this function with the * nolock argument non-zero. */ void age_page_up_nolock(struct page * page) { /* * We're dealing with an inactive page, move the page * to the active list. */ if (!page->age) activate_page_nolock(page); /* The actual page aging bit */ page->age += PAGE_AGE_ADV; if (page->age > PAGE_AGE_MAX) page->age = PAGE_AGE_MAX; } /* * We use this (minimal) function in the case where we * know we can't deactivate the page (yet). */ void age_page_down_ageonly(struct page * page) { page->age /= 2; } void age_page_down_nolock(struct page * page) { /* The actual page aging bit */ page->age /= 2; /* * The page is now an old page. Move to the inactive * list (if possible ... see below). */ if (!page->age) deactivate_page_nolock(page); } void age_page_up(struct page * page) { /* * We're dealing with an inactive page, move the page * to the active list. */ if (!page->age) activate_page(page); /* The actual page aging bit */ page->age += PAGE_AGE_ADV; if (page->age > PAGE_AGE_MAX) page->age = PAGE_AGE_MAX; } void age_page_down(struct page * page) { /* The actual page aging bit */ page->age /= 2; /* * The page is now an old page. Move to the inactive * list (if possible ... see below). */ if (!page->age) deactivate_page(page); } /** * (de)activate_page - move pages from/to active and inactive lists * @page: the page we want to move * @nolock - are we already holding the pagemap_lru_lock? * * Deactivate_page will move an active page to the right * inactive list, while activate_page will move a page back * from one of the inactive lists to the active list. If * called on a page which is not on any of the lists, the * page is left alone. */ void deactivate_page_nolock(struct page * page) { /* * One for the cache, one for the extra reference the * caller has and (maybe) one for the buffers. * * This isn't perfect, but works for just about everything. * Besides, as long as we don't move unfreeable pages to the * inactive_clean list it doesn't need to be perfect... */ int maxcount = (page->buffers ? 3 : 2); page->age = 0; ClearPageReferenced(page); /* * Don't touch it if it's not on the active list. * (some pages aren't on any list at all) */ if (PageActive(page) && page_count(page) <= maxcount && !page_ramdisk(page)) { del_page_from_active_list(page); add_page_to_inactive_dirty_list(page); } } void deactivate_page(struct page * page) { spin_lock(&pagemap_lru_lock); deactivate_page_nolock(page); spin_unlock(&pagemap_lru_lock); } /* * Move an inactive page to the active list. */ void activate_page_nolock(struct page * page) { if (PageInactiveDirty(page)) { del_page_from_inactive_dirty_list(page); add_page_to_active_list(page); } else if (PageInactiveClean(page)) { del_page_from_inactive_clean_list(page); add_page_to_active_list(page); } else { /* * The page was not on any list, so we take care * not to do anything. */ } /* Make sure the page gets a fair chance at staying active. */ if (page->age < PAGE_AGE_START) page->age = PAGE_AGE_START; } void activate_page(struct page * page) { spin_lock(&pagemap_lru_lock); activate_page_nolock(page); spin_unlock(&pagemap_lru_lock); } /** * lru_cache_add: add a page to the page lists * @page: the page to add */ void lru_cache_add(struct page * page) { spin_lock(&pagemap_lru_lock); if (!PageLocked(page)) BUG(); DEBUG_ADD_PAGE add_page_to_active_list(page); /* This should be relatively rare */ if (!page->age) deactivate_page_nolock(page); spin_unlock(&pagemap_lru_lock); } /** * __lru_cache_del: remove a page from the page lists * @page: the page to add * * This function is for when the caller already holds * the pagemap_lru_lock. */ void __lru_cache_del(struct page * page) { if (PageActive(page)) { del_page_from_active_list(page); } else if (PageInactiveDirty(page)) { del_page_from_inactive_dirty_list(page); } else if (PageInactiveClean(page)) { del_page_from_inactive_clean_list(page); } else { printk("VM: __lru_cache_del, found unknown page ?!\n"); } DEBUG_ADD_PAGE } /** * lru_cache_del: remove a page from the page lists * @page: the page to remove */ void lru_cache_del(struct page * page) { if (!PageLocked(page)) BUG(); spin_lock(&pagemap_lru_lock); __lru_cache_del(page); spin_unlock(&pagemap_lru_lock); } /** * recalculate_vm_stats - recalculate VM statistics * * This function should be called once a second to recalculate * some useful statistics the VM subsystem uses to determine * its behaviour. */ void recalculate_vm_stats(void) { /* * Substract one second worth of memory_pressure from * memory_pressure. */ memory_pressure -= (memory_pressure >> INACTIVE_SHIFT); } /* * Perform any setup for the swap system */ void __init swap_setup(void) { /* Use a smaller cluster for memory <16MB or <32MB */ if (num_physpages < ((16 * 1024 * 1024) >> PAGE_SHIFT)) page_cluster = 2; else if (num_physpages < ((32 * 1024 * 1024) >> PAGE_SHIFT)) page_cluster = 3; else page_cluster = 4; } |