# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1205840361 0
# Node ID 3f407392da492ebaa30764406f69549bc11ae791
# Parent e678b42c36c45bc301d365d4d234216301fb11cc
tools: Add PV passthrough PCI device hotplug support.
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@xxxxxxxxxxxxx>
---
tools/python/xen/xend/XendConfig.py | 17 +
tools/python/xen/xend/XendDomainInfo.py | 221 +++++++++++++++++--------
tools/python/xen/xend/server/DevController.py | 50 +++++
tools/python/xen/xend/server/pciif.py | 229 ++++++++++++++++++++++----
tools/python/xen/xm/main.py | 53 +++---
5 files changed, 452 insertions(+), 118 deletions(-)
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xend/XendConfig.py Tue Mar 18 11:39:21 2008 +0000
@@ -1461,6 +1461,23 @@ class XendConfig(dict):
config = cfg_sxp
dev_type, dev_info = self['devices'][dev_uuid]
+
+ if dev_type == 'pci': # Special case for pci
+ pci_devs = []
+ for pci_dev in sxp.children(config, 'dev'):
+ pci_dev_info = {}
+ for opt_val in pci_dev[1:]:
+ try:
+ opt, val = opt_val
+ pci_dev_info[opt] = val
+ except TypeError:
+ pass
+ pci_devs.append(pci_dev_info)
+ self['devices'][dev_uuid] = (dev_type,
+ {'devs': pci_devs,
+ 'uuid': dev_uuid})
+ return True
+
for opt_val in config[1:]:
try:
opt, val = opt_val
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xend/XendDomainInfo.py Tue Mar 18 11:39:21 2008 +0000
@@ -558,18 +558,17 @@ class XendDomainInfo:
count += 1
- def pci_device_create(self, dev_config):
- log.debug("XendDomainInfo.pci_device_create: %s" %
scrub_password(dev_config))
+ def hvm_pci_device_create(self, dev_config):
+ log.debug("XendDomainInfo.hvm_pci_device_create: %s"
+ % scrub_password(dev_config))
if not self.info.is_hvm():
- raise VmError("only HVM guest support pci attach")
+ raise VmError("hvm_pci_device_create called on non-HVM guest")
#all the PCI devs share one conf node
devid = '0'
- dev_type = sxp.name(dev_config)
- new_devs = sxp.child_value(dev_config, 'devs')
- new_dev = new_devs[0]
+ new_dev = dev_config['devs'][0]
dev_info = self._getDeviceInfo_pci(devid)#from self.info['devices']
#check conflict before trigger hotplug event
@@ -611,35 +610,6 @@ class XendDomainInfo:
new_dev['vslt'])
self.image.signalDeviceModel('pci-ins', 'pci-inserted', bdf_str)
- # update the virtual pci slot
- vslt = xstransact.Read("/local/domain/0/device-model/%i/parameter"
- % self.getDomid())
- new_dev['vslt'] = vslt
-
- if dev_info is None:
- # create a new one from scrach
- dev_cfg_sxp = [dev_type,
- ['dev',
- ['domain', new_dev['domain']],
- ['bus', new_dev['bus']],
- ['slot', new_dev['slot']],
- ['func', new_dev['func']],
- ['vslt', new_dev['vslt']]
- ]]
- dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_cfg_sxp)
- dev_config_dict = self.info['devices'][dev_uuid][1]
- try:
- dev_config_dict['devid'] = devid = \
- self._createDevice(dev_type, dev_config_dict)
- self._waitForDevice(dev_type, devid)
- except VmError, ex:
- raise ex
- else:
- # update the pci config to add the new dev
- pci_devs.extend(new_devs)
- self._reconfigureDevice('pci', devid, pci_conf)
-
- return self.getDeviceController('pci').sxpr(devid)
def device_create(self, dev_config):
"""Create a new device.
@@ -649,11 +619,6 @@ class XendDomainInfo:
"""
log.debug("XendDomainInfo.device_create: %s" %
scrub_password(dev_config))
dev_type = sxp.name(dev_config)
-
- if dev_type == 'pci':
- rc = self.pci_device_create(dev_config)
- return rc
-
dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config)
dev_config_dict = self.info['devices'][dev_uuid][1]
log.debug("XendDomainInfo.device_create: %s" %
scrub_password(dev_config_dict))
@@ -676,6 +641,151 @@ class XendDomainInfo:
xen.xend.XendDomain.instance().managed_config_save(self)
return self.getDeviceController(dev_type).sxpr(devid)
+ def pci_convert_sxp_to_dict(self, dev_sxp):
+ """Convert pci device sxp to dict
+ @param dev_sxp: device configuration
+ @type dev_sxp: SXP object (parsed config)
+ @return: dev_config
+ @rtype: dictionary
+ """
+ # In reconfigure phase, config of PCI device looks like below:
+ #
+ # sxp:
+ # [device, [pci, [dev, [domain, '0x0'], [bus, '0x0'], [slot, '0x0'],
+ # [func, '0x0'], [vslt, '0x0']],
+ # [state, 'Initialising']]]
+ #
+ # dict:
+ # {devs: [{domain: '0x0', bus: '0x0', slot: '0x0', func: '0x0',
+ # vslt: '0x0'}],
+ # states: ['Initialising']}
+ #
+ # state 'Initialising' means the device is being attached.
+ # state 'Closing' means the device is being detached.
+
+ dev_config = {}
+ pci_devs = []
+ for pci_dev in sxp.children(dev_sxp, 'dev'):
+ pci_dev_info = {}
+ for opt_val in pci_dev[1:]:
+ try:
+ opt, val = opt_val
+ pci_dev_info[opt] = val
+ except TypeError:
+ pass
+ pci_devs.append(pci_dev_info)
+ dev_config['devs'] = pci_devs
+ pci_states = []
+ for pci_state in sxp.children(dev_sxp, 'state'):
+ try:
+ pci_states.append(pci_state[1])
+ except IndexError:
+ raise XendError("Error reading state while parsing pci sxp")
+ dev_config['states'] = pci_states
+
+ return dev_config
+
+ def pci_device_configure(self, dev_sxp, devid = 0):
+ """Configure an existing pci device.
+
+ @param dev_sxp: device configuration
+ @type dev_sxp: SXP object (parsed config)
+ @param devid: device id
+ @type devid: int
+ @return: Returns True if successfully updated device
+ @rtype: boolean
+ """
+ log.debug("XendDomainInfo.pci_device_configure: %s"
+ % scrub_password(dev_sxp))
+
+ dev_class = sxp.name(dev_sxp)
+
+ if dev_class != 'pci':
+ return False
+
+ pci_state = sxp.child_value(dev_sxp, 'state')
+ existing_dev_info = self._getDeviceInfo_pci(devid)
+
+ if existing_dev_info is None and pci_state != 'Initialising':
+ raise XendError("Cannot detach when pci platform does not exist")
+
+ pci_dev = sxp.children(dev_sxp, 'dev')[0]
+ dev_config = self.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':
+ # HVM PCI device attachment
+ self.hvm_pci_device_create(dev_config)
+ # Update vslt
+ vslt =
xstransact.Read("/local/domain/0/device-model/%i/parameter"
+ % self.getDomid())
+ dev['vslt'] = vslt
+ for n in sxp.children(pci_dev):
+ if(n[0] == 'vslt'):
+ n[1] = vslt
+ else:
+ # HVM PCI device detachment
+ existing_dev_uuid = sxp.child_value(existing_dev_info, 'uuid')
+ existing_pci_conf = self.info['devices'][existing_dev_uuid][1]
+ existing_pci_devs = existing_pci_conf['devs']
+ vslt = '0x0'
+ for x in existing_pci_devs:
+ if ( int(x['domain'], 16) == int(dev['domain'], 16) and
+ int(x['bus'], 16) == int(dev['bus'], 16) and
+ int(x['slot'], 16) == int(dev['slot'], 16) and
+ int(x['func'], 16) == int(dev['func'], 16) ):
+ vslt = x['vslt']
+ break
+ if vslt == '0x0':
+ raise VmError("Device %04x:%02x:%02x.%02x is not connected"
+ % (int(dev['domain'],16), int(dev['bus'],16),
+ int(dev['slot'],16), int(dev['func'],16)))
+ self.hvm_destroyPCIDevice(int(vslt, 16))
+ # Update vslt
+ dev['vslt'] = vslt
+ for n in sxp.children(pci_dev):
+ if(n[0] == 'vslt'):
+ n[1] = vslt
+
+ # If pci platform does not exist, create and exit.
+ if existing_dev_info is None:
+ self.device_create(dev_sxp)
+ return True
+
+ # use DevController.reconfigureDevice to change device config
+ dev_control = self.getDeviceController(dev_class)
+ dev_uuid = dev_control.reconfigureDevice(devid, dev_config)
+ if not self.info.is_hvm():
+ # in PV case, wait until backend state becomes connected.
+ dev_control.waitForDevice_reconfigure(devid)
+ num_devs = dev_control.cleanupDevice(devid)
+
+ # update XendConfig with new device info
+ if dev_uuid:
+ new_dev_sxp = dev_control.configuration(devid)
+ self.info.device_update(dev_uuid, new_dev_sxp)
+
+ # If there is no device left, destroy pci and remove config.
+ if num_devs == 0:
+ if self.info.is_hvm():
+ self.destroyDevice('pci', devid, True)
+ del self.info['devices'][dev_uuid]
+ platform = self.info['platform']
+ orig_dev_num = len(platform['pci'])
+ # TODO: can use this to keep some info to ask high level
+ # management tools to hot insert a new passthrough dev
+ # after migration
+ if orig_dev_num != 0:
+ #platform['pci'] = ["%dDEVs" % orig_dev_num]
+ platform['pci'] = []
+ else:
+ self.destroyDevice('pci', devid)
+ del self.info['devices'][dev_uuid]
+
+ return True
+
def device_configure(self, dev_sxp, devid = None):
"""Configure an existing device.
@@ -690,6 +800,10 @@ class XendDomainInfo:
# convert device sxp to a dict
dev_class = sxp.name(dev_sxp)
dev_config = {}
+
+ if dev_class == 'pci':
+ return self.pci_device_configure(dev_sxp)
+
for opt_val in dev_sxp[1:]:
try:
dev_config[opt_val[0]] = opt_val[1]
@@ -714,11 +828,11 @@ class XendDomainInfo:
for devclass in XendDevices.valid_devices():
self.getDeviceController(devclass).waitForDevices()
- def destroyPCIDevice(self, vslot):
- log.debug("destroyPCIDevice called %s", vslot)
+ def hvm_destroyPCIDevice(self, vslot):
+ log.debug("hvm_destroyPCIDevice called %s", vslot)
if not self.info.is_hvm():
- raise VmError("only HVM guest support pci detach")
+ raise VmError("hvm_destroyPCIDevice called on non-HVM guest")
#all the PCI devs share one conf node
devid = '0'
@@ -744,34 +858,15 @@ class XendDomainInfo:
raise VmError("Device @ vslot 0x%x do not support hotplug." %
(vslot))
bdf_str = "%s:%s:%s.%s" % (x['domain'], x['bus'], x['slot'], x['func'])
- log.info("destroyPCIDevice:%s:%s!", x, bdf_str)
+ log.info("hvm_destroyPCIDevice:%s:%s!", x, bdf_str)
self.image.signalDeviceModel('pci-rem', 'pci-removed', bdf_str)
-
- if pci_len > 1:
- del pci_conf['devs'][devnum]
- self._reconfigureDevice('pci', devid, pci_conf)
- else:
- self.getDeviceController('pci').destroyDevice(devid, True)
- del self.info['devices'][dev_uuid]
- platform = self.info['platform']
- orig_dev_num = len(platform['pci'])
-
- #need remove the pci config
- #TODO:can use this to keep some info to ask high level management
tools to hot insert a new passthrough dev after migration
- if orig_dev_num != 0:
-# platform['pci'] = ["%dDEVs" % orig_dev_num]
- platform['pci'] = []
return 0
def destroyDevice(self, deviceClass, devid, force = False, rm_cfg = False):
log.debug("XendDomainInfo.destroyDevice: deviceClass = %s, device =
%s",
deviceClass, devid)
-
- if deviceClass == 'dpci':
- rc = self.destroyPCIDevice(devid)
- return rc
if rm_cfg:
# Convert devid to device number. A device number is
diff -r e678b42c36c4 -r 3f407392da49
tools/python/xen/xend/server/DevController.py
--- a/tools/python/xen/xend/server/DevController.py Tue Mar 18 11:34:44
2008 +0000
+++ b/tools/python/xen/xend/server/DevController.py Tue Mar 18 11:39:21
2008 +0000
@@ -51,6 +51,8 @@ xenbusState = {
'Connected' : 4,
'Closing' : 5,
'Closed' : 6,
+ 'Reconfiguring': 7,
+ 'Reconfigured' : 8,
}
xoptions = XendOptions.instance()
@@ -88,6 +90,8 @@ class DevController:
(devid, back, front) = self.getDeviceDetails(config)
if devid is None:
return 0
+
+ self.setupDevice(config)
(backpath, frontpath) = self.addStoreEntries(config, devid, back,
front)
@@ -198,6 +202,15 @@ class DevController:
if status == Timeout:
raise VmError("Device %s (%s) could not be disconnected. " %
+ (devid, self.deviceClass))
+
+ def waitForDevice_reconfigure(self, devid):
+ log.debug("Waiting for %s - reconfigureDevice.", devid)
+
+ (status, err) = self.waitForBackend_reconfigure(devid)
+
+ if status == Timeout:
+ raise VmError("Device %s (%s) could not be reconfigured. " %
(devid, self.deviceClass))
@@ -325,6 +338,11 @@ class DevController:
"""
raise NotImplementedError()
+
+ def setupDevice(self, config):
+ """ Setup device from config.
+ """
+ return
def migrate(self, deviceConfig, network, dst, step, domName):
""" Migration of a device. The 'network' parameter indicates
@@ -569,6 +587,22 @@ class DevController:
return result['status']
+ def waitForBackend_reconfigure(self, devid):
+ frontpath = self.frontendPath(devid)
+ backpath = xstransact.Read(frontpath, "backend")
+ if backpath:
+ statusPath = backpath + '/' + "state"
+ ev = Event()
+ result = { 'status': Timeout }
+
+ xswatch(statusPath, xenbusStatusCallback, ev, result)
+
+ ev.wait(DEVICE_CREATE_TIMEOUT)
+
+ return (result['status'], None)
+ else:
+ return (Missing, None)
+
def backendPath(self, backdom, devid):
"""Construct backend path given the backend domain and device id.
@@ -634,3 +668,19 @@ def deviceDestroyCallback(statusPath, ev
ev.set()
return 0
+
+
+def xenbusStatusCallback(statusPath, ev, result):
+ log.debug("xenbusStatusCallback %s.", statusPath)
+
+ status = xstransact.Read(statusPath)
+
+ if status == str(xenbusState['Connected']):
+ result['status'] = Connected
+ else:
+ return 1
+
+ log.debug("xenbusStatusCallback %d.", result['status'])
+
+ ev.set()
+ return 0
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xend/server/pciif.py
--- a/tools/python/xen/xend/server/pciif.py Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xend/server/pciif.py Tue Mar 18 11:39:21 2008 +0000
@@ -24,7 +24,7 @@ from xen.xend.XendError import VmError
from xen.xend.XendError import VmError
from xen.xend.XendLogging import log
-from xen.xend.server.DevController import DevController
+from xen.xend.server.DevController import DevController, xenbusState
import xen.lowlevel.xc
@@ -44,6 +44,15 @@ while not (t&1):
t>>=1
PAGE_SHIFT+=1
+def parse_hex(val):
+ try:
+ if isinstance(val, types.StringTypes):
+ return int(val, 16)
+ else:
+ return val
+ except ValueError:
+ return None
+
class PciController(DevController):
def __init__(self, vm):
@@ -52,15 +61,6 @@ class PciController(DevController):
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- def parse_hex(val):
- try:
- if isinstance(val, types.StringTypes):
- return int(val, 16)
- else:
- return val
- except ValueError:
- return None
-
back = {}
pcidevid = 0
vslots = ""
@@ -74,7 +74,6 @@ class PciController(DevController):
if vslt is not None:
vslots = vslots + vslt + ";"
- self.setupDevice(domain, bus, slot, func)
back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \
(domain, bus, slot, func)
pcidevid += 1
@@ -86,27 +85,80 @@ class PciController(DevController):
back['uuid'] = config.get('uuid','')
return (0, back, {})
+
def reconfigureDevice(self, _, config):
"""@see DevController.reconfigureDevice"""
- #currently only support config changes by hot insert/remove
pass-through dev
- #delete all the devices in xenstore
- (devid, new_back, new_front) = self.getDeviceDetails(config)
- num_devs = self.readBackend(devid, 'num_devs')
- for i in range(int(num_devs)):
- self.removeBackend(devid, 'dev-%d' % i)
- self.removeBackend(devid, 'num_devs')
-
- #create new devices config
- num_devs = new_back['num_devs']
- for i in range(int(num_devs)):
- dev_no = 'dev-%d' % i
- self.writeBackend(devid, dev_no, new_back[dev_no])
- self.writeBackend(devid, 'num_devs', num_devs)
-
- if new_back['vslots'] is not None:
- self.writeBackend(devid, 'vslots', new_back['vslots'])
-
- return new_back.get('uuid')
+ (devid, back, front) = self.getDeviceDetails(config)
+ num_devs = int(back['num_devs'])
+ states = config.get('states', [])
+
+ old_vslots = self.readBackend(devid, 'vslots')
+ if old_vslots is None:
+ old_vslots = ''
+ num_olddevs = int(self.readBackend(devid, 'num_devs'))
+
+ for i in range(num_devs):
+ try:
+ dev = back['dev-%i' % i]
+ state = states[i]
+ except:
+ raise XendError('Error reading config')
+
+ if state == 'Initialising':
+ # PCI device attachment
+ for j in range(num_olddevs):
+ if dev == self.readBackend(devid, 'dev-%i' % j):
+ raise XendError('Device %s is already connected.' %
dev)
+ log.debug('Attaching PCI device %s.' % dev)
+ (domain, bus, slotfunc) = dev.split(':')
+ (slot, func) = slotfunc.split('.')
+ domain = parse_hex(domain)
+ bus = parse_hex(bus)
+ slot = parse_hex(slot)
+ func = parse_hex(func)
+ self.setupOneDevice(domain, bus, slot, func)
+
+ self.writeBackend(devid, 'dev-%i' % (num_olddevs + i), dev)
+ self.writeBackend(devid, 'state-%i' % (num_olddevs + i),
+ str(xenbusState['Initialising']))
+ self.writeBackend(devid, 'num_devs', str(num_olddevs + i + 1))
+
+ # Update vslots
+ if back['vslots'] is not None:
+ vslots = old_vslots + back['vslots']
+ self.writeBackend(devid, 'vslots', vslots)
+
+ elif state == 'Closing':
+ # PCI device detachment
+ found = False
+ for j in range(num_olddevs):
+ if dev == self.readBackend(devid, 'dev-%i' % j):
+ found = True
+ log.debug('Detaching device %s' % dev)
+ self.writeBackend(devid, 'state-%i' % j,
+ str(xenbusState['Closing']))
+ if not found:
+ raise XendError('Device %s is not connected' % dev)
+
+ # Update vslots
+ if back['vslots'] is not None:
+ vslots = old_vslots
+ for vslt in back['vslots'].split(';'):
+ if vslt != '':
+ vslots = vslots.replace(vslt + ';', '', 1)
+ if vslots == '':
+ self.removeBackend(devid, 'vslots')
+ else:
+ self.writeBackend(devid, 'vslots', vslots)
+
+ else:
+ raise XendError('Error configuring device %s: invalid state %s'
+ % (dev,state))
+
+ self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring']))
+
+ return self.readBackend(devid, 'uuid')
+
def getDeviceConfiguration(self, devid, transaction = None):
result = DevController.getDeviceConfiguration(self, devid, transaction)
@@ -136,7 +188,10 @@ class PciController(DevController):
#append vslot info
if vslots is not None:
- dev_dict['vslt'] = slot_list[i]
+ try:
+ dev_dict['vslt'] = slot_list[i]
+ except IndexError:
+ dev_dict['vslt'] = '0x0'
pci_devs.append(dev_dict)
@@ -171,7 +226,7 @@ class PciController(DevController):
return sxpr
- def setupDevice(self, domain, bus, slot, func):
+ def setupOneDevice(self, domain, bus, slot, func):
""" Attach I/O resources for device to frontend domain
"""
fe_domid = self.getDomid()
@@ -225,6 +280,116 @@ class PciController(DevController):
raise VmError(('pci: failed to configure irq on device '+
'%s - errno=%d')%(dev.name,rc))
+ def setupDevice(self, config):
+ """Setup devices from config
+ """
+ for pci_config in config.get('devs', []):
+ domain = parse_hex(pci_config.get('domain', 0))
+ bus = parse_hex(pci_config.get('bus', 0))
+ slot = parse_hex(pci_config.get('slot', 0))
+ func = parse_hex(pci_config.get('func', 0))
+ self.setupOneDevice(domain, bus, slot, func)
+
+ return
+
+ def cleanupOneDevice(self, domain, bus, slot, func):
+ """ Detach I/O resources for device from frontend domain
+ """
+ fe_domid = self.getDomid()
+
+ try:
+ dev = PciDevice(domain, bus, slot, func)
+ except Exception, e:
+ raise VmError("pci: failed to locate device and "+
+ "parse it's resources - "+str(e))
+
+ if dev.driver!='pciback':
+ raise VmError(("pci: PCI Backend does not own device "+ \
+ "%s\n"+ \
+ "See the pciback.hide kernel "+ \
+ "command-line parameter or\n"+ \
+ "bind your slot/device to the PCI backend using sysfs" \
+ )%(dev.name))
+
+ for (start, size) in dev.ioports:
+ log.debug('pci: disabling ioport 0x%x/0x%x'%(start,size))
+ rc = xc.domain_ioport_permission(domid = fe_domid, first_port =
start,
+ nr_ports = size, allow_access = False)
+ if rc<0:
+ raise VmError(('pci: failed to configure I/O ports on device '+
+ '%s - errno=%d')%(dev.name,rc))
+
+ for (start, size) in dev.iomem:
+ # Convert start/size from bytes to page frame sizes
+ start_pfn = start>>PAGE_SHIFT
+ # Round number of pages up to nearest page boundary (if not on one)
+ nr_pfns = (size+(PAGE_SIZE-1))>>PAGE_SHIFT
+
+ log.debug('pci: disabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \
+ (start,size,start_pfn,nr_pfns))
+ rc = xc.domain_iomem_permission(domid = fe_domid,
+ first_pfn = start_pfn,
+ nr_pfns = nr_pfns,
+ allow_access = False)
+ if rc<0:
+ raise VmError(('pci: failed to configure I/O memory on device
'+
+ '%s - errno=%d')%(dev.name,rc))
+
+ if dev.irq>0:
+ log.debug('pci: disabling irq %d'%dev.irq)
+ rc = xc.domain_irq_permission(domid = fe_domid, pirq = dev.irq,
+ allow_access = False)
+ if rc<0:
+ raise VmError(('pci: failed to configure irq on device '+
+ '%s - errno=%d')%(dev.name,rc))
+
+ def cleanupDevice(self, devid):
+ """ Detach I/O resources for device and cleanup xenstore nodes
+ after reconfigure.
+
+ @param devid: The device ID
+ @type devid: int
+ @return: Return the number of devices connected
+ @rtype: int
+ """
+ num_devs = int(self.readBackend(devid, 'num_devs'))
+ new_num_devs = 0
+ for i in range(num_devs):
+ state = int(self.readBackend(devid, 'state-%i' % i))
+ if state == xenbusState['Closing']:
+ # Detach I/O resources.
+ dev = self.readBackend(devid, 'dev-%i' % i)
+ (domain, bus, slotfunc) = dev.split(':')
+ (slot, func) = slotfunc.split('.')
+ domain = parse_hex(domain)
+ bus = parse_hex(bus)
+ slot = parse_hex(slot)
+ func = parse_hex(func)
+ # In HVM case, I/O resources are disabled in ioemu.
+ self.cleanupOneDevice(domain, bus, slot, func)
+ # Remove xenstore nodes.
+ self.removeBackend(devid, 'dev-%i' % i)
+ self.removeBackend(devid, 'vdev-%i' % i)
+ self.removeBackend(devid, 'state-%i' % i)
+ else:
+ if new_num_devs != i:
+ tmpdev = self.readBackend(devid, 'dev-%i' % i)
+ self.writeBackend(devid, 'dev-%i' % new_num_devs, tmpdev)
+ self.removeBackend(devid, 'dev-%i' % i)
+ tmpvdev = self.readBackend(devid, 'vdev-%i' % i)
+ if tmpvdev is not None:
+ self.writeBackend(devid, 'vdev-%i' % new_num_devs,
+ tmpvdev)
+ self.removeBackend(devid, 'vdev-%i' % i)
+ tmpstate = self.readBackend(devid, 'state-%i' % i)
+ self.writeBackend(devid, 'state-%i' % new_num_devs,
tmpstate)
+ self.removeBackend(devid, 'state-%i' % i)
+ new_num_devs = new_num_devs + 1
+
+ self.writeBackend(devid, 'num_devs', str(new_num_devs))
+
+ return new_num_devs
+
def waitForBackend(self,devid):
return (0, "ok - no hotplug")
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xm/main.py Tue Mar 18 11:39:21 2008 +0000
@@ -175,11 +175,11 @@ SUBCOMMAND_HELP = {
'vnet-delete' : ('<VnetId>', 'Delete a Vnet.'),
'vnet-list' : ('[-l|--long]', 'List Vnets.'),
'vtpm-list' : ('<Domain> [--long]', 'List virtual TPM devices.'),
- 'pci-attach ' : ('<Domain> <dom> <bus> <slot> <func> [virtual slot]',
+ 'pci-attach' : ('<Domain> <domain:bus:slot.func> [virtual slot]',
'Insert a new pass-through pci device.'),
- 'pci-detach ' : ('<Domain> <virtual slot>',
+ 'pci-detach' : ('<Domain> <domain:bus:slot.func>',
'Remove a domain\'s pass-through pci device.'),
- 'pci-list' : ('<Domain>',
+ 'pci-list' : ('<Domain>',
'List pass-through pci devices for a domain.'),
# security
@@ -2232,29 +2232,37 @@ def xm_network_attach(args):
vif.append(vif_param)
server.xend.domain.device_create(dom, vif)
-def parse_pci_configuration(args):
+def parse_pci_configuration(args, state):
dom = args[0]
-
- if len(args) == 6:
- vslt = args[5]
+ pci_dev_str = args[1]
+ if len(args) == 3:
+ vslt = args[2]
else:
vslt = '0x0' #chose a free virtual PCI slot
-
- pci = ['pci',
- ['devs',
- [{'domain': "0x%x" % int(args[1], 16),
- 'bus': "0x%x" % int(args[2], 16),
- 'slot': "0x%x" % int(args[3], 16),
- 'func': "0x%x" % int(args[4], 16),
- 'vslt': "0x%x" % int(vslt, 16)}]
- ]]
+ pci=['pci']
+ pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
+ r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
+ r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
+ r"(?P<func>[0-7])$", pci_dev_str)
+ if pci_match == None:
+ raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
+ pci_dev_info = pci_match.groupdict('0')
+ try:
+ pci.append(['dev', ['domain', '0x'+ pci_dev_info['domain']], \
+ ['bus', '0x'+ pci_dev_info['bus']],
+ ['slot', '0x'+ pci_dev_info['slot']],
+ ['func', '0x'+ pci_dev_info['func']],
+ ['vslt', '0x%x' % int(vslt, 16)]])
+ except:
+ raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
+ pci.append(['state', state])
return (dom, pci)
def xm_pci_attach(args):
- arg_check(args, 'pci-attach', 5, 6)
- (dom, pci) = parse_pci_configuration(args)
- server.xend.domain.device_create(dom, pci)
+ arg_check(args, 'pci-attach', 2, 3)
+ (dom, pci) = parse_pci_configuration(args, 'Initialising')
+ server.xend.domain.device_configure(dom, pci)
def detach(args, deviceClass):
rm_cfg = True
@@ -2319,12 +2327,11 @@ def xm_network_detach(args):
arg_check(args, 'network-detach', 2, 3)
detach(args, 'vif')
-
def xm_pci_detach(args):
arg_check(args, 'pci-detach', 2)
- dom = args[0]
- dev = args[1]
- server.xend.domain.destroyDevice(dom, 'dpci', dev)
+ (dom, pci) = parse_pci_configuration(args, 'Closing')
+ server.xend.domain.device_configure(dom, pci)
+
def xm_vnet_list(args):
xenapi_unsupported()
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|