diff options
-rw-r--r-- | include/linux/swap.h | 1 | ||||
-rw-r--r-- | mm/swapfile.c | 39 |
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 { | |||
120 | enum { | 120 | enum { |
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 | */ | ||
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; |