summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/basic/missing_loop.h5
-rw-r--r--src/core/namespace.c1
-rw-r--r--src/dissect/dissect.c1
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c1
-rw-r--r--src/libsystemd/libsystemd.sym5
-rw-r--r--src/libsystemd/sd-device/device-internal.h2
-rw-r--r--src/libsystemd/sd-device/device-private.c26
-rw-r--r--src/libsystemd/sd-device/sd-device.c12
-rw-r--r--src/nspawn/nspawn.c1
-rw-r--r--src/portable/portable.c1
-rw-r--r--src/shared/discover-image.c1
-rw-r--r--src/shared/dissect-image.c56
-rw-r--r--src/shared/dissect-image.h4
-rw-r--r--src/shared/loop-util.c33
-rw-r--r--src/shared/loop-util.h1
-rw-r--r--src/sysext/sysext.c1
-rw-r--r--src/systemd/sd-device.h1
-rw-r--r--src/test/test-loop-block.c6
18 files changed, 140 insertions, 18 deletions
diff --git a/src/basic/missing_loop.h b/src/basic/missing_loop.h
index b22ebda9fd..99e90543ff 100644
--- a/src/basic/missing_loop.h
+++ b/src/basic/missing_loop.h
@@ -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
diff --git a/src/core/namespace.c b/src/core/namespace.c
index a31ea4b1bd..8d4388ded5 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -1905,6 +1905,7 @@ int setup_namespace(
loop_device->fd,
&verity,
root_image_options,
+ loop_device->diskseq,
loop_device->uevent_seqnum_not_before,
loop_device->timestamp_not_before,
dissect_image_flags,
diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c
index 4693e7433b..a42b138a80 100644
--- a/src/dissect/dissect.c
+++ b/src/dissect/dissect.c
@@ -795,6 +795,7 @@ static int run(int argc, char *argv[]) {
arg_image,
&arg_verity_settings,
NULL,
+ d->diskseq,
d->uevent_seqnum_not_before,
d->timestamp_not_before,
arg_flags,
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index 573fcf0d19..64ca9bb2f9 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -699,6 +699,7 @@ static int enumerate_partitions(dev_t devnum) {
r = dissect_image(
fd,
NULL, NULL,
+ /* diskseq= */ 0,
UINT64_MAX,
USEC_INFINITY,
DISSECT_IMAGE_GPT_ONLY|
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 3730db6eef..04db791f64 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -762,3 +762,8 @@ global:
sd_device_new_from_ifname;
sd_device_new_from_ifindex;
} LIBSYSTEMD_248;
+
+LIBSYSTEMD_250 {
+global:
+ sd_device_get_diskseq;
+} LIBSYSTEMD_249;
diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h
index f4d02f995e..76a1727b1c 100644
--- a/src/libsystemd/sd-device/device-internal.h
+++ b/src/libsystemd/sd-device/device-internal.h
@@ -75,6 +75,8 @@ struct sd_device {
uid_t devuid;
gid_t devgid;
+ uint64_t diskseq; /* Block device sequence number, monothonically incremented by the kernel on create/attach */
+
/* only set when device is passed through netlink */
sd_device_action_t action;
uint64_t seqnum;
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index 37c655578c..16a2e9e1e4 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -226,6 +226,28 @@ static int device_set_seqnum(sd_device *device, const char *str) {
return 0;
}
+static int device_set_diskseq(sd_device *device, const char *str) {
+ uint64_t diskseq;
+ int r;
+
+ assert(device);
+ assert(str);
+
+ r = safe_atou64(str, &diskseq);
+ if (r < 0)
+ return r;
+ if (diskseq == 0)
+ return -EINVAL;
+
+ r = device_add_property_internal(device, "DISKSEQ", str);
+ if (r < 0)
+ return r;
+
+ device->diskseq = diskseq;
+
+ return 0;
+}
+
static int device_amend(sd_device *device, const char *key, const char *value) {
int r;
@@ -292,6 +314,10 @@ static int device_amend(sd_device *device, const char *key, const char *value) {
r = device_set_seqnum(device, value);
if (r < 0)
return log_device_debug_errno(device, r, "sd-device: Failed to set SEQNUM to '%s': %m", value);
+ } else if (streq(key, "DISKSEQ")) {
+ r = device_set_diskseq(device, value);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "sd-device: Failed to set DISKSEQ to '%s': %m", value);
} else if (streq(key, "DEVLINKS")) {
for (const char *p = value;;) {
_cleanup_free_ char *word = NULL;
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index c7e1bd8bb8..3c54897536 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -1140,6 +1140,18 @@ _public_ int sd_device_get_seqnum(sd_device *device, uint64_t *ret) {
return 0;
}
+_public_ int sd_device_get_diskseq(sd_device *device, uint64_t *ret) {
+ assert_return(device, -EINVAL);
+
+ if (device->diskseq == 0)
+ return -ENOENT;
+
+ if (ret)
+ *ret = device->diskseq;
+
+ return 0;
+}
+
static bool is_valid_tag(const char *tag) {
assert(tag);
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 0ccab72170..f3d06d70d4 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -5692,6 +5692,7 @@ static int run(int argc, char *argv[]) {
arg_image,
&arg_verity_settings,
NULL,
+ loop->diskseq,
loop->uevent_seqnum_not_before,
loop->timestamp_not_before,
dissect_image_flags,
diff --git a/src/portable/portable.c b/src/portable/portable.c
index ba7fd58fc1..4044c523e1 100644
--- a/src/portable/portable.c
+++ b/src/portable/portable.c
@@ -393,6 +393,7 @@ static int portable_extract_by_path(
r = dissect_image(
d->fd,
NULL, NULL,
+ d->diskseq,
d->uevent_seqnum_not_before,
d->timestamp_not_before,
DISSECT_IMAGE_READ_ONLY |
diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c
index 5f8bf43776..b96a082aa3 100644
--- a/src/shared/discover-image.c
+++ b/src/shared/discover-image.c
@@ -1203,6 +1203,7 @@ int image_read_metadata(Image *i) {
r = dissect_image(
d->fd,
NULL, NULL,
+ d->diskseq,
d->uevent_seqnum_not_before,
d->timestamp_not_before,
DISSECT_IMAGE_GENERIC_ROOT |
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 32b21eb71b..99a2f62e4a 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -284,6 +284,7 @@ struct wait_data {
sd_device *parent_device;
blkid_partition blkidp;
sd_device *found;
+ uint64_t diskseq;
uint64_t uevent_seqnum_not_before;
usec_t timestamp_not_before;
DissectImageFlags flags;
@@ -302,7 +303,25 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
if (device_for_action(device, SD_DEVICE_REMOVE))
return 0;
- if (w->uevent_seqnum_not_before != UINT64_MAX) {
+ if (w->diskseq != 0) {
+ uint64_t diskseq;
+
+ /* If w->diskseq is non-zero, then we must have a disk seqnum */
+ r = sd_device_get_diskseq(device, &diskseq);
+ if (r < 0) {
+ log_debug_errno(r, "Dropping event because it has no diskseq, but waiting for %" PRIu64, w->diskseq);
+ return 0;
+ }
+ if (diskseq < w->diskseq) {
+ log_debug("Dropping event because diskseq too old (%" PRIu64 " < %" PRIu64 ")",
+ diskseq, w->diskseq);
+ return 0;
+ }
+ if (diskseq > w->diskseq) {
+ r = -EBUSY;
+ goto finish; /* Newer than what we were expecting, so we missed it, stop waiting */
+ }
+ } else if (w->uevent_seqnum_not_before != UINT64_MAX) {
uint64_t seqnum;
r = sd_device_get_seqnum(device, &seqnum);
@@ -378,6 +397,7 @@ static int wait_for_partition_device(
sd_device *parent,
blkid_partition pp,
usec_t deadline,
+ uint64_t diskseq,
uint64_t uevent_seqnum_not_before,
usec_t timestamp_not_before,
DissectImageFlags flags,
@@ -423,6 +443,7 @@ static int wait_for_partition_device(
_cleanup_(wait_data_done) struct wait_data w = {
.parent_device = parent,
.blkidp = pp,
+ .diskseq = diskseq,
.uevent_seqnum_not_before = uevent_seqnum_not_before,
.timestamp_not_before = timestamp_not_before,
.flags = flags,
@@ -450,16 +471,21 @@ static int wait_for_partition_device(
return r;
}
- r = sd_event_add_time_relative(
- event, &retry_source,
- CLOCK_MONOTONIC, 500 * USEC_PER_MSEC, 0,
- retry_handler, &w);
- if (r < 0)
- return r;
+ /* If we don't have a disk sequence number then we cannot do exact matching,
+ * and we cannot know if we missed it or if it has not been sent yet, so set
+ * up additional retries to increase the chances of receiving the event. */
+ if (diskseq == 0) {
+ r = sd_event_add_time_relative(
+ event, &retry_source,
+ CLOCK_MONOTONIC, 500 * USEC_PER_MSEC, 0,
+ retry_handler, &w);
+ if (r < 0)
+ return r;
- r = sd_event_source_set_exit_on_failure(retry_source, true);
- if (r < 0)
- return r;
+ r = sd_event_source_set_exit_on_failure(retry_source, true);
+ if (r < 0)
+ return r;
+ }
r = sd_event_loop(event);
if (r < 0)
@@ -583,6 +609,7 @@ int dissect_image(
int fd,
const VeritySettings *verity,
const MountOptions *mount_options,
+ uint64_t diskseq,
uint64_t uevent_seqnum_not_before,
usec_t timestamp_not_before,
DissectImageFlags flags,
@@ -838,7 +865,7 @@ int dissect_image(
if (!pp)
return errno_or_else(EIO);
- r = wait_for_partition_device(d, pp, deadline, uevent_seqnum_not_before, timestamp_not_before, flags, &q);
+ r = wait_for_partition_device(d, pp, deadline, diskseq, uevent_seqnum_not_before, timestamp_not_before, flags, &q);
if (r < 0)
return r;
@@ -2753,6 +2780,7 @@ int dissect_image_and_warn(
const char *name,
const VeritySettings *verity,
const MountOptions *mount_options,
+ uint64_t diskseq,
uint64_t uevent_seqnum_not_before,
usec_t timestamp_not_before,
DissectImageFlags flags,
@@ -2769,7 +2797,7 @@ int dissect_image_and_warn(
name = buffer;
}
- r = dissect_image(fd, verity, mount_options, uevent_seqnum_not_before, timestamp_not_before, flags, ret);
+ r = dissect_image(fd, verity, mount_options, diskseq, uevent_seqnum_not_before, timestamp_not_before, flags, ret);
switch (r) {
case -EOPNOTSUPP:
@@ -2877,7 +2905,7 @@ int mount_image_privately_interactively(
if (r < 0)
return log_error_errno(r, "Failed to set up loopback device for %s: %m", image);
- r = dissect_image_and_warn(d->fd, image, &verity, NULL, d->uevent_seqnum_not_before, d->timestamp_not_before, flags, &dissected_image);
+ r = dissect_image_and_warn(d->fd, image, &verity, NULL, d->diskseq, d->uevent_seqnum_not_before, d->timestamp_not_before, flags, &dissected_image);
if (r < 0)
return r;
@@ -2968,6 +2996,7 @@ int verity_dissect_and_mount(
loop_device->fd,
&verity,
options,
+ loop_device->diskseq,
loop_device->uevent_seqnum_not_before,
loop_device->timestamp_not_before,
dissect_image_flags,
@@ -2978,6 +3007,7 @@ int verity_dissect_and_mount(
loop_device->fd,
&verity,
options,
+ loop_device->diskseq,
loop_device->uevent_seqnum_not_before,
loop_device->timestamp_not_before,
dissect_image_flags | DISSECT_IMAGE_NO_PARTITION_TABLE,
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index 1ce14e915e..cad52f2184 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -162,8 +162,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all);
const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator);
int probe_filesystem(const char *node, char **ret_fstype);
-int dissect_image(int fd, const VeritySettings *verity, const MountOptions *mount_options, uint64_t uevent_seqnum_not_before, usec_t timestamp_not_before, DissectImageFlags flags, DissectedImage **ret);
-int dissect_image_and_warn(int fd, const char *name, const VeritySettings *verity, const MountOptions *mount_options, uint64_t uevent_seqnum_not_before, usec_t timestamp_not_before, DissectImageFlags flags, DissectedImage **ret);
+int dissect_image(int fd, const VeritySettings *verity, const MountOptions *mount_options, uint64_t diskseq, uint64_t uevent_seqnum_not_before, usec_t timestamp_not_before, DissectImageFlags flags, DissectedImage **ret);
+int dissect_image_and_warn(int fd, const char *name, const VeritySettings *verity, const MountOptions *mount_options, uint64_t diskseq, uint64_t uevent_seqnum_not_before, usec_t timestamp_not_before, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);
DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index c038e7aae6..933756cf80 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -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,
};
diff --git a/src/shared/loop-util.h b/src/shared/loop-util.h
index e06dfebb7c..964ce3ed08 100644
--- a/src/shared/loop-util.h
+++ b/src/shared/loop-util.h
@@ -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 */
};
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index 1e9279d612..f15d4dd61d 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -532,6 +532,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
img->path,
&verity_settings,
NULL,
+ d->diskseq,
d->uevent_seqnum_not_before,
d->timestamp_not_before,
flags,
diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h
index 7ab0a8334e..189a110ea0 100644
--- a/src/systemd/sd-device.h
+++ b/src/systemd/sd-device.h
@@ -80,6 +80,7 @@ int sd_device_get_sysname(sd_device *device, const char **ret);
int sd_device_get_sysnum(sd_device *device, const char **ret);
int sd_device_get_action(sd_device *device, sd_device_action_t *ret);
int sd_device_get_seqnum(sd_device *device, uint64_t *ret);
+int sd_device_get_diskseq(sd_device *device, uint64_t *ret);
int sd_device_get_is_initialized(sd_device *device);
int sd_device_get_usec_initialized(sd_device *device, uint64_t *usec);
diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c
index 57f3279b67..1642f82e40 100644
--- a/src/test/test-loop-block.c
+++ b/src/test/test-loop-block.c
@@ -51,7 +51,7 @@ static void* thread_func(void *ptr) {
log_notice("Acquired loop device %s, will mount on %s", loop->node, mounted);
- r = dissect_image(loop->fd, NULL, NULL, loop->uevent_seqnum_not_before, loop->timestamp_not_before, DISSECT_IMAGE_READ_ONLY, &dissected);
+ r = dissect_image(loop->fd, NULL, NULL, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, DISSECT_IMAGE_READ_ONLY, &dissected);
if (r < 0)
log_error_errno(r, "Failed dissect loopback device %s: %m", loop->node);
assert_se(r >= 0);
@@ -188,7 +188,7 @@ int main(int argc, char *argv[]) {
sfdisk = NULL;
assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, LO_FLAGS_PARTSCAN, &loop) >= 0);
- assert_se(dissect_image(loop->fd, NULL, NULL, loop->uevent_seqnum_not_before, loop->timestamp_not_before, 0, &dissected) >= 0);
+ assert_se(dissect_image(loop->fd, NULL, NULL, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, 0, &dissected) >= 0);
assert_se(dissected->partitions[PARTITION_ESP].found);
assert_se(dissected->partitions[PARTITION_ESP].node);
@@ -212,7 +212,7 @@ int main(int argc, char *argv[]) {
assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", id, true) >= 0);
dissected = dissected_image_unref(dissected);
- assert_se(dissect_image(loop->fd, NULL, NULL, loop->uevent_seqnum_not_before, loop->timestamp_not_before, 0, &dissected) >= 0);
+ assert_se(dissect_image(loop->fd, NULL, NULL, loop->diskseq, loop->uevent_seqnum_not_before, loop->timestamp_not_before, 0, &dissected) >= 0);
assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);