From: Mike Yuan Date: Tue, 18 Apr 2023 16:09:08 +0000 (+0800) Subject: sleep: always write resume_offset if possible X-Git-Tag: v254-rc1~124^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1923373a647c620b7aa68a3a21ccb2cfed09e3aa;p=thirdparty%2Fsystemd.git sleep: always write resume_offset if possible There's no need to conditionalize this. Setting resume_offset=0 doesn't harm, and can even help by overriding potentially existing half-written settings. --- diff --git a/src/shared/sleep-util.c b/src/shared/sleep-util.c index eb9a43f5078..1027ecce05c 100644 --- a/src/shared/sleep-util.c +++ b/src/shared/sleep-util.c @@ -1028,6 +1028,52 @@ int read_fiemap(int fd, struct fiemap **ret) { return 0; } +int write_resume_config(dev_t devno, uint64_t offset, const char *device) { + char offset_str[DECIMAL_STR_MAX(uint64_t)]; + _cleanup_free_ char *path = NULL; + const char *devno_str; + int r; + + devno_str = FORMAT_DEVNUM(devno); + xsprintf(offset_str, "%" PRIu64, offset); + + if (!device) { + r = device_path_make_canonical(S_IFBLK, devno, &path); + if (r < 0) + return log_error_errno(r, + "Failed to format canonical device path for devno '" DEVNUM_FORMAT_STR "': %m", + DEVNUM_FORMAT_VAL(devno)); + device = path; + } + + /* We write the offset first since it's safer. Note that this file is only available in 4.17+, so + * fail gracefully if it doesn't exist and we're only overwriting it with 0. */ + r = write_string_file("/sys/power/resume_offset", offset_str, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r == -ENOENT) { + if (offset != 0) + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Can't configure hibernation offset %" PRIu64 ", kernel does not support /sys/power/resume_offset. Refusing.", + offset); + + log_warning_errno(r, "/sys/power/resume_offset is unavailable, skipping writing swap file offset."); + } else if (r < 0) + return log_error_errno(r, + "Failed to write swap file offset %s to /sys/power/resume_offset for device '%s': %m", + offset_str, device); + else + log_debug("Wrote resume_offset=%s for device '%s' to /sys/power/resume_offset.", + offset_str, device); + + r = write_string_file("/sys/power/resume", devno_str, WRITE_STRING_FILE_DISABLE_BUFFER); + if (r < 0) + return log_error_errno(r, + "Failed to write device '%s' (%s) to /sys/power/resume: %m", + device, devno_str); + log_debug("Wrote resume=%s for device '%s' to /sys/power/resume.", devno_str, device); + + return 0; +} + static int can_sleep_internal(const SleepConfig *sleep_config, SleepOperation operation, bool check_allowed); static bool can_s2h(const SleepConfig *sleep_config) { diff --git a/src/shared/sleep-util.h b/src/shared/sleep-util.h index 5f8bf090f92..6480ca86373 100644 --- a/src/shared/sleep-util.h +++ b/src/shared/sleep-util.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include "hashmap.h" #include "time-util.h" @@ -63,6 +64,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(HibernateLocation*, hibernate_location_free); int read_fiemap(int fd, struct fiemap **ret); int parse_sleep_config(SleepConfig **sleep_config); int find_hibernate_location(HibernateLocation **ret_hibernate_location); +int write_resume_config(dev_t devno, uint64_t offset, const char *device); int can_sleep(SleepOperation operation); int can_sleep_disk(char **types); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 46f46914b56..1d34d984530 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -46,48 +46,11 @@ static SleepOperation arg_operation = _SLEEP_OPERATION_INVALID; static int write_hibernate_location_info(const HibernateLocation *hibernate_location) { - char offset_str[DECIMAL_STR_MAX(uint64_t)]; - const char *resume_str; - int r; - assert(hibernate_location); assert(hibernate_location->swap); + assert(IN_SET(hibernate_location->swap->type, SWAP_BLOCK, SWAP_FILE)); - resume_str = FORMAT_DEVNUM(hibernate_location->devno); - - r = write_string_file("/sys/power/resume", resume_str, WRITE_STRING_FILE_DISABLE_BUFFER); - if (r < 0) - return log_debug_errno(r, "Failed to write partition device to /sys/power/resume for '%s': '%s': %m", - hibernate_location->swap->path, resume_str); - - log_debug("Wrote resume= value for %s to /sys/power/resume: %s", hibernate_location->swap->path, resume_str); - - /* if it's a swap partition, we're done */ - if (hibernate_location->swap->type == SWAP_BLOCK) - return 0; - - assert(hibernate_location->swap->type == SWAP_FILE); - - /* Only available in 4.17+ */ - if (hibernate_location->offset > 0 && access("/sys/power/resume_offset", W_OK) < 0) { - if (errno == ENOENT) { - log_debug("Kernel too old, can't configure resume_offset for %s, ignoring: %" PRIu64, - hibernate_location->swap->path, hibernate_location->offset); - return 0; - } - - return log_debug_errno(errno, "/sys/power/resume_offset not writable: %m"); - } - - xsprintf(offset_str, "%" PRIu64, hibernate_location->offset); - r = write_string_file("/sys/power/resume_offset", offset_str, WRITE_STRING_FILE_DISABLE_BUFFER); - if (r < 0) - return log_debug_errno(r, "Failed to write swap file offset to /sys/power/resume_offset for '%s': '%s': %m", - hibernate_location->swap->path, offset_str); - - log_debug("Wrote resume_offset= value for %s to /sys/power/resume_offset: %s", hibernate_location->swap->path, offset_str); - - return 0; + return write_resume_config(hibernate_location->devno, hibernate_location->offset, hibernate_location->swap->path); } static int write_mode(char **modes) { @@ -212,12 +175,14 @@ static int execute( /* Configure hibernation settings if we are supposed to hibernate */ if (!strv_isempty(modes)) { + bool resume_set; + r = find_hibernate_location(&hibernate_location); if (r < 0) return log_error_errno(r, "Failed to find location to hibernate to: %m"); - if (r == 0) { /* 0 means: no hibernation location was configured in the kernel so far, let's - * do it ourselves then. > 0 means: kernel already had a configured hibernation - * location which we shouldn't touch. */ + resume_set = r > 0; + + if (!resume_set) { r = write_hibernate_location_info(hibernate_location); if (r < 0) return log_error_errno(r, "Failed to prepare for hibernation: %m");