From 9df44ce73e5176a5352dba41721dae343a4eac9c Mon Sep 17 00:00:00 2001 From: Rene Peinthor Date: Mon, 7 Sep 2026 08:47:38 +0200 Subject: [PATCH] linstor: escape dashes in the LVM volume group name of snapshot paths Device-mapper doubles every dash in both the volume group and the logical volume name. getSnapshotPath only escaped the resource and snapshot name, so on a VG like "linstor_pool-lvm-thin" the computed /dev/mapper path did not exist and backing up a snapshot to secondary storage failed with "qemu-img: Could not open". Fixes #14011 --- .../storage/datastore/util/LinstorUtil.java | 4 +++- .../storage/datastore/util/LinstorUtilTest.java | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java index 67c070f84eb0..bf5be24f8238 100644 --- a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java +++ b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java @@ -204,8 +204,10 @@ public static String getSnapshotPath(com.linbit.linstor.api.model.StoragePool sp final String path; switch (sp.getProviderKind()) { case LVM_THIN: + // device-mapper doubles every dash in the VG and LV name, so the VG part needs escaping too + final String vgName = backingPool.split("/")[0]; path = String.format("/dev/mapper/%s-%s_%s_%s", - backingPool.split("/")[0], rscName.replace("-", "--"), suffix, snapshotName.replace("-", "--")); + vgName.replace("-", "--"), rscName.replace("-", "--"), suffix, snapshotName.replace("-", "--")); break; case ZFS: case ZFS_THIN: diff --git a/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java b/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java index 55f0c6ebe6dc..e50769b3f9dd 100644 --- a/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java +++ b/plugins/storage/volume/linstor/src/test/java/org/apache/cloudstack/storage/datastore/util/LinstorUtilTest.java @@ -103,6 +103,20 @@ public void testGetSnapshotPath() { Assert.assertEquals("/dev/mapper/storage-cs--cb32532a--dd8f--47e0--a81c--8a75573d3545_00000_snap3", snapPath); } + { + // dashes in the volume group name must be escaped as well (GH issue #14011) + StoragePool spLVMThin = new StoragePool(); + Properties lvmThinProps = new Properties(); + lvmThinProps.put("StorDriver/StorPoolName", "linstor_pool-lvm-thin/thin"); + spLVMThin.setProps(lvmThinProps); + spLVMThin.setProviderKind(ProviderKind.LVM_THIN); + String snapPath = LinstorUtil.getSnapshotPath(spLVMThin, + "cs-12fc4055-3985-4025-8eb5-d6fd53effe37", "cs-d7aea646-5f40-46a2-b9dc-77e41ea29336"); + Assert.assertEquals( + "/dev/mapper/linstor_pool--lvm--thin-cs--12fc4055--3985--4025--8eb5--d6fd53effe37_00000_cs--d7aea646--5f40--46a2--b9dc--77e41ea29336", + snapPath); + } + { StoragePool spZFS = new StoragePool(); Properties zfsProps = new Properties();