aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRik van Riel <riel@redhat.com>2005-11-28 16:44:07 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-28 17:42:25 -0500
commitf7b7fd8f3ebbb2810d6893295aa984acd0fd30db (patch)
tree01afc1edafc50a3c65ec8576c05c60da53d8d242
parenta93a117eaa0bec426d4671a49bfa96a6fdcd2ac9 (diff)
[PATCH] temporarily disable swap token on memory pressure
Some users (hi Zwane) have seen a problem when running a workload that eats nearly all of physical memory - th system does an OOM kill, even when there is still a lot of swap free. The problem appears to be a very big task that is holding the swap token, and the VM has a very hard time finding any other page in the system that is swappable. Instead of ignoring the swap token when sc->priority reaches 0, we could simply take the swap token away from the memory hog and make sure we don't give it back to the memory hog for a few seconds. This patch resolves the problem Zwane ran into. Signed-off-by: Rik van Riel <riel@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/rmap.h4
-rw-r--r--include/linux/swap.h6
-rw-r--r--mm/rmap.c26
-rw-r--r--mm/thrash.c10
-rw-r--r--mm/vmscan.c11
5 files changed, 34 insertions, 23 deletions
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 35b30e6c8cf8..33261f1d2239 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -89,7 +89,7 @@ static inline void page_dup_rmap(struct page *page)
89/* 89/*
90 * Called from mm/vmscan.c to handle paging out 90 * Called from mm/vmscan.c to handle paging out
91 */ 91 */
92int page_referenced(struct page *, int is_locked, int ignore_token); 92int page_referenced(struct page *, int is_locked);
93int try_to_unmap(struct page *); 93int try_to_unmap(struct page *);
94 94
95/* 95/*
@@ -109,7 +109,7 @@ unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
109#define anon_vma_prepare(vma) (0) 109#define anon_vma_prepare(vma) (0)
110#define anon_vma_link(vma) do {} while (0) 110#define anon_vma_link(vma) do {} while (0)
111 111
112#define page_referenced(page,l,i) TestClearPageReferenced(page) 112#define page_referenced(page,l) TestClearPageReferenced(page)
113#define try_to_unmap(page) SWAP_FAIL 113#define try_to_unmap(page) SWAP_FAIL
114 114
115#endif /* CONFIG_MMU */ 115#endif /* CONFIG_MMU */
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 20c975642cab..508668f840b6 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -239,6 +239,11 @@ static inline void put_swap_token(struct mm_struct *mm)
239 __put_swap_token(mm); 239 __put_swap_token(mm);
240} 240}
241 241
242static inline void disable_swap_token(void)
243{
244 put_swap_token(swap_token_mm);
245}
246
242#else /* CONFIG_SWAP */ 247#else /* CONFIG_SWAP */
243 248
244#define total_swap_pages 0 249#define total_swap_pages 0
@@ -283,6 +288,7 @@ static inline swp_entry_t get_swap_page(void)
283#define put_swap_token(x) do { } while(0) 288#define put_swap_token(x) do { } while(0)
284#define grab_swap_token() do { } while(0) 289#define grab_swap_token() do { } while(0)
285#define has_swap_token(x) 0 290#define has_swap_token(x) 0
291#define disable_swap_token() do { } while(0)
286 292
287#endif /* CONFIG_SWAP */ 293#endif /* CONFIG_SWAP */
288#endif /* __KERNEL__*/ 294#endif /* __KERNEL__*/
diff --git a/mm/rmap.c b/mm/rmap.c
index 6389cda02a20..491ac350048f 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -290,7 +290,7 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm,
290 * repeatedly from either page_referenced_anon or page_referenced_file. 290 * repeatedly from either page_referenced_anon or page_referenced_file.
291 */ 291 */
292static int page_referenced_one(struct page *page, 292static int page_referenced_one(struct page *page,
293 struct vm_area_struct *vma, unsigned int *mapcount, int ignore_token) 293 struct vm_area_struct *vma, unsigned int *mapcount)
294{ 294{
295 struct mm_struct *mm = vma->vm_mm; 295 struct mm_struct *mm = vma->vm_mm;
296 unsigned long address; 296 unsigned long address;
@@ -311,7 +311,7 @@ static int page_referenced_one(struct page *page,
311 311
312 /* Pretend the page is referenced if the task has the 312 /* Pretend the page is referenced if the task has the
313 swap token and is in the middle of a page fault. */ 313 swap token and is in the middle of a page fault. */
314 if (mm != current->mm && !ignore_token && has_swap_token(mm) && 314 if (mm != current->mm && has_swap_token(mm) &&
315 rwsem_is_locked(&mm->mmap_sem)) 315 rwsem_is_locked(&mm->mmap_sem))
316 referenced++; 316 referenced++;
317 317
@@ -321,7 +321,7 @@ out:
321 return referenced; 321 return referenced;
322} 322}
323 323
324static int page_referenced_anon(struct page *page, int ignore_token) 324static int page_referenced_anon(struct page *page)
325{ 325{
326 unsigned int mapcount; 326 unsigned int mapcount;
327 struct anon_vma *anon_vma; 327 struct anon_vma *anon_vma;
@@ -334,8 +334,7 @@ static int page_referenced_anon(struct page *page, int ignore_token)
334 334
335 mapcount = page_mapcount(page); 335 mapcount = page_mapcount(page);
336 list_for_each_entry(vma, &anon_vma->head, anon_vma_node) { 336 list_for_each_entry(vma, &anon_vma->head, anon_vma_node) {
337 referenced += page_referenced_one(page, vma, &mapcount, 337 referenced += page_referenced_one(page, vma, &mapcount);
338 ignore_token);
339 if (!mapcount) 338 if (!mapcount)
340 break; 339 break;
341 } 340 }
@@ -354,7 +353,7 @@ static int page_referenced_anon(struct page *page, int ignore_token)
354 * 353 *
355 * This function is only called from page_referenced for object-based pages. 354 * This function is only called from page_referenced for object-based pages.
356 */ 355 */
357static int page_referenced_file(struct page *page, int ignore_token) 356static int page_referenced_file(struct page *page)
358{ 357{
359 unsigned int mapcount; 358 unsigned int mapcount;
360 struct address_space *mapping = page->mapping; 359 struct address_space *mapping = page->mapping;
@@ -392,8 +391,7 @@ static int page_referenced_file(struct page *page, int ignore_token)
392 referenced++; 391 referenced++;
393 break; 392 break;
394 } 393 }
395 referenced += page_referenced_one(page, vma, &mapcount, 394 referenced += page_referenced_one(page, vma, &mapcount);
396 ignore_token);
397 if (!mapcount) 395 if (!mapcount)
398 break; 396 break;
399 } 397 }
@@ -410,13 +408,10 @@ static int page_referenced_file(struct page *page, int ignore_token)
410 * Quick test_and_clear_referenced for all mappings to a page, 408 * Quick test_and_clear_referenced for all mappings to a page,
411 * returns the number of ptes which referenced the page. 409 * returns the number of ptes which referenced the page.
412 */ 410 */
413int page_referenced(struct page *page, int is_locked, int ignore_token) 411int page_referenced(struct page *page, int is_locked)
414{ 412{
415 int referenced = 0; 413 int referenced = 0;
416 414
417 if (!swap_token_default_timeout)
418 ignore_token = 1;
419
420 if (page_test_and_clear_young(page)) 415 if (page_test_and_clear_young(page))
421 referenced++; 416 referenced++;
422 417
@@ -425,15 +420,14 @@ int page_referenced(struct page *page, int is_locked, int ignore_token)
425 420
426 if (page_mapped(page) && page->mapping) { 421 if (page_mapped(page) && page->mapping) {
427 if (PageAnon(page)) 422 if (PageAnon(page))
428 referenced += page_referenced_anon(page, ignore_token); 423 referenced += page_referenced_anon(page);
429 else if (is_locked) 424 else if (is_locked)
430 referenced += page_referenced_file(page, ignore_token); 425 referenced += page_referenced_file(page);
431 else if (TestSetPageLocked(page)) 426 else if (TestSetPageLocked(page))
432 referenced++; 427 referenced++;
433 else { 428 else {
434 if (page->mapping) 429 if (page->mapping)
435 referenced += page_referenced_file(page, 430 referenced += page_referenced_file(page);
436 ignore_token);
437 unlock_page(page); 431 unlock_page(page);
438 } 432 }
439 } 433 }
diff --git a/mm/thrash.c b/mm/thrash.c
index eff3c18c33a1..f4c560b4a2b7 100644
--- a/mm/thrash.c
+++ b/mm/thrash.c
@@ -57,14 +57,17 @@ void grab_swap_token(void)
57 /* We have the token. Let others know we still need it. */ 57 /* We have the token. Let others know we still need it. */
58 if (has_swap_token(current->mm)) { 58 if (has_swap_token(current->mm)) {
59 current->mm->recent_pagein = 1; 59 current->mm->recent_pagein = 1;
60 if (unlikely(!swap_token_default_timeout))
61 disable_swap_token();
60 return; 62 return;
61 } 63 }
62 64
63 if (time_after(jiffies, swap_token_check)) { 65 if (time_after(jiffies, swap_token_check)) {
64 66
65 /* Can't get swapout protection if we exceed our RSS limit. */ 67 if (!swap_token_default_timeout) {
66 // if (current->mm->rss > current->mm->rlimit_rss) 68 swap_token_check = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
67 // return; 69 return;
70 }
68 71
69 /* ... or if we recently held the token. */ 72 /* ... or if we recently held the token. */
70 if (time_before(jiffies, current->mm->swap_token_time)) 73 if (time_before(jiffies, current->mm->swap_token_time))
@@ -95,6 +98,7 @@ void __put_swap_token(struct mm_struct *mm)
95{ 98{
96 spin_lock(&swap_token_lock); 99 spin_lock(&swap_token_lock);
97 if (likely(mm == swap_token_mm)) { 100 if (likely(mm == swap_token_mm)) {
101 mm->swap_token_time = jiffies + SWAP_TOKEN_CHECK_INTERVAL;
98 swap_token_mm = &init_mm; 102 swap_token_mm = &init_mm;
99 swap_token_check = jiffies; 103 swap_token_check = jiffies;
100 } 104 }
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 28130541270f..078cf920208a 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -407,7 +407,7 @@ static int shrink_list(struct list_head *page_list, struct scan_control *sc)
407 if (PageWriteback(page)) 407 if (PageWriteback(page))
408 goto keep_locked; 408 goto keep_locked;
409 409
410 referenced = page_referenced(page, 1, sc->priority <= 0); 410 referenced = page_referenced(page, 1);
411 /* In active use or really unfreeable? Activate it. */ 411 /* In active use or really unfreeable? Activate it. */
412 if (referenced && page_mapping_inuse(page)) 412 if (referenced && page_mapping_inuse(page))
413 goto activate_locked; 413 goto activate_locked;
@@ -756,7 +756,7 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc)
756 if (page_mapped(page)) { 756 if (page_mapped(page)) {
757 if (!reclaim_mapped || 757 if (!reclaim_mapped ||
758 (total_swap_pages == 0 && PageAnon(page)) || 758 (total_swap_pages == 0 && PageAnon(page)) ||
759 page_referenced(page, 0, sc->priority <= 0)) { 759 page_referenced(page, 0)) {
760 list_add(&page->lru, &l_active); 760 list_add(&page->lru, &l_active);
761 continue; 761 continue;
762 } 762 }
@@ -960,6 +960,8 @@ int try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
960 sc.nr_reclaimed = 0; 960 sc.nr_reclaimed = 0;
961 sc.priority = priority; 961 sc.priority = priority;
962 sc.swap_cluster_max = SWAP_CLUSTER_MAX; 962 sc.swap_cluster_max = SWAP_CLUSTER_MAX;
963 if (!priority)
964 disable_swap_token();
963 shrink_caches(zones, &sc); 965 shrink_caches(zones, &sc);
964 shrink_slab(sc.nr_scanned, gfp_mask, lru_pages); 966 shrink_slab(sc.nr_scanned, gfp_mask, lru_pages);
965 if (reclaim_state) { 967 if (reclaim_state) {
@@ -1056,6 +1058,10 @@ loop_again:
1056 int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */ 1058 int end_zone = 0; /* Inclusive. 0 = ZONE_DMA */
1057 unsigned long lru_pages = 0; 1059 unsigned long lru_pages = 0;
1058 1060
1061 /* The swap token gets in the way of swapout... */
1062 if (!priority)
1063 disable_swap_token();
1064
1059 all_zones_ok = 1; 1065 all_zones_ok = 1;
1060 1066
1061 if (nr_pages == 0) { 1067 if (nr_pages == 0) {
@@ -1360,6 +1366,7 @@ int zone_reclaim(struct zone *zone, gfp_t gfp_mask, unsigned int order)
1360 sc.nr_reclaimed = 0; 1366 sc.nr_reclaimed = 0;
1361 /* scan at the highest priority */ 1367 /* scan at the highest priority */
1362 sc.priority = 0; 1368 sc.priority = 0;
1369 disable_swap_token();
1363 1370
1364 if (nr_pages > SWAP_CLUSTER_MAX) 1371 if (nr_pages > SWAP_CLUSTER_MAX)
1365 sc.swap_cluster_max = nr_pages; 1372 sc.swap_cluster_max = nr_pages;