]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fstab-generator: support swap on network block devices
authorFrantisek Sumsal <frantisek@sumsal.cz>
Tue, 7 Apr 2026 09:16:42 +0000 (11:16 +0200)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 8 Apr 2026 10:51:09 +0000 (11:51 +0100)
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>
15 files changed:
man/systemd.swap.xml
src/core/swap.c
src/fstab-generator/fstab-generator.c
src/shared/generator.c
test/test-fstab-generator/test-21-swap-netdev.fstab.expected.container.sysroot/local-fs.target.wants/systemd-remount-fs.service [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected.container/initrd-usr-fs.target.requires/sysroot.mount [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/dev-sdx1.device.d/50-netdev-dependencies.conf [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/dev-sdx1.swap [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/local-fs.target.wants/systemd-remount-fs.service [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/remote-fs.target.requires/dev-sdx1.swap [new symlink]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected/dev-sdx1.device.d/50-netdev-dependencies.conf [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected/dev-sdx1.swap [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected/initrd-usr-fs.target.requires/sysroot.mount [new file with mode: 0644]
test/test-fstab-generator/test-21-swap-netdev.fstab.expected/remote-fs.target.requires/dev-sdx1.swap [new symlink]
test/test-fstab-generator/test-21-swap-netdev.fstab.input [new file with mode: 0644]

index 2b65ba68f3f6dfa68f45019fa187c25aaf125689..2dc98d3f5d9bbd708f00159aaeb6d5723407a2ef 100644 (file)
       <para>The following dependencies are added unless <varname>DefaultDependencies=no</varname> is set:</para>
 
       <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
         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>
     </refsect2>
   </refsect1>
 
         <listitem><para>With <option>noauto</option>, the swap unit
         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
         by some other unit. The <option>auto</option> option has the
         opposite meaning and is the default.</para>
 
         <listitem><para>With <option>nofail</option>, the swap unit
         will be only wanted, not required by
-        <filename>swap.target</filename>. This means that the boot
-        will continue even if this swap device is not activated
+        <filename>swap.target</filename> (or <filename>remote-fs.target</filename> for network swap
+        devices). This means that the boot will continue even if this swap device is not activated
         successfully.</para>
 
         <xi:include href="version-info.xml" xpointer="v218"/>
 
         <xi:include href="version-info.xml" xpointer="v240"/></listitem>
       </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>
   </refsect1>
 
index 960d831c5cc3d3fce4744c9ff23936ffc7f5bb77..cedabc430dc0ccddb2c215d0c23850620198c58a 100644 (file)
@@ -223,6 +223,7 @@ static int swap_add_device_dependencies(Swap *s) {
 }
 
 static int swap_add_default_dependencies(Swap *s) {
+        SwapParameters *p;
         int r;
 
         assert(s);
@@ -236,13 +237,46 @@ static int swap_add_default_dependencies(Swap *s) {
         if (detect_container() > 0)
                 return 0;
 
-        /* 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, true, UNIT_DEPENDENCY_DEFAULT);
-        if (r < 0)
-                return r;
+        p = swap_get_parameters(s);
+
+        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, true, UNIT_DEPENDENCY_DEFAULT);
+        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) {
index 1bfebf3c4089f6c4983bdfcfd65b6f83d3dd8596..572f30a1cf7f42851c732e67802dffc18813cbf3 100644 (file)
@@ -221,6 +221,7 @@ static int add_swap(
 
         _cleanup_free_ char *name = NULL;
         _cleanup_fclose_ FILE *f = NULL;
+        bool is_network;
         int r;
 
         assert(what);
@@ -240,11 +241,14 @@ static int add_swap(
                 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,
                   yes_no(flags & MOUNT_MAKEFS), yes_no(flags & MOUNT_GROWFS),
                   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);
         if (r < 0)
@@ -285,6 +289,12 @@ static int add_swap(
         if (r < 0)
                 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) {
                 r = generator_hook_up_mkswap(arg_dest, what);
                 if (r < 0)
@@ -300,7 +310,8 @@ static int add_swap(
                 log_warning("%s: validating swap devices is currently unsupported.", what);
 
         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);
                 if (r < 0)
                         return r;
index 603e969436e9b4852e83904ec968b5a5e9ae73bd..fd527b3e6d65a2aa1380b47b319189c302592870 100644 (file)
@@ -490,9 +490,8 @@ int generator_write_network_device_deps(
 
         assert(dir);
         assert(what);
-        assert(where);
 
-        if (fstab_is_extrinsic(where, opts))
+        if (where && fstab_is_extrinsic(where, opts))
                 return 0;
 
         if (!fstab_test_option(opts, "_netdev\0"))
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.container.sysroot/local-fs.target.wants/systemd-remount-fs.service b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.container.sysroot/local-fs.target.wants/systemd-remount-fs.service
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.container/initrd-usr-fs.target.requires/sysroot.mount b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.container/initrd-usr-fs.target.requires/sysroot.mount
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/dev-sdx1.device.d/50-netdev-dependencies.conf b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/dev-sdx1.device.d/50-netdev-dependencies.conf
new file mode 100644 (file)
index 0000000..33d814c
--- /dev/null
@@ -0,0 +1,5 @@
+# Automatically generated by systemd-fstab-generator
+
+[Unit]
+After=network-online.target network.target
+Wants=network-online.target
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/dev-sdx1.swap b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/dev-sdx1.swap
new file mode 100644 (file)
index 0000000..32f276c
--- /dev/null
@@ -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
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/local-fs.target.wants/systemd-remount-fs.service b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/local-fs.target.wants/systemd-remount-fs.service
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/remote-fs.target.requires/dev-sdx1.swap b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected.sysroot/remote-fs.target.requires/dev-sdx1.swap
new file mode 120000 (symlink)
index 0000000..00f0c5c
--- /dev/null
@@ -0,0 +1 @@
+../dev-sdx1.swap
\ No newline at end of file
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/dev-sdx1.device.d/50-netdev-dependencies.conf b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/dev-sdx1.device.d/50-netdev-dependencies.conf
new file mode 100644 (file)
index 0000000..33d814c
--- /dev/null
@@ -0,0 +1,5 @@
+# Automatically generated by systemd-fstab-generator
+
+[Unit]
+After=network-online.target network.target
+Wants=network-online.target
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/dev-sdx1.swap b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/dev-sdx1.swap
new file mode 100644 (file)
index 0000000..32f276c
--- /dev/null
@@ -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
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/initrd-usr-fs.target.requires/sysroot.mount b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/initrd-usr-fs.target.requires/sysroot.mount
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/remote-fs.target.requires/dev-sdx1.swap b/test/test-fstab-generator/test-21-swap-netdev.fstab.expected/remote-fs.target.requires/dev-sdx1.swap
new file mode 120000 (symlink)
index 0000000..00f0c5c
--- /dev/null
@@ -0,0 +1 @@
+../dev-sdx1.swap
\ No newline at end of file
diff --git a/test/test-fstab-generator/test-21-swap-netdev.fstab.input b/test/test-fstab-generator/test-21-swap-netdev.fstab.input
new file mode 100644 (file)
index 0000000..5f719a4
--- /dev/null
@@ -0,0 +1 @@
+/dev/sdx1  none  swap  _netdev  0 0