diff options
author | Hugh Dickins <hugh@veritas.com> | 2009-01-06 17:39:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 18:59:05 -0500 |
commit | 6a6ba83175c029c7820765bae44692266b29e67a (patch) | |
tree | 30bfb4938c73b715eb90dd15c09777fe0bbf93e6 /mm | |
parent | ebebbbe904634b0ca1c674457b399f68db5e05b1 (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.c | 39 |
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 | */ | ||
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 | #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; |