]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev-node: skip stack directory creation for diskseq
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 6 Oct 2024 05:43:45 +0000 (14:43 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 7 Oct 2024 00:56:26 +0000 (09:56 +0900)
The disk/by-diskseq symlink should not be shared with multiple block
devices. Hence, it is not necessary to create stack directory for the
symlink that manages which device owns the symlink.

This is not just a optimization.
If a service unit tries to mount a disk image but the service fails, then
the diskseq of the loop device for the image may be continuously increased
during restart, and inodes in /run may increase rapidly, as the stack
directories are cleaned up only when udev queue is empty.

Fixes #34637.

src/udev/udev-node.c

index a4e73025a0ed6df6636696b7f20b0384bf9cda15..0b9ce5ed6a6d140c580fc4e058be4ba9db9a4f19 100644 (file)
@@ -423,6 +423,85 @@ static int node_get_current(const char *slink, int dirfd, char **ret_id, int *re
         return 0;
 }
 
+static int link_update_diskseq(sd_device *dev, const char *slink, bool add) {
+        _cleanup_free_ char *buf = NULL;
+        const char *fname, *diskseq;
+        int r;
+
+        assert(dev);
+        assert(slink);
+
+        if (!device_in_subsystem(dev, "block"))
+                return 0;
+
+        fname = path_startswith(slink, "/dev/disk/by-diskseq");
+        if (isempty(fname))
+                return 0;
+
+        if (device_is_devtype(dev, "partition")) {
+                _cleanup_free_ char *suffix = NULL;
+                const char *partn, *p;
+
+                /* Check if the symlink has an expected suffix "-part%n". See 60-persistent-storage.rules. */
+
+                r = sd_device_get_sysnum(dev, &partn);
+                if (r < 0) {
+                        /* Cannot verify the symlink is owned by this device. Let's create the stack directory for the symlink. */
+                        log_device_debug_errno(dev, r, "Failed to get sysnum, but symlink '%s' is requested, ignoring: %m", slink);
+                        return 0;
+                }
+
+                suffix = strjoin("-part", partn);
+                if (!suffix)
+                        return -ENOMEM;
+
+                p = endswith(fname, suffix);
+                if (!p) {
+                        log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested, proceeding anyway.", slink);
+                        return 0;
+                }
+
+                buf = strndup(fname, p - fname);
+                if (!buf)
+                        return -ENOMEM;
+
+                fname = buf;
+        }
+
+        /* Check if the diskseq part of the symlink is in digits. */
+        if (!in_charset(fname, DIGITS)) {
+                log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested, proceeding anyway.", slink);
+                return 0; /* unexpected by-diskseq symlink */
+        }
+
+        /* On removal, we cannot verify the diskseq. Skipping further check below. */
+        if (!add) {
+                if (unlink(slink) < 0 && errno != ENOENT)
+                        return log_device_debug_errno(dev, errno, "Failed to remove '%s': %m", slink);
+
+                (void) rmdir_parents(slink, "/dev");
+                return 1; /* done */
+        }
+
+        /* Check if the diskseq matches with the DISKSEQ property. */
+        r = sd_device_get_property_value(dev, "DISKSEQ", &diskseq);
+        if (r < 0) {
+                log_device_debug_errno(dev, r, "Failed to get DISKSEQ property, but symlink '%s' is requested, ignoring: %m", slink);
+                return 0;
+        }
+
+        if (!streq(fname, diskseq)) {
+                log_device_debug(dev, "Unexpected by-diskseq symlink '%s' is requested (DISKSEQ=%s), proceeding anyway.", slink, diskseq);
+                return 0;
+        }
+
+        r = node_symlink(dev, /* devnode = */ NULL, slink);
+        if (r < 0)
+                return r;
+
+        return 1; /* done */
+}
+
 static int link_update(sd_device *dev, const char *slink, bool add) {
         _cleanup_free_ char *current_id = NULL, *devnode = NULL;
         _cleanup_close_ int dirfd = -EBADF, lockfd = -EBADF;
@@ -431,6 +510,10 @@ static int link_update(sd_device *dev, const char *slink, bool add) {
         assert(dev);
         assert(slink);
 
+        r = link_update_diskseq(dev, slink, add);
+        if (r != 0)
+                return r;
+
         r = stack_directory_open(dev, slink, &dirfd, &lockfd);
         if (r < 0)
                 return r;