Introduce the necessary changes to swapon(8) allowing a sysadmin to leverage the new changes introduced to sys_swapon by "swap: discard while swapping only if SWAP_FLAG_DISCARD_PAGES", therefore allowing a more flexible set of choices when selection the discard policy for mounted swap areas. This patch introduces the following optional arguments to the already existent swapon(8) "--discard" option, in order to allow a discard type to be selected at swapon time: * once : only single-time area discards are issued. (swapon) * pages : discard freed pages before they are reused. If no policy is selected both discard types are enabled. (default) Signed-off-by: Rafael Aquini <aquini@xxxxxxxxxx> --- sys-utils/swapon.8 | 24 +++++++++++++------ sys-utils/swapon.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 77 insertions(+), 17 deletions(-) diff --git a/sys-utils/swapon.8 b/sys-utils/swapon.8 index 385bf5a..17f7970 100644 --- a/sys-utils/swapon.8 +++ b/sys-utils/swapon.8 @@ -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 long option \-\-discard 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 --git a/sys-utils/swapon.c b/sys-utils/swapon.c index f1e2433..8a90bfe 100644 --- a/sys-utils/swapon.c +++ b/sys-utils/swapon.c @@ -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 = 0; /* don't send swap discards by default */ /* If true, don't complain if the device/file doesn't exist */ static int ifexists; @@ -570,8 +581,22 @@ static int do_swapon(const char *orig_special, int prio, << 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) @@ -611,12 +636,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) @@ -647,7 +682,7 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out) fputs(USAGE_OPTIONS, out); fputs(_(" -a, --all enable all swaps from /etc/fstab\n" - " -d, --discard discard freed pages before they are reused\n" + " -d, --discard[=policy] 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 <prio> specify the priority of the swap device\n" @@ -672,6 +707,11 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out) " <device> name of device to be used\n" " <file> 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)); @@ -696,7 +736,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' }, @@ -739,7 +779,17 @@ int main(int argc, char *argv[]) add_uuid(optarg); break; case 'd': - discard = 1; + discard |= SWAP_FLAG_DISCARD; + + if (optarg) { + /* only single-time discards are wanted */ + if (strcmp(optarg, "once") == 0) + discard |= SWAP_FLAG_DISCARD_ONCE; + + /* do discard for every released swap page */ + if (strcmp(optarg, "pages") == 0) + discard |= SWAP_FLAG_DISCARD_PAGES; + } break; case 'e': /* ifexists */ ifexists = 1; -- 1.8.1.4 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>