systemd-sleep: (bug) use resume_offset value if set

Use hibernation configuration as defined in
/sys/power/resume and /sys/power/resume_offset
if present before inspecting /proc/swaps and
attempting to calculate swapfile offset
This commit is contained in:
Zach Smith 2019-06-08 20:44:34 -07:00
parent a7c5865098
commit 2002d8cdae
3 changed files with 35 additions and 6 deletions

4
TODO
View File

@ -56,10 +56,6 @@ Features:
with a nice speed-up on services that have many processes running in the same with a nice speed-up on services that have many processes running in the same
cgroup. cgroup.
* clean up sleep.c:
- Make sure resume= and resume_offset= on the kernel cmdline always take
precedence
* make MAINPID= message reception checks even stricter: if service uses User=, * make MAINPID= message reception checks even stricter: if service uses User=,
then check sending UID and ignore message if it doesn't match the user or then check sending UID and ignore message if it doesn't match the user or
root. root.

View File

@ -178,6 +178,7 @@ int find_hibernate_location(char **device, char **type, size_t *size, size_t *us
(void) fscanf(f, "%*s %*s %*s %*s %*s\n"); (void) fscanf(f, "%*s %*s %*s %*s %*s\n");
// TODO: sort swaps in priority order rather than using first successful option
for (i = 1;; i++) { for (i = 1;; i++) {
_cleanup_free_ char *dev_field = NULL, *type_field = NULL; _cleanup_free_ char *dev_field = NULL, *type_field = NULL;
size_t size_field, used_field; size_t size_field, used_field;

View File

@ -80,6 +80,7 @@ static int write_hibernate_location_info(void) {
if (r < 0) if (r < 0)
return log_debug_errno(errno, "Unable to stat %s: %m", device); return log_debug_errno(errno, "Unable to stat %s: %m", device);
// TODO check for btrfs and fail if offset is not provided; calculation will fail
r = read_fiemap(fd, &fiemap); r = read_fiemap(fd, &fiemap);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Unable to read extent map for '%s': %m", device); return log_debug_errno(r, "Unable to read extent map for '%s': %m", device);
@ -93,11 +94,15 @@ static int write_hibernate_location_info(void) {
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to write offset '%s': %m", offset_str); return log_debug_errno(r, "Failed to write offset '%s': %m", offset_str);
log_debug("Wrote calculated resume_offset value to /sys/power/resume_offset: %s", offset_str);
xsprintf(device_str, "%lx", (unsigned long)stb.st_dev); xsprintf(device_str, "%lx", (unsigned long)stb.st_dev);
r = write_string_file("/sys/power/resume", device_str, WRITE_STRING_FILE_DISABLE_BUFFER); r = write_string_file("/sys/power/resume", device_str, WRITE_STRING_FILE_DISABLE_BUFFER);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to write device '%s': %m", device_str); return log_debug_errno(r, "Failed to write device '%s': %m", device_str);
log_debug("Wrote device id to /sys/power/resume: %s", device_str);
return 0; return 0;
} }
@ -143,6 +148,32 @@ static int write_state(FILE **f, char **states) {
return r; return r;
} }
static int configure_hibernation(void) {
_cleanup_free_ char *resume = NULL, *resume_offset = NULL;
int r;
/* check for proper hibernation configuration */
r = read_one_line_file("/sys/power/resume", &resume);
if (r < 0)
return log_debug_errno(r, "Error reading from /sys/power/resume: %m");
r = read_one_line_file("/sys/power/resume_offset", &resume_offset);
if (r < 0)
return log_debug_errno(r, "Error reading from /sys/power/resume_offset: %m");
if (!streq(resume_offset, "0") && !streq(resume, "0:0")) {
log_debug("Hibernating using device id and offset read from /sys/power/resume: %s and /sys/power/resume_offset: %s", resume, resume_offset);
return 0;
} else if (!streq(resume, "0:0")) {
log_debug("Hibernating using device id read from /sys/power/resume: %s", resume);
return 0;
} else if (!streq(resume_offset, "0"))
log_debug("Found offset in /sys/power/resume_offset: %s; no device id found in /sys/power/resume; ignoring offset", resume_offset);
/* if hibernation is not properly configured, attempt to calculate and write values */
return write_hibernate_location_info();
}
static int execute(char **modes, char **states) { static int execute(char **modes, char **states) {
char *arguments[] = { char *arguments[] = {
NULL, NULL,
@ -168,9 +199,10 @@ static int execute(char **modes, char **states) {
/* Configure the hibernation mode */ /* Configure the hibernation mode */
if (!strv_isempty(modes)) { if (!strv_isempty(modes)) {
r = write_hibernate_location_info(); r = configure_hibernation();
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write hibernation disk offset: %m"); return log_error_errno(r, "Failed to prepare for hibernation: %m");
r = write_mode(modes); r = write_mode(modes);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");; return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;