diff options
Diffstat (limited to 'mm/rmap.c')
| -rw-r--r-- | mm/rmap.c | 48 |
1 files changed, 33 insertions, 15 deletions
| @@ -14,7 +14,7 @@ | |||
| 14 | * Original design by Rik van Riel <riel@conectiva.com.br> 2001 | 14 | * Original design by Rik van Riel <riel@conectiva.com.br> 2001 |
| 15 | * File methods by Dave McCracken <dmccr@us.ibm.com> 2003, 2004 | 15 | * File methods by Dave McCracken <dmccr@us.ibm.com> 2003, 2004 |
| 16 | * Anonymous methods by Andrea Arcangeli <andrea@suse.de> 2004 | 16 | * Anonymous methods by Andrea Arcangeli <andrea@suse.de> 2004 |
| 17 | * Contributions by Hugh Dickins <hugh@veritas.com> 2003, 2004 | 17 | * Contributions by Hugh Dickins 2003, 2004 |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | /* | 20 | /* |
| @@ -333,7 +333,9 @@ static int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) | |||
| 333 | * repeatedly from either page_referenced_anon or page_referenced_file. | 333 | * repeatedly from either page_referenced_anon or page_referenced_file. |
| 334 | */ | 334 | */ |
| 335 | static int page_referenced_one(struct page *page, | 335 | static int page_referenced_one(struct page *page, |
| 336 | struct vm_area_struct *vma, unsigned int *mapcount) | 336 | struct vm_area_struct *vma, |
| 337 | unsigned int *mapcount, | ||
| 338 | unsigned long *vm_flags) | ||
| 337 | { | 339 | { |
| 338 | struct mm_struct *mm = vma->vm_mm; | 340 | struct mm_struct *mm = vma->vm_mm; |
| 339 | unsigned long address; | 341 | unsigned long address; |
| @@ -356,6 +358,7 @@ static int page_referenced_one(struct page *page, | |||
| 356 | */ | 358 | */ |
| 357 | if (vma->vm_flags & VM_LOCKED) { | 359 | if (vma->vm_flags & VM_LOCKED) { |
| 358 | *mapcount = 1; /* break early from loop */ | 360 | *mapcount = 1; /* break early from loop */ |
| 361 | *vm_flags |= VM_LOCKED; | ||
| 359 | goto out_unmap; | 362 | goto out_unmap; |
| 360 | } | 363 | } |
| 361 | 364 | ||
| @@ -381,11 +384,14 @@ out_unmap: | |||
| 381 | (*mapcount)--; | 384 | (*mapcount)--; |
| 382 | pte_unmap_unlock(pte, ptl); | 385 | pte_unmap_unlock(pte, ptl); |
| 383 | out: | 386 | out: |
| 387 | if (referenced) | ||
| 388 | *vm_flags |= vma->vm_flags; | ||
| 384 | return referenced; | 389 | return referenced; |
| 385 | } | 390 | } |
| 386 | 391 | ||
| 387 | static int page_referenced_anon(struct page *page, | 392 | static int page_referenced_anon(struct page *page, |
| 388 | struct mem_cgroup *mem_cont) | 393 | struct mem_cgroup *mem_cont, |
| 394 | unsigned long *vm_flags) | ||
| 389 | { | 395 | { |
| 390 | unsigned int mapcount; | 396 | unsigned int mapcount; |
| 391 | struct anon_vma *anon_vma; | 397 | struct anon_vma *anon_vma; |
| @@ -405,7 +411,8 @@ static int page_referenced_anon(struct page *page, | |||
| 405 | */ | 411 | */ |
| 406 | if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont)) | 412 | if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont)) |
| 407 | continue; | 413 | continue; |
| 408 | referenced += page_referenced_one(page, vma, &mapcount); | 414 | referenced += page_referenced_one(page, vma, |
| 415 | &mapcount, vm_flags); | ||
| 409 | if (!mapcount) | 416 | if (!mapcount) |
| 410 | break; | 417 | break; |
| 411 | } | 418 | } |
| @@ -418,6 +425,7 @@ static int page_referenced_anon(struct page *page, | |||
| 418 | * page_referenced_file - referenced check for object-based rmap | 425 | * page_referenced_file - referenced check for object-based rmap |
| 419 | * @page: the page we're checking references on. | 426 | * @page: the page we're checking references on. |
| 420 | * @mem_cont: target memory controller | 427 | * @mem_cont: target memory controller |
| 428 | * @vm_flags: collect encountered vma->vm_flags who actually referenced the page | ||
| 421 | * | 429 | * |
| 422 | * For an object-based mapped page, find all the places it is mapped and | 430 | * For an object-based mapped page, find all the places it is mapped and |
| 423 | * check/clear the referenced flag. This is done by following the page->mapping | 431 | * check/clear the referenced flag. This is done by following the page->mapping |
| @@ -427,7 +435,8 @@ static int page_referenced_anon(struct page *page, | |||
| 427 | * This function is only called from page_referenced for object-based pages. | 435 | * This function is only called from page_referenced for object-based pages. |
| 428 | */ | 436 | */ |
| 429 | static int page_referenced_file(struct page *page, | 437 | static int page_referenced_file(struct page *page, |
| 430 | struct mem_cgroup *mem_cont) | 438 | struct mem_cgroup *mem_cont, |
| 439 | unsigned long *vm_flags) | ||
| 431 | { | 440 | { |
| 432 | unsigned int mapcount; | 441 | unsigned int mapcount; |
| 433 | struct address_space *mapping = page->mapping; | 442 | struct address_space *mapping = page->mapping; |
| @@ -467,7 +476,8 @@ static int page_referenced_file(struct page *page, | |||
| 467 | */ | 476 | */ |
| 468 | if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont)) | 477 | if (mem_cont && !mm_match_cgroup(vma->vm_mm, mem_cont)) |
| 469 | continue; | 478 | continue; |
| 470 | referenced += page_referenced_one(page, vma, &mapcount); | 479 | referenced += page_referenced_one(page, vma, |
| 480 | &mapcount, vm_flags); | ||
| 471 | if (!mapcount) | 481 | if (!mapcount) |
| 472 | break; | 482 | break; |
| 473 | } | 483 | } |
| @@ -481,29 +491,35 @@ static int page_referenced_file(struct page *page, | |||
| 481 | * @page: the page to test | 491 | * @page: the page to test |
| 482 | * @is_locked: caller holds lock on the page | 492 | * @is_locked: caller holds lock on the page |
| 483 | * @mem_cont: target memory controller | 493 | * @mem_cont: target memory controller |
| 494 | * @vm_flags: collect encountered vma->vm_flags who actually referenced the page | ||
| 484 | * | 495 | * |
| 485 | * Quick test_and_clear_referenced for all mappings to a page, | 496 | * Quick test_and_clear_referenced for all mappings to a page, |
| 486 | * returns the number of ptes which referenced the page. | 497 | * returns the number of ptes which referenced the page. |
| 487 | */ | 498 | */ |
| 488 | int page_referenced(struct page *page, int is_locked, | 499 | int page_referenced(struct page *page, |
| 489 | struct mem_cgroup *mem_cont) | 500 | int is_locked, |
| 501 | struct mem_cgroup *mem_cont, | ||
| 502 | unsigned long *vm_flags) | ||
| 490 | { | 503 | { |
| 491 | int referenced = 0; | 504 | int referenced = 0; |
| 492 | 505 | ||
| 493 | if (TestClearPageReferenced(page)) | 506 | if (TestClearPageReferenced(page)) |
| 494 | referenced++; | 507 | referenced++; |
| 495 | 508 | ||
| 509 | *vm_flags = 0; | ||
| 496 | if (page_mapped(page) && page->mapping) { | 510 | if (page_mapped(page) && page->mapping) { |
| 497 | if (PageAnon(page)) | 511 | if (PageAnon(page)) |
| 498 | referenced += page_referenced_anon(page, mem_cont); | 512 | referenced += page_referenced_anon(page, mem_cont, |
| 513 | vm_flags); | ||
| 499 | else if (is_locked) | 514 | else if (is_locked) |
| 500 | referenced += page_referenced_file(page, mem_cont); | 515 | referenced += page_referenced_file(page, mem_cont, |
| 516 | vm_flags); | ||
| 501 | else if (!trylock_page(page)) | 517 | else if (!trylock_page(page)) |
| 502 | referenced++; | 518 | referenced++; |
| 503 | else { | 519 | else { |
| 504 | if (page->mapping) | 520 | if (page->mapping) |
| 505 | referenced += | 521 | referenced += page_referenced_file(page, |
| 506 | page_referenced_file(page, mem_cont); | 522 | mem_cont, vm_flags); |
| 507 | unlock_page(page); | 523 | unlock_page(page); |
| 508 | } | 524 | } |
| 509 | } | 525 | } |
| @@ -688,8 +704,10 @@ void page_add_new_anon_rmap(struct page *page, | |||
| 688 | */ | 704 | */ |
| 689 | void page_add_file_rmap(struct page *page) | 705 | void page_add_file_rmap(struct page *page) |
| 690 | { | 706 | { |
| 691 | if (atomic_inc_and_test(&page->_mapcount)) | 707 | if (atomic_inc_and_test(&page->_mapcount)) { |
| 692 | __inc_zone_page_state(page, NR_FILE_MAPPED); | 708 | __inc_zone_page_state(page, NR_FILE_MAPPED); |
| 709 | mem_cgroup_update_mapped_file_stat(page, 1); | ||
| 710 | } | ||
| 693 | } | 711 | } |
| 694 | 712 | ||
| 695 | #ifdef CONFIG_DEBUG_VM | 713 | #ifdef CONFIG_DEBUG_VM |
| @@ -738,6 +756,7 @@ void page_remove_rmap(struct page *page) | |||
| 738 | mem_cgroup_uncharge_page(page); | 756 | mem_cgroup_uncharge_page(page); |
| 739 | __dec_zone_page_state(page, | 757 | __dec_zone_page_state(page, |
| 740 | PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED); | 758 | PageAnon(page) ? NR_ANON_PAGES : NR_FILE_MAPPED); |
| 759 | mem_cgroup_update_mapped_file_stat(page, -1); | ||
| 741 | /* | 760 | /* |
| 742 | * It would be tidy to reset the PageAnon mapping here, | 761 | * It would be tidy to reset the PageAnon mapping here, |
| 743 | * but that might overwrite a racing page_add_anon_rmap | 762 | * but that might overwrite a racing page_add_anon_rmap |
| @@ -1202,7 +1221,6 @@ int try_to_unmap(struct page *page, int migration) | |||
| 1202 | return ret; | 1221 | return ret; |
| 1203 | } | 1222 | } |
| 1204 | 1223 | ||
| 1205 | #ifdef CONFIG_UNEVICTABLE_LRU | ||
| 1206 | /** | 1224 | /** |
| 1207 | * try_to_munlock - try to munlock a page | 1225 | * try_to_munlock - try to munlock a page |
| 1208 | * @page: the page to be munlocked | 1226 | * @page: the page to be munlocked |
| @@ -1226,4 +1244,4 @@ int try_to_munlock(struct page *page) | |||
| 1226 | else | 1244 | else |
| 1227 | return try_to_unmap_file(page, 1, 0); | 1245 | return try_to_unmap_file(page, 1, 0); |
| 1228 | } | 1246 | } |
| 1229 | #endif | 1247 | |
