diff --git a/man/bootup.xml b/man/bootup.xml
index 31f7a31518..c872b13c68 100644
--- a/man/bootup.xml
+++ b/man/bootup.xml
@@ -210,7 +210,7 @@ emergency.service | | |
Before any file systems are mounted, the manager will determine whether the system shall resume from
hibernation or proceed with normal boot. This is accomplished by
- systemd-hibernate-resume@.service which must be finished before
+ systemd-hibernate-resume.service which must be finished before
local-fs-pre.target, so no filesystems can be mounted before the check is complete.
When the root device becomes available,
diff --git a/man/rules/meson.build b/man/rules/meson.build
index ac32891731..74027f35a5 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -931,7 +931,7 @@ manpages = [
['systemd-getty-generator', '8', [], ''],
['systemd-gpt-auto-generator', '8', [], 'HAVE_BLKID'],
['systemd-hibernate-resume-generator', '8', [], 'ENABLE_HIBERNATE'],
- ['systemd-hibernate-resume@.service',
+ ['systemd-hibernate-resume.service',
'8',
['systemd-hibernate-resume'],
'ENABLE_HIBERNATE'],
diff --git a/man/systemd-hibernate-resume-generator.xml b/man/systemd-hibernate-resume-generator.xml
index 910fcaeb25..7d0039dcf2 100644
--- a/man/systemd-hibernate-resume-generator.xml
+++ b/man/systemd-hibernate-resume-generator.xml
@@ -29,8 +29,8 @@
systemd-hibernate-resume-generator is a
generator that initiates the procedure to resume the system from hibernation.
- It instantiates the
- systemd-hibernate-resume@.service8
+ It creates the
+ systemd-hibernate-resume.service8
unit according to the value of parameter
specified on the kernel command line, which will instruct the kernel
to resume the system from the hibernation image on that device.
@@ -55,6 +55,13 @@
supported.
+
+ resume_offset=
+
+ Takes the page offset of the swap space from the resume device.
+ Defaults to 0.
+
+
resumeflags=
@@ -75,7 +82,7 @@
See Alsosystemd1,
- systemd-hibernate-resume@.service8,
+ systemd-hibernate-resume.service8,
kernel-command-line7
diff --git a/man/systemd-hibernate-resume@.service.xml b/man/systemd-hibernate-resume.service.xml
similarity index 55%
rename from man/systemd-hibernate-resume@.service.xml
rename to man/systemd-hibernate-resume.service.xml
index b6ae1f93de..6f457f34ab 100644
--- a/man/systemd-hibernate-resume@.service.xml
+++ b/man/systemd-hibernate-resume.service.xml
@@ -3,46 +3,43 @@
-
+
- systemd-hibernate-resume@.service
+ systemd-hibernate-resume.servicesystemd
- systemd-hibernate-resume@.service
+ systemd-hibernate-resume.service8
- systemd-hibernate-resume@.service
+ systemd-hibernate-resume.servicesystemd-hibernate-resumeResume from hibernation
- systemd-hibernate-resume@.service
+ systemd-hibernate-resume.service/usr/lib/systemd/systemd-hibernate-resumeDescription
- systemd-hibernate-resume@.service
- initiates the resume from hibernation. It is instantiated with the
- device to resume from as the template argument.
+ systemd-hibernate-resume.service initiates the resume from hibernation.
- systemd-hibernate-resume only supports
- the in-kernel hibernation implementation, see
- Swap suspend.
- Internally, it works by writing the major:minor of specified
- device node to /sys/power/resume.
+ systemd-hibernate-resume only supports the in-kernel hibernation
+ implementation, see Swap suspend.
+ Internally, it works by writing the major:minor of specified device node to
+ /sys/power/resume, along with the offset in memory pages
+ (/sys/power/resume_offset) if supported.
- Failing to initiate a resume is not an error condition. It
- may mean that there was no resume image (e. g. if the system has
- been simply powered off and not hibernated). In such case, the
- boot is ordinarily continued.
+ Failing to initiate a resume is not an error condition. It may mean that there was
+ no resume image (e. g. if the system has been simply powered off and not hibernated).
+ In such cases, the boot is ordinarily continued.
diff --git a/src/basic/special.h b/src/basic/special.h
index 98fcddf631..bc9c9eb011 100644
--- a/src/basic/special.h
+++ b/src/basic/special.h
@@ -93,6 +93,7 @@
#define SPECIAL_GROWFS_ROOT_SERVICE "systemd-growfs-root.service"
#define SPECIAL_PCRFS_SERVICE "systemd-pcrfs@.service"
#define SPECIAL_PCRFS_ROOT_SERVICE "systemd-pcrfs-root.service"
+#define SPECIAL_HIBERNATE_RESUME_SERVICE "systemd-hibernate-resume.service"
/* Services systemd relies on */
#define SPECIAL_DBUS_SERVICE "dbus.service"
diff --git a/src/core/mount.c b/src/core/mount.c
index 36ea9bbefb..542c39e186 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -502,7 +502,7 @@ static int mount_add_default_ordering_dependencies(Mount *m, MountParameters *p,
* it's not technically part of the basic initrd filesystem itself, and so
* shouldn't inherit the default Before=local-fs.target dependency. However,
* these mounts still need to start after local-fs-pre.target, as a sync point
- * for things like systemd-hibernate-resume@.service that should start before
+ * for things like systemd-hibernate-resume.service that should start before
* any mounts. */
after = SPECIAL_LOCAL_FS_PRE_TARGET;
diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c
index 1bcf9d69df..db23a1d526 100644
--- a/src/hibernate-resume/hibernate-resume-generator.c
+++ b/src/hibernate-resume/hibernate-resume-generator.c
@@ -6,12 +6,14 @@
#include "alloc-util.h"
#include "dropin.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "fstab-util.h"
#include "generator.h"
#include "initrd-util.h"
#include "log.h"
#include "main-func.h"
-#include "mkdir-label.h"
+#include "parse-util.h"
#include "proc-cmdline.h"
#include "special.h"
#include "string-util.h"
@@ -22,14 +24,16 @@ static char *arg_resume_device = NULL;
static char *arg_resume_options = NULL;
static char *arg_root_options = NULL;
static bool arg_noresume = false;
+static uint64_t arg_resume_offset = 0;
STATIC_DESTRUCTOR_REGISTER(arg_resume_device, freep);
STATIC_DESTRUCTOR_REGISTER(arg_resume_options, freep);
STATIC_DESTRUCTOR_REGISTER(arg_root_options, freep);
static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
+ int r;
- if (streq(key, "resume")) {
+ if (proc_cmdline_key_streq(key, "resume")) {
char *s;
if (proc_cmdline_value_missing(key, value))
@@ -41,7 +45,16 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
free_and_replace(arg_resume_device, s);
- } else if (streq(key, "resumeflags")) {
+ } else if (proc_cmdline_key_streq(key, "resume_offset")) {
+
+ if (proc_cmdline_value_missing(key, value))
+ return 0;
+
+ r = safe_atou64(value, &arg_resume_offset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resume_offset=%s: %m", value);
+
+ } else if (proc_cmdline_key_streq(key, "resumeflags")) {
if (proc_cmdline_value_missing(key, value))
return 0;
@@ -49,7 +62,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (!strextend_with_separator(&arg_resume_options, ",", value))
return log_oom();
- } else if (streq(key, "rootflags")) {
+ } else if (proc_cmdline_key_streq(key, "rootflags")) {
if (proc_cmdline_value_missing(key, value))
return 0;
@@ -57,7 +70,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
if (!strextend_with_separator(&arg_root_options, ",", value))
return log_oom();
- } else if (streq(key, "noresume")) {
+ } else if (proc_cmdline_key_streq(key, "noresume")) {
if (value) {
log_warning("\"noresume\" kernel command line switch specified with an argument, ignoring.");
return 0;
@@ -70,35 +83,53 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
}
static int process_resume(void) {
- _cleanup_free_ char *service_unit = NULL, *device_unit = NULL, *lnk = NULL;
+ _cleanup_free_ char *device_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
int r;
if (!arg_resume_device)
return 0;
- r = unit_name_from_path_instance("systemd-hibernate-resume", arg_resume_device, ".service",
- &service_unit);
- if (r < 0)
- return log_error_errno(r, "Failed to generate unit name: %m");
-
- lnk = strjoin(arg_dest, "/" SPECIAL_SYSINIT_TARGET ".wants/", service_unit);
- if (!lnk)
- return log_oom();
-
- (void) mkdir_parents_label(lnk, 0755);
- if (symlink(SYSTEM_DATA_UNIT_DIR "/systemd-hibernate-resume@.service", lnk) < 0)
- return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
-
r = unit_name_from_path(arg_resume_device, ".device", &device_unit);
if (r < 0)
- return log_error_errno(r, "Failed to generate unit name: %m");
+ return log_error_errno(r, "Failed to generate device unit name from path '%s': %m", arg_resume_device);
r = write_drop_in(arg_dest, device_unit, 40, "device-timeout",
"# Automatically generated by systemd-hibernate-resume-generator\n\n"
"[Unit]\n"
"JobTimeoutSec=infinity\n");
if (r < 0)
- log_warning_errno(r, "Failed to write device timeout drop-in: %m");
+ log_warning_errno(r, "Failed to write device timeout drop-in, ignoring: %m");
+
+ r = generator_open_unit_file(arg_dest, NULL, SPECIAL_HIBERNATE_RESUME_SERVICE, &f);
+ if (r < 0)
+ return r;
+
+ fprintf(f,
+ "[Unit]\n"
+ "Description=Resume from hibernation\n"
+ "Documentation=man:systemd-hibernate-resume.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%1$s\n"
+ "Wants=local-fs-pre.target\n"
+ "After=%1$s\n"
+ "Before=local-fs-pre.target\n"
+ "AssertPathExists=/etc/initrd-release\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "ExecStart=" ROOTLIBEXECDIR "/systemd-hibernate-resume %2$s %3$" PRIu64,
+ device_unit,
+ arg_resume_device,
+ arg_resume_offset);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create " SPECIAL_HIBERNATE_RESUME_SERVICE ": %m");
+
+ r = generator_add_symlink(arg_dest, SPECIAL_SYSINIT_TARGET, "wants", SPECIAL_HIBERNATE_RESUME_SERVICE);
+ if (r < 0)
+ return r;
r = generator_write_timeouts(arg_dest,
arg_resume_device,
@@ -112,7 +143,7 @@ static int process_resume(void) {
}
static int run(const char *dest, const char *dest_early, const char *dest_late) {
- int r = 0;
+ int r;
arg_dest = ASSERT_PTR(dest);
diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c
index 9a9df5d22f..28cab191fc 100644
--- a/src/hibernate-resume/hibernate-resume.c
+++ b/src/hibernate-resume/hibernate-resume.c
@@ -1,58 +1,55 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include
-#include
#include
-#include "alloc-util.h"
#include "devnum-util.h"
-#include "fileio.h"
#include "initrd-util.h"
#include "log.h"
+#include "main-func.h"
+#include "parse-util.h"
+#include "sleep-util.h"
-int main(int argc, char *argv[]) {
+static const char *arg_resume_device = NULL;
+static uint64_t arg_resume_offset = 0; /* in memory pages */
+
+static int run(int argc, char *argv[]) {
struct stat st;
- const char *device;
int r;
- if (argc != 2) {
- log_error("This program expects one argument.");
- return EXIT_FAILURE;
- }
-
log_setup();
+ if (argc < 2 || argc > 3)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program expects one or two arguments.");
+
umask(0022);
- /* Refuse to run unless we are in an initrd() */
if (!in_initrd())
- return EXIT_SUCCESS;
+ return 0;
- device = argv[1];
+ arg_resume_device = argv[1];
- if (stat(device, &st) < 0) {
- log_error_errno(errno, "Failed to stat '%s': %m", device);
- return EXIT_FAILURE;
+ if (argc == 3) {
+ r = safe_atou64(argv[2], &arg_resume_offset);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse resume offset %s: %m", argv[2]);
}
- if (!S_ISBLK(st.st_mode)) {
- log_error("Resume device '%s' is not a block device.", device);
- return EXIT_FAILURE;
- }
+ if (stat(arg_resume_device, &st) < 0)
+ return log_error_errno(errno, "Failed to stat resume device '%s': %m", arg_resume_device);
- r = write_string_file("/sys/power/resume", FORMAT_DEVNUM(st.st_rdev), WRITE_STRING_FILE_DISABLE_BUFFER);
- if (r < 0) {
- log_error_errno(r, "Failed to write '" DEVNUM_FORMAT_STR "' to /sys/power/resume: %m", DEVNUM_FORMAT_VAL(st.st_rdev));
- return EXIT_FAILURE;
- }
+ if (!S_ISBLK(st.st_mode))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Resume device '%s' is not a block device.", arg_resume_device);
- /*
- * The write above shall not return.
- *
- * However, failed resume is a normal condition (may mean that there is
- * no hibernation image).
- */
+ /* The write shall not return if a resume takes place. */
+ r = write_resume_config(st.st_rdev, arg_resume_offset, arg_resume_device);
+ log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG,
+ r < 0 ? r : SYNTHETIC_ERRNO(ENOENT),
+ "Unable to resume from device '%s' (" DEVNUM_FORMAT_STR ") offset %" PRIu64 ", continuing boot process.",
+ arg_resume_device, DEVNUM_FORMAT_VAL(st.st_rdev), arg_resume_offset);
- log_info("Could not resume from '%s' (" DEVNUM_FORMAT_STR ").", device, DEVNUM_FORMAT_VAL(st.st_rdev));
- return EXIT_SUCCESS;
+ return r;
}
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/units/meson.build b/units/meson.build
index df6da78abe..dff7b3904f 100644
--- a/units/meson.build
+++ b/units/meson.build
@@ -281,10 +281,6 @@ units = [
{ 'file' : 'systemd-growfs-root.service.in' },
{ 'file' : 'systemd-growfs@.service.in' },
{ 'file' : 'systemd-halt.service' },
- {
- 'file' : 'systemd-hibernate-resume@.service.in',
- 'conditions' : ['ENABLE_HIBERNATE'],
- },
{
'file' : 'systemd-hibernate.service.in',
'conditions' : ['ENABLE_HIBERNATE'],
diff --git a/units/systemd-hibernate-resume@.service.in b/units/systemd-hibernate-resume@.service.in
deleted file mode 100644
index 142bb339e1..0000000000
--- a/units/systemd-hibernate-resume@.service.in
+++ /dev/null
@@ -1,22 +0,0 @@
-# SPDX-License-Identifier: LGPL-2.1-or-later
-#
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-
-[Unit]
-Description=Resume from hibernation using device %f
-Documentation=man:systemd-hibernate-resume@.service(8)
-DefaultDependencies=no
-BindsTo=%i.device
-Wants=local-fs-pre.target
-After=%i.device
-Before=local-fs-pre.target
-AssertPathExists=/etc/initrd-release
-
-[Service]
-Type=oneshot
-ExecStart={{ROOTLIBEXECDIR}}/systemd-hibernate-resume %f