Skip to content

Commit 56c7aeb

Browse files
author
Pearl Dsilva
committed
optimization
1 parent f438897 commit 56c7aeb

4 files changed

Lines changed: 74 additions & 25 deletions

File tree

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ClvmStorageAdaptor.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
2828
import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
2929
import com.cloud.hypervisor.kvm.resource.LibvirtStoragePoolDef;
30-
import com.cloud.hypervisor.kvm.resource.LibvirtStorageVolumeDef;
3130
import com.cloud.storage.Storage;
3231
import com.cloud.storage.Storage.StoragePoolType;
3332
import com.cloud.storage.StorageLayer;
@@ -145,12 +144,11 @@ public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
145144
return getPhysicalDiskWithClvmFallback(volumeUuid, pool, libvirtPool);
146145
}
147146

148-
LibvirtStorageVolumeDef voldef = getStorageVolumeDef(libvirtPool.getPool().getConnect(), vol);
147+
boolean isQcow2 = StoragePoolType.CLVM_NG.equals(pool.getType());
149148
KVMPhysicalDisk disk = new KVMPhysicalDisk(vol.getPath(), vol.getName(), pool);
150149
disk.setSize(vol.getInfo().allocation);
151-
disk.setVirtualSize(vol.getInfo().capacity);
152-
disk.setFormat(voldef.getFormat() == LibvirtStorageVolumeDef.VolumeFormat.QCOW2
153-
? PhysicalDiskFormat.QCOW2 : PhysicalDiskFormat.RAW);
150+
disk.setVirtualSize(isQcow2 ? getQcow2VirtualSize(vol.getPath()) : vol.getInfo().capacity);
151+
disk.setFormat(isQcow2 ? PhysicalDiskFormat.QCOW2 : PhysicalDiskFormat.RAW);
154152
return disk;
155153
} catch (LibvirtException e) {
156154
logger.warn("LibvirtException looking up volume {}: {}", volumeUuid, e.getMessage());
@@ -400,12 +398,11 @@ private KVMPhysicalDisk getPhysicalDiskWithClvmFallback(String volumeUuid, KVMSt
400398
StorageVol vol = getVolume(libvirtPool.getPool(), volumeUuid);
401399
if (vol != null) {
402400
logger.info("Volume found after pool refresh: {}", volumeUuid);
403-
LibvirtStorageVolumeDef voldef = getStorageVolumeDef(libvirtPool.getPool().getConnect(), vol);
401+
boolean isQcow2 = StoragePoolType.CLVM_NG.equals(pool.getType());
404402
KVMPhysicalDisk disk = new KVMPhysicalDisk(vol.getPath(), vol.getName(), pool);
405403
disk.setSize(vol.getInfo().allocation);
406-
disk.setVirtualSize(vol.getInfo().capacity);
407-
disk.setFormat(voldef.getFormat() == LibvirtStorageVolumeDef.VolumeFormat.QCOW2
408-
? PhysicalDiskFormat.QCOW2 : PhysicalDiskFormat.RAW);
404+
disk.setVirtualSize(isQcow2 ? getQcow2VirtualSize(vol.getPath()) : vol.getInfo().capacity);
405+
disk.setFormat(isQcow2 ? PhysicalDiskFormat.QCOW2 : PhysicalDiskFormat.RAW);
409406
return disk;
410407
}
411408
} catch (LibvirtException refreshEx) {
@@ -588,7 +585,7 @@ private KVMPhysicalDisk createPhysicalDiskFromClvmLv(String lvPath, String volum
588585
KVMPhysicalDisk disk = new KVMPhysicalDisk(lvPath, volumeUuid, pool);
589586
disk.setFormat(diskFormat);
590587
disk.setSize(size);
591-
disk.setVirtualSize(size);
588+
disk.setVirtualSize(diskFormat == PhysicalDiskFormat.QCOW2 ? getQcow2VirtualSize(lvPath) : size);
592589

593590
logger.info("Successfully accessed CLVM/CLVM_NG volume via direct block device: {} with format: {} and size: {} bytes",
594591
lvPath, diskFormat, size);
@@ -753,10 +750,9 @@ private long getVgPhysicalExtentSize(String vgName) {
753750

754751
/**
755752
* Calculate LVM LV size for CLVM_NG volume allocation.
753+
* {@code peSize} must be the Physical Extent size of the VG (from {@link #getVgPhysicalExtentSize}).
756754
*/
757-
private long calculateClvmNgLvSize(long virtualSize, String vgName) {
758-
long peSize = getVgPhysicalExtentSize(vgName);
759-
755+
private long calculateClvmNgLvSize(long virtualSize, long peSize) {
760756
long clusterSize = 64 * 1024L;
761757
long l2Multiplier = 4096L;
762758

@@ -782,6 +778,7 @@ private long getQcow2VirtualSize(String imagePath) {
782778
Script qemuImg = new Script("qemu-img", 300000, logger);
783779
qemuImg.add("info");
784780
qemuImg.add("--output=json");
781+
qemuImg.add("-U");
785782
qemuImg.add(imagePath);
786783

787784
OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
@@ -825,11 +822,14 @@ private long getQcow2PhysicalSize(String imagePath) {
825822
private KVMPhysicalDisk createClvmNgDiskWithBacking(String volumeUuid, int timeout, long virtualSize, String backingFile,
826823
KVMStoragePool pool, Storage.ProvisioningType provisioningType) {
827824
String vgName = getVgName(pool.getLocalPath());
828-
long lvSize = calculateClvmNgLvSize(virtualSize, vgName);
825+
// Query PE size once and reuse for both the QCOW2 virtual-size alignment and the
826+
long peSize = getVgPhysicalExtentSize(vgName);
827+
long peAlignedVirtualSize = ((virtualSize + peSize - 1) / peSize) * peSize;
828+
long lvSize = calculateClvmNgLvSize(peAlignedVirtualSize, peSize);
829829
String volumePath = "/dev/" + vgName + "/" + volumeUuid;
830830

831-
logger.debug("Creating CLVM_NG volume {} with LV size {} bytes (virtual size: {} bytes, provisioning: {})",
832-
volumeUuid, lvSize, virtualSize, provisioningType);
831+
logger.debug("Creating CLVM_NG volume {} with LV size {} bytes (requested virtual: {} bytes, PE-aligned virtual: {} bytes, provisioning: {})",
832+
volumeUuid, lvSize, virtualSize, peAlignedVirtualSize, provisioningType);
833833

834834
Script lvcreate = new Script("lvcreate", Duration.millis(timeout), logger);
835835
lvcreate.add("-n", volumeUuid);
@@ -860,7 +860,7 @@ private KVMPhysicalDisk createClvmNgDiskWithBacking(String volumeUuid, int timeo
860860

861861
qemuImg.add("-o", qcow2Options.toString());
862862
qemuImg.add(volumePath);
863-
qemuImg.add(virtualSize + "");
863+
qemuImg.add(peAlignedVirtualSize + "");
864864

865865
result = qemuImg.execute();
866866
if (result != null) {
@@ -872,10 +872,10 @@ private KVMPhysicalDisk createClvmNgDiskWithBacking(String volumeUuid, int timeo
872872
KVMPhysicalDisk disk = new KVMPhysicalDisk(volumePath, volumeUuid, pool);
873873
disk.setFormat(PhysicalDiskFormat.QCOW2);
874874
disk.setSize(actualSize);
875-
disk.setVirtualSize(actualSize);
875+
disk.setVirtualSize(peAlignedVirtualSize);
876876

877-
logger.info("Successfully created CLVM_NG volume {} (LV size: {}, virtual size: {}, provisioning: {}, preallocation: {})",
878-
volumeUuid, lvSize, virtualSize, provisioningType, preallocation);
877+
logger.info("Successfully created CLVM_NG volume {} (LV size: {}, PE-aligned virtual size: {}, provisioning: {}, preallocation: {})",
878+
volumeUuid, lvSize, peAlignedVirtualSize, provisioningType, preallocation);
879879

880880
return disk;
881881
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1943,7 +1943,11 @@ public Answer createVolume(final CreateObjectCommand cmd) {
19431943
format = vol.getFormat();
19441944
}
19451945
}
1946-
newVol.setSize(volume.getSize());
1946+
if (StoragePoolType.CLVM_NG.equals(primaryStore.getPoolType()) && vol != null && vol.getVirtualSize() > 0) {
1947+
newVol.setSize(vol.getVirtualSize());
1948+
} else {
1949+
newVol.setSize(volume.getSize());
1950+
}
19471951
newVol.setFormat(ImageFormat.valueOf(format.toString().toUpperCase()));
19481952

19491953
return new CreateObjectAnswer(newVol);

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/storage/ClvmStorageAdaptorTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,20 @@
1818
package com.cloud.hypervisor.kvm.storage;
1919

2020
import static org.junit.Assert.assertEquals;
21+
import static org.junit.Assert.assertFalse;
2122
import static org.junit.Assert.assertNotNull;
23+
import static org.junit.Assert.assertTrue;
2224
import static org.mockito.ArgumentMatchers.anyInt;
2325
import static org.mockito.ArgumentMatchers.anyString;
2426
import static org.mockito.ArgumentMatchers.eq;
27+
import static org.mockito.Mockito.doAnswer;
2528
import static org.mockito.Mockito.never;
2629
import static org.mockito.Mockito.when;
2730
import java.lang.reflect.InvocationTargetException;
2831
import java.lang.reflect.Method;
32+
import java.util.ArrayList;
2933
import java.util.HashMap;
34+
import java.util.List;
3035
import java.util.Map;
3136
import java.util.UUID;
3237
import org.junit.After;
@@ -1043,4 +1048,43 @@ public void testCLVMPoolLocalPathValidation() {
10431048
assertNotNull("Local path should not be null", localPath);
10441049
assert !localPath.isEmpty() : "Local path should not be empty";
10451050
}
1051+
1052+
@Test
1053+
public void testCreateClvmNgDiskWithBacking_NonPeAlignedSizeIsRoundedUp() throws Exception {
1054+
String volumeUuid = UUID.randomUUID().toString();
1055+
int timeout = 30000;
1056+
// 50 MiB is not a multiple of the default 4 MiB PE, so lvcreate on a CLVM
1057+
// destination would round it up to 52 MiB. The QCOW2 must be created with
1058+
// the same 52 MiB so libvirt does not abort migration with "different sizes".
1059+
long nonAlignedVirtualSize = 52428800L; // 50 MiB
1060+
long peAlignedVirtualSize = 54525952L; // 52 MiB = 13 × 4 MiB (default PE)
1061+
String vgName = "testvg";
1062+
1063+
Mockito.when(mockPool.getLocalPath()).thenReturn(vgName);
1064+
1065+
List<String> qemuImgAddArgs = new ArrayList<>();
1066+
1067+
mockScriptConstruction = Mockito.mockConstruction(Script.class,
1068+
(mock, context) -> {
1069+
when(mock.execute()).thenReturn(null);
1070+
if (!context.arguments().isEmpty() && "qemu-img".equals(context.arguments().get(0))) {
1071+
doAnswer(inv -> { qemuImgAddArgs.add(inv.getArgument(0)); return null; })
1072+
.when(mock).add(anyString());
1073+
}
1074+
});
1075+
1076+
Method method = ClvmStorageAdaptor.class.getDeclaredMethod(
1077+
"createClvmNgDiskWithBacking",
1078+
String.class, int.class, long.class, String.class,
1079+
KVMStoragePool.class, Storage.ProvisioningType.class);
1080+
method.setAccessible(true);
1081+
1082+
method.invoke(clvmStorageAdaptor, volumeUuid, timeout, nonAlignedVirtualSize, null,
1083+
mockPool, Storage.ProvisioningType.THIN);
1084+
1085+
assertTrue("qemu-img create must use PE-aligned virtual size to match CLVM destination LV",
1086+
qemuImgAddArgs.contains(String.valueOf(peAlignedVirtualSize)));
1087+
assertFalse("qemu-img create must not use non-PE-aligned virtual size",
1088+
qemuImgAddArgs.contains(String.valueOf(nonAlignedVirtualSize)));
1089+
}
10461090
}

scripts/storage/qcow2/resizevolume.sh

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,9 @@ resizeclvmng() {
208208
target_lv_size=$(( newsize + metadata_overhead ))
209209
# Round up to PE boundary
210210
lv_size=$(( ((target_lv_size + pe_size - 1) / pe_size) * pe_size ))
211+
pe_aligned_newsize=$(( ((newsize + pe_size - 1) / pe_size) * pe_size ))
211212

212-
log "CLVM_NG resize: path=$path vg=$vgname pe_size=${pe_size}B virtual=${newsize}B metadata=${metadata_overhead}B lv_size=${lv_size}B"
213+
log "CLVM_NG resize: path=$path vg=$vgname pe_size=${pe_size}B virtual=${newsize}B pe_aligned_virtual=${pe_aligned_newsize}B metadata=${metadata_overhead}B lv_size=${lv_size}B"
213214

214215
# Use -U (force-share) if qemu-img >= 2.10 so we can read info even when
215216
# QEMU has the file open with an exclusive lock (VM running case)
@@ -265,7 +266,7 @@ resizeclvmng() {
265266
if `virsh domstate $vmname >/dev/null 2>&1`
266267
then
267268
log "VM $vmname is running, using virsh blockresize for safe live QCOW2 resize"
268-
sizeinkb=$(($newsize/1024))
269+
sizeinkb=$(($pe_aligned_newsize/1024))
269270
devicepath=$(virsh domblklist $vmname | grep $path | awk '{print $1}')
270271
if [[ -z "$devicepath" ]]
271272
then
@@ -283,14 +284,14 @@ resizeclvmng() {
283284
log "virsh blockresize succeeded: $vmname $devicepath to ${sizeinkb}KiB virtual"
284285
else
285286
log "VM $vmname is not running, using qemu-img resize"
286-
output=`qemu-img resize $path $newsize 2>&1`
287+
output=`qemu-img resize $path $pe_aligned_newsize 2>&1`
287288
retval=$?
288289
if [ -z $retval ] || [ $retval -ne 0 ]
289290
then
290291
log "qemu-img resize failed: $output" 1
291292
exit 1
292293
fi
293-
log "qemu-img resize succeeded: $path to ${newsize}B virtual"
294+
log "qemu-img resize succeeded: $path to ${pe_aligned_newsize}B virtual"
294295
fi
295296

296297
log "performed successful CLVM_NG resize - currentsize:$currentsize newsize:$newsize lv_size:$lv_size path:$path vmname:$vmname live:$liveresize shrink:$shrink"

0 commit comments

Comments
 (0)