loop: parse and store disk sequence number

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.
This commit is contained in:
Luca Boccassi
2021-07-28 19:59:38 +01:00
parent 122adcb294
commit bcef1743a5
3 changed files with 39 additions and 0 deletions
+5
View 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
+33
View 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,
};
+1
View 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 */
};