Fix bug in DM iteration and standardise how to iterate through DM layers (#40426)

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. And while we're at it also make cgroups use the
same logic.

Fixes: #40419
This commit is contained in:
Yu Watanabe
2026-01-30 15:36:03 +09:00
committed by GitHub
8 changed files with 48 additions and 17 deletions
+1 -2
View File
@@ -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);
+1 -1
View File
@@ -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");
+1 -1
View File
@@ -9935,7 +9935,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)
+40 -7
View File
@@ -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;
@@ -313,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);
r = block_get_originating(*ret, ret, /* recursive= */ true);
if (r < 0)
log_debug_errno(r, "Failed to chase block device, ignoring: %m");
+2 -3
View File
@@ -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);
+1 -1
View File
@@ -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)
+1 -1
View File
@@ -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= */ true);
if (r < 0 && r != -ENOENT)
log_device_debug_errno(d, r, "Failed to get originating device for '%s', ignoring: %m", strna(devname));
+1 -1
View File
@@ -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;
}