[2024-feb-29] Sad news: Eric Layton aka Nocturnal Slacker aka vtel57 passed away on Feb 26th, shortly after hospitalization. He was one of our Wiki's most prominent admins. He will be missed.

Welcome to the Slackware Documentation Project

Hibernation with LVM, LUKS and a Swapfile

With this How To you can use a swap file instead a swap partition as described here.

First create a swap file (you can choose another name and / or size if you want):

dd if=/dev/zero of=/swapfile bs=1M count=4096
mkswap /swapfile 

Activate the swap:

swapon /swapfile

Check if the swap file is recognized by the system:

cat /proc/swaps 
Filename                                Type            Size    Used    Priority
/swapfile                               file            4194300 0       -1

Add to the fstab

/swapfile        none             swap        defaults         0   0

For suspend/resume you need to append 2 kernel parameter in /etc/lilo.conf resume and resume_offset.

resume is the partition where the swap file is located (e.g /dev/sda, /dev/cryptslack/root) resume_offset is the beginning of the swap file on the resume partition, you can get the offset with:

sudo /sbin/filefrag -v /swapfile | head -n -3 | tail -n 1 | awk ' {print $3 }'

Your lilo entry should look like this:

# Append any additional kernel parameters:
 append="vt.default_utf8=1 resume=/dev/cryptslack/root resume_offset=1134591"

You need to patch the initrd to recognize the resume_offset parameter

init-swapfile.patch
--- init.orig   2012-12-01 14:03:39.344538490 +0100                                                                                                            
+++ init        2012-12-01 14:01:12.526373970 +0100                                                                                                            
@@ -69,6 +69,7 @@                                                                                                                                              
 LUKSDEV=$(cat /luksdev)                                                                                                                                       
 LUKSKEY=$(cat /lukskey)                                                                                                                                       
 RESUMEDEV=$(cat /resumedev)                                                                                                                                   
+RESOFFSET=$(cat /resoffset)                                                                                                                                   
 WAIT=$(cat /wait-for-root)                                                                                                                                    
 KEYMAP=$(cat /keymap)                                                                                                                                         
 INIT=/sbin/init                                                                                                                                               
@@ -269,18 +270,35 @@
     umount -l /mountkey
     rmdir /mountkey 2>/dev/null
   fi
-  
-  # Resume state from swap
-  if [ "$RESUMEDEV" != "" ]; then
-    if ls -l $RESUMEDEV | grep -q "^l" ; then
-      #RESUMEDEV=$(ls -l $RESUMEDEV | awk '{ print $NF }')
-      RESUMEDEV=$(readlink -f $RESUMEDEV)
-    fi
-    echo "Trying to resume from $RESUMEDEV"
-    RESMAJMIN=$(ls -l $RESUMEDEV | tr , : | awk '{ print $5$6 }')
-    echo $RESMAJMIN > /sys/power/resume
-  fi
-
+ 
+if [ "$RESUMEDEV" != "" ]; then
+       # be lvm aware
+        RESUMEDEV=$(readlink -f ${RESUMEDEV} | awk -F '/' '{ print $3 }')
+       if [ -r "/sys/class/block/${RESUMEDEV}/dev" ] ; then
+       # try sysfs 
+               read RESMAJMIN < "/sys/class/block/${RESUMEDEV}/dev"
+       elif [ -r "/proc/partitions" ] ; then
+       # otherwise run through /proc/partitions
+               while read m n b d jnk ; do
+                       if [ "$d" = "${RESUMEDEV}" ] ; then
+                               RESMAJMIN="$m:$n"
+                               break
+                       fi
+               done < "/proc/partitions"
+               fi
+       if [ -z "${RESMAJMIN}" ] ; then
+               # Device does not exist (not found in /proc/partitions)
+               exit 99
+       fi
+
+       if [ -n "${RESOFFSET}" ]; then
+                echo "Try resume from ${RESMAJMIN}:${RESOFFSET}"
+               echo "${RESMAJMIN}:${RESOFFSET}" > /sys/power/resume
+       else
+               echo "${RESMAJMIN}" > /sys/power/resume
+       fi
+fi
+ 
mkdir patched_initrd
cd patched_initrd
cp -r /boot/initrd-tree .
echo "1134591" > resoffset
patch < init-swapfile.patch

After successful patching, pack the initrd to /boot/initrd-swapfile.gz:

find . -print0 | cpio -ov -0 --format=newc | gzip -9 > /boot/initrd-swapfile.gz
I recommend to test this initrd first with another boot entry
image = /boot/vmlinuz
initrd = /boot/initrd-swapfile.gz
root = /dev/cryptslack/root
label = "Linux Swapfile"
read-only

Then you need to run lilo to save the changes

lilo

After a reboot you can suspend to your swap file as with your swap partition

You need the reboot, suspend also uses resume_offset to find the swap file

Sources

 howtos:slackware_admin:swapfile_hibernation ()