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

Reply via email to