Commit 68a22394c286a2daf06ee8d65d8835f738faefa5
Committed by
Linus Torvalds
1 parent
f04e9ebbe4
Exists in
master
and in
20 other branches
vmscan: free swap space on swap-in/activation
If vm_swap_full() (swap space more than 50% full), the system will free swap space at swapin time. With this patch, the system will also free the swap space in the pageout code, when we decide that the page is not a candidate for swapout (and just wasting swap space). Signed-off-by: Rik van Riel <riel@redhat.com> Signed-off-by: Lee Schermerhorn <Lee.Schermerhorn@hp.com> Signed-off-by: MinChan Kim <minchan.kim@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 5 changed files with 60 additions and 3 deletions Side-by-side Diff
include/linux/pagevec.h
... | ... | @@ -25,6 +25,7 @@ |
25 | 25 | void __pagevec_free(struct pagevec *pvec); |
26 | 26 | void ____pagevec_lru_add(struct pagevec *pvec, enum lru_list lru); |
27 | 27 | void pagevec_strip(struct pagevec *pvec); |
28 | +void pagevec_swap_free(struct pagevec *pvec); | |
28 | 29 | unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, |
29 | 30 | pgoff_t start, unsigned nr_pages); |
30 | 31 | unsigned pagevec_lookup_tag(struct pagevec *pvec, |
include/linux/swap.h
... | ... | @@ -265,6 +265,7 @@ |
265 | 265 | extern struct swap_info_struct *get_swap_info_struct(unsigned); |
266 | 266 | extern int can_share_swap_page(struct page *); |
267 | 267 | extern int remove_exclusive_swap_page(struct page *); |
268 | +extern int remove_exclusive_swap_page_ref(struct page *); | |
268 | 269 | struct backing_dev_info; |
269 | 270 | |
270 | 271 | /* linux/mm/thrash.c */ |
... | ... | @@ -349,6 +350,11 @@ |
349 | 350 | #define swap_token_default_timeout 0 |
350 | 351 | |
351 | 352 | static inline int remove_exclusive_swap_page(struct page *p) |
353 | +{ | |
354 | + return 0; | |
355 | +} | |
356 | + | |
357 | +static inline int remove_exclusive_swap_page_ref(struct page *page) | |
352 | 358 | { |
353 | 359 | return 0; |
354 | 360 | } |
mm/swap.c
... | ... | @@ -428,6 +428,30 @@ |
428 | 428 | } |
429 | 429 | |
430 | 430 | /** |
431 | + * pagevec_swap_free - try to free swap space from the pages in a pagevec | |
432 | + * @pvec: pagevec with swapcache pages to free the swap space of | |
433 | + * | |
434 | + * The caller needs to hold an extra reference to each page and | |
435 | + * not hold the page lock on the pages. This function uses a | |
436 | + * trylock on the page lock so it may not always free the swap | |
437 | + * space associated with a page. | |
438 | + */ | |
439 | +void pagevec_swap_free(struct pagevec *pvec) | |
440 | +{ | |
441 | + int i; | |
442 | + | |
443 | + for (i = 0; i < pagevec_count(pvec); i++) { | |
444 | + struct page *page = pvec->pages[i]; | |
445 | + | |
446 | + if (PageSwapCache(page) && trylock_page(page)) { | |
447 | + if (PageSwapCache(page)) | |
448 | + remove_exclusive_swap_page_ref(page); | |
449 | + unlock_page(page); | |
450 | + } | |
451 | + } | |
452 | +} | |
453 | + | |
454 | +/** | |
431 | 455 | * pagevec_lookup - gang pagecache lookup |
432 | 456 | * @pvec: Where the resulting pages are placed |
433 | 457 | * @mapping: The address_space to search |
mm/swapfile.c
... | ... | @@ -344,7 +344,7 @@ |
344 | 344 | * Work out if there are any other processes sharing this |
345 | 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 | 349 | int retval; |
350 | 350 | struct swap_info_struct * p; |
... | ... | @@ -357,7 +357,7 @@ |
357 | 357 | return 0; |
358 | 358 | if (PageWriteback(page)) |
359 | 359 | return 0; |
360 | - if (page_count(page) != 2) /* 2: us + cache */ | |
360 | + if (page_count(page) != count) /* us + cache + ptes */ | |
361 | 361 | return 0; |
362 | 362 | |
363 | 363 | entry.val = page_private(page); |
... | ... | @@ -370,7 +370,7 @@ |
370 | 370 | if (p->swap_map[swp_offset(entry)] == 1) { |
371 | 371 | /* Recheck the page count with the swapcache lock held.. */ |
372 | 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 | 374 | __delete_from_swap_cache(page); |
375 | 375 | SetPageDirty(page); |
376 | 376 | retval = 1; |
... | ... | @@ -385,6 +385,25 @@ |
385 | 385 | } |
386 | 386 | |
387 | 387 | return retval; |
388 | +} | |
389 | + | |
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)); | |
388 | 407 | } |
389 | 408 | |
390 | 409 | /* |
mm/vmscan.c
... | ... | @@ -647,6 +647,9 @@ |
647 | 647 | continue; |
648 | 648 | |
649 | 649 | activate_locked: |
650 | + /* Not a candidate for swapping, so reclaim swap space. */ | |
651 | + if (PageSwapCache(page) && vm_swap_full()) | |
652 | + remove_exclusive_swap_page_ref(page); | |
650 | 653 | SetPageActive(page); |
651 | 654 | pgactivate++; |
652 | 655 | keep_locked: |
... | ... | @@ -1228,6 +1231,8 @@ |
1228 | 1231 | __mod_zone_page_state(zone, NR_ACTIVE, pgmoved); |
1229 | 1232 | pgmoved = 0; |
1230 | 1233 | spin_unlock_irq(&zone->lru_lock); |
1234 | + if (vm_swap_full()) | |
1235 | + pagevec_swap_free(&pvec); | |
1231 | 1236 | __pagevec_release(&pvec); |
1232 | 1237 | spin_lock_irq(&zone->lru_lock); |
1233 | 1238 | } |
... | ... | @@ -1237,6 +1242,8 @@ |
1237 | 1242 | __count_zone_vm_events(PGREFILL, zone, pgscanned); |
1238 | 1243 | __count_vm_events(PGDEACTIVATE, pgdeactivate); |
1239 | 1244 | spin_unlock_irq(&zone->lru_lock); |
1245 | + if (vm_swap_full()) | |
1246 | + pagevec_swap_free(&pvec); | |
1240 | 1247 | |
1241 | 1248 | pagevec_release(&pvec); |
1242 | 1249 | } |