]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: mirror discard limits from backing device
authornkraetzschmar <9020053+nkraetzschmar@users.noreply.github.com>
Wed, 15 Oct 2025 22:12:50 +0000 (00:12 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 20 Oct 2025 10:49:39 +0000 (12:49 +0200)
src/shared/loop-util.c

index 53d7759e2ef44b4f6b568fcb3efea7da310c485e..690f6aeb2a710f9d66e5b9f4978574a057382c20 100644 (file)
@@ -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;