1
0
mirror of https://github.com/systemd/systemd.git synced 2025-08-25 13:49:55 +03:00

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.
This commit is contained in:
Mike Yuan
2023-04-19 00:09:08 +08:00
parent 191b891bf1
commit 1923373a64
3 changed files with 55 additions and 42 deletions

View File

@ -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) {

View File

@ -2,6 +2,7 @@
#pragma once
#include <linux/fiemap.h>
#include <sys/types.h>
#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);

View File

@ -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");