Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for late resume #139

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ Importing this module will run `btrfs device scan` and pull btrfs modules.

When enabled, attempts to resume after hibernation if resume= is passed on the kernel command line.

> Please use the following option with **CAUTION** as it can be unstable in certain configurations! Any writes to disks that occur pre-resume run the risk of causing system instability! For more information have a read of the warnings in the [kernel docs](https://www.kernel.org/doc/html/latest/power/swsusp.html).

* `late_resume` (true) When enabled will attempt to resume from hibernation after decryption and device mapping, allowing resume from encrypted or otherwise hidden swap devices.

### Cryptographic modules

Several cryptographic modules are provided, mostly to assist in mounting encrypted volumes and handling keyfiles.
Expand Down
64 changes: 45 additions & 19 deletions src/ugrd/fs/resume.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
__version__ = "0.4.0"

from zenlib.util import contains, unset

def handle_resume(self) -> None:
def resume(self) -> None:
"""Returns a bash script handling resume from hibernation.
Checks that /sys/power/resume is writable, resume= is set, and noresume is not set, if so,
checks if PARTUUID= is in the resume var, and tries to use blkid to find the resume device.
Expand All @@ -15,23 +16,48 @@ def handle_resume(self) -> None:
Distinguising between a fresh boot and missing/borked hibernation image is not possible at run time.
"""
return [
"resumeval=$(readvar resume)", # read the cmdline resume var
'if ! check_var noresume && [ -n "$resumeval" ] && [ -w /sys/power/resume ]; then',
' if echo "$resumeval" | grep -q "PARTUUID="; then', # resolve partuuid to device
# Check resume support
'[ -n "$1" ] || (ewarn "No device?" ; return 1)',
'[ -w /sys/power/resume ] || (ewarn "Kernel does not support resume!" ; return 1)',
'[[ ! "$(cat /sys/power/resume)" == "0:0" ]] || ewarn "/sys/power/resume not empty, resume has already been attempted!"',

# Safety checks
'if ! [ -z $(lsblk -Q MOUNTPOINT)] ; then',
r' eerror "Cannot safely resume with mounted block devices:\n$(lsblk -Q MOUNTPOINT -no PATH)"',
' return 1',
'fi',

'[ -b "$1" ] || (ewarn "\'$1\' is not a valid block device!" ; return 1)',

'einfo "Attempting resume from: $1"',
'echo -n "$1" > /sys/power/resume',
'einfo "No image on $resume"',
'return 0',
]

def handle_early_resume(self) -> None:
return [
'resumeval=$(readvar resume)',
'if ! check_var noresume && [ -n "$resumeval" ] ; then',
' if echo "$resumeval" | grep -qE "^PARTUUID=|^UUID="; then',
' resume=$(blkid -t "$resumeval" -o device)',
" else",
" resume=$resumeval",
" fi",
' if [ -e "$resume" ]; then', # Check if the resume device exists
' einfo "Resuming from: $resume"',
' echo -n "$resume" > /sys/power/resume', # Attempt to resume
' ewarn "Failed to resume from: $resume"',
" else",
' ewarn "Resume device not found: $resume)"', # Warn if the resume device does not exist
r' eerror "Block devices:\n$(blkid)"',
' eerror "If you wish to continue booting, remove the resume= kernel parameter."',
''' eerror " or run 'setvar noresume 1' from the recovery shell to skip resuming."''',
' rd_fail "Failed to resume from $(readvar resume)."',
" fi",
"fi",
' else',
' resume="$resumeval"',
' fi',

' if ! [ -z $resume ] ; then',
' if ! resume "$resume" ; then',
' eerror "If you wish to continue booting, remove the resume= kernel parameter."',
''' eerror " or run 'setvar noresume 1' from the recovery shell to skip resuming."''',
' rd_fail "Failed to resume from $(readvar resume)."',
' fi',
' else',
' einfo "Resume device \'$resumeval\' not found"',
' fi',
'fi',
]

@contains('late_resume')
def handle_late_resume(self) -> None:
self.logger.warning("[late_resume] enabled, this can result in data loss if filesystems are modified before resuming. Read the docs for more info.")
return handle_early_resume(self) # At the moment it's the same code but delayed, will change when more features are added
13 changes: 12 additions & 1 deletion src/ugrd/fs/resume.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
cmdline_strings = [ "resume" ]

binaries = [ 'lsblk' ]

[imports.init_early]
"ugrd.fs.resume" = [ "handle_resume" ]
"ugrd.fs.resume" = [ "handle_early_resume" ]

[imports.init_premount]
"ugrd.fs.resume" = [ "handle_late_resume"]

[imports.functions]
"ugrd.fs.resume" = ["resume"]

[custom_parameters]
late_resume = "bool"