]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
hibernate-resume: rework to follow the logic of sleep.c and use
authorMike Yuan <me@yhndnzj.com>
Tue, 18 Apr 2023 17:21:55 +0000 (01:21 +0800)
committerMike Yuan <me@yhndnzj.com>
Fri, 23 Jun 2023 15:57:49 +0000 (23:57 +0800)
main-func.h

Preparation for #27247

man/bootup.xml
man/rules/meson.build
man/systemd-hibernate-resume-generator.xml
man/systemd-hibernate-resume.service.xml [moved from man/systemd-hibernate-resume@.service.xml with 55% similarity]
src/basic/special.h
src/core/mount.c
src/hibernate-resume/hibernate-resume-generator.c
src/hibernate-resume/hibernate-resume.c
units/meson.build
units/systemd-hibernate-resume@.service.in [deleted file]

index 31f7a315180ae98922f1ec3b4f044fcdfe80829d..c872b13c685c4ab94359870a98cb70f523aa1f19 100644 (file)
@@ -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
-    <filename>systemd-hibernate-resume@.service</filename> which must be finished before
+    <filename>systemd-hibernate-resume.service</filename> which must be finished before
     <filename>local-fs-pre.target</filename>, so no filesystems can be mounted before the check is complete.
 
     When the root device becomes available,
index ac32891731831735c4bb53e00f61629509b690cf..74027f35a5dd4f8e74e495df42632297fa8ab243 100644 (file)
@@ -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'],
index 910fcaeb2508ef664cfcd80f3a06d311a504ccdb..7d0039dcf2eb9227f900ca5780ed630e88bb2b87 100644 (file)
@@ -29,8 +29,8 @@
 
     <para><command>systemd-hibernate-resume-generator</command> is a
     generator that initiates the procedure to resume the system from hibernation.
-    It instantiates the
-    <citerefentry><refentrytitle>systemd-hibernate-resume@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    It creates the
+    <citerefentry><refentrytitle>systemd-hibernate-resume.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
     unit according to the value of <option>resume=</option> parameter
     specified on the kernel command line, which will instruct the kernel
     to resume the system from the hibernation image on that device.</para>
         supported.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>resume_offset=</varname></term>
+
+        <listitem><para>Takes the page offset of the swap space from the resume device.
+        Defaults to <literal>0</literal>.</para></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>resumeflags=</varname></term>
 
@@ -75,7 +82,7 @@
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd-hibernate-resume@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-hibernate-resume.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     </para>
   </refsect1>
similarity index 55%
rename from man/systemd-hibernate-resume@.service.xml
rename to man/systemd-hibernate-resume.service.xml
index b6ae1f93deb68ddf7a6b4d36f35733877d06a995..6f457f34abee6f403a8bc67e846773125c43f5fe 100644 (file)
@@ -3,46 +3,43 @@
 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
-<refentry id="systemd-hibernate-resume@.service" conditional='ENABLE_HIBERNATE'>
+<refentry id="systemd-hibernate-resume.service" conditional='ENABLE_HIBERNATE'>
 
   <refentryinfo>
-    <title>systemd-hibernate-resume@.service</title>
+    <title>systemd-hibernate-resume.service</title>
     <productname>systemd</productname>
   </refentryinfo>
 
   <refmeta>
-    <refentrytitle>systemd-hibernate-resume@.service</refentrytitle>
+    <refentrytitle>systemd-hibernate-resume.service</refentrytitle>
     <manvolnum>8</manvolnum>
   </refmeta>
 
   <refnamediv>
-    <refname>systemd-hibernate-resume@.service</refname>
+    <refname>systemd-hibernate-resume.service</refname>
     <refname>systemd-hibernate-resume</refname>
     <refpurpose>Resume from hibernation</refpurpose>
   </refnamediv>
 
   <refsynopsisdiv>
-    <para><filename>systemd-hibernate-resume@.service</filename></para>
+    <para><filename>systemd-hibernate-resume.service</filename></para>
     <para><filename>/usr/lib/systemd/systemd-hibernate-resume</filename></para>
   </refsynopsisdiv>
 
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-hibernate-resume@.service</filename>
-    initiates the resume from hibernation. It is instantiated with the
-    device to resume from as the template argument.</para>
+    <para><filename>systemd-hibernate-resume.service</filename> initiates the resume from hibernation.</para>
 
-    <para><filename>systemd-hibernate-resume</filename> only supports
-    the in-kernel hibernation implementation, see
-    <ulink url="https://docs.kernel.org/power/swsusp.html">Swap suspend</ulink>.
-    Internally, it works by writing the major:minor of specified
-    device node to <filename>/sys/power/resume</filename>.</para>
+    <para><filename>systemd-hibernate-resume</filename> only supports the in-kernel hibernation
+    implementation, see <ulink url="https://docs.kernel.org/power/swsusp.html">Swap suspend</ulink>.
+    Internally, it works by writing the major:minor of specified device node to
+    <filename>/sys/power/resume</filename>, along with the offset in memory pages
+    (<filename>/sys/power/resume_offset</filename>) if supported.</para>
 
-    <para>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.</para>
+    <para>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.</para>
   </refsect1>
 
   <refsect1>
index 98fcddf6318b3939b42618b5e7ffd40a049e9efa..bc9c9eb011c8a6a68eeec1ae07e97d1dd342614d 100644 (file)
@@ -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"
index 36ea9bbefb0cc3356f54290cba76ffa6033a4596..542c39e186365fa009b3f8e0eece8fae15d12851 100644 (file)
@@ -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;
index 1bcf9d69df04c0015c0fbf2e147dcfe886941da1..db23a1d5262a904a5e1631c38fa7646b7168248c 100644 (file)
@@ -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);
 
index 9a9df5d22f6a64678ca7a62fe47c2d32bdd3c533..28cab191fc9a2875eb6d255788ff04da966412a5 100644 (file)
@@ -1,58 +1,55 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <errno.h>
-#include <stdio.h>
 #include <sys/stat.h>
 
-#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);
index df6da78abecfa9051a06f752293f01dc6092eed3..dff7b3904f5ef764208a474fbeaae0c587967bda 100644 (file)
@@ -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 (file)
index 142bb33..0000000
+++ /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