Skip to content

Commit aca8235

Browse files
author
Daan Hoogland
committed
Merge branch '4.19' into 4.20
2 parents 823cb00 + a208db5 commit aca8235

File tree

4 files changed

+60
-40
lines changed

4 files changed

+60
-40
lines changed

plugins/storage/volume/linstor/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2025-10-03]
9+
10+
### Changed
11+
12+
- Revert qcow2 snapshot now use sparse/discard options to convert on thin devices.
13+
814
## [2025-08-05]
915

1016
### Fixed

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LinstorRevertBackupSnapshotCommandWrapper.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,24 +26,39 @@
2626
import com.cloud.resource.CommandWrapper;
2727
import com.cloud.resource.ResourceWrapper;
2828
import com.cloud.storage.Storage;
29+
import com.cloud.utils.script.Script;
2930
import org.apache.cloudstack.storage.command.CopyCmdAnswer;
31+
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
3032
import org.apache.cloudstack.storage.to.SnapshotObjectTO;
3133
import org.apache.cloudstack.storage.to.VolumeObjectTO;
3234
import org.apache.cloudstack.utils.qemu.QemuImg;
3335
import org.apache.cloudstack.utils.qemu.QemuImgException;
3436
import org.apache.cloudstack.utils.qemu.QemuImgFile;
37+
import org.joda.time.Duration;
3538
import org.libvirt.LibvirtException;
3639

3740
@ResourceWrapper(handles = LinstorRevertBackupSnapshotCommand.class)
3841
public final class LinstorRevertBackupSnapshotCommandWrapper
3942
extends CommandWrapper<LinstorRevertBackupSnapshotCommand, CopyCmdAnswer, LibvirtComputingResource>
4043
{
41-
private void convertQCow2ToRAW(final String srcPath, final String dstPath, int waitMilliSeconds)
44+
45+
private void convertQCow2ToRAW(
46+
KVMStoragePool pool, final String srcPath, final String dstUuid, int waitMilliSeconds)
4247
throws LibvirtException, QemuImgException
4348
{
49+
final String dstPath = pool.getPhysicalDisk(dstUuid).getPath();
4450
final QemuImgFile srcQemuFile = new QemuImgFile(
4551
srcPath, QemuImg.PhysicalDiskFormat.QCOW2);
46-
final QemuImg qemu = new QemuImg(waitMilliSeconds);
52+
boolean zeroedDevice = LinstorUtil.resourceSupportZeroBlocks(pool, LinstorUtil.RSC_PREFIX + dstUuid);
53+
if (zeroedDevice)
54+
{
55+
// blockdiscard the device to ensure the device is filled with zeroes
56+
Script blkDiscardScript = new Script("blkdiscard", Duration.millis(waitMilliSeconds));
57+
blkDiscardScript.add("-f");
58+
blkDiscardScript.add(dstPath);
59+
blkDiscardScript.execute();
60+
}
61+
final QemuImg qemu = new QemuImg(waitMilliSeconds, zeroedDevice, true);
4762
final QemuImgFile dstFile = new QemuImgFile(dstPath, QemuImg.PhysicalDiskFormat.RAW);
4863
qemu.convert(srcQemuFile, dstFile);
4964
}
@@ -70,8 +85,9 @@ public CopyCmdAnswer execute(LinstorRevertBackupSnapshotCommand cmd, LibvirtComp
7085
srcDataStore.getUrl() + File.separator + srcFile.getParent());
7186

7287
convertQCow2ToRAW(
88+
linstorPool,
7389
secondaryPool.getLocalPath() + File.separator + srcFile.getName(),
74-
linstorPool.getPhysicalDisk(dst.getPath()).getPath(),
90+
dst.getPath(),
7591
cmd.getWaitInMillSeconds());
7692

7793
final VolumeObjectTO dstVolume = new VolumeObjectTO();

plugins/storage/volume/linstor/src/main/java/com/cloud/hypervisor/kvm/storage/LinstorStorageAdaptor.java

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import com.cloud.storage.Storage;
3131
import com.cloud.utils.exception.CloudRuntimeException;
3232
import com.cloud.utils.script.Script;
33-
3433
import org.apache.cloudstack.storage.datastore.util.LinstorUtil;
3534
import org.apache.cloudstack.utils.qemu.QemuImg;
3635
import org.apache.cloudstack.utils.qemu.QemuImgException;
@@ -57,7 +56,6 @@
5756
import com.linbit.linstor.api.model.ResourceMakeAvailable;
5857
import com.linbit.linstor.api.model.ResourceWithVolumes;
5958
import com.linbit.linstor.api.model.StoragePool;
60-
import com.linbit.linstor.api.model.Volume;
6159
import com.linbit.linstor.api.model.VolumeDefinition;
6260

6361
import java.io.File;
@@ -573,40 +571,6 @@ public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMSt
573571
return copyPhysicalDisk(disk, name, destPool, timeout, null, null, null);
574572
}
575573

576-
/**
577-
* Checks if all diskful resource are on a zeroed block device.
578-
* @param destPool Linstor pool to use
579-
* @param resName Linstor resource name
580-
* @return true if all resources are on a provider with zeroed blocks.
581-
*/
582-
private boolean resourceSupportZeroBlocks(KVMStoragePool destPool, String resName) {
583-
final DevelopersApi api = getLinstorAPI(destPool);
584-
585-
try {
586-
List<ResourceWithVolumes> resWithVols = api.viewResources(
587-
Collections.emptyList(),
588-
Collections.singletonList(resName),
589-
Collections.emptyList(),
590-
Collections.emptyList(),
591-
null,
592-
null);
593-
594-
if (resWithVols != null) {
595-
return resWithVols.stream()
596-
.allMatch(res -> {
597-
Volume vol0 = res.getVolumes().get(0);
598-
return vol0 != null && (vol0.getProviderKind() == ProviderKind.LVM_THIN ||
599-
vol0.getProviderKind() == ProviderKind.ZFS ||
600-
vol0.getProviderKind() == ProviderKind.ZFS_THIN ||
601-
vol0.getProviderKind() == ProviderKind.DISKLESS);
602-
} );
603-
}
604-
} catch (ApiException apiExc) {
605-
logger.error(apiExc.getMessage());
606-
}
607-
return false;
608-
}
609-
610574
/**
611575
* Checks if the given disk is the SystemVM template, by checking its properties file in the same directory.
612576
* The initial systemvm template resource isn't created on the management server, but
@@ -677,7 +641,7 @@ public KVMPhysicalDisk copyPhysicalDisk(KVMPhysicalDisk disk, String name, KVMSt
677641
destFile.setFormat(dstDisk.getFormat());
678642
destFile.setSize(disk.getVirtualSize());
679643

680-
boolean zeroedDevice = resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
644+
boolean zeroedDevice = LinstorUtil.resourceSupportZeroBlocks(destPools, getLinstorRscName(name));
681645
try {
682646
final QemuImg qemu = new QemuImg(timeout, zeroedDevice, true);
683647
qemu.convert(srcFile, destFile);

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/util/LinstorUtil.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import java.util.Optional;
4343
import java.util.stream.Collectors;
4444

45+
import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
4546
import com.cloud.utils.Pair;
4647
import com.cloud.utils.exception.CloudRuntimeException;
4748
import org.apache.logging.log4j.Logger;
@@ -431,4 +432,37 @@ public static ResourceDefinition findResourceDefinition(DevelopersApi api, Strin
431432
public static boolean isRscDiskless(ResourceWithVolumes rsc) {
432433
return rsc.getFlags() != null && rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS);
433434
}
435+
436+
/**
437+
* Checks if all diskful resource are on a zeroed block device.
438+
* @param pool Linstor pool to use
439+
* @param resName Linstor resource name
440+
* @return true if all resources are on a provider with zeroed blocks.
441+
*/
442+
public static boolean resourceSupportZeroBlocks(KVMStoragePool pool, String resName) {
443+
final DevelopersApi api = getLinstorAPI(pool.getSourceHost());
444+
try {
445+
List<ResourceWithVolumes> resWithVols = api.viewResources(
446+
Collections.emptyList(),
447+
Collections.singletonList(resName),
448+
Collections.emptyList(),
449+
Collections.emptyList(),
450+
null,
451+
null);
452+
453+
if (resWithVols != null) {
454+
return resWithVols.stream()
455+
.allMatch(res -> {
456+
Volume vol0 = res.getVolumes().get(0);
457+
return vol0 != null && (vol0.getProviderKind() == ProviderKind.LVM_THIN ||
458+
vol0.getProviderKind() == ProviderKind.ZFS ||
459+
vol0.getProviderKind() == ProviderKind.ZFS_THIN ||
460+
vol0.getProviderKind() == ProviderKind.DISKLESS);
461+
} );
462+
}
463+
} catch (ApiException apiExc) {
464+
LOGGER.error(apiExc.getMessage());
465+
}
466+
return false;
467+
}
434468
}

0 commit comments

Comments
 (0)