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 | } |