mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
xend: pass-through: fix "xm pci-list-assignable-devices' for pv_guest
xc.test_assign_device(dev) can only tell us if dev is assigned to hvm guest; if a device is assigned to pv guest, xc.test_assign_device() still tells us the device is not assigned yet, as a result, the device still appears in the output of "xm pci-list-assignable-devices", and xend would not prevent us from assigning the device to a new pv or hvm guest. To judge if a device has been assigned to guest, we have to scan xenstore. Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
This commit is contained in:
1 parent
0a8f3082f6
commit
fb4a420c9b
4 files changed
+50
-41
No files matched your search
@@ -2059,9 +2059,6 @@ class XendConfig(dict):
|
||||
return self['platform'].get('hap', 0)
|
||||
|
||||
def update_platform_pci(self):
|
||||
if not self.is_hvm():
|
||||
return
|
||||
|
||||
pci = []
|
||||
for dev_type, dev_info in self.all_devices_sxpr():
|
||||
if dev_type != 'pci':
|
||||
|
||||
@@ -42,7 +42,7 @@ from xen.util import xsconstants
|
||||
from xen.util.pci import serialise_pci_opts, pci_opts_list_to_sxp, \
|
||||
pci_dict_to_bdf_str, pci_dict_to_xc_str, \
|
||||
pci_convert_sxp_to_dict, pci_convert_dict_to_sxp, \
|
||||
pci_dict_cmp, PCI_DEVFN, PCI_SLOT, PCI_FUNC
|
||||
pci_dict_cmp, PCI_DEVFN, PCI_SLOT, PCI_FUNC, parse_hex
|
||||
|
||||
from xen.xend import balloon, sxp, uuid, image, arch
|
||||
from xen.xend import XendOptions, XendNode, XendConfig
|
||||
@@ -296,20 +296,11 @@ def dom_get(dom):
|
||||
log.trace("domain_getinfo(%d) failed, ignoring: %s", dom, str(err))
|
||||
return None
|
||||
|
||||
def get_assigned_pci_devices(domid):
|
||||
dev_str_list = []
|
||||
path = '/local/domain/0/backend/pci/%u/0/' % domid
|
||||
num_devs = xstransact.Read(path + 'num_devs');
|
||||
if num_devs is None or num_devs == "":
|
||||
return dev_str_list
|
||||
num_devs = int(num_devs);
|
||||
for i in range(num_devs):
|
||||
dev_str = xstransact.Read(path + 'dev-%i' % i)
|
||||
dev_str_list = dev_str_list + [dev_str]
|
||||
return dev_str_list
|
||||
from xen.xend.server.pciif import parse_pci_name, PciDevice,\
|
||||
get_assigned_pci_devices, get_all_assigned_pci_devices
|
||||
|
||||
|
||||
def do_FLR(domid):
|
||||
from xen.xend.server.pciif import parse_pci_name, PciDevice
|
||||
dev_str_list = get_assigned_pci_devices(domid)
|
||||
|
||||
for dev_str in dev_str_list:
|
||||
@@ -686,15 +677,14 @@ class XendDomainInfo:
|
||||
raise VmError("device is already inserted")
|
||||
|
||||
# Test whether the devices can be assigned with VT-d
|
||||
bdf = xc.test_assign_device(0, pci_dict_to_xc_str(new_dev))
|
||||
if bdf != 0:
|
||||
if bdf == -1:
|
||||
raise VmError("failed to assign device: maybe the platform"
|
||||
" doesn't support VT-d, or VT-d isn't enabled"
|
||||
" properly?")
|
||||
raise VmError("fail to assign device(%s): maybe it has"
|
||||
" already been assigned to other domain, or maybe"
|
||||
" it doesn't exist." % pci_dict_to_bdf_str(new_dev))
|
||||
pci_name = '%04x:%02x:%02x.%x' % \
|
||||
(parse_hex(new_dev['domain']),\
|
||||
parse_hex(new_dev['bus']),\
|
||||
parse_hex(new_dev['slot']),\
|
||||
parse_hex(new_dev['func']))
|
||||
if pci_name in get_all_assigned_pci_devices():
|
||||
raise VmError("failed to assign device %s that has"
|
||||
" already been assigned to other domain." % pci_str)
|
||||
|
||||
# Here, we duplicate some checkings (in some cases, we mustn't allow
|
||||
# a device to be hot-plugged into an HVM guest) that are also done in
|
||||
@@ -732,8 +722,7 @@ class XendDomainInfo:
|
||||
pci_device.devs_check_driver(coassignment_list)
|
||||
assigned_pci_device_str_list = self._get_assigned_pci_devices()
|
||||
for pci_str in coassignment_list:
|
||||
pci_dev = parse_pci_name(pci_str)
|
||||
if xc.test_assign_device(0, pci_dict_to_xc_str(pci_dev)) == 0:
|
||||
if not (pci_str in get_all_assigned_pci_devices()):
|
||||
continue
|
||||
if not pci_str in assigned_pci_device_str_list:
|
||||
raise VmError(("pci: failed to pci-attach %s to domain %s" + \
|
||||
@@ -859,7 +848,7 @@ class XendDomainInfo:
|
||||
pci_dev = sxp.children(dev_sxp, 'dev')[0]
|
||||
dev_config = pci_convert_sxp_to_dict(dev_sxp)
|
||||
dev = dev_config['devs'][0]
|
||||
|
||||
|
||||
# Do HVM specific processing
|
||||
if self.info.is_hvm():
|
||||
if pci_state == 'Initialising':
|
||||
@@ -2454,7 +2443,8 @@ class XendDomainInfo:
|
||||
if pci and len(pci) > 0:
|
||||
pci = map(lambda x: x[0:4], pci) # strip options
|
||||
pci_str = str(pci)
|
||||
if hvm and pci_str:
|
||||
|
||||
if hvm and pci_str != '':
|
||||
bdf = xc.test_assign_device(0, pci_str)
|
||||
if bdf != 0:
|
||||
if bdf == -1:
|
||||
@@ -2465,10 +2455,18 @@ class XendDomainInfo:
|
||||
devfn = (bdf >> 8) & 0xff
|
||||
dev = (devfn >> 3) & 0x1f
|
||||
func = devfn & 0x7
|
||||
raise VmError("fail to assign device(%x:%x.%x): maybe it has"
|
||||
raise VmError("failed to assign device(%x:%x.%x): maybe it has"
|
||||
" already been assigned to other domain, or maybe"
|
||||
" it doesn't exist." % (bus, dev, func))
|
||||
|
||||
# This test is done for both pv and hvm guest.
|
||||
for p in pci:
|
||||
pci_name = '%04x:%02x:%02x.%x' % \
|
||||
(parse_hex(p[0]), parse_hex(p[1]), parse_hex(p[2]), parse_hex(p[3]))
|
||||
if pci_name in get_all_assigned_pci_devices():
|
||||
raise VmError("failed to assign device %s that has"
|
||||
" already been assigned to other domain." % pci_name)
|
||||
|
||||
# register the domain in the list
|
||||
from xen.xend import XendDomain
|
||||
XendDomain.instance().add_domain(self)
|
||||
|
||||
@@ -834,6 +834,9 @@ class XendNode:
|
||||
|
||||
|
||||
def pciinfo(self):
|
||||
from xen.xend.server.pciif import get_all_assigned_pci_devices
|
||||
assigned_devs = get_all_assigned_pci_devices()
|
||||
|
||||
# Each element of dev_list is a PciDevice
|
||||
dev_list = PciUtil.find_all_assignable_devices()
|
||||
|
||||
@@ -847,11 +850,7 @@ class XendNode:
|
||||
for dev_list in devs_list:
|
||||
available = True
|
||||
for d in dev_list:
|
||||
pci_str = '0x%x,0x%x,0x%x,0x%x' %(d.domain, d.bus, d.slot, d.func)
|
||||
# Xen doesn't care what the domid is, so we pass 0 here...
|
||||
domid = 0
|
||||
bdf = self.xc.test_assign_device(domid, pci_str)
|
||||
if bdf != 0:
|
||||
if d.name in assigned_devs:
|
||||
available = False
|
||||
break
|
||||
if available:
|
||||
|
||||
@@ -58,6 +58,25 @@ def parse_hex(val):
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
def get_assigned_pci_devices(domid):
|
||||
dev_str_list = []
|
||||
path = '/local/domain/0/backend/pci/%u/0/' % domid
|
||||
num_devs = xstransact.Read(path + 'num_devs');
|
||||
if num_devs is None or num_devs == "":
|
||||
return dev_str_list
|
||||
num_devs = int(num_devs)
|
||||
for i in range(num_devs):
|
||||
dev_str = xstransact.Read(path + 'dev-%i' % i)
|
||||
dev_str_list = dev_str_list + [dev_str]
|
||||
return dev_str_list
|
||||
|
||||
def get_all_assigned_pci_devices():
|
||||
dom_list = xstransact.List('/local/domain')
|
||||
pci_str_list = []
|
||||
for d in dom_list:
|
||||
pci_str_list = pci_str_list + get_assigned_pci_devices(int(d))
|
||||
return pci_str_list
|
||||
|
||||
class PciController(DevController):
|
||||
|
||||
def __init__(self, vm):
|
||||
@@ -368,11 +387,8 @@ class PciController(DevController):
|
||||
dev.devs_check_driver(funcs)
|
||||
for f in funcs:
|
||||
if not f in pci_str_list:
|
||||
(f_dom, f_bus, f_slot, f_func) = parse_pci_name(f)
|
||||
f_pci_str = '0x%x,0x%x,0x%x,0x%x' % \
|
||||
(f_dom, f_bus, f_slot, f_func)
|
||||
# f has been assigned to other guest?
|
||||
if xc.test_assign_device(0, f_pci_str) != 0:
|
||||
if f in get_all_assigned_pci_devices():
|
||||
err_msg = 'pci: %s must be co-assigned to' + \
|
||||
' the same guest with %s'
|
||||
raise VmError(err_msg % (f, dev.name))
|
||||
@@ -396,9 +412,8 @@ class PciController(DevController):
|
||||
dev.devs_check_driver(devs_str)
|
||||
for s in devs_str:
|
||||
if not s in pci_str_list:
|
||||
s_pci_str = pci_dict_to_bdf_str(parse_pci_name(s))
|
||||
# s has been assigned to other guest?
|
||||
if xc.test_assign_device(0, s_pci_str) != 0:
|
||||
if s in get_all_assigned_pci_devices():
|
||||
err_msg = 'pci: %s must be co-assigned to the'+\
|
||||
' same guest with %s'
|
||||
raise VmError(err_msg % (s, dev.name))
|
||||
|
||||