Skip to content

Commit b3ca884

Browse files
rp-dhslove
authored andcommitted
kvm: ref-count secondary storage pool usage (apache#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 cdec6b8 commit b3ca884

File tree

9 files changed

+62
-10
lines changed

9 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
@@ -389,7 +389,7 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri
389389
//Note: due to bug CLOUDSTACK-4459, createStoragepool can be called in parallel, so need to be synced.
390390
private synchronized KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean primaryStorage) {
391391
StorageAdaptor adaptor = getStorageAdaptor(type);
392-
KVMStoragePool pool = adaptor.createStoragePool(name, host, port, path, userInfo, type, details);
392+
KVMStoragePool pool = adaptor.createStoragePool(name, host, port, path, userInfo, type, details, primaryStorage);
393393

394394
// LibvirtStorageAdaptor-specific statement
395395
if (type == StoragePoolType.NetworkFilesystem && primaryStorage) {

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

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
import java.util.Arrays;
7676
import java.util.HashSet;
7777
import java.util.Set;
78+
import java.util.concurrent.ConcurrentHashMap;
7879
import java.util.stream.Collectors;
7980

8081

@@ -83,6 +84,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
8384
private StorageLayer _storageLayer;
8485
private String _mountPoint = "/mnt";
8586
private String _manageSnapshotPath;
87+
private static final ConcurrentHashMap<String, Integer> storagePoolRefCounts = new ConcurrentHashMap<>();
8688

8789
private String rbdTemplateSnapName = "cloudstack-base-snap";
8890
private static final int RBD_FEATURE_LAYERING = 1;
@@ -684,8 +686,44 @@ public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
684686
}
685687
}
686688

689+
/**
690+
* adjust refcount
691+
*/
692+
private int adjustStoragePoolRefCount(String uuid, int adjustment) {
693+
final String mutexKey = storagePoolRefCounts.keySet().stream()
694+
.filter(k -> k.equals(uuid))
695+
.findFirst()
696+
.orElse(uuid);
697+
synchronized (mutexKey) {
698+
// some access on the storagePoolRefCounts.key(mutexKey) element
699+
int refCount = storagePoolRefCounts.computeIfAbsent(mutexKey, k -> 0);
700+
refCount += adjustment;
701+
if (refCount < 1) {
702+
storagePoolRefCounts.remove(mutexKey);
703+
} else {
704+
storagePoolRefCounts.put(mutexKey, refCount);
705+
}
706+
return refCount;
707+
}
708+
}
709+
/**
710+
* Thread-safe increment storage pool usage refcount
711+
* @param uuid UUID of the storage pool to increment the count
712+
*/
713+
private void incStoragePoolRefCount(String uuid) {
714+
adjustStoragePoolRefCount(uuid, 1);
715+
}
716+
/**
717+
* Thread-safe decrement storage pool usage refcount for the given uuid and return if storage pool still in use.
718+
* @param uuid UUID of the storage pool to decrement the count
719+
* @return true if the storage pool is still used, else false.
720+
*/
721+
private boolean decStoragePoolRefCount(String uuid) {
722+
return adjustStoragePoolRefCount(uuid, -1) > 0;
723+
}
724+
687725
@Override
688-
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details) {
726+
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
689727
logger.info("Attempting to create storage pool " + name + " (" + type.toString() + ") in libvirt");
690728

691729
// gluefs mount script call
@@ -805,6 +843,12 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri
805843
}
806844

807845
try {
846+
if (!isPrimaryStorage) {
847+
// only ref count storage pools for secondary storage, as primary storage is assumed
848+
// to be always mounted, as long the primary storage isn't fully deleted.
849+
incStoragePoolRefCount(name);
850+
}
851+
808852
if (sp.isActive() == 0) {
809853
logger.debug("Attempting to activate pool " + name);
810854
sp.create(0);
@@ -816,6 +860,7 @@ public KVMStoragePool createStoragePool(String name, String host, int port, Stri
816860

817861
return getStoragePool(name);
818862
} catch (LibvirtException e) {
863+
decStoragePoolRefCount(name);
819864
String error = e.toString();
820865
if (error.contains("Storage source conflict")) {
821866
throw new CloudRuntimeException("A pool matching this location already exists in libvirt, " +
@@ -866,7 +911,14 @@ private boolean destroyStoragePoolHandleException(Connect conn, String uuid)
866911
@Override
867912
public boolean deleteStoragePool(String uuid) {
868913
logger.info("Attempting to remove storage pool " + uuid + " from libvirt");
869-
Connect conn = null;
914+
915+
// decrement and check if storage pool still in use
916+
if (decStoragePoolRefCount(uuid)) {
917+
s_logger.info(String.format("deleteStoragePool: Storage pool %s still in use", uuid));
918+
return true;
919+
}
920+
921+
Connect conn;
870922
try {
871923
conn = LibvirtConnection.getConnection();
872924
} catch (LibvirtException e) {

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
@@ -56,7 +56,7 @@ public ManagedNfsStorageAdaptor(StorageLayer storagelayer) {
5656
}
5757

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

6161
LibvirtStoragePool storagePool = new LibvirtStoragePool(uuid, path, StoragePoolType.ManagedNFS, this, null);
6262
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
@@ -169,7 +169,7 @@ private KVMPhysicalDisk getPhysicalDisk(AddressInfo address, KVMStoragePool pool
169169
}
170170

171171
@Override
172-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details) {
172+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
173173
LOGGER.info(String.format("createStoragePool(uuid,host,port,path,type) called with args (%s, %s, %s, %s, %s)", uuid, host, ""+port, path, type));
174174
MultipathSCSIPool storagePool = new MultipathSCSIPool(uuid, host, port, path, type, details, this);
175175
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
@@ -146,7 +146,7 @@ public KVMPhysicalDisk getPhysicalDisk(String volumePath, KVMStoragePool pool) {
146146
}
147147

148148
@Override
149-
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details) {
149+
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
150150
ScaleIOStoragePool storagePool = new ScaleIOStoragePool(uuid, host, port, path, type, details, this);
151151
MapStorageUuidToStoragePool.put(uuid, storagePool);
152152
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
@@ -40,7 +40,7 @@ public interface StorageAdaptor {
4040
// it with info from local disk, and return it
4141
public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool);
4242

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

4545
public boolean deleteStoragePool(String uuid);
4646

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/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)