From 29ee9c6fb7c75c421f887c8579c65eb04d4f634d Mon Sep 17 00:00:00 2001 From: nkraetzschmar <9020053+nkraetzschmar@users.noreply.github.com> Date: Thu, 16 Oct 2025 00:12:50 +0200 Subject: [PATCH] loop-util: mirror discard limits from backing device --- src/shared/loop-util.c | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 53d7759e2ef..690f6aeb2a7 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -375,6 +375,44 @@ static int loop_configure( return 0; } +static int fd_get_max_discard(int fd, uint64_t *ret) { + struct stat st; + char sysfs_path[STRLEN("/sys/dev/block/" ":" "/queue/discard_max_bytes") + DECIMAL_STR_MAX(dev_t) * 2 + 1]; + _cleanup_free_ char *buffer = NULL; + int r; + + assert(ret); + + if (fstat(ASSERT_FD(fd), &st) < 0) + return -errno; + + if (!S_ISBLK(st.st_mode)) + return -ENOTBLK; + + xsprintf(sysfs_path, "/sys/dev/block/" DEVNUM_FORMAT_STR "/queue/discard_max_bytes", DEVNUM_FORMAT_VAL(st.st_rdev)); + + r = read_one_line_file(sysfs_path, &buffer); + if (r < 0) + return r; + + return safe_atou64(buffer, ret); +} + +static int fd_set_max_discard(int fd, uint64_t max_discard) { + struct stat st; + char sysfs_path[STRLEN("/sys/dev/block/" ":" "/queue/discard_max_bytes") + DECIMAL_STR_MAX(dev_t) * 2 + 1]; + + if (fstat(ASSERT_FD(fd), &st) < 0) + return -errno; + + if (!S_ISBLK(st.st_mode)) + return -ENOTBLK; + + xsprintf(sysfs_path, "/sys/dev/block/" DEVNUM_FORMAT_STR "/queue/discard_max_bytes", DEVNUM_FORMAT_VAL(st.st_rdev)); + + return write_string_filef(sysfs_path, WRITE_STRING_FILE_DISABLE_BUFFER, "%" PRIu64, max_discard); +} + static int loop_device_make_internal( const char *path, int fd, @@ -572,6 +610,19 @@ static int loop_device_make_internal( (void) usleep_safe(usec); } + if (S_ISBLK(st.st_mode)) { + uint64_t discard_max_bytes; + + r = fd_get_max_discard(fd, &discard_max_bytes); + if (r < 0) + log_debug_errno(r, "Failed to read 'discard_max_bytes' of backing device, ignoring: %m"); + else { + r = fd_set_max_discard(d->fd, discard_max_bytes); + if (r < 0) + log_debug_errno(r, "Failed to write 'discard_max_bytes' of loop device, ignoring: %m"); + } + } + d->backing_file = TAKE_PTR(backing_file); d->backing_inode = st.st_ino; d->backing_devno = st.st_dev;