mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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.
This commit is contained in:
parent
adbf370909
commit
dfe4a67859
@ -43,7 +43,7 @@ public class IscsiAdmStorageAdaptor implements StorageAdaptor {
|
||||
private static final Map<String, KVMStoragePool> MapStorageUuidToStoragePool = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details) {
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
IscsiAdmStoragePool storagePool = new IscsiAdmStoragePool(uuid, host, port, storagePoolType, this);
|
||||
|
||||
MapStorageUuidToStoragePool.put(uuid, storagePool);
|
||||
|
||||
@ -361,7 +361,7 @@ public class KVMStoragePoolManager {
|
||||
//Note: due to bug CLOUDSTACK-4459, createStoragepool can be called in parallel, so need to be synced.
|
||||
private synchronized KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean primaryStorage) {
|
||||
StorageAdaptor adaptor = getStorageAdaptor(type);
|
||||
KVMStoragePool pool = adaptor.createStoragePool(name, host, port, path, userInfo, type, details);
|
||||
KVMStoragePool pool = adaptor.createStoragePool(name, host, port, path, userInfo, type, details, primaryStorage);
|
||||
|
||||
// LibvirtStorageAdaptor-specific statement
|
||||
if (pool.isPoolSupportHA() && primaryStorage) {
|
||||
|
||||
@ -72,6 +72,7 @@ import static com.cloud.utils.NumbersUtil.toHumanReadableSize;
|
||||
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<String, Integer> storagePoolRefCounts = new ConcurrentHashMap<>();
|
||||
|
||||
private String rbdTemplateSnapName = "cloudstack-base-snap";
|
||||
private static final int RBD_FEATURE_LAYERING = 1;
|
||||
@ -637,8 +639,44 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adjust refcount
|
||||
*/
|
||||
private int adjustStoragePoolRefCount(String uuid, int adjustment) {
|
||||
final String mutexKey = storagePoolRefCounts.keySet().stream()
|
||||
.filter(k -> k.equals(uuid))
|
||||
.findFirst()
|
||||
.orElse(uuid);
|
||||
synchronized (mutexKey) {
|
||||
// some access on the storagePoolRefCounts.key(mutexKey) element
|
||||
int refCount = storagePoolRefCounts.computeIfAbsent(mutexKey, k -> 0);
|
||||
refCount += adjustment;
|
||||
if (refCount < 1) {
|
||||
storagePoolRefCounts.remove(mutexKey);
|
||||
} else {
|
||||
storagePoolRefCounts.put(mutexKey, 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<String, String> details) {
|
||||
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
s_logger.info("Attempting to create storage pool " + name + " (" + type.toString() + ") in libvirt");
|
||||
|
||||
StoragePool sp = null;
|
||||
@ -744,6 +782,12 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
}
|
||||
|
||||
try {
|
||||
if (!isPrimaryStorage) {
|
||||
// only ref count storage pools for secondary storage, as primary storage is assumed
|
||||
// to be always mounted, as long the primary storage isn't fully deleted.
|
||||
incStoragePoolRefCount(name);
|
||||
}
|
||||
|
||||
if (sp.isActive() == 0) {
|
||||
s_logger.debug("Attempting to activate pool " + name);
|
||||
sp.create(0);
|
||||
@ -755,6 +799,7 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
|
||||
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 +850,13 @@ public class LibvirtStorageAdaptor implements StorageAdaptor {
|
||||
@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();
|
||||
|
||||
@ -55,7 +55,7 @@ public class ManagedNfsStorageAdaptor implements StorageAdaptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details) {
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
|
||||
LibvirtStoragePool storagePool = new LibvirtStoragePool(uuid, path, StoragePoolType.ManagedNFS, this, null);
|
||||
storagePool.setSourceHost(host);
|
||||
|
||||
@ -168,7 +168,7 @@ public abstract class MultipathSCSIAdapterBase implements StorageAdaptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details) {
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
LOGGER.info(String.format("createStoragePool(uuid,host,port,path,type) called with args (%s, %s, %s, %s, %s)", uuid, host, ""+port, path, type));
|
||||
MultipathSCSIPool storagePool = new MultipathSCSIPool(uuid, host, port, path, type, details, this);
|
||||
MapStorageUuidToStoragePool.put(uuid, storagePool);
|
||||
|
||||
@ -143,7 +143,7 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor {
|
||||
}
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details) {
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
ScaleIOStoragePool storagePool = new ScaleIOStoragePool(uuid, host, port, path, type, details, this);
|
||||
MapStorageUuidToStoragePool.put(uuid, storagePool);
|
||||
return storagePool;
|
||||
|
||||
@ -38,7 +38,7 @@ public interface StorageAdaptor {
|
||||
// it with info from local disk, and return it
|
||||
public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool);
|
||||
|
||||
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details);
|
||||
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo, StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage);
|
||||
|
||||
public boolean deleteStoragePool(String uuid);
|
||||
|
||||
|
||||
@ -86,6 +86,6 @@ public class LibvirtStorageAdaptorTest {
|
||||
|
||||
Map<String, String> details = new HashMap<>();
|
||||
details.put("nfsmountopts", "vers=4.1, nconnect=4");
|
||||
KVMStoragePool pool = libvirtStorageAdaptor.createStoragePool(uuid, null, 0, dir, null, Storage.StoragePoolType.NetworkFilesystem, details);
|
||||
KVMStoragePool pool = libvirtStorageAdaptor.createStoragePool(uuid, null, 0, dir, null, Storage.StoragePoolType.NetworkFilesystem, details, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +149,7 @@ public class LinstorStorageAdaptor implements StorageAdaptor {
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String name, String host, int port, String path, String userInfo,
|
||||
Storage.StoragePoolType type, Map<String, String> details)
|
||||
Storage.StoragePoolType type, Map<String, String> details, boolean isPrimaryStorage)
|
||||
{
|
||||
s_logger.debug(String.format(
|
||||
"Linstor createStoragePool: name: '%s', host: '%s', path: %s, userinfo: %s", name, host, path, userInfo));
|
||||
|
||||
@ -57,7 +57,7 @@ public class StorPoolStorageAdaptor implements StorageAdaptor {
|
||||
private static final Map<String, KVMStoragePool> storageUuidToStoragePool = new HashMap<String, KVMStoragePool>();
|
||||
|
||||
@Override
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details) {
|
||||
public KVMStoragePool createStoragePool(String uuid, String host, int port, String path, String userInfo, StoragePoolType storagePoolType, Map<String, String> details, boolean isPrimaryStorage) {
|
||||
SP_LOG("StorPoolStorageAdaptor.createStoragePool: uuid=%s, host=%s:%d, path=%s, userInfo=%s, type=%s", uuid, host, port, path, userInfo, storagePoolType);
|
||||
|
||||
StorPoolStoragePool storagePool = new StorPoolStoragePool(uuid, host, port, storagePoolType, this);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user