]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: re-introduce symlinks for loopback block device
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 21 Jul 2023 01:26:13 +0000 (10:26 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 9 Aug 2023 22:05:47 +0000 (07:05 +0900)
But the directories are changed from /dev/loop/by-ref/ -> /dev/disk/by-loop-ref/
and /dev/loop/by-inode/ -> /dev/disk/by-loop-inode/.
As /dev/loop/ is used by losetup command for other purpose.
See issue #28475.

This effectively reverts commits 9915cc60868c77e7e8cecb669ddb90516dffc7df,
5022fab15fc16204d163883ca818fd6092dc919c, and
c0d998248e10e1dcf18108fdbb70f259acd452eb.

NEWS
man/systemd-dissect.xml
rules.d/60-persistent-storage.rules.in
src/shared/loop-util.c
test/units/testsuite-50.sh

diff --git a/NEWS b/NEWS
index e369b60af29cb35114d0f4a3a5106c1ecf1d34ab..6492b713f368e172a8cbabe80fdb783a1fd11018 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,23 @@ CHANGES WITH 255 in spe:
           by default when combined with --scope, will be changed in a future
           release to be enabled by default.
 
+        Device Management:
+
+        * udev will now create symlinks to loopback block devices in the
+          /dev/disk/by-loop-ref/ directory that are based on the .lo_file_name
+          string field selected during allocation. The systemd-dissect tool and
+          the util-linux losetup command now supports a complementing new
+          switch --loop-ref= for selecting the string. This means a loopback
+          block device may now be allocated under a caller-chosen reference and
+          can subsequently be referenced by that without first having to look
+          up the block device name the caller ended up with.
+
+        * udev also creates symlinks to loopback block devices in the
+          /dev/disk/by-loop-inode/ directory based on the .st_dev/st_ino fields
+          of the inode attached to the loopback block device. This means that
+          attaching a file to a loopback device will implicitly make a handle
+          available to be found via that file's inode information.
+
         Network Management:
 
         * The "duid-only" option for DHCPv4 client's ClientIdentifier= setting
index 9a3ed6ce7b2059b59ee34eda2f6747bf55be04a2..27c5d3c7a84858764afd839eeb2e1b1ce44b4211 100644 (file)
         <literal>.lo_file_name</literal> field for the block device. Note this is distinct from the
         <filename>/sys/class/block/loopX/loop/backing_file</filename> attribute file that always reports a
         path referring to the actual backing file. The latter is subject to mount namespace translation, the
-        former is not.</para></listitem>
+        former is not.</para>
+
+        <para>This setting is particularly useful in combination with the <option>--attach</option> command,
+        as it allows later referencing the allocated loop device via
+        <filename>/dev/disk/by-loop-ref/…</filename> symlinks. Example: first, set up the loopback device
+        via <command>systemd-dissect attach --loop-ref=quux foo.raw</command>, and then reference it in a
+        command via the specified filename: <command>cfdisk /dev/disk/by-loop-ref/quux</command>.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
index d5e0f5f705ee0cd46203f77ad5d34124338ed1c2..39a65550457bc1f654ce188e73988ae97c877757 100644 (file)
@@ -161,4 +161,13 @@ ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/
 # the right device, to access specific disks in a race-free fashion)
 ENV{DISKSEQ}=="?*", ENV{ID_IGNORE_DISKSEQ}!="1", SYMLINK+="disk/by-diskseq/$env{DISKSEQ}$env{.PART_SUFFIX}"
 
+# Create symlinks that allow referencing loopback devices by their backing file's inode number
+ENV{ID_LOOP_BACKING_DEVICE}!="", ENV{ID_LOOP_BACKING_INODE}!="", SYMLINK+="disk/by-loop-inode/$env{ID_LOOP_BACKING_DEVICE}-$env{ID_LOOP_BACKING_INODE}$env{.PART_SUFFIX}"
+
+# Similar, but uses the .lo_file_name field of the loopback device (note that
+# this is basically just a free-form string passed from userspace to the kernel
+# when the device is created, it is not necessarily a file system path like the
+# "loop/backing_file" sysfs attribute, which is always an absolute path)
+ENV{ID_LOOP_BACKING_FILENAME_ENC}!="", SYMLINK+="disk/by-loop-ref/$env{ID_LOOP_BACKING_FILENAME_ENC}$env{.PART_SUFFIX}"
+
 LABEL="persistent_storage_end"
index 9c31d265b6f4d016c1301338f03d62e12d27d60b..cab8ef3e7a9630f7c402dd1c53f398ce48307d2e 100644 (file)
@@ -1156,7 +1156,11 @@ int loop_device_set_filename(LoopDevice *d, const char *name) {
         /* Sets the .lo_file_name of the loopback device. This is supposed to contain the path to the file
          * backing the block device, but is actually just a free-form string you can pass to the kernel. Most
          * tools that actually care for the backing file path use the sysfs attribute file loop/backing_file
-         * which is a kernel generated string, subject to file system namespaces and such. */
+         * which is a kernel generated string, subject to file system namespaces and such.
+         *
+         * .lo_file_name is useful since userspace can select it freely when creating a loopback block
+         * device, and we can use it for /dev/disk/by-loop-ref/ symlinks, and similar, so that apps can
+         * recognize their own loopback files. */
 
         if (name && strlen(name) >= sizeof(info.lo_file_name))
                 return -ENOBUFS;
index efdbe6ac74e471a2ad541f75159173c6014e15a4..21e9c75526345d71dba151cf70be5f016f88ef31 100755 (executable)
@@ -470,6 +470,48 @@ mount -t ddi "${image}.gpt" "$T" -o ro,X-mount.mkdir,discard
 umount -R "$T"
 rmdir "$T"
 
+LOOP="$(systemd-dissect --attach --loop-ref=waldo "${image}.raw")"
+
+# Wait until the symlinks we want to test are established
+udevadm trigger -w "$LOOP"
+
+# Check if the /dev/loop/* symlinks really reference the right device
+test /dev/disk/by-loop-ref/waldo -ef "$LOOP"
+
+if [ "$(stat -c '%Hd:%Ld' "${image}.raw")" != '?d:?d' ] ; then
+   # Old stat didn't know the %Hd and %Ld specifiers and turned them into ?d
+   # instead. Let's simply skip the test on such old systems.
+   test "$(stat -c '/dev/disk/by-loop-inode/%Hd:%Ld-%i' "${image}.raw")" -ef "$LOOP"
+fi
+
+# Detach by loopback device
+systemd-dissect --detach "$LOOP"
+
+# Test long reference name.
+# Note, sizeof_field(struct loop_info64, lo_file_name) == 64,
+# and --loop-ref accepts upto 63 characters, and udev creates symlink
+# based on the name when it has upto _62_ characters.
+name="$(for _ in {1..62}; do echo -n 'x'; done)"
+LOOP="$(systemd-dissect --attach --loop-ref="$name" "${image}.raw")"
+udevadm trigger -w "$LOOP"
+
+# Check if the /dev/disk/by-loop-ref/$name symlink really references the right device
+test "/dev/disk/by-loop-ref/$name" -ef "$LOOP"
+
+# Detach by the /dev/disk/by-loop-ref symlink
+systemd-dissect --detach "/dev/disk/by-loop-ref/$name"
+
+name="$(for _ in {1..63}; do echo -n 'x'; done)"
+LOOP="$(systemd-dissect --attach --loop-ref="$name" "${image}.raw")"
+udevadm trigger -w "$LOOP"
+
+# Check if the /dev/disk/by-loop-ref/$name symlink does not exist
+test ! -e "/dev/disk/by-loop-ref/$name"
+
+# Detach by backing inode
+systemd-dissect --detach "${image}.raw"
+(! systemd-dissect --detach "${image}.raw")
+
 # check for confext functionality
 mkdir -p /run/confexts/test/etc/extension-release.d
 echo "ID=_any" >/run/confexts/test/etc/extension-release.d/extension-release.test