Tookmund / Swapspace

A fork of Jeroen T. Vermeulen's excellent dynamic swap space manager
GNU General Public License v2.0
139 stars 13 forks source link

hibernation support #33

Closed axet closed 2 years ago

axet commented 3 years ago

Hello!

Seems like for hiberation in linux to work swap has to be free for about 30% of it is capacity. If free swap space drops below that level, hibernation will fail.

Apps eat memory and you can't be sure hibernate swap file/partition always enough for hibernation to work.

By using swaspace you can guarantee you will never run out swap space, because swapspace adding swap files dynamically. But this approach does not prevent filling hibernate partition which is used for hibernation. Simple example (not actual values):

root@axet-laptop:/home/axet# swapon -s
Filename                Type        Size        Used        Priority
/swapfile                               file        3145724     85260       -1
/var/lib/swapspace/1                    file        1942788     0       -2

Dynamically allocated swap files has lower priority, and therefore will not prevent hibernate /swapfile to filling up. We need to specify swap priority for newly added swapfiles to be higher then system swap file.

Can we have additional swapspace options which can help us fixing hibernation partition to filling up? Set minimum space in gigabytes to be free? Set swap files priority or just first swap file created by swapspace?

Idea is to keep hibernate /swapfile free for about 30% of system memory. Since it is not possible, we can try to fix this, by specifying priority of dynamic swapfiles higher then system swap.

EDIT: I suggest swapspace should have two options: do not count system swap as memory space (so other thresholds will works as usual), set start priority for all swap files created dynamically count down.

For example:

ignore_system_swap=1 start_swap_priority=1000

axet commented 3 years ago

Simple implementation, without additional configuration variables or optimizations.

Look nice to have the SWAP_FLAG_DISCARD option as well.

I do not know if it is right to treat SawpChached as free memory. This is memory just loaded into the memory from swap, but still persist in the swap. Not clear if it is can be reused...

Whatever, this is an example:

diff --git a/src/memory.c b/src/memory.c
index 14ed37e..2a1abfe 100644
--- a/src/memory.c
+++ b/src/memory.c
@@ -346,15 +346,14 @@ static inline memsize_t space_free(const struct memstate *st)
    * considered in-use.
    */
   return st->MemFree +
-    st->SwapFree +
-    st->SwapCached +
+    free_swaps() +
     buffers_free(st) +
     cache_free(st);
 }

 static inline memsize_t space_total(const struct memstate *st)
 {
-  return st->MemTotal + st->SwapTotal;
+  return st->MemTotal + total_swaps();
 }

 static inline int pct_free(const struct memstate *st)
diff --git a/src/swaps.c b/src/swaps.c
index e477344..74d1952 100644
--- a/src/swaps.c
+++ b/src/swaps.c
@@ -336,7 +336,10 @@ memsize_t swapfs_size(void)
 static bool enable_swapfile(const char file[])
 {
   runcommand("mkswap", file);
-  const bool ok = (swapon(file, 0) == 0);
+  int activeswaps = 0;
+  for (int i=0; i<MAX_SWAPFILES; ++i) if (swapfiles[i].size) ++activeswaps;
+  int prio = 1000 - activeswaps + 1;
+  const bool ok = (swapon(file, ((prio << SWAP_FLAG_PRIO_SHIFT) & SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER | SWAP_FLAG_DISCARD) == 0);
   if (unlikely(!ok))
     log_perr_str(LOG_ERR, "Could not enable swapfile", file, errno);
   return ok;
@@ -912,3 +915,17 @@ void free_swapfile(memsize_t maxsize)
   const int victim = find_retirable(maxsize);
   if (victim < MAX_SWAPFILES) retire_swapfile(victim);
 }
+
+memsize_t total_swaps() {
+  memsize_t total = 0;
+  for (int i=0; i<MAX_SWAPFILES; ++i)
+    total += swapfiles[i].size;
+  return total;
+}
+
+memsize_t free_swaps() {
+  memsize_t total = 0;
+  for (int i=0; i<MAX_SWAPFILES; ++i)
+    total += swapfiles[i].size - swapfiles[i].used;
+  return total;
+}
axet commented 2 years ago

I think this is a bad idea. Prefer to dynamic swap on / off for hibernation to prevent polution for hibernation file/partition.

If anyone trying to achieve the same, I wrote simple script for this:

MilesBHuff commented 3 weeks ago

We need to specify swap priority for newly added swapfiles to be higher then system swap file.

I've created an issue for this here: #46.

There's more discussion in #31, but it sounds like what Swapspace needs to do to support hibernation is to limit itself to 31 swapfiles and to implement priorities.

axet commented 3 weeks ago

Right now I'm using preallocated 16GB swap+discard partition on my NVME device with TRIM support without swapspace.

Technically it does not waste any space since most of the time (99%) swap partition is not used and therefore even when swap is allocated it is not using any NVME blocks.

MilesBHuff commented 3 weeks ago

@axet What is the command to make that?

axet commented 3 weeks ago

/etc/fstab

     /swapfile swap swap discard 0 0

Also crypttab if you use those.

MilesBHuff commented 2 weeks ago

Ah, I see -- by "discard", you just meant the mount option, not some special creation procedure. Got it -- thanks!

axet commented 2 weeks ago

Sure. Since all NVME works better with more GB free drive has (it improve speed, and durability) creating big swap file helps with booth cases. Having 16GB less on a drive, no longer a issue as it used to be with HDD.

I guess swapspace still can be useful with HDD configs.