Hi all,
I recently migrated my notebook (ThinkPad E480, but I'm pretty sure that doesn't matter) from a HD to a NVMe SSD as root. I created the necessary partitions and rsynced all data over. After that, I tweaked fstab and re-installed grub. So far so good, I could boot and all seemed to work.
But: Suspend to disk didn't work anymore. I then found that I forgot to also alter the resume= kernel parameter. However, even after that, I could not resume a suspended session.
After some research, I found that I had to activate the "resume" hook in /etc/mkinitcpio.conf. That sounded meaningful … after that, suspend to disk worked again.
But now, I wonder: Why did everything work with the default config, without that "resume" hook, as long as I used a normal HD, and now that I have a NVMe SSD, I need the "resume" hook?
Sorry if that's a silly question … I come from Gentoo, I never used an initrd before …
Thanks for all clarifiaction/explanation!
Hi l3u!
While I'm not an Artix expert, my guess is that the new SSD uses a different kernel driver, so the resume= is not enough now and something needs to be managed through userspace. From the Arch wiki (https://wiki.archlinux.org/title/mkinitcpio#Common_hooks):
Though this is just a guess, someone please correct me if I'm wrong :)
You can also try reading the hook script itself in /usr/lib/initcpio/hooks/resume
By the way, which init system are you using?
I'm using OpenRC. However, I think the resume happens before the init system does something, no?
Well, a different driver would actually be an explanation. It's the type of SSD that shows up as /dev/nvme0n1, not as /dev/sda1.
I found an interesting Reddit post (https://www.reddit.com/r/archlinux/comments/17ehl3o/do_i_need_to_include_the_resume_hook_to_the_hooks/):
...which seems to be exactly what the resume hook does based on its script:
read -r major minor < <(stat -Lc '0x%t 0x%T' "$resumedev")
printf '%d:%d' "$major" "$minor" >/sys/power/resume
I wanted to test different resume= parameters in a virtual machine, but couldn't figure out how to get hibernation working in qemu :(
How does you current resume= parameter look?
Do you remember which naming scheme you used for resume= on the HDD?
With the normal HD, it was resume=/dev/sda2, now, I changed it to resume=/dev/nvme0n1p2.
But I also tried the resume=UUID=xyz parameter before activating the "resume" hook. Which did not make it work.
Quite interesting :-)
Solved it!
Basically, hibernation comes down to the magic numbers in (https://wiki.archlinux.org/title/Power_management/Suspend_and_hibernate#Manually_specify_hibernate_location) /sys/power/resume :
Digging more into magic numbers (https://www.ibm.com/docs/en/linux-on-systems?topic=hdaa-device-nodes-numbers):
So, some magic numbers are static, and some are dynamic. Here is a list of reserved major numbers (https://www.kernel.org/doc/html/latest/admin-guide/devices.html):
So, for HDDs the major number will
always be 8, unless you go further /dev/sdp. Now, what about NVMe drives? It shows up as major number 259 (https://askubuntu.com/questions/1367342/major-number-259-on-ubuntu-20-04-3-lts), so from the reserved numbers:
...and there's no mention of NVMe. Which means that major number 259 is not always going to be an NVMe drive! Now, why is this important? Because this means that the kernel can't reconstruct the magic numbers from a simple resume=/dev/nvme0n1p2, and needs the script from the resume hook discussed before.
But since the number 8 is
reserved for /dev/sdX, the kernel can reconstruct from resume=/dev/sdXY, placing the appropriate numbers into /sys/power/resume.
Also, I recently had an opportunity to test this with hardware. Installed Artix from the base ISO, placed resume=/dev/sda2 into GRUB_CMDLINE_LINUX_DEFAULT, updated GRUB, rebooted, ran loginctl hibernate, and... everything resumed perfectly, with 8:2 being in /sys/power/hibernate, no need for a resume hook!
Now, I'm not a kernel wizard, so feel free to correct me, but this explanation seems to be right :)
This was a
very interesting and thought provoking question, thanks, l3u! ;)
P.S. If anyone's curious, the source code for reading the magic numbers can be found in <your_linux_source_dir>/kernel/power/hibernate.c around line 1185 (the maj, min variables should be there)