diff options
Diffstat (limited to 'mm/swapfile.c')
| -rw-r--r-- | mm/swapfile.c | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index 1e330f2998fa..90cb67a5417c 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
| @@ -344,7 +344,7 @@ int can_share_swap_page(struct page *page) | |||
| 344 | * Work out if there are any other processes sharing this | 344 | * Work out if there are any other processes sharing this |
| 345 | * swap cache page. Free it if you can. Return success. | 345 | * swap cache page. Free it if you can. Return success. |
| 346 | */ | 346 | */ |
| 347 | int remove_exclusive_swap_page(struct page *page) | 347 | static int remove_exclusive_swap_page_count(struct page *page, int count) |
| 348 | { | 348 | { |
| 349 | int retval; | 349 | int retval; |
| 350 | struct swap_info_struct * p; | 350 | struct swap_info_struct * p; |
| @@ -357,7 +357,7 @@ int remove_exclusive_swap_page(struct page *page) | |||
| 357 | return 0; | 357 | return 0; |
| 358 | if (PageWriteback(page)) | 358 | if (PageWriteback(page)) |
| 359 | return 0; | 359 | return 0; |
| 360 | if (page_count(page) != 2) /* 2: us + cache */ | 360 | if (page_count(page) != count) /* us + cache + ptes */ |
| 361 | return 0; | 361 | return 0; |
| 362 | 362 | ||
| 363 | entry.val = page_private(page); | 363 | entry.val = page_private(page); |
| @@ -370,7 +370,7 @@ int remove_exclusive_swap_page(struct page *page) | |||
| 370 | if (p->swap_map[swp_offset(entry)] == 1) { | 370 | if (p->swap_map[swp_offset(entry)] == 1) { |
| 371 | /* Recheck the page count with the swapcache lock held.. */ | 371 | /* Recheck the page count with the swapcache lock held.. */ |
| 372 | spin_lock_irq(&swapper_space.tree_lock); | 372 | spin_lock_irq(&swapper_space.tree_lock); |
| 373 | if ((page_count(page) == 2) && !PageWriteback(page)) { | 373 | if ((page_count(page) == count) && !PageWriteback(page)) { |
| 374 | __delete_from_swap_cache(page); | 374 | __delete_from_swap_cache(page); |
| 375 | SetPageDirty(page); | 375 | SetPageDirty(page); |
| 376 | retval = 1; | 376 | retval = 1; |
| @@ -388,6 +388,25 @@ int remove_exclusive_swap_page(struct page *page) | |||
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | /* | 390 | /* |
| 391 | * Most of the time the page should have two references: one for the | ||
| 392 | * process and one for the swap cache. | ||
| 393 | */ | ||
| 394 | int remove_exclusive_swap_page(struct page *page) | ||
| 395 | { | ||
| 396 | return remove_exclusive_swap_page_count(page, 2); | ||
| 397 | } | ||
| 398 | |||
| 399 | /* | ||
| 400 | * The pageout code holds an extra reference to the page. That raises | ||
| 401 | * the reference count to test for to 2 for a page that is only in the | ||
| 402 | * swap cache plus 1 for each process that maps the page. | ||
| 403 | */ | ||
| 404 | int remove_exclusive_swap_page_ref(struct page *page) | ||
| 405 | { | ||
| 406 | return remove_exclusive_swap_page_count(page, 2 + page_mapcount(page)); | ||
| 407 | } | ||
| 408 | |||
| 409 | /* | ||
| 391 | * Free the swap entry like above, but also try to | 410 | * Free the swap entry like above, but also try to |
| 392 | * free the page cache entry if it is the last user. | 411 | * free the page cache entry if it is the last user. |
| 393 | */ | 412 | */ |
| @@ -403,7 +422,7 @@ void free_swap_and_cache(swp_entry_t entry) | |||
| 403 | if (p) { | 422 | if (p) { |
| 404 | if (swap_entry_free(p, swp_offset(entry)) == 1) { | 423 | if (swap_entry_free(p, swp_offset(entry)) == 1) { |
| 405 | page = find_get_page(&swapper_space, entry.val); | 424 | page = find_get_page(&swapper_space, entry.val); |
| 406 | if (page && unlikely(!trylock_page(page))) { | 425 | if (page && !trylock_page(page)) { |
| 407 | page_cache_release(page); | 426 | page_cache_release(page); |
| 408 | page = NULL; | 427 | page = NULL; |
| 409 | } | 428 | } |
