aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/swap.h1
-rw-r--r--mm/swapfile.c39
2 files changed, 38 insertions, 2 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 9cabb8b21aba..0b9210ea96c7 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -120,6 +120,7 @@ struct swap_extent {
120enum { 120enum {
121 SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ 121 SWP_USED = (1 << 0), /* is slot in swap_info[] used? */
122 SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */ 122 SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */
123 SWP_DISCARDABLE = (1 << 2), /* blkdev supports discard */
123 /* add others here before... */ 124 /* add others here before... */
124 SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */ 125 SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */
125}; 126};
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;