From c599a58463525289f01dd9c6e24f4817452ff5e1 Mon Sep 17 00:00:00 2001 From: Rene Peinthor Date: Wed, 7 Aug 2024 12:02:37 +0200 Subject: [PATCH] kvm: ref-count storage pool usage If a storage pool is used by e.g. 2 concurrent snapshot->template actions, if the first action finished it removed the netfs mount point for the other action. Now the storage pools are usage ref-counted and will only deleted if there are no more users. --- .../kvm/storage/LibvirtStorageAdaptor.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java index cad9d429969c..720a7cfddf18 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/LibvirtStorageAdaptor.java @@ -72,6 +72,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; @@ -80,6 +81,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor { private StorageLayer _storageLayer; private String _mountPoint = "/mnt"; private String _manageSnapshotPath; + private static final ConcurrentHashMap storagePoolRefCounts = new ConcurrentHashMap<>(); private String rbdTemplateSnapName = "cloudstack-base-snap"; private static final int RBD_FEATURE_LAYERING = 1; @@ -637,6 +639,39 @@ public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) { } } + /** + * adjust refcount + */ + private int adjustStoragePoolRefCount(String uuid, int adjustment) { + synchronized (uuid) { + // some access on the storagePoolRefCounts.key(uuid) element + int refCount = storagePoolRefCounts.computeIfAbsent(uuid, k -> 0); + refCount += adjustment; + storagePoolRefCounts.put(uuid, refCount); + if (refCount < 1) { + storagePoolRefCounts.remove(uuid); + } else { + storagePoolRefCounts.put(uuid, refCount); + } + return refCount; + } + } + /** + * Thread-safe increment storage pool usage refcount + * @param uuid UUID of the storage pool to increment the count + */ + private void incStoragePoolRefCount(String uuid) { + adjustStoragePoolRefCount(uuid, 1); + } + /** + * Thread-safe decrement storage pool usage refcount for the given uuid and return if storage pool still in use. + * @param uuid UUID of the storage pool to decrement the count + * @return true if the storage pool is still used, else false. + */ + private boolean decStoragePoolRefCount(String uuid) { + return adjustStoragePoolRefCount(uuid, -1) > 0; + } + @Override public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map details) { s_logger.info("Attempting to create storage pool " + name + " (" + type.toString() + ") in libvirt"); @@ -744,6 +779,7 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri } try { + incStoragePoolRefCount(name); if (sp.isActive() == 0) { s_logger.debug("Attempting to activate pool " + name); sp.create(0); @@ -755,6 +791,7 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri return getStoragePool(name); } catch (LibvirtException e) { + decStoragePoolRefCount(name); String error = e.toString(); if (error.contains("Storage source conflict")) { throw new CloudRuntimeException("A pool matching this location already exists in libvirt, " + @@ -805,6 +842,13 @@ private boolean destroyStoragePoolHandleException(Connect conn, String uuid) @Override public boolean deleteStoragePool(String uuid) { s_logger.info("Attempting to remove storage pool " + uuid + " from libvirt"); + + // decrement and check if storage pool still in use + if (decStoragePoolRefCount(uuid)) { + s_logger.info(String.format("deleteStoragePool: Storage pool %s still in use", uuid)); + return true; + } + Connect conn; try { conn = LibvirtConnection.getConnection();