Tookmund / Swapspace

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

hibernation support #33

Closed axet closed 2 years ago

axet commented 2 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 2 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: