diff --git a/util-linux/Config.src b/util-linux/Config.src index 5a8b0063b..c1cd6daa4 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -599,6 +599,15 @@ config SWAPONOFF space. If you are not using any swap space, you can leave this option disabled. +config FEATURE_SWAPON_DISCARD + bool "Support discard option -d" + default y + depends on SWAPONOFF + help + Enable support for discarding swap area blocks at swapon and/or as + the kernel frees them. This option enables both the -d option on + 'swapon' and the 'discard' option for swap entries in /etc/fstab. + config FEATURE_SWAPON_PRI bool "Support priority option -p" default y diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c index d5bfe1888..a7ad6db79 100644 --- a/util-linux/swaponoff.c +++ b/util-linux/swaponoff.c @@ -8,10 +8,14 @@ */ //usage:#define swapon_trivial_usage -//usage: "[-a]" IF_FEATURE_SWAPON_PRI(" [-p PRI]") " [DEVICE]" +//usage: "[-a]" IF_FEATURE_SWAPON_DISCARD(" [-d[POL]]") IF_FEATURE_SWAPON_PRI(" [-p PRI]") " [DEVICE]" //usage:#define swapon_full_usage "\n\n" //usage: "Start swapping on DEVICE\n" //usage: "\n -a Start swapping on all swap devices" +//usage: IF_FEATURE_SWAPON_DISCARD( +//usage: "\n -d[POL] Discard blocks at swapon (POL=once)," +//usage: "\n as freed (POL=pages), or both (POL omitted)" +//usage: ) //usage: IF_FEATURE_SWAPON_PRI( //usage: "\n -p PRI Set swap device priority" //usage: ) @@ -38,7 +42,22 @@ # define MNTTYPE_SWAP "swap" #endif -#if ENABLE_FEATURE_SWAPON_PRI +#if ENABLE_FEATURE_SWAPON_DISCARD +#ifndef SWAP_FLAG_DISCARD +#define SWAP_FLAG_DISCARD 0x10000 +#endif +#ifndef SWAP_FLAG_DISCARD_ONCE +#define SWAP_FLAG_DISCARD_ONCE 0x20000 +#endif +#ifndef SWAP_FLAG_DISCARD_PAGES +#define SWAP_FLAG_DISCARD_PAGES 0x40000 +#endif +#define SWAP_FLAG_DISCARD_MASK \ + (SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | SWAP_FLAG_DISCARD_PAGES) +#endif + + +#if ENABLE_FEATURE_SWAPON_DISCARD || ENABLE_FEATURE_SWAPON_PRI struct globals { int flags; } FIX_ALIASING; @@ -98,9 +117,23 @@ static int do_em_all(void) if (applet_name[5] != 'n' || hasmntopt(m, MNTOPT_NOAUTO) == NULL ) { -#if ENABLE_FEATURE_SWAPON_PRI +#if ENABLE_FEATURE_SWAPON_DISCARD || ENABLE_FEATURE_SWAPON_PRI char *p; g_flags = cl_flags; /* each swap space might have different flags */ +#if ENABLE_FEATURE_SWAPON_DISCARD + p = hasmntopt(m, "discard"); + if (p) { + if (p[7] == '=') { + if (strncmp(p + 8, "once", 4) == 0 && (p[12] == ',' || p[12] == '\0')) + g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE; + else if (strncmp(p + 8, "pages", 5) == 0 && (p[13] == ',' || p[13] == '\0')) + g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_PAGES; + } + else if (p[7] == ',' || p[7] == '\0') + g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD; + } +#endif +#if ENABLE_FEATURE_SWAPON_PRI p = hasmntopt(m, "pri"); if (p) { /* Max allowed 32767 (== SWAP_FLAG_PRIO_MASK) */ @@ -111,6 +144,7 @@ static int do_em_all(void) MIN(prio, SWAP_FLAG_PRIO_MASK); } } +#endif #endif err += swap_enable_disable(m->mnt_fsname); } @@ -127,24 +161,57 @@ int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int swap_on_off_main(int argc UNUSED_PARAM, char **argv) { int ret; +#if ENABLE_FEATURE_SWAPON_DISCARD + char *discard = NULL; +#endif #if ENABLE_FEATURE_SWAPON_PRI unsigned prio; #endif INIT_G(); -#if !ENABLE_FEATURE_SWAPON_PRI +#if !ENABLE_FEATURE_SWAPON_DISCARD && !ENABLE_FEATURE_SWAPON_PRI ret = getopt32(argv, "a"); #else +#if ENABLE_FEATURE_SWAPON_PRI if (applet_name[5] == 'n') opt_complementary = "p+"; - ret = getopt32(argv, (applet_name[5] == 'n') ? "ap:" : "a", &prio); +#endif + ret = getopt32(argv, (applet_name[5] == 'n') ? +#if ENABLE_FEATURE_SWAPON_DISCARD + "d::" +#endif +#if ENABLE_FEATURE_SWAPON_PRI + "p:" +#endif + "a" : "a" +#if ENABLE_FEATURE_SWAPON_DISCARD + , &discard +#endif +#if ENABLE_FEATURE_SWAPON_PRI + , &prio +#endif + ); +#endif - if (ret & 2) { // -p - g_flags = SWAP_FLAG_PREFER | - MIN(prio, SWAP_FLAG_PRIO_MASK); - ret &= 1; +#if ENABLE_FEATURE_SWAPON_DISCARD + if (ret & 1) { // -d + if (!discard) + g_flags |= SWAP_FLAG_DISCARD; + else if (strcmp(discard, "once") == 0) + g_flags |= SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE; + else if (strcmp(discard, "pages") == 0) + g_flags |= SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_PAGES; + else + bb_show_usage(); } + ret >>= 1; +#endif +#if ENABLE_FEATURE_SWAPON_PRI + if (ret & 1) // -p + g_flags |= SWAP_FLAG_PREFER | + MIN(prio, SWAP_FLAG_PRIO_MASK); + ret >>= 1; #endif if (ret /* & 1: not needed */) // -a