diff options
Diffstat (limited to 'mm/vmscan.c')
| -rw-r--r-- | mm/vmscan.c | 93 |
1 files changed, 66 insertions, 27 deletions
diff --git a/mm/vmscan.c b/mm/vmscan.c index 967d30ccd92b..1ff1a58e7c10 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <linux/kthread.h> | 38 | #include <linux/kthread.h> |
| 39 | #include <linux/freezer.h> | 39 | #include <linux/freezer.h> |
| 40 | #include <linux/memcontrol.h> | 40 | #include <linux/memcontrol.h> |
| 41 | #include <linux/delayacct.h> | ||
| 41 | 42 | ||
| 42 | #include <asm/tlbflush.h> | 43 | #include <asm/tlbflush.h> |
| 43 | #include <asm/div64.h> | 44 | #include <asm/div64.h> |
| @@ -390,17 +391,15 @@ static pageout_t pageout(struct page *page, struct address_space *mapping, | |||
| 390 | } | 391 | } |
| 391 | 392 | ||
| 392 | /* | 393 | /* |
| 393 | * Attempt to detach a locked page from its ->mapping. If it is dirty or if | 394 | * Same as remove_mapping, but if the page is removed from the mapping, it |
| 394 | * someone else has a ref on the page, abort and return 0. If it was | 395 | * gets returned with a refcount of 0. |
| 395 | * successfully detached, return 1. Assumes the caller has a single ref on | ||
| 396 | * this page. | ||
| 397 | */ | 396 | */ |
| 398 | int remove_mapping(struct address_space *mapping, struct page *page) | 397 | static int __remove_mapping(struct address_space *mapping, struct page *page) |
| 399 | { | 398 | { |
| 400 | BUG_ON(!PageLocked(page)); | 399 | BUG_ON(!PageLocked(page)); |
| 401 | BUG_ON(mapping != page_mapping(page)); | 400 | BUG_ON(mapping != page_mapping(page)); |
| 402 | 401 | ||
| 403 | write_lock_irq(&mapping->tree_lock); | 402 | spin_lock_irq(&mapping->tree_lock); |
| 404 | /* | 403 | /* |
| 405 | * The non racy check for a busy page. | 404 | * The non racy check for a busy page. |
| 406 | * | 405 | * |
| @@ -426,28 +425,48 @@ int remove_mapping(struct address_space *mapping, struct page *page) | |||
| 426 | * Note that if SetPageDirty is always performed via set_page_dirty, | 425 | * Note that if SetPageDirty is always performed via set_page_dirty, |
| 427 | * and thus under tree_lock, then this ordering is not required. | 426 | * and thus under tree_lock, then this ordering is not required. |
| 428 | */ | 427 | */ |
| 429 | if (unlikely(page_count(page) != 2)) | 428 | if (!page_freeze_refs(page, 2)) |
| 430 | goto cannot_free; | 429 | goto cannot_free; |
| 431 | smp_rmb(); | 430 | /* note: atomic_cmpxchg in page_freeze_refs provides the smp_rmb */ |
| 432 | if (unlikely(PageDirty(page))) | 431 | if (unlikely(PageDirty(page))) { |
| 432 | page_unfreeze_refs(page, 2); | ||
| 433 | goto cannot_free; | 433 | goto cannot_free; |
| 434 | } | ||
| 434 | 435 | ||
| 435 | if (PageSwapCache(page)) { | 436 | if (PageSwapCache(page)) { |
| 436 | swp_entry_t swap = { .val = page_private(page) }; | 437 | swp_entry_t swap = { .val = page_private(page) }; |
| 437 | __delete_from_swap_cache(page); | 438 | __delete_from_swap_cache(page); |
| 438 | write_unlock_irq(&mapping->tree_lock); | 439 | spin_unlock_irq(&mapping->tree_lock); |
| 439 | swap_free(swap); | 440 | swap_free(swap); |
| 440 | __put_page(page); /* The pagecache ref */ | 441 | } else { |
| 441 | return 1; | 442 | __remove_from_page_cache(page); |
| 443 | spin_unlock_irq(&mapping->tree_lock); | ||
| 442 | } | 444 | } |
| 443 | 445 | ||
| 444 | __remove_from_page_cache(page); | ||
| 445 | write_unlock_irq(&mapping->tree_lock); | ||
| 446 | __put_page(page); | ||
| 447 | return 1; | 446 | return 1; |
| 448 | 447 | ||
| 449 | cannot_free: | 448 | cannot_free: |
| 450 | write_unlock_irq(&mapping->tree_lock); | 449 | spin_unlock_irq(&mapping->tree_lock); |
| 450 | return 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | /* | ||
| 454 | * Attempt to detach a locked page from its ->mapping. If it is dirty or if | ||
| 455 | * someone else has a ref on the page, abort and return 0. If it was | ||
| 456 | * successfully detached, return 1. Assumes the caller has a single ref on | ||
| 457 | * this page. | ||
| 458 | */ | ||
| 459 | int remove_mapping(struct address_space *mapping, struct page *page) | ||
| 460 | { | ||
| 461 | if (__remove_mapping(mapping, page)) { | ||
| 462 | /* | ||
| 463 | * Unfreezing the refcount with 1 rather than 2 effectively | ||
| 464 | * drops the pagecache ref for us without requiring another | ||
| 465 | * atomic operation. | ||
| 466 | */ | ||
| 467 | page_unfreeze_refs(page, 1); | ||
| 468 | return 1; | ||
| 469 | } | ||
| 451 | return 0; | 470 | return 0; |
| 452 | } | 471 | } |
| 453 | 472 | ||
| @@ -477,7 +496,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, | |||
| 477 | page = lru_to_page(page_list); | 496 | page = lru_to_page(page_list); |
| 478 | list_del(&page->lru); | 497 | list_del(&page->lru); |
| 479 | 498 | ||
| 480 | if (TestSetPageLocked(page)) | 499 | if (!trylock_page(page)) |
| 481 | goto keep; | 500 | goto keep; |
| 482 | 501 | ||
| 483 | VM_BUG_ON(PageActive(page)); | 502 | VM_BUG_ON(PageActive(page)); |
| @@ -563,7 +582,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, | |||
| 563 | * A synchronous write - probably a ramdisk. Go | 582 | * A synchronous write - probably a ramdisk. Go |
| 564 | * ahead and try to reclaim the page. | 583 | * ahead and try to reclaim the page. |
| 565 | */ | 584 | */ |
| 566 | if (TestSetPageLocked(page)) | 585 | if (!trylock_page(page)) |
| 567 | goto keep; | 586 | goto keep; |
| 568 | if (PageDirty(page) || PageWriteback(page)) | 587 | if (PageDirty(page) || PageWriteback(page)) |
| 569 | goto keep_locked; | 588 | goto keep_locked; |
| @@ -597,18 +616,34 @@ static unsigned long shrink_page_list(struct list_head *page_list, | |||
| 597 | if (PagePrivate(page)) { | 616 | if (PagePrivate(page)) { |
| 598 | if (!try_to_release_page(page, sc->gfp_mask)) | 617 | if (!try_to_release_page(page, sc->gfp_mask)) |
| 599 | goto activate_locked; | 618 | goto activate_locked; |
| 600 | if (!mapping && page_count(page) == 1) | 619 | if (!mapping && page_count(page) == 1) { |
| 601 | goto free_it; | 620 | unlock_page(page); |
| 621 | if (put_page_testzero(page)) | ||
| 622 | goto free_it; | ||
| 623 | else { | ||
| 624 | /* | ||
| 625 | * rare race with speculative reference. | ||
| 626 | * the speculative reference will free | ||
| 627 | * this page shortly, so we may | ||
| 628 | * increment nr_reclaimed here (and | ||
| 629 | * leave it off the LRU). | ||
| 630 | */ | ||
| 631 | nr_reclaimed++; | ||
| 632 | continue; | ||
| 633 | } | ||
| 634 | } | ||
| 602 | } | 635 | } |
| 603 | 636 | ||
| 604 | if (!mapping || !remove_mapping(mapping, page)) | 637 | if (!mapping || !__remove_mapping(mapping, page)) |
| 605 | goto keep_locked; | 638 | goto keep_locked; |
| 606 | 639 | ||
| 607 | free_it: | ||
| 608 | unlock_page(page); | 640 | unlock_page(page); |
| 641 | free_it: | ||
| 609 | nr_reclaimed++; | 642 | nr_reclaimed++; |
| 610 | if (!pagevec_add(&freed_pvec, page)) | 643 | if (!pagevec_add(&freed_pvec, page)) { |
| 611 | __pagevec_release_nonlru(&freed_pvec); | 644 | __pagevec_free(&freed_pvec); |
| 645 | pagevec_reinit(&freed_pvec); | ||
| 646 | } | ||
| 612 | continue; | 647 | continue; |
| 613 | 648 | ||
| 614 | activate_locked: | 649 | activate_locked: |
| @@ -622,7 +657,7 @@ keep: | |||
| 622 | } | 657 | } |
| 623 | list_splice(&ret_pages, page_list); | 658 | list_splice(&ret_pages, page_list); |
| 624 | if (pagevec_count(&freed_pvec)) | 659 | if (pagevec_count(&freed_pvec)) |
| 625 | __pagevec_release_nonlru(&freed_pvec); | 660 | __pagevec_free(&freed_pvec); |
| 626 | count_vm_events(PGACTIVATE, pgactivate); | 661 | count_vm_events(PGACTIVATE, pgactivate); |
| 627 | return nr_reclaimed; | 662 | return nr_reclaimed; |
| 628 | } | 663 | } |
| @@ -1316,6 +1351,8 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, | |||
| 1316 | struct zone *zone; | 1351 | struct zone *zone; |
| 1317 | enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask); | 1352 | enum zone_type high_zoneidx = gfp_zone(sc->gfp_mask); |
| 1318 | 1353 | ||
| 1354 | delayacct_freepages_start(); | ||
| 1355 | |||
| 1319 | if (scan_global_lru(sc)) | 1356 | if (scan_global_lru(sc)) |
| 1320 | count_vm_event(ALLOCSTALL); | 1357 | count_vm_event(ALLOCSTALL); |
| 1321 | /* | 1358 | /* |
| @@ -1371,7 +1408,7 @@ static unsigned long do_try_to_free_pages(struct zonelist *zonelist, | |||
| 1371 | if (sc->nr_scanned && priority < DEF_PRIORITY - 2) | 1408 | if (sc->nr_scanned && priority < DEF_PRIORITY - 2) |
| 1372 | congestion_wait(WRITE, HZ/10); | 1409 | congestion_wait(WRITE, HZ/10); |
| 1373 | } | 1410 | } |
| 1374 | /* top priority shrink_caches still had more to do? don't OOM, then */ | 1411 | /* top priority shrink_zones still had more to do? don't OOM, then */ |
| 1375 | if (!sc->all_unreclaimable && scan_global_lru(sc)) | 1412 | if (!sc->all_unreclaimable && scan_global_lru(sc)) |
| 1376 | ret = nr_reclaimed; | 1413 | ret = nr_reclaimed; |
| 1377 | out: | 1414 | out: |
| @@ -1396,6 +1433,8 @@ out: | |||
| 1396 | } else | 1433 | } else |
| 1397 | mem_cgroup_record_reclaim_priority(sc->mem_cgroup, priority); | 1434 | mem_cgroup_record_reclaim_priority(sc->mem_cgroup, priority); |
| 1398 | 1435 | ||
| 1436 | delayacct_freepages_end(); | ||
| 1437 | |||
| 1399 | return ret; | 1438 | return ret; |
| 1400 | } | 1439 | } |
| 1401 | 1440 | ||
| @@ -1940,7 +1979,7 @@ module_init(kswapd_init) | |||
| 1940 | int zone_reclaim_mode __read_mostly; | 1979 | int zone_reclaim_mode __read_mostly; |
| 1941 | 1980 | ||
| 1942 | #define RECLAIM_OFF 0 | 1981 | #define RECLAIM_OFF 0 |
| 1943 | #define RECLAIM_ZONE (1<<0) /* Run shrink_cache on the zone */ | 1982 | #define RECLAIM_ZONE (1<<0) /* Run shrink_inactive_list on the zone */ |
| 1944 | #define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */ | 1983 | #define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */ |
| 1945 | #define RECLAIM_SWAP (1<<2) /* Swap pages out during reclaim */ | 1984 | #define RECLAIM_SWAP (1<<2) /* Swap pages out during reclaim */ |
| 1946 | 1985 | ||
