Skip to content

Commit 89d9f50

Browse files
kvm: look RBD volumes up through librbd instead of refreshing the pool
getPhysicalDisk() asks libvirt for the volume. A volume that was just created by the management server is not in this host's libvirt pool cache, so the lookup misses and getVolume() falls back to refreshing the whole pool. Refreshing an RBD pool opens and stats every image in it, so the cost grows with the number of volumes in the pool and is paid on every VM start. On a pool holding 950 images that is 11.7 seconds added to each start, against 0.005 seconds to list the image names. Look RBD volumes up directly through librbd instead. Creating, cloning, resizing, copying and deleting RBD volumes in this class already use librbd directly; only the lookup went through libvirt. Signed-off-by: Brad House <bhouse@nexthop.ai>
1 parent 10037c8 commit 89d9f50

1 file changed

Lines changed: 54 additions & 0 deletions

File tree

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,19 @@ public KVMStoragePool getStoragePool(String uuid, boolean refreshInfo) {
659659
public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
660660
LibvirtStoragePool libvirtPool = (LibvirtStoragePool)pool;
661661

662+
/*
663+
* An RBD volume is looked up through librbd rather than through libvirt.
664+
* A volume that was created by another host is not in the libvirt pool
665+
* cache, so looking it up through libvirt misses and forces a refresh of
666+
* the whole pool. Refreshing an RBD pool stats every image in it, so that
667+
* cost grows with the number of volumes in the pool and is paid on every
668+
* VM start. Every other RBD operation in this class already uses librbd
669+
* directly.
670+
*/
671+
if (pool.getType() == StoragePoolType.RBD) {
672+
return getRbdPhysicalDisk(volumeUuid, libvirtPool);
673+
}
674+
662675
try {
663676
StorageVol vol = getVolume(libvirtPool.getPool(), volumeUuid);
664677
KVMPhysicalDisk disk;
@@ -696,6 +709,47 @@ public KVMPhysicalDisk getPhysicalDisk(String volumeUuid, KVMStoragePool pool) {
696709
}
697710
}
698711

712+
/**
713+
* Looks an RBD volume up directly through librbd.
714+
*
715+
* The size reported by librbd is used for both the size and the virtual size of
716+
* the disk, matching what this class already does after converting an image into
717+
* an RBD volume.
718+
*/
719+
private KVMPhysicalDisk getRbdPhysicalDisk(String volumeUuid, LibvirtStoragePool pool) {
720+
try {
721+
Rados r = new Rados(pool.getAuthUserName());
722+
r.confSet("mon_host", pool.getSourceHost() + ":" + pool.getSourcePort());
723+
r.confSet("key", pool.getAuthSecret());
724+
r.confSet("client_mount_timeout", "30");
725+
r.connect();
726+
727+
IoCTX io = r.ioCtxCreate(pool.getSourceDir());
728+
try {
729+
Rbd rbd = new Rbd(io);
730+
RbdImage image = rbd.open(volumeUuid);
731+
try {
732+
RbdImageInfo rbdInfo = image.stat();
733+
KVMPhysicalDisk disk = new KVMPhysicalDisk(pool.getSourceDir() + "/" + volumeUuid, volumeUuid, pool);
734+
disk.setFormat(PhysicalDiskFormat.RAW);
735+
disk.setSize(rbdInfo.size);
736+
disk.setVirtualSize(rbdInfo.size);
737+
return disk;
738+
} finally {
739+
rbd.close(image);
740+
}
741+
} finally {
742+
r.ioCtxDestroy(io);
743+
}
744+
} catch (RadosException e) {
745+
logger.error("A Ceph RADOS operation failed (" + e.getReturnValue() + "). The error was: " + e.getMessage());
746+
throw new CloudRuntimeException(e.toString(), e);
747+
} catch (RbdException e) {
748+
logger.error("A Ceph RBD operation failed (" + e.getReturnValue() + "). The error was: " + e.getMessage());
749+
throw new CloudRuntimeException(e.toString(), e);
750+
}
751+
}
752+
699753
/**
700754
* adjust refcount
701755
*/

0 commit comments

Comments
 (0)