fstab-generator: support swap on network block devices

Teach swap units to support the _netdev option as well, which should
make swaps on iSCSI possible. This mirrors the logic we already have for
regular mounts in both the fstab-generator and the core
(mount.c/swap.c).

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Frantisek Sumsal
2026-04-08 11:51:09 +01:00
committed by Luca Boccassi
parent 5332cf31fc
commit 3d5bd67a22
15 changed files with 114 additions and 15 deletions
+26 -4
View File
@@ -90,9 +90,15 @@
<para>The following dependencies are added unless <varname>DefaultDependencies=no</varname> is set:</para> <para>The following dependencies are added unless <varname>DefaultDependencies=no</varname> is set:</para>
<itemizedlist> <itemizedlist>
<listitem><para>Swap units automatically acquire a <varname>Conflicts=</varname> and a <listitem><para>Local swap units automatically acquire a <varname>Conflicts=</varname> and a
<varname>Before=</varname> dependency on <filename>umount.target</filename> so that they are deactivated at <varname>Before=</varname> dependency on <filename>umount.target</filename> so that they are deactivated at
shutdown as well as a <varname>Before=swap.target</varname> dependency.</para></listitem> shutdown as well as a <varname>Before=swap.target</varname> dependency.</para></listitem>
<listitem><para>Network swap units (those with <option>_netdev</option> in their options) automatically acquire
<varname>After=</varname> dependencies on <filename>remote-fs-pre.target</filename> and
<filename>network.target</filename>, plus <varname>After=</varname> and <varname>Wants=</varname> dependencies
on <filename>network-online.target</filename>, and a <varname>Before=</varname> dependency on
<filename>remote-fs.target</filename> instead of <filename>swap.target</filename>.</para></listitem>
</itemizedlist> </itemizedlist>
</refsect2> </refsect2>
</refsect1> </refsect1>
@@ -124,7 +130,8 @@
<listitem><para>With <option>noauto</option>, the swap unit <listitem><para>With <option>noauto</option>, the swap unit
will not be added as a dependency for will not be added as a dependency for
<filename>swap.target</filename>. This means that it will not <filename>swap.target</filename> (or <filename>remote-fs.target</filename> for network swap devices,
see <option>_netdev</option> below). This means that it will not
be activated automatically during boot, unless it is pulled in be activated automatically during boot, unless it is pulled in
by some other unit. The <option>auto</option> option has the by some other unit. The <option>auto</option> option has the
opposite meaning and is the default.</para> opposite meaning and is the default.</para>
@@ -138,8 +145,8 @@
<listitem><para>With <option>nofail</option>, the swap unit <listitem><para>With <option>nofail</option>, the swap unit
will be only wanted, not required by will be only wanted, not required by
<filename>swap.target</filename>. This means that the boot <filename>swap.target</filename> (or <filename>remote-fs.target</filename> for network swap
will continue even if this swap device is not activated devices). This means that the boot will continue even if this swap device is not activated
successfully.</para> successfully.</para>
<xi:include href="version-info.xml" xpointer="v218"/> <xi:include href="version-info.xml" xpointer="v218"/>
@@ -167,6 +174,21 @@
<xi:include href="version-info.xml" xpointer="v240"/></listitem> <xi:include href="version-info.xml" xpointer="v240"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>_netdev</option></term>
<listitem><para>Marks this swap device as requiring network access. This is useful for swap on
network block devices (e.g. iSCSI).</para>
<para>Network swap units are ordered between <filename>remote-fs-pre.target</filename> and
<filename>remote-fs.target</filename>, instead of being ordered before
<filename>swap.target</filename>. They also pull in <filename>network-online.target</filename> and
are ordered after it and <filename>network.target</filename>.</para>
<xi:include href="version-info.xml" xpointer="v261"/>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
+40 -6
View File
@@ -223,6 +223,7 @@ static int swap_add_device_dependencies(Swap *s) {
} }
static int swap_add_default_dependencies(Swap *s) { static int swap_add_default_dependencies(Swap *s) {
SwapParameters *p;
int r; int r;
assert(s); assert(s);
@@ -236,13 +237,46 @@ static int swap_add_default_dependencies(Swap *s) {
if (detect_container() > 0) if (detect_container() > 0)
return 0; return 0;
/* swap units generated for the swap dev links are missing the p = swap_get_parameters(s);
* ordering dep against the swap target. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, UNIT_DEPENDENCY_DEFAULT); if (p && fstab_test_option(p->options, "_netdev\0")) {
/* Network swap devices (those with _netdev in options) are routed through
* remote-fs.target instead of swap.target, mirroring how network mounts use
* remote-fs.target instead of local-fs.target. This avoids an ordering cycle:
* swap.target is pulled in at sysinit.target time, but network-online.target
* only comes after basic.target which is after sysinit.target. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOTE_FS_PRE_TARGET,
/* add_reference= */ true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET,
/* add_reference= */ true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
/* Pull in and order after network-online.target, analogous to
* mount_add_default_network_dependencies() for network mounts. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_NETWORK_TARGET,
/* add_reference= */ true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET,
/* add_reference= */ true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
} else {
/* swap units generated for the swap dev links are missing the
* ordering dep against the swap target. */
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET,
/* add_reference= */ true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
}
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET,
/* add_reference= */ true, UNIT_DEPENDENCY_DEFAULT);
} }
static int swap_verify(Swap *s) { static int swap_verify(Swap *s) {
+14 -3
View File
@@ -221,6 +221,7 @@ static int add_swap(
_cleanup_free_ char *name = NULL; _cleanup_free_ char *name = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
bool is_network;
int r; int r;
assert(what); assert(what);
@@ -240,11 +241,14 @@ static int add_swap(
return true; return true;
} }
log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s", is_network = fstab_test_option(options, "_netdev\0");
log_debug("Found swap entry what=%s makefs=%s growfs=%s pcrfs=%s validatefs=%s noauto=%s nofail=%s netdev=%s",
what, what,
yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS), yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
yes_no(flags & MOUNT_PCRFS), yes_no(flags & MOUNT_VALIDATEFS), yes_no(flags & MOUNT_PCRFS), yes_no(flags & MOUNT_VALIDATEFS),
yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL)); yes_no(flags & MOUNT_NOAUTO), yes_no(flags & MOUNT_NOFAIL),
yes_no(is_network));
r = unit_name_from_path(what, ".swap", &name); r = unit_name_from_path(what, ".swap", &name);
if (r < 0) if (r < 0)
@@ -285,6 +289,12 @@ static int add_swap(
if (r < 0) if (r < 0)
return r; return r;
if (is_network) {
r = generator_write_network_device_deps(arg_dest, what, /* where= */ NULL, options);
if (r < 0)
return r;
}
if (flags & MOUNT_MAKEFS) { if (flags & MOUNT_MAKEFS) {
r = generator_hook_up_mkswap(arg_dest, what); r = generator_hook_up_mkswap(arg_dest, what);
if (r < 0) if (r < 0)
@@ -300,7 +310,8 @@ static int add_swap(
log_warning("%s: validating swap devices is currently unsupported.", what); log_warning("%s: validating swap devices is currently unsupported.", what);
if (!(flags & MOUNT_NOAUTO)) { if (!(flags & MOUNT_NOAUTO)) {
r = generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, const char *target = is_network ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_SWAP_TARGET;
r = generator_add_symlink(arg_dest, target,
(flags & MOUNT_NOFAIL) ? "wants" : "requires", name); (flags & MOUNT_NOFAIL) ? "wants" : "requires", name);
if (r < 0) if (r < 0)
return r; return r;
+1 -2
View File
@@ -490,9 +490,8 @@ int generator_write_network_device_deps(
assert(dir); assert(dir);
assert(what); assert(what);
assert(where);
if (fstab_is_extrinsic(where, opts)) if (where && fstab_is_extrinsic(where, opts))
return 0; return 0;
if (!fstab_test_option(opts, "_netdev\0")) if (!fstab_test_option(opts, "_netdev\0"))
@@ -0,0 +1,5 @@
# Automatically generated by systemd-fstab-generator
[Unit]
After=network-online.target network.target
Wants=network-online.target
@@ -0,0 +1,10 @@
# Automatically generated by systemd-fstab-generator
[Unit]
Documentation=man:fstab(5) man:systemd-fstab-generator(8)
SourcePath=/etc/fstab
After=blockdev@dev-sdx1.target
[Swap]
What=/dev/sdx1
Options=_netdev
@@ -0,0 +1,5 @@
# Automatically generated by systemd-fstab-generator
[Unit]
After=network-online.target network.target
Wants=network-online.target
@@ -0,0 +1,10 @@
# Automatically generated by systemd-fstab-generator
[Unit]
Documentation=man:fstab(5) man:systemd-fstab-generator(8)
SourcePath=/etc/fstab
After=blockdev@dev-sdx1.target
[Swap]
What=/dev/sdx1
Options=_netdev
@@ -0,0 +1 @@
/dev/sdx1 none swap _netdev 0 0