]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
swapon: allow a more flexible swap discard policy
authorRafael Aquini <aquini@redhat.com>
Sun, 26 May 2013 04:31:56 +0000 (01:31 -0300)
committerKarel Zak <kzak@redhat.com>
Fri, 23 Aug 2013 10:50:39 +0000 (12:50 +0200)
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)

[kzak@redhat.com: - support <policy> argument for short -d option too,
                  - add errx() on unsupported policy name]

Signed-off-by: Rafael Aquini <aquini@redhat.com>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
sys-utils/swapon.8
sys-utils/swapon.c

index 385bf5aea421873f34a9c317dfb9dfdad4979c40..836b17277625536bfde19b2165414900ef2984a8 100644 (file)
@@ -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.
index cc9bdbc836413ba00720becaccebdfebc89555a9..572636a187e24f97b675130f37a4cdf1fe8e29ec 100644 (file)
 #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;
@@ -572,8 +583,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)
@@ -613,12 +638,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)
@@ -648,17 +683,17 @@ static void __attribute__ ((__noreturn__)) usage(FILE * out)
        fprintf(out, _(" %s [options] [<spec>]\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 <prio>  specify the priority of the swap device\n"
-               " -s, --summary          display summary about used swap devices\n"
-               "     --show[=<columns>] 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[=<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"
+               " -s, --summary            display summary about used swap devices\n"
+               "     --show[=<columns>]   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);
@@ -674,6 +709,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));
@@ -698,7 +738,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' },
@@ -721,7 +761,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 */
@@ -741,7 +781,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;