diff options
-rw-r--r-- | src/basic/missing_loop.h | 5 | ||||
-rw-r--r-- | src/core/namespace.c | 1 | ||||
-rw-r--r-- | src/dissect/dissect.c | 1 | ||||
-rw-r--r-- | src/gpt-auto-generator/gpt-auto-generator.c | 1 | ||||
-rw-r--r-- | src/libsystemd/libsystemd.sym | 5 | ||||
-rw-r--r-- | src/libsystemd/sd-device/device-internal.h | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-device/device-private.c | 26 | ||||
-rw-r--r-- | src/libsystemd/sd-device/sd-device.c | 12 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 1 | ||||
-rw-r--r-- | src/portable/portable.c | 1 | ||||
-rw-r--r-- | src/shared/discover-image.c | 1 | ||||
-rw-r--r-- | src/shared/dissect-image.c | 56 | ||||
-rw-r--r-- | src/shared/dissect-image.h | 4 | ||||
-rw-r--r-- | src/shared/loop-util.c | 33 | ||||
-rw-r--r-- | src/shared/loop-util.h | 1 | ||||
-rw-r--r-- | src/sysext/sysext.c | 1 | ||||
-rw-r--r-- | src/systemd/sd-device.h | 1 | ||||
-rw-r--r-- | src/test/test-loop-block.c | 6 |
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); |