diff options
Diffstat (limited to 'mm/swapfile.c')
-rw-r--r-- | mm/swapfile.c | 55 |
1 files changed, 50 insertions, 5 deletions
diff --git a/mm/swapfile.c b/mm/swapfile.c index 746af55b8455..36af6eeaa67e 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -212,7 +212,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si, | |||
212 | si->cluster_nr = SWAPFILE_CLUSTER - 1; | 212 | si->cluster_nr = SWAPFILE_CLUSTER - 1; |
213 | goto checks; | 213 | goto checks; |
214 | } | 214 | } |
215 | if (si->flags & SWP_DISCARDABLE) { | 215 | if (si->flags & SWP_PAGE_DISCARD) { |
216 | /* | 216 | /* |
217 | * Start range check on racing allocations, in case | 217 | * Start range check on racing allocations, in case |
218 | * they overlap the cluster we eventually decide on | 218 | * they overlap the cluster we eventually decide on |
@@ -322,7 +322,7 @@ checks: | |||
322 | 322 | ||
323 | if (si->lowest_alloc) { | 323 | if (si->lowest_alloc) { |
324 | /* | 324 | /* |
325 | * Only set when SWP_DISCARDABLE, and there's a scan | 325 | * Only set when SWP_PAGE_DISCARD, and there's a scan |
326 | * for a free cluster in progress or just completed. | 326 | * for a free cluster in progress or just completed. |
327 | */ | 327 | */ |
328 | if (found_free_cluster) { | 328 | if (found_free_cluster) { |
@@ -2016,6 +2016,20 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p, | |||
2016 | return nr_extents; | 2016 | return nr_extents; |
2017 | } | 2017 | } |
2018 | 2018 | ||
2019 | /* | ||
2020 | * Helper to sys_swapon determining if a given swap | ||
2021 | * backing device queue supports DISCARD operations. | ||
2022 | */ | ||
2023 | static bool swap_discardable(struct swap_info_struct *si) | ||
2024 | { | ||
2025 | struct request_queue *q = bdev_get_queue(si->bdev); | ||
2026 | |||
2027 | if (!q || !blk_queue_discard(q)) | ||
2028 | return false; | ||
2029 | |||
2030 | return true; | ||
2031 | } | ||
2032 | |||
2019 | SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | 2033 | SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) |
2020 | { | 2034 | { |
2021 | struct swap_info_struct *p; | 2035 | struct swap_info_struct *p; |
@@ -2123,8 +2137,37 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
2123 | p->flags |= SWP_SOLIDSTATE; | 2137 | p->flags |= SWP_SOLIDSTATE; |
2124 | p->cluster_next = 1 + (prandom_u32() % p->highest_bit); | 2138 | p->cluster_next = 1 + (prandom_u32() % p->highest_bit); |
2125 | } | 2139 | } |
2126 | if ((swap_flags & SWAP_FLAG_DISCARD) && discard_swap(p) == 0) | 2140 | |
2127 | p->flags |= SWP_DISCARDABLE; | 2141 | if ((swap_flags & SWAP_FLAG_DISCARD) && swap_discardable(p)) { |
2142 | /* | ||
2143 | * When discard is enabled for swap with no particular | ||
2144 | * policy flagged, we set all swap discard flags here in | ||
2145 | * order to sustain backward compatibility with older | ||
2146 | * swapon(8) releases. | ||
2147 | */ | ||
2148 | p->flags |= (SWP_DISCARDABLE | SWP_AREA_DISCARD | | ||
2149 | SWP_PAGE_DISCARD); | ||
2150 | |||
2151 | /* | ||
2152 | * By flagging sys_swapon, a sysadmin can tell us to | ||
2153 | * either do single-time area discards only, or to just | ||
2154 | * perform discards for released swap page-clusters. | ||
2155 | * Now it's time to adjust the p->flags accordingly. | ||
2156 | */ | ||
2157 | if (swap_flags & SWAP_FLAG_DISCARD_ONCE) | ||
2158 | p->flags &= ~SWP_PAGE_DISCARD; | ||
2159 | else if (swap_flags & SWAP_FLAG_DISCARD_PAGES) | ||
2160 | p->flags &= ~SWP_AREA_DISCARD; | ||
2161 | |||
2162 | /* issue a swapon-time discard if it's still required */ | ||
2163 | if (p->flags & SWP_AREA_DISCARD) { | ||
2164 | int err = discard_swap(p); | ||
2165 | if (unlikely(err)) | ||
2166 | printk(KERN_ERR | ||
2167 | "swapon: discard_swap(%p): %d\n", | ||
2168 | p, err); | ||
2169 | } | ||
2170 | } | ||
2128 | } | 2171 | } |
2129 | 2172 | ||
2130 | mutex_lock(&swapon_mutex); | 2173 | mutex_lock(&swapon_mutex); |
@@ -2135,11 +2178,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags) | |||
2135 | enable_swap_info(p, prio, swap_map, frontswap_map); | 2178 | enable_swap_info(p, prio, swap_map, frontswap_map); |
2136 | 2179 | ||
2137 | printk(KERN_INFO "Adding %uk swap on %s. " | 2180 | printk(KERN_INFO "Adding %uk swap on %s. " |
2138 | "Priority:%d extents:%d across:%lluk %s%s%s\n", | 2181 | "Priority:%d extents:%d across:%lluk %s%s%s%s%s\n", |
2139 | p->pages<<(PAGE_SHIFT-10), name->name, p->prio, | 2182 | p->pages<<(PAGE_SHIFT-10), name->name, p->prio, |
2140 | nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), | 2183 | nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10), |
2141 | (p->flags & SWP_SOLIDSTATE) ? "SS" : "", | 2184 | (p->flags & SWP_SOLIDSTATE) ? "SS" : "", |
2142 | (p->flags & SWP_DISCARDABLE) ? "D" : "", | 2185 | (p->flags & SWP_DISCARDABLE) ? "D" : "", |
2186 | (p->flags & SWP_AREA_DISCARD) ? "s" : "", | ||
2187 | (p->flags & SWP_PAGE_DISCARD) ? "c" : "", | ||
2143 | (frontswap_map) ? "FS" : ""); | 2188 | (frontswap_map) ? "FS" : ""); |
2144 | 2189 | ||
2145 | mutex_unlock(&swapon_mutex); | 2190 | mutex_unlock(&swapon_mutex); |