Skip to content

Commit dfe4a67

Browse files
authored
kvm: ref-count secondary storage pool usage (#9498)
If a secondary 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.
1 parent adbf370 commit dfe4a67

File tree

10 files changed

+62
-10
lines changed

10 files changed

+62
-10
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class IscsiAdmStorageAdaptor implements StorageAdaptor {
4343
private static final Map<String, KVMStoragePool> MapStorageUuidToStoragePool = new HashMap<>();
4444

4545
@Override
46-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details) {
46+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details, boolean isPrimaryStorage) {
4747
IscsiAdmStoragePool storagePool = new IscsiAdmStoragePool(uuid, host, port, storagePoolType, this);
4848

4949
MapStorageUuidToStoragePool.put(uuid, storagePool);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri
361361
//Note: due to bug CLOUDSTACK-4459, createStoragepool can be called in parallel, so need to be synced.
362362
private synchronized KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean primaryStorage) {
363363
StorageAdaptor adaptor = getStorageAdaptor(type);
364-
KVMStoragePool pool = adaptor.createStoragePool(name, host, port, path, userInfo, type, details);
364+
KVMStoragePool pool = adaptor.createStoragePool(name, host, port, path, userInfo, type, details, primaryStorage);
365365

366366
// LibvirtStorageAdaptor-specific statement
367367
if (pool.isPoolSupportHA() && primaryStorage) {

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

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import java.util.Arrays;
7373
import java.util.HashSet;
7474
import java.util.Set;
75+
import java.util.concurrent.ConcurrentHashMap;
7576
import java.util.stream.Collectors;
7677

7778

@@ -80,6 +81,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
8081
private StorageLayer _storageLayer;
8182
private String _mountPoint = "/mnt";
8283
private String _manageSnapshotPath;
84+
private static final ConcurrentHashMap<String, Integer> storagePoolRefCounts = new ConcurrentHashMap<>();
8385

8486
private String rbdTemplateSnapName = "cloudstack-base-snap";
8587
private static final int RBD_FEATURE_LAYERING = 1;
@@ -637,8 +639,44 @@ public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
637639
}
638640
}
639641

642+
/**
643+
* adjust refcount
644+
*/
645+
private int adjustStoragePoolRefCount(String uuid, int adjustment) {
646+
final String mutexKey = storagePoolRefCounts.keySet().stream()
647+
.filter(k -> k.equals(uuid))
648+
.findFirst()
649+
.orElse(uuid);
650+
synchronized (mutexKey) {
651+
// some access on the storagePoolRefCounts.key(mutexKey) element
652+
int refCount = storagePoolRefCounts.computeIfAbsent(mutexKey, k -> 0);
653+
refCount += adjustment;
654+
if (refCount < 1) {
655+
storagePoolRefCounts.remove(mutexKey);
656+
} else {
657+
storagePoolRefCounts.put(mutexKey, refCount);
658+
}
659+
return refCount;
660+
}
661+
}
662+
/**
663+
* Thread-safe increment storage pool usage refcount
664+
* @param uuid UUID of the storage pool to increment the count
665+
*/
666+
private void incStoragePoolRefCount(String uuid) {
667+
adjustStoragePoolRefCount(uuid, 1);
668+
}
669+
/**
670+
* Thread-safe decrement storage pool usage refcount for the given uuid and return if storage pool still in use.
671+
* @param uuid UUID of the storage pool to decrement the count
672+
* @return true if the storage pool is still used, else false.
673+
*/
674+
private boolean decStoragePoolRefCount(String uuid) {
675+
return adjustStoragePoolRefCount(uuid, -1) > 0;
676+
}
677+
640678
@Override
641-
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details) {
679+
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
642680
s_logger.info("Attempting to create storage pool " + name + " (" + type.toString() + ") in libvirt");
643681

644682
StoragePool sp = null;
@@ -744,6 +782,12 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri
744782
}
745783

746784
try {
785+
if (!isPrimaryStorage) {
786+
// only ref count storage pools for secondary storage, as primary storage is assumed
787+
// to be always mounted, as long the primary storage isn't fully deleted.
788+
incStoragePoolRefCount(name);
789+
}
790+
747791
if (sp.isActive() == 0) {
748792
s_logger.debug("Attempting to activate pool " + name);
749793
sp.create(0);
@@ -755,6 +799,7 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri
755799

756800
return getStoragePool(name);
757801
} catch (LibvirtException e) {
802+
decStoragePoolRefCount(name);
758803
String error = e.toString();
759804
if (error.contains("Storage source conflict")) {
760805
throw new CloudRuntimeException("A pool matching this location already exists in libvirt, " +
@@ -805,6 +850,13 @@ private boolean destroyStoragePoolHandleException(Connect conn, String uuid)
805850
@Override
806851
public boolean deleteStoragePool(String uuid) {
807852
s_logger.info("Attempting to remove storage pool " + uuid + " from libvirt");
853+
854+
// decrement and check if storage pool still in use
855+
if (decStoragePoolRefCount(uuid)) {
856+
s_logger.info(String.format("deleteStoragePool: Storage pool %s still in use", uuid));
857+
return true;
858+
}
859+
808860
Connect conn;
809861
try {
810862
conn = LibvirtConnection.getConnection();

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public ManagedNfsStorageAdaptor(StorageLayer storagelayer) {
5555
}
5656

5757
@Override
58-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details) {
58+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details, boolean isPrimaryStorage) {
5959

6060
LibvirtStoragePool storagePool = new LibvirtStoragePool(uuid, path, StoragePoolType.ManagedNFS, this, null);
6161
storagePool.setSourceHost(host);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ private KVMPhysicalDisk getPhysicalDisk(AddressInfo address, KVMStoragePool pool
168168
}
169169

170170
@Override
171-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details) {
171+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
172172
LOGGER.info(String.format("createStoragePool(uuid,host,port,path,type) called with args (%s, %s, %s, %s, %s)", uuid, host, ""+port, path, type));
173173
MultipathSCSIPool storagePool = new MultipathSCSIPool(uuid, host, port, path, type, details, this);
174174
MapStorageUuidToStoragePool.put(uuid, storagePool);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ public KVMPhysicalDisk getPhysicalDisk(String volumePath, KVMStoragePool pool) {
143143
}
144144

145145
@Override
146-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details) {
146+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
147147
ScaleIOStoragePool storagePool = new ScaleIOStoragePool(uuid, host, port, path, type, details, this);
148148
MapStorageUuidToStoragePool.put(uuid, storagePool);
149149
return storagePool;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public interface StorageAdaptor {
3838
// it with info from local disk, and return it
3939
public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool);
4040

41-
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details);
41+
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage);
4242

4343
public boolean deleteStoragePool(String uuid);
4444

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,6 @@ public void testCreateStoragePoolWithNFSMountOpts() throws Exception {
8686

8787
Map<String, String> details = new HashMap<>();
8888
details.put("nfsmountopts", "vers=4.1, nconnect=4");
89-
KVMStoragePool pool = libvirtStorageAdaptor.createStoragePool(uuid, null, 0, dir, null, Storage.StoragePoolType.NetworkFilesystem, details);
89+
KVMStoragePool pool = libvirtStorageAdaptor.createStoragePool(uuid, null, 0, dir, null, Storage.StoragePoolType.NetworkFilesystem, details, true);
9090
}
9191
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ public KVMPhysicalDisk getPhysicalDisk(String name, KVMStoragePool pool)
149149

150150
@Override
151151
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo,
152-
Storage.StoragePoolType type, Map<String, String> details)
152+
Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage)
153153
{
154154
s_logger.debug(String.format(
155155
"Linstor createStoragePool: name: '%s', host: '%s', path: %s, userinfo: %s", name, host, path, userInfo));

plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static void SP_LOG(String fmt, Object... args) {
5757
private static final Map<String, KVMStoragePool> storageUuidToStoragePool = new HashMap<String, KVMStoragePool>();
5858

5959
@Override
60-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details) {
60+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details, boolean isPrimaryStorage) {
6161
SP_LOG("StorPoolStorageAdaptor.createStoragePool: uuid=%s, host=%s:%d, path=%s, userInfo=%s, type=%s", uuid, host, port, path, userInfo, storagePoolType);
6262

6363
StorPoolStoragePool storagePool = new StorPoolStoragePool(uuid, host, port, storagePoolType, this);

0 commit comments

Comments
 (0)