]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop: parse and store disk sequence number
authorLuca Boccassi <luca.boccassi@microsoft.com>
Tue, 20 Jul 2021 14:25:06 +0000 (15:25 +0100)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Wed, 28 Jul 2021 18:59:38 +0000 (19:59 +0100)
When loop devices are re-used, the disk sequence number is increased.
Parse it when creating a loop device and store it.
The kernel will never return DISKSEQ=0, so use it to signal that it's
not supported by the current kernel.

src/basic/missing_loop.h
src/shared/loop-util.c
src/shared/loop-util.h

index b22ebda9fda26528d0121a6344624dc40cab745f..99e90543ffa995e21137fe0acc50fc7d3c104581 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
+#include <linux/fs.h>
 #include <linux/loop.h>
 
 #ifndef LOOP_CONFIGURE
@@ -13,3 +14,7 @@ struct loop_config {
 
 #define LOOP_CONFIGURE 0x4C0A
 #endif
+
+#ifndef BLKGETDISKSEQ
+#define BLKGETDISKSEQ _IOR(0x12,128,__u64)
+#endif
index c038e7aae6c60aae05586765fa8002e6e69908c7..933756cf80b24e61a254b45690332d496d360a07 100644 (file)
@@ -127,6 +127,27 @@ static int device_has_block_children(sd_device *d) {
         return 0;
 }
 
+static int loop_get_diskseq(int fd, uint64_t *ret_diskseq) {
+        uint64_t diskseq;
+
+        assert(fd >= 0);
+        assert(ret_diskseq);
+
+        if (ioctl(fd, BLKGETDISKSEQ, &diskseq) < 0) {
+                /* Note that the kernel is weird: non-existing ioctls currently return EINVAL
+                 * rather than ENOTTY on loopback block devices. They should fix that in the kernel,
+                 * but in the meantime we accept both here. */
+                if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL)
+                        return -errno;
+
+                return -EOPNOTSUPP;
+        }
+
+        *ret_diskseq = diskseq;
+
+        return 0;
+}
+
 static int loop_configure(
                 int fd,
                 int nr,
@@ -388,6 +409,7 @@ int loop_device_make(
 
                 if (offset == 0 && IN_SET(size, 0, UINT64_MAX)) {
                         _cleanup_close_ int copy = -1;
+                        uint64_t diskseq = 0;
 
                         /* If this is already a block device, store a copy of the fd as it is */
 
@@ -395,6 +417,10 @@ int loop_device_make(
                         if (copy < 0)
                                 return -errno;
 
+                        r = loop_get_diskseq(copy, &diskseq);
+                        if (r < 0 && r != -EOPNOTSUPP)
+                                return r;
+
                         d = new(LoopDevice, 1);
                         if (!d)
                                 return -ENOMEM;
@@ -404,6 +430,7 @@ int loop_device_make(
                                 .node = TAKE_PTR(loopdev),
                                 .relinquished = true, /* It's not allocated by us, don't destroy it when this object is freed */
                                 .devno = st.st_rdev,
+                                .diskseq = diskseq,
                                 .uevent_seqnum_not_before = UINT64_MAX,
                                 .timestamp_not_before = USEC_INFINITY,
                         };
@@ -482,6 +509,11 @@ int loop_device_make(
                 return -errno;
         assert(S_ISBLK(st.st_mode));
 
+        uint64_t diskseq = 0;
+        r = loop_get_diskseq(loop_with_fd, &diskseq);
+        if (r < 0 && r != -EOPNOTSUPP)
+                return r;
+
         d = new(LoopDevice, 1);
         if (!d)
                 return -ENOMEM;
@@ -490,6 +522,7 @@ int loop_device_make(
                 .node = TAKE_PTR(loopdev),
                 .nr = nr,
                 .devno = st.st_rdev,
+                .diskseq = diskseq,
                 .uevent_seqnum_not_before = seqnum,
                 .timestamp_not_before = timestamp,
         };
index e06dfebb7c6656ca39b12deb6298c9cab358f70e..964ce3ed083c1affe098d345acbaba8dc0b954e6 100644 (file)
@@ -14,6 +14,7 @@ struct LoopDevice {
         dev_t devno;
         char *node;
         bool relinquished;
+        uint64_t diskseq; /* Block device sequence number, monothonically incremented by the kernel on create/attach, or 0 if we don't know */
         uint64_t uevent_seqnum_not_before; /* uevent sequm right before we attached the loopback device, or UINT64_MAX if we don't know */
         usec_t timestamp_not_before; /* CLOCK_MONOTONIC timestamp taken immediately before attaching the loopback device, or USEC_INFINITY if we don't know */
 };