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,
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 */
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;
.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,
};
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;
.node = TAKE_PTR(loopdev),
.nr = nr,
.devno = st.st_rdev,
+ .diskseq = diskseq,
.uevent_seqnum_not_before = seqnum,
.timestamp_not_before = timestamp,
};
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 */
};