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