aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorHugh Dickins <hugh@veritas.com>2009-01-06 17:39:51 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-06 18:59:05 -0500
commit6a6ba83175c029c7820765bae44692266b29e67a (patch)
tree30bfb4938c73b715eb90dd15c09777fe0bbf93e6 /mm
parentebebbbe904634b0ca1c674457b399f68db5e05b1 (diff)
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>
Diffstat (limited to 'mm')
-rw-r--r--mm/swapfile.c39
1 files changed, 37 insertions, 2 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 4d9855f86e7d..fbeb4bb8eb50 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -84,6 +84,37 @@ void swap_unplug_io_fn(struct backing_dev_info *unused_bdi, struct page *page)
84 up_read(&swap_unplug_sem); 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 */
91static 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#define SWAPFILE_CLUSTER 256 118#define SWAPFILE_CLUSTER 256
88#define LATENCY_LIMIT 256 119#define LATENCY_LIMIT 256
89 120
@@ -1658,6 +1689,9 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
1658 goto bad_swap; 1689 goto bad_swap;
1659 } 1690 }
1660 1691
1692 if (discard_swap(p) == 0)
1693 p->flags |= SWP_DISCARDABLE;
1694
1661 mutex_lock(&swapon_mutex); 1695 mutex_lock(&swapon_mutex);
1662 spin_lock(&swap_lock); 1696 spin_lock(&swap_lock);
1663 if (swap_flags & SWAP_FLAG_PREFER) 1697 if (swap_flags & SWAP_FLAG_PREFER)
@@ -1671,9 +1705,10 @@ asmlinkage long sys_swapon(const char __user * specialfile, int swap_flags)
1671 total_swap_pages += nr_good_pages; 1705 total_swap_pages += nr_good_pages;
1672 1706
1673 printk(KERN_INFO "Adding %uk swap on %s. " 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 nr_good_pages<<(PAGE_SHIFT-10), name, p->prio, 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 /* insert swap space into swap_list: */ 1713 /* insert swap space into swap_list: */
1679 prev = -1; 1714 prev = -1;