Commit 68a22394c286a2daf06ee8d65d8835f738faefa5

Authored by Rik van Riel
Committed by Linus Torvalds
1 parent f04e9ebbe4

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 }
... ... @@ -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
... ... @@ -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 /*
... ... @@ -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 }