From 7b8c4d01e61f61145fcffbfcee5844b305a780fa Mon Sep 17 00:00:00 2001 From: Chris Down Date: Thu, 22 Jan 2026 18:13:44 +0800 Subject: [PATCH 1/3] blockdev-util: Add recursive lookup flag Originating device lookups currently use separate entry points and callers must decide between the single-step helper and manual looping. Add a recursive flag to block_device_get_originating() and block_get_originating(), and update callers to pass an explicit value. --- src/core/cgroup.c | 3 +-- src/cryptenroll/cryptenroll.c | 2 +- src/repart/repart.c | 2 +- src/shared/blockdev-util.c | 43 ++++++++++++++++++++++++++---- src/shared/blockdev-util.h | 5 ++-- src/sleep/sleep.c | 2 +- src/storagetm/storagetm.c | 2 +- src/sysupdate/sysupdate-resource.c | 2 +- 8 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 6a434eba84..35c0898e03 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -973,8 +973,7 @@ static int lookup_block_device(const char *p, dev_t *ret) { } /* If this is a LUKS/DM device, recursively try to get the originating block device */ - while (block_get_originating(*ret, ret) >= 0) - ; + (void) block_get_originating(*ret, ret, /* recursive= */ true); /* If this is a partition, try to get the originating block device */ (void) block_get_whole_disk(*ret, ret); diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c index a4be09d3e0..86d57e964f 100644 --- a/src/cryptenroll/cryptenroll.c +++ b/src/cryptenroll/cryptenroll.c @@ -152,7 +152,7 @@ static int determine_default_node(void) { return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "Block device backing /var/ is not a LUKS2 device."); _cleanup_(sd_device_unrefp) sd_device *origin = NULL; - r = block_device_get_originating(dev, &origin); + r = block_device_get_originating(dev, &origin, /* recursive= */ false); if (r < 0) return log_error_errno(r, "Failed to get originating device of LUKS2 device backing /var/: %m"); diff --git a/src/repart/repart.c b/src/repart/repart.c index 100e03aab5..65b7d1be31 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -9934,7 +9934,7 @@ static int acquire_root_devno( return -ENOTBLK; /* From dm-crypt to backing partition */ - r = block_get_originating(devno, &devno); + r = block_get_originating(devno, &devno, /* recursive= */ false); if (r == -ENOENT) log_debug_errno(r, "Device '%s' has no dm-crypt/dm-verity device, no need to look for underlying block device.", p); else if (r < 0) diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index 3242ea23da..b138455acc 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -101,7 +101,7 @@ int block_device_get_whole_disk(sd_device *dev, sd_device **ret) { return 0; } -int block_device_get_originating(sd_device *dev, sd_device **ret) { +static int block_device_get_originating_one(sd_device *dev, sd_device **ret) { _cleanup_(sd_device_unrefp) sd_device *first_found = NULL; const char *suffix; dev_t devnum = 0; /* avoid false maybe-uninitialized warning */ @@ -148,6 +148,39 @@ int block_device_get_originating(sd_device *dev, sd_device **ret) { return 0; } +int block_device_get_originating(sd_device *dev, sd_device **ret, bool recursive) { + _cleanup_(sd_device_unrefp) sd_device *current = NULL; + int r; + + assert(dev); + assert(ret); + + if (!recursive) + return block_device_get_originating_one(dev, ret); + + current = sd_device_ref(dev); + + for (;;) { + sd_device *origin; + + r = block_device_get_originating_one(current, &origin); + if (r == -ENOENT) + break; + if (r < 0) + return r; + + sd_device_unref(current); + current = origin; + } + + if (current == dev) + return -ENOENT; + + *ret = TAKE_PTR(current); + + return 0; +} + int block_device_new_from_fd(int fd, BlockDeviceLookupFlags flags, sd_device **ret) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; dev_t devnum; @@ -172,7 +205,7 @@ int block_device_new_from_fd(int fd, BlockDeviceLookupFlags flags, sd_device **r if (r < 0) return r; - r = block_device_get_originating(dev_whole_disk, &dev_origin); + r = block_device_get_originating(dev_whole_disk, &dev_origin, /* recursive= */ false); if (r >= 0) device_unref_and_replace(dev, dev_origin); else if (r != -ENOENT) @@ -290,7 +323,7 @@ int get_block_device(const char *path, dev_t *ret) { return get_block_device_fd(fd, ret); } -int block_get_originating(dev_t dt, dev_t *ret) { +int block_get_originating(dev_t dt, dev_t *ret, bool recursive) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL, *origin = NULL; int r; @@ -300,7 +333,7 @@ int block_get_originating(dev_t dt, dev_t *ret) { if (r < 0) return r; - r = block_device_get_originating(dev, &origin); + r = block_device_get_originating(dev, &origin, recursive); if (r < 0) return r; @@ -320,7 +353,7 @@ int get_block_device_harder_fd(int fd, dev_t *ret) { if (r <= 0) return r; - r = block_get_originating(*ret, ret); + r = block_get_originating(*ret, ret, /* recursive= */ false); if (r < 0) log_debug_errno(r, "Failed to chase block device, ignoring: %m"); diff --git a/src/shared/blockdev-util.h b/src/shared/blockdev-util.h index 871596f618..3a20a5307d 100644 --- a/src/shared/blockdev-util.h +++ b/src/shared/blockdev-util.h @@ -24,10 +24,9 @@ int block_device_new_from_path(const char *path, BlockDeviceLookupFlags flags, s int block_device_is_whole_disk(sd_device *dev); int block_device_get_whole_disk(sd_device *dev, sd_device **ret); -int block_device_get_originating(sd_device *dev, sd_device **ret); - +int block_device_get_originating(sd_device *dev, sd_device **ret, bool recursive); int block_get_whole_disk(dev_t d, dev_t *ret); -int block_get_originating(dev_t d, dev_t *ret); +int block_get_originating(dev_t d, dev_t *ret, bool recursive); int get_block_device_fd(int fd, dev_t *ret); int get_block_device(const char *path, dev_t *ret); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 4fa6f16fcd..0d128053ba 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -61,7 +61,7 @@ static int determine_auto_swap(sd_device *device) { assert(device); - r = block_device_get_originating(device, &origin); + r = block_device_get_originating(device, &origin, /* recursive= */ false); if (r < 0 && r != -ENOENT) return r; if (r >= 0) diff --git a/src/storagetm/storagetm.c b/src/storagetm/storagetm.c index 54d516ef12..89a6e0b552 100644 --- a/src/storagetm/storagetm.c +++ b/src/storagetm/storagetm.c @@ -848,7 +848,7 @@ static void device_track_back(sd_device *d, sd_device **ret) { (void) sd_device_get_devname(d, &devname); _cleanup_(sd_device_unrefp) sd_device *d_originating = NULL; - r = block_device_get_originating(d, &d_originating); + r = block_device_get_originating(d, &d_originating, /* recursive= */ false); if (r < 0 && r != -ENOENT) log_device_debug_errno(d, r, "Failed to get originating device for '%s', ignoring: %m", strna(devname)); diff --git a/src/sysupdate/sysupdate-resource.c b/src/sysupdate/sysupdate-resource.c index c9e6981261..b268841899 100644 --- a/src/sysupdate/sysupdate-resource.c +++ b/src/sysupdate/sysupdate-resource.c @@ -678,7 +678,7 @@ static int get_sysext_overlay_block(const char *p, dev_t *ret) { return 0; } - (void) block_get_originating(*ret, ret); + (void) block_get_originating(*ret, ret, /* recursive= */ false); return 1; } From 53c7b19572ec306cb40f0aa57f02b90b5b2c2c2a Mon Sep 17 00:00:00 2001 From: Chris Down Date: Fri, 23 Jan 2026 12:57:48 +0800 Subject: [PATCH 2/3] storagetm: Track backing device recursively device_track_back() only checks a single DM layer when resolving the originating device. Use block_device_get_originating(..., /* recursive= */ true) to follow stacked layers. --- src/storagetm/storagetm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storagetm/storagetm.c b/src/storagetm/storagetm.c index 89a6e0b552..7461964267 100644 --- a/src/storagetm/storagetm.c +++ b/src/storagetm/storagetm.c @@ -848,7 +848,7 @@ static void device_track_back(sd_device *d, sd_device **ret) { (void) sd_device_get_devname(d, &devname); _cleanup_(sd_device_unrefp) sd_device *d_originating = NULL; - r = block_device_get_originating(d, &d_originating, /* recursive= */ false); + r = block_device_get_originating(d, &d_originating, /* recursive= */ true); if (r < 0 && r != -ENOENT) log_device_debug_errno(d, r, "Failed to get originating device for '%s', ignoring: %m", strna(devname)); From b38943b01bfe3aa375c91164d2709272b5a90119 Mon Sep 17 00:00:00 2001 From: Chris Down Date: Thu, 22 Jan 2026 18:15:33 +0800 Subject: [PATCH 3/3] blockdev-util: Iterate through all DM layers get_block_device_harder_fd() currently only traverses one level of device mapper stacking when looking for the underlying block device. This causes issues with nested DM setups like dm-crypt on top of dm-integrity, where we don't traverse enough to get the actual physical device. Fix this by iterating through all DM layers until we reach a device with no underlying device. Fixes: #40419 --- src/shared/blockdev-util.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shared/blockdev-util.c b/src/shared/blockdev-util.c index b138455acc..44feae5ab6 100644 --- a/src/shared/blockdev-util.c +++ b/src/shared/blockdev-util.c @@ -346,14 +346,14 @@ int get_block_device_harder_fd(int fd, dev_t *ret) { assert(fd >= 0); assert(ret); - /* Gets the backing block device for a file system, and handles LUKS encrypted file systems, looking for its - * immediate parent, if there is one. */ + /* Gets the backing block device for a file system, and handles LUKS encrypted file systems, looking + * for its underlying physical device, if there is one. */ r = get_block_device_fd(fd, ret); if (r <= 0) return r; - r = block_get_originating(*ret, ret, /* recursive= */ false); + r = block_get_originating(*ret, ret, /* recursive= */ true); if (r < 0) log_debug_errno(r, "Failed to chase block device, ignoring: %m");