Skip to content

Commit 826ea7a

Browse files
committed
server: Avoid device id collision between config drive ISO and data volumes on KVM
ConfigDriveNetworkElement hardcodes disk sequence 4 (CONFIGDRIVEDISKSEQ) for the config drive ISO, but the volume device-id allocators (VolumeApiServiceImpl.getDeviceId, KVMGuru.getNextAvailableDeviceId) only look at persisted VolumeVO rows and have no knowledge that slot 4 is reserved by the config drive. When a VM using ConfigDrive already has data disks on device ids 1 and 2, attaching a 3rd data disk gets assigned device id 4 as well, producing two disks with the same libvirt target device (e.g. "sde") once both end up on the same bus namespace, as happens with Q35/UEFI machine types. Both allocators now skip CONFIGDRIVEDISKSEQ when the VM has a config drive (detected via the existing CONFIG_DRIVE_LOCATION vm detail), the same way they already permanently reserve device id 3 for the CD-ROM slot.
1 parent 2b3cca6 commit 826ea7a

3 files changed

Lines changed: 19 additions & 5 deletions

File tree

‎server/src/main/java/com/cloud/hypervisor/KVMGuru.java‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import com.cloud.hypervisor.Hypervisor.HypervisorType;
2828
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
2929
import com.cloud.hypervisor.kvm.dpdk.DpdkHelper;
30+
import com.cloud.network.element.ConfigDriveNetworkElement;
3031
import com.cloud.service.ServiceOfferingVO;
3132
import com.cloud.storage.DataStoreRole;
3233
import com.cloud.storage.GuestOSHypervisorVO;
@@ -42,7 +43,9 @@
4243
import com.cloud.vm.VMInstanceVO;
4344
import com.cloud.vm.VirtualMachine;
4445
import com.cloud.vm.VirtualMachineProfile;
46+
import com.cloud.vm.VmDetailConstants;
4547
import com.cloud.vm.dao.VMInstanceDao;
48+
import com.cloud.vm.dao.VMInstanceDetailsDao;
4649
import org.apache.cloudstack.backup.Backup;
4750
import org.apache.cloudstack.storage.command.CopyCommand;
4851
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
@@ -71,6 +74,8 @@ public class KVMGuru extends HypervisorGuruBase implements HypervisorGuru {
7174
VolumeDao _volumeDao;
7275
@Inject
7376
HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
77+
@Inject
78+
VMInstanceDetailsDao _vmInstanceDetailsDao;
7479

7580

7681
@Override
@@ -86,7 +91,7 @@ protected KVMGuru() {
8691
* Get next free DeviceId for a KVM Guest
8792
*/
8893

89-
protected Long getNextAvailableDeviceId(List<VolumeVO> vmVolumes) {
94+
protected Long getNextAvailableDeviceId(long vmId, List<VolumeVO> vmVolumes) {
9095

9196
int maxDataVolumesSupported;
9297
int maxDeviceId;
@@ -103,6 +108,9 @@ protected Long getNextAvailableDeviceId(List<VolumeVO> vmVolumes) {
103108
devIds.add(String.valueOf(i));
104109
}
105110
devIds.remove("3");
111+
if (_vmInstanceDetailsDao.findDetail(vmId, VmDetailConstants.CONFIG_DRIVE_LOCATION) != null) {
112+
devIds.remove(ConfigDriveNetworkElement.CONFIGDRIVEDISKSEQ.toString());
113+
}
106114
for (VolumeVO vmVolume : vmVolumes) {
107115
devIds.remove(vmVolume.getDeviceId().toString().trim());
108116
}
@@ -371,7 +379,7 @@ public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId,
371379
} else if (VMVolToRestore.getType() == Volume.Type.DATADISK) {
372380
List<VolumeVO> vmVolumes = _volumeDao.findByInstance(vm.getId());
373381
_volumeDao.update(volume.getId(), volume);
374-
_volumeDao.attachVolume(volume.getId(), vm.getId(), getNextAvailableDeviceId(vmVolumes));
382+
_volumeDao.attachVolume(volume.getId(), vm.getId(), getNextAvailableDeviceId(vm.getId(), vmVolumes));
375383
}
376384
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_ATTACH, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
377385
volume.getDiskOfferingId(), volume.getTemplateId(), volume.getSize(), Volume.class.getName(), volume.getUuid(), vm.getId(), volume.isDisplay());
@@ -389,7 +397,7 @@ public VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId,
389397
VolumeVO restoredVolume = _volumeDao.findByUuid(location);
390398
if (restoredVolume != null) {
391399
try {
392-
_volumeDao.attachVolume(restoredVolume.getId(), vm.getId(), getNextAvailableDeviceId(vmVolumes));
400+
_volumeDao.attachVolume(restoredVolume.getId(), vm.getId(), getNextAvailableDeviceId(vm.getId(), vmVolumes));
393401
restoredVolume.setState(Volume.State.Ready);
394402
_volumeDao.update(restoredVolume.getId(), restoredVolume);
395403
UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_ATTACH, restoredVolume.getAccountId(), restoredVolume.getDataCenterId(), restoredVolume.getId(), restoredVolume.getName(),

‎server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
142142
@Inject
143143
private HypervisorGuruManager _hvGuruMgr;
144144

145-
private final static Integer CONFIGDRIVEDISKSEQ = 4;
145+
public final static Integer CONFIGDRIVEDISKSEQ = 4;
146146

147147
private boolean canHandle(TrafficType trafficType) {
148148
return trafficType.equals(TrafficType.Guest);

‎server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@
160160
import com.cloud.hypervisor.Hypervisor.HypervisorType;
161161
import com.cloud.hypervisor.HypervisorCapabilitiesVO;
162162
import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
163+
import com.cloud.network.element.ConfigDriveNetworkElement;
163164
import com.cloud.offering.DiskOffering;
164165
import com.cloud.org.Cluster;
165166
import com.cloud.org.Grouping;
@@ -5042,8 +5043,10 @@ private Long getDeviceId(UserVmVO vm, Long deviceId) {
50425043
int maxDevices = getMaxDataVolumesSupported(vm) + 2; // add 2 to consider devices root volume and cdrom
50435044
int maxDeviceId = maxDevices - 1;
50445045
List<VolumeVO> vols = _volsDao.findByInstance(vm.getId());
5046+
boolean vmHasConfigDrive = vmInstanceDetailsDao.findDetail(vm.getId(), VmDetailConstants.CONFIG_DRIVE_LOCATION) != null;
50455047
if (deviceId != null) {
5046-
if (deviceId.longValue() < 0 || deviceId.longValue() > maxDeviceId || deviceId.longValue() == 3) {
5048+
if (deviceId.longValue() < 0 || deviceId.longValue() > maxDeviceId || deviceId.longValue() == 3
5049+
|| (vmHasConfigDrive && deviceId.longValue() == ConfigDriveNetworkElement.CONFIGDRIVEDISKSEQ)) {
50475050
throw new RuntimeException("deviceId should be 0,1,2,4-" + maxDeviceId);
50485051
}
50495052
for (VolumeVO vol : vols) {
@@ -5058,6 +5061,9 @@ private Long getDeviceId(UserVmVO vm, Long deviceId) {
50585061
devIds.add(String.valueOf(i));
50595062
}
50605063
devIds.remove("3");
5064+
if (vmHasConfigDrive) {
5065+
devIds.remove(ConfigDriveNetworkElement.CONFIGDRIVEDISKSEQ.toString());
5066+
}
50615067
for (VolumeVO vol : vols) {
50625068
devIds.remove(vol.getDeviceId().toString().trim());
50635069
}

0 commit comments

Comments
 (0)