[PATCHv2] lxc: truncate LOOP_GET_STATUS64.lo_file_name for long loop backing paths

Radoslaw Smigielski via Devel posted 1 patch 3 days, 6 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/libvirt tags/patchew/20260601121513.146590-1-rsmigiel@redhat.com
src/util/virfile.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
[PATCHv2] lxc: truncate LOOP_GET_STATUS64.lo_file_name for long loop backing paths
Posted by Radoslaw Smigielski via Devel 3 days, 6 hours ago
From: Radoslaw Smigielski <rsmigiel@redhat.com>

LXC domains using a file-backed filesystem with the loop driver fail to
start when the backing image path is longer than LO_NAME_SIZE (64 bytes,
63 characters plus NUL). virFileLoopDeviceAssociate() treated a failed
virStrcpy() into loop_info64.lo_file_name as fatal and reported a
misleading virReportSystemError(errno, ...), so users saw errors such as
"Unable to set backing file ...: Success" or ENOENT even when the file
existed.

The kernel only stores a short name in lo_file_name for LOOP_SET_STATUS64
metadata. The backing file is opened by full path. Copy the path with
virStrcpy(), allow truncation into lo_file_name, and mark truncation with '*'
at LO_NAME_SIZE - 2 to match losetup behavior.
Log truncation at debug level only.

XML example that failed before this change:

    <filesystem type='file' accessmode='passthrough'>
      <driver type='loop' format='raw'/>
      <source file='/root/demoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.raw'/>
      <target dir='/'/>
    </filesystem>

Fixes: https://gitlab.com/libvirt/libvirt/-/work_items/63

Signed-off-by: Radoslaw Smigielski <rsmigiel@redhat.com>
---
 src/util/virfile.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/util/virfile.c b/src/util/virfile.c
index a0c6cb804862..443d0ed9adab 100644
--- a/src/util/virfile.c
+++ b/src/util/virfile.c
@@ -995,11 +995,15 @@ int virFileLoopDeviceAssociate(const char *file,
 
     lo.lo_flags = LO_FLAGS_AUTOCLEAR;
 
-    /* Set backing file name for LOOP_GET_STATUS64 queries */
+    /* lo_file_name is loop device name, max length is LO_NAME_SIZE bytes.
+     * Truncate loop device name if file path is longer than LO_NAME_SIZE,
+     * and still use the full path to open backing file. */
     if (virStrcpy((char *) lo.lo_file_name, file, LO_NAME_SIZE) < 0) {
-        virReportSystemError(errno,
-                             _("Unable to set backing file %1$s"), file);
-        goto cleanup;
+        /* virStrcpy() only returns -1 on truncation. Mark truncation with
+         * asterisk at position LO_NAME_SIZE-2 to match losetup behavior. */
+        lo.lo_file_name[LO_NAME_SIZE - 2] = '*';
+        VIR_DEBUG("lo_file_name for '%s' truncated to %d bytes in loop metadata",
+                  file, LO_NAME_SIZE);
     }
 
     if ((fsfd = open(file, O_RDWR)) < 0) {
-- 
2.54.0