Commit 6a6ba83175c029c7820765bae44692266b29e67a

Authored by Hugh Dickins
Committed by Linus Torvalds
1 parent ebebbbe904

swapfile: swapon use discard (trim)

When adding swap, all the old data on swap can be forgotten: sys_swapon()
discard all but the header page of the swap partition (or every extent but
the header of the swap file), to give a solidstate swap device the
opportunity to optimize its wear-levelling.

If that succeeds, note SWP_DISCARDABLE for later use, and report it with a
"D" at the right end of the kernel's "Adding ...  swap" message.  Perhaps
something should be shown in /proc/swaps (swapon -s), but we have to be
more cautious before making any addition to that format.

Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: David Woodhouse <dwmw2@infradead.org>
Cc: Jens Axboe <jens.axboe@oracle.com>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: Joern Engel <joern@logfs.org>
Cc: James Bottomley <James.Bottomley@HansenPartnership.com>
Cc: Donjun Shin <djshin90@gmail.com>
Cc: Tejun Heo <teheo@suse.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 38 additions and 2 deletions Side-by-side Diff

include/linux/swap.h
... ... @@ -120,6 +120,7 @@
120 120 enum {
121 121 SWP_USED = (1 << 0), /* is slot in swap_info[] used? */
122 122 SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */
  123 + SWP_DISCARDABLE = (1 << 2), /* blkdev supports discard */
123 124 /* add others here before... */
124 125 SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */
125 126 };
... ... @@ -84,6 +84,37 @@
84 84 up_read(&swap_unplug_sem);
85 85 }
86 86  
  87 +/*
  88 + * swapon tell device that all the old swap contents can be discarded,
  89 + * to allow the swap device to optimize its wear-levelling.
  90 + */
  91 +static int discard_swap(struct swap_info_struct *si)
  92 +{
  93 + struct swap_extent *se;
  94 + int err = 0;
  95 +
  96 + list_for_each_entry(se, &si->extent_list, list) {
  97 + sector_t start_block = se->start_block << (PAGE_SHIFT - 9);
  98 + pgoff_t nr_blocks = se->nr_pages << (PAGE_SHIFT - 9);
  99 +
  100 + if (se->start_page == 0) {
  101 + /* Do not discard the swap header page! */
  102 + start_block += 1 << (PAGE_SHIFT - 9);
  103 + nr_blocks -= 1 << (PAGE_SHIFT - 9);
  104 + if (!nr_blocks)
  105 + continue;
  106 + }
  107 +
  108 + err = blkdev_issue_discard(si->bdev, start_block,
  109 + nr_blocks, GFP_KERNEL);
  110 + if (err)
  111 + break;
  112 +
  113 + cond_resched();
  114 + }
  115 + return err; /* That will often be -EOPNOTSUPP */
  116 +}
  117 +
87 118 #define SWAPFILE_CLUSTER 256
88 119 #define LATENCY_LIMIT 256
89 120  
... ... @@ -1658,6 +1689,9 @@
1658 1689 goto bad_swap;
1659 1690 }
1660 1691  
  1692 + if (discard_swap(p) == 0)
  1693 + p->flags |= SWP_DISCARDABLE;
  1694 +
1661 1695 mutex_lock(&swapon_mutex);
1662 1696 spin_lock(&swap_lock);
1663 1697 if (swap_flags & SWAP_FLAG_PREFER)
1664 1698  
... ... @@ -1671,9 +1705,10 @@
1671 1705 total_swap_pages += nr_good_pages;
1672 1706  
1673 1707 printk(KERN_INFO "Adding %uk swap on %s. "
1674   - "Priority:%d extents:%d across:%lluk\n",
  1708 + "Priority:%d extents:%d across:%lluk%s\n",
1675 1709 nr_good_pages<<(PAGE_SHIFT-10), name, p->prio,
1676   - nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10));
  1710 + nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
  1711 + (p->flags & SWP_DISCARDABLE) ? " D" : "");
1677 1712  
1678 1713 /* insert swap space into swap_list: */
1679 1714 prev = -1;