1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-28 02:50:16 +03:00

hibernate-resume: rework to follow the logic of sleep.c and use

main-func.h

Preparation for #27247
This commit is contained in:
Mike Yuan 2023-04-19 01:21:55 +08:00
parent 93d82cfcae
commit 760e99bb52
No known key found for this signature in database
GPG Key ID: 417471C0A40F58B3
10 changed files with 111 additions and 104 deletions

View 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,

View 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'],

View 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>
@ -55,6 +55,13 @@
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>

View 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>

View 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"

View 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;

View 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);

View 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);

View 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'],

View File

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