3df8c3
diff -up util-linux-2.23.2/sys-utils/swapon.8.kzak util-linux-2.23.2/sys-utils/swapon.8
3df8c3
--- util-linux-2.23.2/sys-utils/swapon.8.kzak	2013-06-13 09:46:10.544651682 +0200
3df8c3
+++ util-linux-2.23.2/sys-utils/swapon.8	2014-09-24 10:57:45.855230767 +0200
3df8c3
@@ -112,15 +112,25 @@ All devices marked as ``swap'' in
3df8c3
 are made available, except for those with the ``noauto'' option.
3df8c3
 Devices that are already being used as swap are silently skipped.
3df8c3
 .TP
3df8c3
-.B "\-d, \-\-discard"
3df8c3
-Discard freed swap pages before they are reused, if the swap
3df8c3
-device supports the discard or trim operation.  This may improve
3df8c3
-performance on some Solid State Devices, but often it does not.
3df8c3
+.B "\-d, \-\-discard\fR [=\fIpolicy\fR]"
3df8c3
+Enable swap discards, if the swap backing device supports the discard or
3df8c3
+trim operation. This may improve performance on some Solid State Devices,
3df8c3
+but often it does not. The option allows one to select between two
3df8c3
+available swap discard policies:
3df8c3
+.BI \-\-discard=once
3df8c3
+to perform a single-time discard operation for the whole swap area at swapon;
3df8c3
+or
3df8c3
+.BI \-\-discard=pages
3df8c3
+to discard freed swap pages before they are reused, while swapping.
3df8c3
+If no policy is selected, the default behavior is to enable both discard types.
3df8c3
 The
3df8c3
 .I /etc/fstab
3df8c3
-mount option
3df8c3
-.BI discard
3df8c3
-may be also used to enable discard flag.
3df8c3
+mount options
3df8c3
+.BI discard,
3df8c3
+.BI discard=once,
3df8c3
+or
3df8c3
+.BI discard=pages
3df8c3
+may be also used to enable discard flags.
3df8c3
 .TP
3df8c3
 .B "\-e, \-\-ifexists"
3df8c3
 Silently skip devices that do not exist.
3df8c3
diff -up util-linux-2.23.2/sys-utils/swapon.c.kzak util-linux-2.23.2/sys-utils/swapon.c
3df8c3
--- util-linux-2.23.2/sys-utils/swapon.c.kzak	2013-07-30 10:39:26.348739643 +0200
3df8c3
+++ util-linux-2.23.2/sys-utils/swapon.c	2014-09-24 10:57:45.855230767 +0200
3df8c3
@@ -34,9 +34,20 @@
3df8c3
 #endif
3df8c3
 
3df8c3
 #ifndef SWAP_FLAG_DISCARD
3df8c3
-# define SWAP_FLAG_DISCARD	0x10000 /* discard swap cluster after use */
3df8c3
+# define SWAP_FLAG_DISCARD	0x10000 /* enable discard for swap */
3df8c3
 #endif
3df8c3
 
3df8c3
+#ifndef SWAP_FLAG_DISCARD_ONCE
3df8c3
+# define SWAP_FLAG_DISCARD_ONCE 0x20000 /* discard swap area at swapon-time */
3df8c3
+#endif
3df8c3
+
3df8c3
+#ifndef SWAP_FLAG_DISCARD_PAGES
3df8c3
+# define SWAP_FLAG_DISCARD_PAGES 0x40000 /* discard page-clusters after use */
3df8c3
+#endif
3df8c3
+
3df8c3
+#define SWAP_FLAGS_DISCARD_VALID (SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | \
3df8c3
+				  SWAP_FLAG_DISCARD_PAGES)
3df8c3
+
3df8c3
 #ifndef SWAP_FLAG_PREFER
3df8c3
 # define SWAP_FLAG_PREFER	0x8000	/* set if swap priority specified */
3df8c3
 #endif
3df8c3
@@ -70,7 +81,7 @@ enum {
3df8c3
 
3df8c3
 static int all;
3df8c3
 static int priority = -1;	/* non-prioritized swap by default */
3df8c3
-static int discard;
3df8c3
+static int discard;		/* don't send swap discards by default */
3df8c3
 
3df8c3
 /* If true, don't complain if the device/file doesn't exist */
3df8c3
 static int ifexists;
3df8c3
@@ -567,8 +578,22 @@ static int do_swapon(const char *orig_sp
3df8c3
 			   << SWAP_FLAG_PRIO_SHIFT);
3df8c3
 	}
3df8c3
 #endif
3df8c3
-	if (fl_discard)
3df8c3
-		flags |= SWAP_FLAG_DISCARD;
3df8c3
+	/*
3df8c3
+	 * Validate the discard flags passed and set them
3df8c3
+	 * accordingly before calling sys_swapon.
3df8c3
+	 */
3df8c3
+	if (fl_discard && !(fl_discard & ~SWAP_FLAGS_DISCARD_VALID)) {
3df8c3
+		/*
3df8c3
+		 * If we get here with both discard policy flags set,
3df8c3
+		 * we just need to tell the kernel to enable discards
3df8c3
+		 * and it will do correctly, just as we expect.
3df8c3
+		 */
3df8c3
+		if ((fl_discard & SWAP_FLAG_DISCARD_ONCE) &&
3df8c3
+		    (fl_discard & SWAP_FLAG_DISCARD_PAGES))
3df8c3
+			flags |= SWAP_FLAG_DISCARD;
3df8c3
+		else
3df8c3
+			flags |= fl_discard;
3df8c3
+	}
3df8c3
 
3df8c3
 	status = swapon(special, flags);
3df8c3
 	if (status < 0)
3df8c3
@@ -608,12 +633,22 @@ static int swapon_all(void)
3df8c3
 	while (mnt_table_find_next_fs(tb, itr, match_swap, NULL, &fs) == 0) {
3df8c3
 		/* defaults */
3df8c3
 		int pri = priority, dsc = discard, nofail = ifexists;
3df8c3
-		char *p, *src;
3df8c3
+		char *p, *src, *dscarg;
3df8c3
 
3df8c3
 		if (mnt_fs_get_option(fs, "noauto", NULL, NULL) == 0)
3df8c3
 			continue;
3df8c3
-		if (mnt_fs_get_option(fs, "discard", NULL, NULL) == 0)
3df8c3
-			dsc = 1;
3df8c3
+		if (mnt_fs_get_option(fs, "discard", &dscarg, NULL) == 0) {
3df8c3
+			dsc |= SWAP_FLAG_DISCARD;
3df8c3
+			if (dscarg) {
3df8c3
+				/* only single-time discards are wanted */
3df8c3
+				if (strcmp(dscarg, "once") == 0)
3df8c3
+					dsc |= SWAP_FLAG_DISCARD_ONCE;
3df8c3
+
3df8c3
+				/* do discard for every released swap page */
3df8c3
+				if (strcmp(dscarg, "pages") == 0)
3df8c3
+					dsc |= SWAP_FLAG_DISCARD_PAGES;
3df8c3
+			}
3df8c3
+		}
3df8c3
 		if (mnt_fs_get_option(fs, "nofail", NULL, NULL) == 0)
3df8c3
 			nofail = 1;
3df8c3
 		if (mnt_fs_get_option(fs, "pri", &p, NULL) == 0 && p)
3df8c3
@@ -643,17 +678,17 @@ static void __attribute__ ((__noreturn__
3df8c3
 	fprintf(out, _(" %s [options] [<spec>]\n"), program_invocation_short_name);
3df8c3
 
3df8c3
 	fputs(USAGE_OPTIONS, out);
3df8c3
-	fputs(_(" -a, --all              enable all swaps from /etc/fstab\n"
3df8c3
-		" -d, --discard          discard freed pages before they are reused\n"
3df8c3
-		" -e, --ifexists         silently skip devices that do not exist\n"
3df8c3
-		" -f, --fixpgsz          reinitialize the swap space if necessary\n"
3df8c3
-		" -p, --priority <prio>  specify the priority of the swap device\n"
3df8c3
-		" -s, --summary          display summary about used swap devices\n"
3df8c3
-		"     --show[=<columns>] display summary in definable table\n"
3df8c3
-		"     --noheadings       don't print headings, use with --show\n"
3df8c3
-		"     --raw              use the raw output format, use with --show\n"
3df8c3
-		"     --bytes            display swap size in bytes in --show output\n"
3df8c3
-		" -v, --verbose          verbose mode\n"), out);
3df8c3
+	fputs(_(" -a, --all                enable all swaps from /etc/fstab\n"
3df8c3
+		" -d, --discard[=<policy>] enable swap discards, if supported by device\n"
3df8c3
+		" -e, --ifexists           silently skip devices that do not exist\n"
3df8c3
+		" -f, --fixpgsz            reinitialize the swap space if necessary\n"
3df8c3
+		" -p, --priority <prio>    specify the priority of the swap device\n"
3df8c3
+		" -s, --summary            display summary about used swap devices\n"
3df8c3
+		"     --show[=<columns>]   display summary in definable table\n"
3df8c3
+		"     --noheadings         don't print headings, use with --show\n"
3df8c3
+		"     --raw                use the raw output format, use with --show\n"
3df8c3
+		"     --bytes              display swap size in bytes in --show output\n"
3df8c3
+		" -v, --verbose            verbose mode\n"), out);
3df8c3
 
3df8c3
 	fputs(USAGE_SEPARATOR, out);
3df8c3
 	fputs(USAGE_HELP, out);
3df8c3
@@ -669,6 +704,11 @@ static void __attribute__ ((__noreturn__
3df8c3
 		" <device>               name of device to be used\n"
3df8c3
 		" <file>                 name of file to be used\n"), out);
3df8c3
 
3df8c3
+	fputs(_("\nAvailable discard policy types (for --discard):\n"
3df8c3
+		" once	  : only single-time area discards are issued. (swapon)\n"
3df8c3
+		" pages	  : discard freed pages before they are reused.\n"
3df8c3
+		" * if no policy is selected both discard types are enabled. (default)\n"), out);
3df8c3
+
3df8c3
 	fputs(_("\nAvailable columns (for --show):\n"), out);
3df8c3
 	for (i = 0; i < NCOLS; i++)
3df8c3
 		fprintf(out, " %4s  %s\n", infos[i].name, _(infos[i].help));
3df8c3
@@ -693,7 +733,7 @@ int main(int argc, char *argv[])
3df8c3
 
3df8c3
 	static const struct option long_opts[] = {
3df8c3
 		{ "priority", 1, 0, 'p' },
3df8c3
-		{ "discard",  0, 0, 'd' },
3df8c3
+		{ "discard",  2, 0, 'd' },
3df8c3
 		{ "ifexists", 0, 0, 'e' },
3df8c3
 		{ "summary",  0, 0, 's' },
3df8c3
 		{ "fixpgsz",  0, 0, 'f' },
3df8c3
@@ -716,7 +756,7 @@ int main(int argc, char *argv[])
3df8c3
 	mnt_init_debug(0);
3df8c3
 	mntcache = mnt_new_cache();
3df8c3
 
3df8c3
-	while ((c = getopt_long(argc, argv, "ahdefp:svVL:U:",
3df8c3
+	while ((c = getopt_long(argc, argv, "ahd::efp:svVL:U:",
3df8c3
 				long_opts, NULL)) != -1) {
3df8c3
 		switch (c) {
3df8c3
 		case 'a':		/* all */
3df8c3
@@ -736,7 +776,18 @@ int main(int argc, char *argv[])
3df8c3
 			add_uuid(optarg);
3df8c3
 			break;
3df8c3
 		case 'd':
3df8c3
-			discard = 1;
3df8c3
+			discard |= SWAP_FLAG_DISCARD;
3df8c3
+			if (optarg) {
3df8c3
+				if (*optarg == '=')
3df8c3
+					optarg++;
3df8c3
+
3df8c3
+				if (strcmp(optarg, "once") == 0)
3df8c3
+					discard |= SWAP_FLAG_DISCARD_ONCE;
3df8c3
+				else if (strcmp(optarg, "pages") == 0)
3df8c3
+					discard |= SWAP_FLAG_DISCARD_PAGES;
3df8c3
+				else
3df8c3
+					errx(EXIT_FAILURE, _("unsupported discard policy: %s"), optarg);
3df8c3
+			}
3df8c3
 			break;
3df8c3
 		case 'e':               /* ifexists */
3df8c3
 		        ifexists = 1;