Commit 6a6ba83175c029c7820765bae44692266b29e67a
Committed by
Linus Torvalds
1 parent
ebebbbe904
Exists in
master
and in
4 other branches
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 | }; |
mm/swapfile.c
... | ... | @@ -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; |