From mboxrd@z Thu Jan 1 00:00:00 1970 From: Yosuke Iwamatsu Subject: [PATCH] PV Passthrough PCI Device Hotplug Support (Tools Part) Date: Mon, 10 Mar 2008 10:19:10 +0900 Message-ID: <47D48C8E.7060206@ab.jp.nec.com> References: <47BEA1AC.40707@ab.jp.nec.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------020904080901070409010901" Return-path: In-Reply-To: <47BEA1AC.40707@ab.jp.nec.com> List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: Keir Fraser , xen-devel@lists.xensource.com, "Zhai, Edwin" List-Id: xen-devel@lists.xenproject.org This is a multi-part message in MIME format. --------------020904080901070409010901 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Hi, This is the updated patch of PV PCI passthrough hotplug (tools portion). Changes to xm command: - Let 'xm pci-attach' command use expression rather than use separated arguments like . This is the same expression of the domain configuration file and I believe it is more user-friendly. - Let 'xm pci-detach' command use the same expression. Formerly, was used as the key to indicate which device we were detaching. But for the current implementation of PV PCI hotplug, virtual slots don't have much meaning. I think using the same physical device name in both attachment and detachment is appropriate here. Changes to xend: - Both attach and detach commands are received by device_configure() and handled by pci_device_configure(). - HVM specific processings are done in hvm_pci_create_device() and hvm_destroyPCIDevice(). The major problem I encoutered during this work is that, I don't have a vt-d enabled machine and could not confirm that HVM PCI hotplug would still work after modifications :-( Then I hacked libxc a little to pretend as if there existed a vt-d hardware, and could see HVM PCI attach/detach working correctly. So now I'm pretty sure that we can do both PV and HVM hotplugs with this patch, but I would appreciate it if someone could test this on a real vt-d machine. Regards, ------------------- Yosuke Iwamatsu NEC Corporation --------------020904080901070409010901 Content-Type: all/allfiles; name="pv_pcihp_tools_merge.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="pv_pcihp_tools_merge.patch" # HG changeset patch # User y-iwamatsu@ab.jp.nec.com # Date 1205112166 -32400 # Node ID 6db8d8a026fc65da4cddd9508bd0da44637031ee # Parent 59b8768d0d0d3bf2125c33adafbd1256e75e2755 tools: add PV Passtrough PCI device hotplug support. Signed-off-by: Yosuke Iwamatsu diff -r 59b8768d0d0d -r 6db8d8a026fc tools/python/xen/xend/XendConfig.py --- a/tools/python/xen/xend/XendConfig.py Wed Mar 05 11:18:25 2008 +0000 +++ b/tools/python/xen/xend/XendConfig.py Mon Mar 10 10:22:46 2008 +0900 @@ -1407,6 +1407,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 59b8768d0d0d -r 6db8d8a026fc tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Wed Mar 05 11:18:25 2008 +0000 +++ b/tools/python/xen/xend/XendDomainInfo.py Mon Mar 10 10:22:46 2008 +0900 @@ -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 59b8768d0d0d -r 6db8d8a026fc tools/python/xen/xend/server/DevController.py --- a/tools/python/xen/xend/server/DevController.py Wed Mar 05 11:18:25 2008 +0000 +++ b/tools/python/xen/xend/server/DevController.py Mon Mar 10 10:22:46 2008 +0900 @@ -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 59b8768d0d0d -r 6db8d8a026fc tools/python/xen/xend/server/pciif.py --- a/tools/python/xen/xend/server/pciif.py Wed Mar 05 11:18:25 2008 +0000 +++ b/tools/python/xen/xend/server/pciif.py Mon Mar 10 10:22:46 2008 +0900 @@ -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 59b8768d0d0d -r 6db8d8a026fc tools/python/xen/xm/main.py --- a/tools/python/xen/xm/main.py Wed Mar 05 11:18:25 2008 +0000 +++ b/tools/python/xen/xm/main.py Mon Mar 10 10:22:46 2008 +0900 @@ -175,11 +175,11 @@ SUBCOMMAND_HELP = { 'vnet-delete' : ('', 'Delete a Vnet.'), 'vnet-list' : ('[-l|--long]', 'List Vnets.'), 'vtpm-list' : (' [--long]', 'List virtual TPM devices.'), - 'pci-attach ' : (' [virtual slot]', + 'pci-attach' : (' [virtual slot]', 'Insert a new pass-through pci device.'), - 'pci-detach ' : (' ', + 'pci-detach' : (' ', 'Remove a domain\'s pass-through pci device.'), - 'pci-list' : ('', + 'pci-list' : ('', 'List pass-through pci devices for a domain.'), # security @@ -2229,29 +2229,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[0-9a-fA-F]{1,4})[:,])?" + \ + r"(?P[0-9a-fA-F]{1,2})[:,]" + \ + r"(?P[0-9a-fA-F]{1,2})[.,]" + \ + r"(?P[0-9a-fA-F])", 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 @@ -2316,12 +2324,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) + arg_check(args, 'pci-detach', 2, 2) + (dom, pci) = parse_pci_configuration(args, 'Closing') + server.xend.domain.device_configure(dom, pci) + def xm_vnet_list(args): xenapi_unsupported() --------------020904080901070409010901 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --------------020904080901070409010901--