Martin Betak has uploaded a new change for review. Change subject: backend: Enable granular hostdev passthrough support ......................................................................
backend: Enable granular hostdev passthrough support Added flag to VmHostDevice entity that marks whether this device should be visible to the guest OS (iommuPlaceholder=false) or is there just to satisfy IOMMU group constrained for other (primary) device (iommuPlaceholder=true). This flag is send to VDSM as a part of spec params. When adding/removing VmHostDevices we take this flag into account. Change-Id: I1c8a80adce97ef98174bd85ac75f09dfe2a36de9 Signed-off-by: Martin Betak <mbe...@redhat.com> --- M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AbstractVmHostDevicesCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AddVmHostDevicesCommand.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/RemoveVmHostDevicesCommand.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmHostDevice.java 4 files changed, 127 insertions(+), 25 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/59/42159/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AbstractVmHostDevicesCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AbstractVmHostDevicesCommand.java index 4f88fa8..2fa41bf 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AbstractVmHostDevicesCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AbstractVmHostDevicesCommand.java @@ -7,6 +7,7 @@ import org.ovirt.engine.core.common.businessentities.VMStatus; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceGeneralType; +import org.ovirt.engine.core.common.businessentities.VmHostDevice; import org.ovirt.engine.core.common.errors.VdcBllMessages; import org.ovirt.engine.core.dao.HostDeviceDao; import org.ovirt.engine.core.dao.VmDeviceDAO; @@ -32,8 +33,14 @@ private List<HostDevice> hostDevices; + /** + * Contains device names that are explicitly passed in the command parameters + */ + private Set<String> primaryDeviceNames; + public AbstractVmHostDevicesCommand(P parameters) { super(parameters); + primaryDeviceNames = new HashSet<>(parameters.getDeviceNames()); } @Override @@ -60,6 +67,10 @@ } return true; + } + + protected Set<String> getPrimaryDeviceNames() { + return primaryDeviceNames; } protected VmDeviceDAO getVmDeviceDao() { @@ -89,8 +100,7 @@ } private Collection<HostDevice> getDeviceAtomicGroup(HostDevice hostDevice) { - // iommu group restriction only applicable to 'pci' devices - if (!CAPABILITY_PCI.equals(hostDevice.getCapability()) || hostDevice.getIommuGroup() == null) { + if (!hasIommu(hostDevice)) { return Collections.singleton(hostDevice); } @@ -98,12 +108,21 @@ hostDevice.getIommuGroup()); } + protected boolean hasIommu(HostDevice hostDevice) { + // iommu group restriction only applicable to 'pci' devices + return CAPABILITY_PCI.equals(hostDevice.getCapability()) || hostDevice.getIommuGroup() == null; + } + private HostDevice fetchHostDevice(String deviceName) { return hostDeviceDao.getHostDeviceByHostIdAndDeviceName(getVm().getDedicatedVmForVds(), deviceName); } - protected Map<String, VmDevice> getExistingVmHostDevicesByName() { + protected Map<String, VmHostDevice> getExistingVmHostDevicesByName() { List<VmDevice> existingDevices = vmDeviceDao.getVmDeviceByVmIdAndType(getVmId(), VmDeviceGeneralType.HOSTDEV); - return Entities.vmDevicesByDevice(existingDevices); + List<VmHostDevice> result = new ArrayList<>(); + for (VmDevice device : existingDevices) { + result.add(new VmHostDevice(device)); + } + return Entities.vmDevicesByDevice(result); } } diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AddVmHostDevicesCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AddVmHostDevicesCommand.java index 161e7a8..c8506e6 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AddVmHostDevicesCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/AddVmHostDevicesCommand.java @@ -21,24 +21,44 @@ @Override protected void executeCommand() { - List<VmDevice> addDevicesBatch = getAddDevicesBatch(); - getVmDeviceDao().saveAllInBatch(addDevicesBatch); - setSucceeded(true); - setActionReturnValue(namesAdded); - } - private List<VmDevice> getAddDevicesBatch() { namesAdded = new ArrayList<>(); + Set<HostDevice> affectedHostDevices = getAffectedHostDevices(); - Map<String, VmDevice> existingDevices = getExistingVmHostDevicesByName(); + Map<String, VmHostDevice> existingDevices = getExistingVmHostDevicesByName(); + List<VmDevice> devicesToAdd = new ArrayList<>(); + List<VmDevice> devicesToUpdate = new ArrayList<>(); + for (HostDevice hostDevice : affectedHostDevices) { if (!existingDevices.containsKey(hostDevice.getDeviceName())) { - devicesToAdd.add(new VmHostDevice(getVmId(), hostDevice)); + VmHostDevice device = new VmHostDevice(getVmId(), hostDevice); + + // if the device was not explicitly intended by the user (only added due to the IOMMU group + // we mark it as as placeholder + boolean required = getPrimaryDeviceNames().contains(device.getDevice()); + device.setIommuPlaceholder(!required); + + devicesToAdd.add(device); namesAdded.add(hostDevice.getDeviceName()); + } else { + VmHostDevice device = new VmHostDevice(existingDevices.get(hostDevice.getDeviceName())); + // if the device was previously only added as placeholder we update the flag + // as it is now explicitly requested by the user + if (getPrimaryDeviceNames().contains(device.getDevice()) && device.isIommuPlaceholder()) { + device.setIommuPlaceholder(false); + + devicesToUpdate.add(device); + namesAdded.add(hostDevice.getDeviceName()); + } } } - return devicesToAdd; + + getVmDeviceDao().saveAllInBatch(devicesToAdd); + getVmDeviceDao().updateAllInBatch(devicesToUpdate); + + setSucceeded(true); + setActionReturnValue(namesAdded); } @Override diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/RemoveVmHostDevicesCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/RemoveVmHostDevicesCommand.java index b65b602..ac9733b 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/RemoveVmHostDevicesCommand.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/hostdev/RemoveVmHostDevicesCommand.java @@ -2,14 +2,21 @@ import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.VmHostDevicesParameters; +import org.ovirt.engine.core.common.businessentities.Entities; import org.ovirt.engine.core.common.businessentities.HostDevice; import org.ovirt.engine.core.common.businessentities.VmDevice; import org.ovirt.engine.core.common.businessentities.VmDeviceId; +import org.ovirt.engine.core.common.businessentities.VmHostDevice; +import org.ovirt.engine.core.utils.collections.MultiValueMapUtils; import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; + +import static org.ovirt.engine.core.utils.collections.MultiValueMapUtils.addToMap; public class RemoveVmHostDevicesCommand extends AbstractVmHostDevicesCommand<VmHostDevicesParameters> { @@ -21,24 +28,64 @@ @Override protected void executeCommand() { - List<VmDeviceId> removeDeviceBatch = getRemoveDeviceBatch(); - getVmDeviceDao().removeAll(removeDeviceBatch); + namesRemoved = new ArrayList<>(); + + Set<HostDevice> affectedHostDevices = getAffectedHostDevices(); + Map<String, VmHostDevice> existingDevices = getExistingVmHostDevicesByName(); + + Map<Integer, List<VmHostDevice>> devicesByIommuGroup = new HashMap<>(); + + for (HostDevice hostDevice : affectedHostDevices) { + boolean shouldRemoveDevice = getPrimaryDeviceNames().contains(hostDevice.getDeviceName()); + boolean deviceExists = existingDevices.containsKey(hostDevice.getDeviceName()); + if (shouldRemoveDevice && deviceExists) { + // first just set the flag that this device is not required + VmHostDevice device = existingDevices.get(hostDevice.getDeviceName()); + device.setIommuPlaceholder(true); + + addToMap(getIommuGroupKey(hostDevice.getIommuGroup()), device, devicesByIommuGroup); + + namesRemoved.add(hostDevice.getDeviceName()); + } + } + + List<VmDevice> devicesToRemove = new ArrayList<>(); + List<VmDevice> devicesToUpdate = new ArrayList<>(); + + // go through all the affected IOMMU groups and remove those who only contain + // no longer needed (placeholder) devices + for (Map.Entry<Integer, List<VmHostDevice>> group : devicesByIommuGroup.entrySet()) { + List<VmHostDevice> devices = group.getValue(); + + // devices without IOMMU group can be safely removed + boolean noIommuDeviceGroup = group.getKey() == getIommuGroupKey(null); + if (noIommuDeviceGroup || allPlaceholder(devices)) { + // all devices in this group became unnecessary, so remove them + devicesToRemove.addAll(devices); + } else { + // some devices in this group are still required so just update the placeholder flag + devicesToUpdate.addAll(devices); + } + } + + getVmDeviceDao().removeAllInBatch(devicesToRemove); + getVmDeviceDao().updateAllInBatch(devicesToUpdate); + setSucceeded(true); setActionReturnValue(namesRemoved); } - private List<VmDeviceId> getRemoveDeviceBatch() { - namesRemoved = new ArrayList<>(); - Set<HostDevice> affectedHostDevices = getAffectedHostDevices(); - Map<String, VmDevice> existingDevices = getExistingVmHostDevicesByName(); - List<VmDeviceId> devicesToRemove = new ArrayList<>(); - for (HostDevice hostDevice : affectedHostDevices) { - if (existingDevices.containsKey(hostDevice.getDeviceName())) { - devicesToRemove.add(existingDevices.get(hostDevice.getDeviceName()).getId()); - namesRemoved.add(hostDevice.getDeviceName()); + private static boolean allPlaceholder(Collection<VmHostDevice> devices) { + for (VmHostDevice device : devices) { + if (!device.isIommuPlaceholder()) { + return false; } } - return devicesToRemove; + return true; + } + + private static int getIommuGroupKey(Integer iommuGroup) { + return iommuGroup == null ? -1 : iommuGroup; } @Override diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmHostDevice.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmHostDevice.java index 8ad3319..f3853e1 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmHostDevice.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/businessentities/VmHostDevice.java @@ -4,12 +4,20 @@ public class VmHostDevice extends VmDevice { + /** + * Spec param flag that distinguishes devices that are intended + * by user from those that are just placeholders to satisfy the + * IOMMU group restriction + */ + public static final String IOMMU_PLACEHOLDER = "iommuPlaceholder"; + public VmHostDevice() { setType(VmDeviceGeneralType.HOSTDEV); setAddress(""); setIsManaged(true); setIsPlugged(true); setId(new VmDeviceId()); + setIommuPlaceholder(false); } public VmHostDevice(VmDevice device) { @@ -25,4 +33,12 @@ setVmId(vmId); setDevice(device.getDeviceName()); } + + public void setIommuPlaceholder(boolean placeholder) { + getSpecParams().put(IOMMU_PLACEHOLDER, placeholder); + } + + public boolean isIommuPlaceholder() { + return Boolean.TRUE.equals(getSpecParams().get(IOMMU_PLACEHOLDER)); + } } -- To view, visit https://gerrit.ovirt.org/42159 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I1c8a80adce97ef98174bd85ac75f09dfe2a36de9 Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: master Gerrit-Owner: Martin Betak <mbe...@redhat.com> _______________________________________________ Engine-patches mailing list Engine-patches@ovirt.org http://lists.ovirt.org/mailman/listinfo/engine-patches