]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemd-sleep: (bug) use resume_offset value if set
authorZach Smith <z@zxmth.us>
Sun, 9 Jun 2019 03:44:34 +0000 (20:44 -0700)
committerZach Smith <z@zxmth.us>
Thu, 27 Jun 2019 05:04:59 +0000 (22:04 -0700)
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

TODO
src/shared/sleep-config.c
src/sleep/sleep.c

diff --git a/TODO b/TODO
index d54e5ddeaf023eb41469092f8c2d07ddcd72e841..02299bb7caae83f14d8336261ced792b84244ec9 100644 (file)
--- a/TODO
+++ b/TODO
@@ -56,10 +56,6 @@ Features:
   with a nice speed-up on services that have many processes running in the same
   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=,
   then check sending UID and ignore message if it doesn't match the user or
   root.
index 4026655809ae44524ef6223fe6f4343f4b8641df..0efbd7c7bed68c6c0f3c4f3645f94db22e9a3fff 100644 (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");
 
+        // TODO: sort swaps in priority order rather than using first successful option
         for (i = 1;; i++) {
                 _cleanup_free_ char *dev_field = NULL, *type_field = NULL;
                 size_t size_field, used_field;
index c38aa4ccf67927e68459ee83d81b50bcb6f18c2b..435e5592e624de6838d5d5fb5e5bcbdf6fd790d5 100644 (file)
@@ -80,6 +80,7 @@ static int write_hibernate_location_info(void) {
         if (r < 0)
                 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);
         if (r < 0)
                 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)
                 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);
         r = write_string_file("/sys/power/resume", device_str, WRITE_STRING_FILE_DISABLE_BUFFER);
         if (r < 0)
                 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;
 }
 
@@ -143,6 +148,32 @@ static int write_state(FILE **f, char **states) {
         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) {
         char *arguments[] = {
                 NULL,
@@ -168,9 +199,10 @@ static int execute(char **modes, char **states) {
 
         /* Configure the hibernation mode */
         if (!strv_isempty(modes)) {
-                r = write_hibernate_location_info();
+                r = configure_hibernation();
                 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);
                 if (r < 0)
                         return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;