summaryrefslogtreecommitdiffstats
path: root/src/shared/hibernate-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/hibernate-util.c')
-rw-r--r--src/shared/hibernate-util.c51
1 files changed, 30 insertions, 21 deletions
diff --git a/src/shared/hibernate-util.c b/src/shared/hibernate-util.c
index c3991cf..7c21157 100644
--- a/src/shared/hibernate-util.c
+++ b/src/shared/hibernate-util.c
@@ -159,8 +159,9 @@ static int read_resume_config(dev_t *ret_devno, uint64_t *ret_offset) {
}
if (devno == 0 && offset > 0 && offset != UINT64_MAX)
- return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "Found resume_offset=%" PRIu64 " but resume= is unset, refusing.", offset);
+ return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM),
+ "Found populated /sys/power/resume_offset (%" PRIu64 ") but /sys/power/resume is not set, refusing.",
+ offset);
*ret_devno = devno;
*ret_offset = offset;
@@ -393,7 +394,7 @@ int find_suitable_hibernation_device_full(HibernationDevice *ret_device, uint64_
if (!entry) {
/* No need to check n_swaps == 0, since it's rejected early */
assert(resume_config_devno > 0);
- return log_debug_errno(SYNTHETIC_ERRNO(ENOSPC), "Cannot find swap entry corresponding to /sys/power/resume.");
+ return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Cannot find swap entry corresponding to /sys/power/resume.");
}
if (ret_device) {
@@ -451,11 +452,11 @@ int hibernation_is_safe(void) {
bypass_space_check = getenv_bool("SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK") > 0;
r = find_suitable_hibernation_device_full(NULL, &size, &used);
- if (r == -ENOSPC && bypass_space_check)
- /* If we don't have any available swap space at all, and SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK
- * is set, skip all remaining checks since we can't do that properly anyway. It is quite
- * possible that the user is using a setup similar to #30083. When we actually perform
- * hibernation in sleep.c we'll check everything again. */
+ if (IN_SET(r, -ENOSPC, -ESTALE) && bypass_space_check)
+ /* If we don't have any available swap space at all, or the specified resume device is missing,
+ * and $SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK is set, skip all remaining checks since
+ * we can't do that properly anyway. It is quite possible that the user is using a setup
+ * similar to #30083. When we actually perform hibernation in sleep.c we'll check everything again. */
return 0;
if (r < 0)
return r;
@@ -466,7 +467,7 @@ int hibernation_is_safe(void) {
"Not running on EFI and resume= is not set. Hibernation is not safe.");
if (bypass_space_check)
- return true;
+ return 0;
r = get_proc_meminfo_active(&active);
if (r < 0)
@@ -483,30 +484,23 @@ int hibernation_is_safe(void) {
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;
+ assert(devno > 0);
+ assert(device);
+
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);
+ "Can't configure swap file offset %s, kernel does not support /sys/power/resume_offset. Refusing.",
+ offset_str);
log_warning_errno(r, "/sys/power/resume_offset is unavailable, skipping writing swap file offset.");
} else if (r < 0)
@@ -526,3 +520,18 @@ int write_resume_config(dev_t devno, uint64_t offset, const char *device) {
return 0;
}
+
+int clear_efi_hibernate_location_and_warn(void) {
+ int r;
+
+ if (!is_efi_boot())
+ return 0;
+
+ r = efi_set_variable(EFI_SYSTEMD_VARIABLE(HibernateLocation), NULL, 0);
+ if (r == -ENOENT)
+ return 0;
+ if (r < 0)
+ return log_warning_errno(r, "Failed to clear HibernateLocation EFI variable: %m");
+
+ return 1;
+}