Change in vdsm[ovirt-3.6]: hostdev: change ownership for passthrough USB devices

mpolednik at redhat.com mpolednik at redhat.com
Tue Sep 22 14:04:44 UTC 2015


Martin Polednik has uploaded a new change for review.

Change subject: hostdev: change ownership for passthrough USB devices
......................................................................

hostdev: change ownership for passthrough USB devices

In order co correctly passthrough an USB device while qemu doesn't run
under root user, permission must be set for
/dev/bus/usb/${bus}/${device} node so qemu can access it. This patch
dynamically changes the ownership of the node and later reverts it
and triggers relevant udev rules.

Change-Id: I1f72f63186187254cd4aded0a2e6c396001ca28b
Bug-Url: https://bugzilla.redhat.com/1248105
Signed-off-by: Martin Polednik <mpolednik at redhat.com>
---
M vdsm/hostdev.py
M vdsm/supervdsmServer
2 files changed, 57 insertions(+), 2 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/27/46527/1

diff --git a/vdsm/hostdev.py b/vdsm/hostdev.py
index 01e22fe..0638557 100644
--- a/vdsm/hostdev.py
+++ b/vdsm/hostdev.py
@@ -173,28 +173,38 @@
 
 def detach_detachable(device_name):
     libvirt_device, device_params = _get_device_ref_and_params(device_name)
+    capability = CAPABILITY_TO_XML_ATTR[device_params['capability']]
 
-    if CAPABILITY_TO_XML_ATTR[device_params['capability']] == 'pci':
+    if capability == 'pci':
         try:
             iommu_group = device_params['iommu_group']
         except KeyError:
             raise NoIOMMUSupportException('hostdev passthrough without iommu')
         supervdsm.getProxy().appropriateIommuGroup(iommu_group)
         libvirt_device.detachFlags(None)
+    elif capability == 'usb':
+        supervdsm.getProxy().appropriateUSBDevice(
+            device_params['address']['bus'],
+            device_params['address']['device'])
 
     return device_params
 
 
 def reattach_detachable(device_name):
     libvirt_device, device_params = _get_device_ref_and_params(device_name)
+    capability = CAPABILITY_TO_XML_ATTR[device_params['capability']]
 
-    if CAPABILITY_TO_XML_ATTR[device_params['capability']] == 'pci':
+    if capability == 'pci':
         try:
             iommu_group = device_params['iommu_group']
         except KeyError:
             raise NoIOMMUSupportException
         supervdsm.getProxy().rmAppropriateIommuGroup(iommu_group)
         libvirt_device.reAttach()
+    elif capability == 'usb':
+        supervdsm.getProxy().rmAppropriateUSBDevice(
+            device_params['address']['bus'],
+            device_params['address']['device'])
 
 
 def change_numvfs(device_name, numvfs):
diff --git a/vdsm/supervdsmServer b/vdsm/supervdsmServer
index 0dc0670..fddd0f6 100755
--- a/vdsm/supervdsmServer
+++ b/vdsm/supervdsmServer
@@ -91,6 +91,10 @@
 _UDEV_RULE_FILE_NAME_VFIO = os.path.join(
     _UDEV_RULE_FILE_DIR, _UDEV_RULE_FILE_PREFIX + "iommu_group_%s" +
     _UDEV_RULE_FILE_EXT)
+_UDEV_RULE_FILE_NAME_USB = os.path.join(
+    _UDEV_RULE_FILE_DIR, _UDEV_RULE_FILE_PREFIX + "usb_%s_%s" +
+    _UDEV_RULE_FILE_EXT)
+_USB_DEVICE_PATH = '/dev/bus/usb/%03d/%03d'
 
 RUN_AS_TIMEOUT = config.getint("irs", "process_pool_timeout")
 
@@ -388,6 +392,47 @@
             self._udevTrigger(subsystem_matches=('vfio',))
 
     @logDecorator
+    def appropriateUSBDevice(self, bus, device):
+        rule_file = _UDEV_RULE_FILE_NAME_USB % (bus, device)
+        rule = ('SUBSYSTEM=="usb", ATTRS{{busnum}}=="{}", '
+                'ATTRS{{devnum}}=="{}", OWNER:="{}", GROUP:="{}"\n').format(
+                    bus, device, QEMU_PROCESS_USER, QEMU_PROCESS_GROUP)
+
+        self.log.debug("Creating rule %s: %r", rule_file, rule)
+
+        with open(rule_file, "w") as rf:
+            rf.write(rule)
+
+        self._udevTrigger(attr_matches=(('busnum', int(bus)),
+                                        ('devnum', int(device))))
+
+    @logDecorator
+    def rmAppropriateUSBDevice(self, bus, device):
+        rule_file = _UDEV_RULE_FILE_NAME_USB % (bus, device)
+        self.log.debug("Removing rule %s", rule_file)
+        try:
+            os.remove(rule_file)
+        except OSError as e:
+            if e.errno != errno.ENOENT:
+                raise
+
+            self.log.warning('Rule %s missing', rule_file)
+
+        self.log.debug('Changing ownership (to root:root) of device '
+                       'bus: %s, device:: %s', bus, device)
+        device_path = _USB_DEVICE_PATH % (int(bus), int(device))
+        cmd = [EXT_CHOWN, 'root:root', device_path]
+        rc, out, err = utils.execCmd(cmd)
+        if err:
+            raise OSError(errno.EINVAL, 'Could not change ownership'
+                          'out %s\nerr %s' % (out, err))
+
+        # It's possible that the device was in input class or had rule
+        # matched against it, trigger to make sure everything is fine.
+        self._udevTrigger(attr_matches=(('busnum', int(bus)),
+                                        ('devnum', int(device))))
+
+    @logDecorator
     def ksmTune(self, tuningParams):
         '''
         Set KSM tuning parameters for MOM, which runs without root privilege


-- 
To view, visit https://gerrit.ovirt.org/46527
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1f72f63186187254cd4aded0a2e6c396001ca28b
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: ovirt-3.6
Gerrit-Owner: Martin Polednik <mpolednik at redhat.com>


More information about the vdsm-patches mailing list