|
@@ -212,7 +212,7 @@ static unsigned long scan_swap_map(struct swap_info_struct *si,
|
|
|
si->cluster_nr = SWAPFILE_CLUSTER - 1;
|
|
|
goto checks;
|
|
|
}
|
|
|
- if (si->flags & SWP_DISCARDABLE) {
|
|
|
+ if (si->flags & SWP_PAGE_DISCARD) {
|
|
|
/*
|
|
|
* Start range check on racing allocations, in case
|
|
|
* they overlap the cluster we eventually decide on
|
|
@@ -322,7 +322,7 @@ checks:
|
|
|
|
|
|
if (si->lowest_alloc) {
|
|
|
/*
|
|
|
- * Only set when SWP_DISCARDABLE, and there's a scan
|
|
|
+ * Only set when SWP_PAGE_DISCARD, and there's a scan
|
|
|
* for a free cluster in progress or just completed.
|
|
|
*/
|
|
|
if (found_free_cluster) {
|
|
@@ -2016,6 +2016,20 @@ static int setup_swap_map_and_extents(struct swap_info_struct *p,
|
|
|
return nr_extents;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Helper to sys_swapon determining if a given swap
|
|
|
+ * backing device queue supports DISCARD operations.
|
|
|
+ */
|
|
|
+static bool swap_discardable(struct swap_info_struct *si)
|
|
|
+{
|
|
|
+ struct request_queue *q = bdev_get_queue(si->bdev);
|
|
|
+
|
|
|
+ if (!q || !blk_queue_discard(q))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
|
|
{
|
|
|
struct swap_info_struct *p;
|
|
@@ -2123,8 +2137,37 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
|
|
p->flags |= SWP_SOLIDSTATE;
|
|
|
p->cluster_next = 1 + (prandom_u32() % p->highest_bit);
|
|
|
}
|
|
|
- if ((swap_flags & SWAP_FLAG_DISCARD) && discard_swap(p) == 0)
|
|
|
- p->flags |= SWP_DISCARDABLE;
|
|
|
+
|
|
|
+ if ((swap_flags & SWAP_FLAG_DISCARD) && swap_discardable(p)) {
|
|
|
+ /*
|
|
|
+ * When discard is enabled for swap with no particular
|
|
|
+ * policy flagged, we set all swap discard flags here in
|
|
|
+ * order to sustain backward compatibility with older
|
|
|
+ * swapon(8) releases.
|
|
|
+ */
|
|
|
+ p->flags |= (SWP_DISCARDABLE | SWP_AREA_DISCARD |
|
|
|
+ SWP_PAGE_DISCARD);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * By flagging sys_swapon, a sysadmin can tell us to
|
|
|
+ * either do single-time area discards only, or to just
|
|
|
+ * perform discards for released swap page-clusters.
|
|
|
+ * Now it's time to adjust the p->flags accordingly.
|
|
|
+ */
|
|
|
+ if (swap_flags & SWAP_FLAG_DISCARD_ONCE)
|
|
|
+ p->flags &= ~SWP_PAGE_DISCARD;
|
|
|
+ else if (swap_flags & SWAP_FLAG_DISCARD_PAGES)
|
|
|
+ p->flags &= ~SWP_AREA_DISCARD;
|
|
|
+
|
|
|
+ /* issue a swapon-time discard if it's still required */
|
|
|
+ if (p->flags & SWP_AREA_DISCARD) {
|
|
|
+ int err = discard_swap(p);
|
|
|
+ if (unlikely(err))
|
|
|
+ printk(KERN_ERR
|
|
|
+ "swapon: discard_swap(%p): %d\n",
|
|
|
+ p, err);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
mutex_lock(&swapon_mutex);
|
|
@@ -2135,11 +2178,13 @@ SYSCALL_DEFINE2(swapon, const char __user *, specialfile, int, swap_flags)
|
|
|
enable_swap_info(p, prio, swap_map, frontswap_map);
|
|
|
|
|
|
printk(KERN_INFO "Adding %uk swap on %s. "
|
|
|
- "Priority:%d extents:%d across:%lluk %s%s%s\n",
|
|
|
+ "Priority:%d extents:%d across:%lluk %s%s%s%s%s\n",
|
|
|
p->pages<<(PAGE_SHIFT-10), name->name, p->prio,
|
|
|
nr_extents, (unsigned long long)span<<(PAGE_SHIFT-10),
|
|
|
(p->flags & SWP_SOLIDSTATE) ? "SS" : "",
|
|
|
(p->flags & SWP_DISCARDABLE) ? "D" : "",
|
|
|
+ (p->flags & SWP_AREA_DISCARD) ? "s" : "",
|
|
|
+ (p->flags & SWP_PAGE_DISCARD) ? "c" : "",
|
|
|
(frontswap_map) ? "FS" : "");
|
|
|
|
|
|
mutex_unlock(&swapon_mutex);
|