ia64/xen-unstable

changeset 15743:95f90f24f3b1

Fix xm block/network-detach command.

- To remove device info, it waits for the backend path of the device
to be removed.
- It removes device info from domain info.
- It saves domain info to the config.sxp of the managed domain.

Signed-off-by: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Thu Aug 09 16:21:41 2007 +0100 (2007-08-09)
parents f0298301ba8b
children 8c77ae93f982
files tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/DevController.py tools/python/xen/xend/server/blkif.py tools/python/xen/xm/main.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Aug 09 16:14:56 2007 +0100
     1.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Aug 09 16:21:41 2007 +0100
     1.3 @@ -558,9 +558,64 @@ class XendDomainInfo:
     1.4          for devclass in XendDevices.valid_devices():
     1.5              self.getDeviceController(devclass).waitForDevices()
     1.6  
     1.7 -    def destroyDevice(self, deviceClass, devid, force = False):
     1.8 -        log.debug("dev = %s", devid)
     1.9 -        return self.getDeviceController(deviceClass).destroyDevice(devid, force)
    1.10 +    def destroyDevice(self, deviceClass, devid, force = False, rm_cfg = False):
    1.11 +        log.debug("XendDomainInfo.destroyDevice: deviceClass = %s, device = %s",
    1.12 +                  deviceClass, devid)
    1.13 +
    1.14 +        if rm_cfg:
    1.15 +            # Convert devid to device number.  A device number is
    1.16 +            # needed to remove its configuration.
    1.17 +            dev = self.getDeviceController(deviceClass).convertToDeviceNumber(devid)
    1.18 +            
    1.19 +            # Save current sxprs.  A device number and a backend
    1.20 +            # path are needed to remove its configuration but sxprs
    1.21 +            # do not have those after calling destroyDevice.
    1.22 +            sxprs = self.getDeviceSxprs(deviceClass)
    1.23 +
    1.24 +        rc = None
    1.25 +        if self.domid is not None:
    1.26 +            rc = self.getDeviceController(deviceClass).destroyDevice(devid, force)
    1.27 +            if not force and rm_cfg:
    1.28 +                # The backend path, other than the device itself,
    1.29 +                # has to be passed because its accompanied frontend
    1.30 +                # path may be void until its removal is actually
    1.31 +                # issued.  It is probable because destroyDevice is
    1.32 +                # issued first.
    1.33 +                for dev_num, dev_info in sxprs:
    1.34 +                    dev_num = int(dev_num)
    1.35 +                    if dev_num == dev:
    1.36 +                        for x in dev_info:
    1.37 +                            if x[0] == 'backend':
    1.38 +                                backend = x[1]
    1.39 +                                break
    1.40 +                        break
    1.41 +                self._waitForDevice_destroy(deviceClass, devid, backend)
    1.42 +
    1.43 +        if rm_cfg:
    1.44 +            if deviceClass == 'vif':
    1.45 +                if self.domid is not None:
    1.46 +                    for dev_num, dev_info in sxprs:
    1.47 +                        dev_num = int(dev_num)
    1.48 +                        if dev_num == dev:
    1.49 +                            for x in dev_info:
    1.50 +                                if x[0] == 'mac':
    1.51 +                                    mac = x[1]
    1.52 +                                    break
    1.53 +                            break
    1.54 +                    dev_info = self.getDeviceInfo_vif(mac)
    1.55 +                else:
    1.56 +                    _, dev_info = sxprs[dev]
    1.57 +            else:  # 'vbd' or 'tap'
    1.58 +                dev_info = self.getDeviceInfo_vbd(dev)
    1.59 +            if dev_info is None:
    1.60 +                return rc
    1.61 +
    1.62 +            dev_uuid = sxp.child_value(dev_info, 'uuid')
    1.63 +            del self.info['devices'][dev_uuid]
    1.64 +            self.info['%s_refs' % deviceClass].remove(dev_uuid)
    1.65 +            xen.xend.XendDomain.instance().managed_config_save(self)
    1.66 +
    1.67 +        return rc
    1.68  
    1.69      def getDeviceSxprs(self, deviceClass):
    1.70          if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
    1.71 @@ -574,6 +629,23 @@ class XendDomainInfo:
    1.72                      dev_num += 1
    1.73              return sxprs
    1.74  
    1.75 +    def getDeviceInfo_vif(self, mac):
    1.76 +        for dev_type, dev_info in self.info.all_devices_sxpr():
    1.77 +            if dev_type != 'vif':
    1.78 +                continue
    1.79 +            if mac == sxp.child_value(dev_info, 'mac'):
    1.80 +                return dev_info
    1.81 +
    1.82 +    def getDeviceInfo_vbd(self, devid):
    1.83 +        for dev_type, dev_info in self.info.all_devices_sxpr():
    1.84 +            if dev_type != 'vbd' and dev_type != 'tap':
    1.85 +                continue
    1.86 +            dev = sxp.child_value(dev_info, 'dev')
    1.87 +            dev = dev.split(':')[0]
    1.88 +            dev = self.getDeviceController(dev_type).convertToDeviceNumber(dev)
    1.89 +            if devid == dev:
    1.90 +                return dev_info
    1.91 +
    1.92  
    1.93      def setMemoryTarget(self, target):
    1.94          """Set the memory target of this domain.
    1.95 @@ -1321,6 +1393,10 @@ class XendDomainInfo:
    1.96          deviceClass, config = self.info['devices'].get(dev_uuid)
    1.97          self._waitForDevice(deviceClass, config['devid'])
    1.98  
    1.99 +    def _waitForDevice_destroy(self, deviceClass, devid, backpath):
   1.100 +        return self.getDeviceController(deviceClass).waitForDevice_destroy(
   1.101 +            devid, backpath)
   1.102 +
   1.103      def _reconfigureDevice(self, deviceClass, devid, devconfig):
   1.104          return self.getDeviceController(deviceClass).reconfigureDevice(
   1.105              devid, devconfig)
     2.1 --- a/tools/python/xen/xend/server/DevController.py	Thu Aug 09 16:14:56 2007 +0100
     2.2 +++ b/tools/python/xen/xend/server/DevController.py	Thu Aug 09 16:21:41 2007 +0100
     2.3 @@ -28,17 +28,19 @@ from xen.xend.xenstore.xswatch import xs
     2.4  
     2.5  import os
     2.6  
     2.7 -DEVICE_CREATE_TIMEOUT = 100
     2.8 +DEVICE_CREATE_TIMEOUT  = 100
     2.9 +DEVICE_DESTROY_TIMEOUT = 100
    2.10  HOTPLUG_STATUS_NODE = "hotplug-status"
    2.11  HOTPLUG_ERROR_NODE  = "hotplug-error"
    2.12  HOTPLUG_STATUS_ERROR = "error"
    2.13  HOTPLUG_STATUS_BUSY  = "busy"
    2.14  
    2.15 -Connected = 1
    2.16 -Error     = 2
    2.17 -Missing   = 3
    2.18 -Timeout   = 4
    2.19 -Busy      = 5
    2.20 +Connected    = 1
    2.21 +Error        = 2
    2.22 +Missing      = 3
    2.23 +Timeout      = 4
    2.24 +Busy         = 5
    2.25 +Disconnected = 6
    2.26  
    2.27  xenbusState = {
    2.28      'Unknown'      : 0,
    2.29 @@ -185,6 +187,18 @@ class DevController:
    2.30                            (devid, self.deviceClass, err))
    2.31  
    2.32  
    2.33 +    def waitForDevice_destroy(self, devid, backpath):
    2.34 +        log.debug("Waiting for %s - destroyDevice.", devid)
    2.35 +
    2.36 +        if not self.hotplug:
    2.37 +            return
    2.38 +
    2.39 +        status = self.waitForBackend_destroy(backpath)
    2.40 +
    2.41 +        if status == Timeout:
    2.42 +            raise VmError("Device %s (%s) could not be disconnected. " %
    2.43 +                          (devid, self.deviceClass))
    2.44 +
    2.45  
    2.46      def reconfigureDevice(self, devid, config):
    2.47          """Reconfigure the specified device.
    2.48 @@ -209,12 +223,7 @@ class DevController:
    2.49          here.
    2.50          """
    2.51  
    2.52 -        try:
    2.53 -            dev = int(devid)
    2.54 -        except ValueError:
    2.55 -            # Does devid contain devicetype/deviceid?
    2.56 -            # Propogate exception if unable to find an integer devid
    2.57 -            dev = int(type(devid) is str and devid.split('/')[-1] or None)
    2.58 +        dev = self.convertToDeviceNumber(devid)
    2.59  
    2.60          # Modify online status /before/ updating state (latter is watched by
    2.61          # drivers, so this ordering avoids a race).
    2.62 @@ -283,6 +292,15 @@ class DevController:
    2.63              all_configs[devid] = config_dict
    2.64          return all_configs
    2.65  
    2.66 +
    2.67 +    def convertToDeviceNumber(self, devid):
    2.68 +        try:
    2.69 +            return int(devid)
    2.70 +        except ValueError:
    2.71 +            # Does devid contain devicetype/deviceid?
    2.72 +            # Propogate exception if unable to find an integer devid
    2.73 +            return int(type(devid) is str and devid.split('/')[-1] or None)
    2.74 +
    2.75      ## protected:
    2.76  
    2.77      def getDeviceDetails(self, config):
    2.78 @@ -513,6 +531,19 @@ class DevController:
    2.79              return (Missing, None)
    2.80  
    2.81  
    2.82 +    def waitForBackend_destroy(self, backpath):
    2.83 +
    2.84 +        statusPath = backpath + '/' + HOTPLUG_STATUS_NODE
    2.85 +        ev = Event()
    2.86 +        result = { 'status': Timeout }
    2.87 +
    2.88 +        xswatch(statusPath, deviceDestroyCallback, ev, result)
    2.89 +
    2.90 +        ev.wait(DEVICE_DESTROY_TIMEOUT)
    2.91 +
    2.92 +        return result['status']
    2.93 +
    2.94 +
    2.95      def backendPath(self, backdom, devid):
    2.96          """Construct backend path given the backend domain and device id.
    2.97  
    2.98 @@ -561,3 +592,19 @@ def hotplugStatusCallback(statusPath, ev
    2.99  
   2.100      ev.set()
   2.101      return 0
   2.102 +
   2.103 +
   2.104 +def deviceDestroyCallback(statusPath, ev, result):
   2.105 +    log.debug("deviceDestroyCallback %s.", statusPath)
   2.106 +
   2.107 +    status = xstransact.Read(statusPath)
   2.108 +
   2.109 +    if status is None:
   2.110 +        result['status'] = Disconnected
   2.111 +    else:
   2.112 +        return 1
   2.113 +
   2.114 +    log.debug("deviceDestroyCallback %d.", result['status'])
   2.115 +
   2.116 +    ev.set()
   2.117 +    return 0
     3.1 --- a/tools/python/xen/xend/server/blkif.py	Thu Aug 09 16:14:56 2007 +0100
     3.2 +++ b/tools/python/xen/xend/server/blkif.py	Thu Aug 09 16:21:41 2007 +0100
     3.3 @@ -165,11 +165,23 @@ class BlkifController(DevController):
     3.4          try:
     3.5              DevController.destroyDevice(self, devid, force)
     3.6          except ValueError:
     3.7 -            devid_end = type(devid) is str and devid.split('/')[-1] or None
     3.8 +            dev = self.convertToDeviceNumber(devid)
     3.9  
    3.10              for i in self.deviceIDs():
    3.11 -                d = self.readBackend(i, 'dev')
    3.12 -                if d == devid or (devid_end and d == devid_end):
    3.13 +                if i == dev:
    3.14                      DevController.destroyDevice(self, i, force)
    3.15                      return
    3.16              raise VmError("Device %s not connected" % devid)
    3.17 +
    3.18 +    def convertToDeviceNumber(self, devid):
    3.19 +        try:
    3.20 +            dev = int(devid)
    3.21 +        except ValueError:
    3.22 +            if type(devid) is not str:
    3.23 +                raise VmError("devid %s is wrong type" % str(devid))
    3.24 +            try:
    3.25 +                dev = devid.split('/')[-1]
    3.26 +                dev = int(dev)
    3.27 +            except ValueError:
    3.28 +                dev = blkif.blkdev_name_to_number(dev)
    3.29 +        return dev
     4.1 --- a/tools/python/xen/xm/main.py	Thu Aug 09 16:14:56 2007 +0100
     4.2 +++ b/tools/python/xen/xm/main.py	Thu Aug 09 16:21:41 2007 +0100
     4.3 @@ -2186,6 +2186,7 @@ def xm_network_attach(args):
     4.4  
     4.5  
     4.6  def detach(args, deviceClass):
     4.7 +    rm_cfg = True
     4.8      dom = args[0]
     4.9      dev = args[1]
    4.10      try:
    4.11 @@ -2196,7 +2197,7 @@ def detach(args, deviceClass):
    4.12      except IndexError:
    4.13          force = None
    4.14  
    4.15 -    server.xend.domain.destroyDevice(dom, deviceClass, dev, force)
    4.16 +    server.xend.domain.destroyDevice(dom, deviceClass, dev, force, rm_cfg)
    4.17  
    4.18  
    4.19  def xm_block_detach(args):