293 lines
10 KiB
Diff
293 lines
10 KiB
Diff
|
# HG changeset patch
|
||
|
# User kfraser@localhost.localdomain
|
||
|
# Date 1186672901 -3600
|
||
|
# Node ID 95f90f24f3b1f33f911d3e9a01cb1d7bce5b29e0
|
||
|
# Parent f0298301ba8b34ac3e5470cf953a3591f7730d26
|
||
|
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>
|
||
|
|
||
|
Index: xen-3.1-testing/tools/python/xen/xend/XendDomainInfo.py
|
||
|
===================================================================
|
||
|
--- xen-3.1-testing.orig/tools/python/xen/xend/XendDomainInfo.py
|
||
|
+++ xen-3.1-testing/tools/python/xen/xend/XendDomainInfo.py
|
||
|
@@ -552,9 +552,64 @@ class XendDomainInfo:
|
||
|
for devclass in XendDevices.valid_devices():
|
||
|
self.getDeviceController(devclass).waitForDevices()
|
||
|
|
||
|
- def destroyDevice(self, deviceClass, devid, force = False):
|
||
|
- log.debug("dev = %s", devid)
|
||
|
- return self.getDeviceController(deviceClass).destroyDevice(devid, force)
|
||
|
+ def destroyDevice(self, deviceClass, devid, force = False, rm_cfg = False):
|
||
|
+ log.debug("XendDomainInfo.destroyDevice: deviceClass = %s, device = %s",
|
||
|
+ deviceClass, devid)
|
||
|
+
|
||
|
+ if rm_cfg:
|
||
|
+ # Convert devid to device number. A device number is
|
||
|
+ # needed to remove its configuration.
|
||
|
+ dev = self.getDeviceController(deviceClass).convertToDeviceNumber(devid)
|
||
|
+
|
||
|
+ # Save current sxprs. A device number and a backend
|
||
|
+ # path are needed to remove its configuration but sxprs
|
||
|
+ # do not have those after calling destroyDevice.
|
||
|
+ sxprs = self.getDeviceSxprs(deviceClass)
|
||
|
+
|
||
|
+ rc = None
|
||
|
+ if self.domid is not None:
|
||
|
+ rc = self.getDeviceController(deviceClass).destroyDevice(devid, force)
|
||
|
+ if not force and rm_cfg:
|
||
|
+ # The backend path, other than the device itself,
|
||
|
+ # has to be passed because its accompanied frontend
|
||
|
+ # path may be void until its removal is actually
|
||
|
+ # issued. It is probable because destroyDevice is
|
||
|
+ # issued first.
|
||
|
+ for dev_num, dev_info in sxprs:
|
||
|
+ dev_num = int(dev_num)
|
||
|
+ if dev_num == dev:
|
||
|
+ for x in dev_info:
|
||
|
+ if x[0] == 'backend':
|
||
|
+ backend = x[1]
|
||
|
+ break
|
||
|
+ break
|
||
|
+ self._waitForDevice_destroy(deviceClass, devid, backend)
|
||
|
+
|
||
|
+ if rm_cfg:
|
||
|
+ if deviceClass == 'vif':
|
||
|
+ if self.domid is not None:
|
||
|
+ for dev_num, dev_info in sxprs:
|
||
|
+ dev_num = int(dev_num)
|
||
|
+ if dev_num == dev:
|
||
|
+ for x in dev_info:
|
||
|
+ if x[0] == 'mac':
|
||
|
+ mac = x[1]
|
||
|
+ break
|
||
|
+ break
|
||
|
+ dev_info = self.getDeviceInfo_vif(mac)
|
||
|
+ else:
|
||
|
+ _, dev_info = sxprs[dev]
|
||
|
+ else: # 'vbd' or 'tap'
|
||
|
+ dev_info = self.getDeviceInfo_vbd(dev)
|
||
|
+ if dev_info is None:
|
||
|
+ return rc
|
||
|
+
|
||
|
+ dev_uuid = sxp.child_value(dev_info, 'uuid')
|
||
|
+ del self.info['devices'][dev_uuid]
|
||
|
+ self.info['%s_refs' % deviceClass].remove(dev_uuid)
|
||
|
+ xen.xend.XendDomain.instance().managed_config_save(self)
|
||
|
+
|
||
|
+ return rc
|
||
|
|
||
|
def getDeviceSxprs(self, deviceClass):
|
||
|
if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
|
||
|
@@ -568,6 +623,23 @@ class XendDomainInfo:
|
||
|
dev_num += 1
|
||
|
return sxprs
|
||
|
|
||
|
+ def getDeviceInfo_vif(self, mac):
|
||
|
+ for dev_type, dev_info in self.info.all_devices_sxpr():
|
||
|
+ if dev_type != 'vif':
|
||
|
+ continue
|
||
|
+ if mac == sxp.child_value(dev_info, 'mac'):
|
||
|
+ return dev_info
|
||
|
+
|
||
|
+ def getDeviceInfo_vbd(self, devid):
|
||
|
+ for dev_type, dev_info in self.info.all_devices_sxpr():
|
||
|
+ if dev_type != 'vbd' and dev_type != 'tap':
|
||
|
+ continue
|
||
|
+ dev = sxp.child_value(dev_info, 'dev')
|
||
|
+ dev = dev.split(':')[0]
|
||
|
+ dev = self.getDeviceController(dev_type).convertToDeviceNumber(dev)
|
||
|
+ if devid == dev:
|
||
|
+ return dev_info
|
||
|
+
|
||
|
|
||
|
def setMemoryTarget(self, target):
|
||
|
"""Set the memory target of this domain.
|
||
|
@@ -1296,6 +1368,10 @@ class XendDomainInfo:
|
||
|
deviceClass, config = self.info['devices'].get(dev_uuid)
|
||
|
self._waitForDevice(deviceClass, config['devid'])
|
||
|
|
||
|
+ def _waitForDevice_destroy(self, deviceClass, devid, backpath):
|
||
|
+ return self.getDeviceController(deviceClass).waitForDevice_destroy(
|
||
|
+ devid, backpath)
|
||
|
+
|
||
|
def _reconfigureDevice(self, deviceClass, devid, devconfig):
|
||
|
return self.getDeviceController(deviceClass).reconfigureDevice(
|
||
|
devid, devconfig)
|
||
|
Index: xen-3.1-testing/tools/python/xen/xend/server/DevController.py
|
||
|
===================================================================
|
||
|
--- xen-3.1-testing.orig/tools/python/xen/xend/server/DevController.py
|
||
|
+++ xen-3.1-testing/tools/python/xen/xend/server/DevController.py
|
||
|
@@ -28,17 +28,19 @@ from xen.xend.xenstore.xswatch import xs
|
||
|
|
||
|
import os
|
||
|
|
||
|
-DEVICE_CREATE_TIMEOUT = 100
|
||
|
+DEVICE_CREATE_TIMEOUT = 100
|
||
|
+DEVICE_DESTROY_TIMEOUT = 100
|
||
|
HOTPLUG_STATUS_NODE = "hotplug-status"
|
||
|
HOTPLUG_ERROR_NODE = "hotplug-error"
|
||
|
HOTPLUG_STATUS_ERROR = "error"
|
||
|
HOTPLUG_STATUS_BUSY = "busy"
|
||
|
|
||
|
-Connected = 1
|
||
|
-Error = 2
|
||
|
-Missing = 3
|
||
|
-Timeout = 4
|
||
|
-Busy = 5
|
||
|
+Connected = 1
|
||
|
+Error = 2
|
||
|
+Missing = 3
|
||
|
+Timeout = 4
|
||
|
+Busy = 5
|
||
|
+Disconnected = 6
|
||
|
|
||
|
xenbusState = {
|
||
|
'Unknown' : 0,
|
||
|
@@ -185,6 +187,18 @@ class DevController:
|
||
|
(devid, self.deviceClass, err))
|
||
|
|
||
|
|
||
|
+ def waitForDevice_destroy(self, devid, backpath):
|
||
|
+ log.debug("Waiting for %s - destroyDevice.", devid)
|
||
|
+
|
||
|
+ if not self.hotplug:
|
||
|
+ return
|
||
|
+
|
||
|
+ status = self.waitForBackend_destroy(backpath)
|
||
|
+
|
||
|
+ if status == Timeout:
|
||
|
+ raise VmError("Device %s (%s) could not be disconnected. " %
|
||
|
+ (devid, self.deviceClass))
|
||
|
+
|
||
|
|
||
|
def reconfigureDevice(self, devid, config):
|
||
|
"""Reconfigure the specified device.
|
||
|
@@ -209,12 +223,7 @@ class DevController:
|
||
|
here.
|
||
|
"""
|
||
|
|
||
|
- try:
|
||
|
- dev = int(devid)
|
||
|
- except ValueError:
|
||
|
- # Does devid contain devicetype/deviceid?
|
||
|
- # Propogate exception if unable to find an integer devid
|
||
|
- dev = int(type(devid) is str and devid.split('/')[-1] or None)
|
||
|
+ dev = self.convertToDeviceNumber(devid)
|
||
|
|
||
|
# Modify online status /before/ updating state (latter is watched by
|
||
|
# drivers, so this ordering avoids a race).
|
||
|
@@ -283,6 +292,15 @@ class DevController:
|
||
|
all_configs[devid] = config_dict
|
||
|
return all_configs
|
||
|
|
||
|
+
|
||
|
+ def convertToDeviceNumber(self, devid):
|
||
|
+ try:
|
||
|
+ return int(devid)
|
||
|
+ except ValueError:
|
||
|
+ # Does devid contain devicetype/deviceid?
|
||
|
+ # Propogate exception if unable to find an integer devid
|
||
|
+ return int(type(devid) is str and devid.split('/')[-1] or None)
|
||
|
+
|
||
|
## protected:
|
||
|
|
||
|
def getDeviceDetails(self, config):
|
||
|
@@ -511,6 +529,19 @@ class DevController:
|
||
|
return (Missing, None)
|
||
|
|
||
|
|
||
|
+ def waitForBackend_destroy(self, backpath):
|
||
|
+
|
||
|
+ statusPath = backpath + '/' + HOTPLUG_STATUS_NODE
|
||
|
+ ev = Event()
|
||
|
+ result = { 'status': Timeout }
|
||
|
+
|
||
|
+ xswatch(statusPath, deviceDestroyCallback, ev, result)
|
||
|
+
|
||
|
+ ev.wait(DEVICE_DESTROY_TIMEOUT)
|
||
|
+
|
||
|
+ return result['status']
|
||
|
+
|
||
|
+
|
||
|
def backendPath(self, backdom, devid):
|
||
|
"""Construct backend path given the backend domain and device id.
|
||
|
|
||
|
@@ -559,3 +590,19 @@ def hotplugStatusCallback(statusPath, ev
|
||
|
|
||
|
ev.set()
|
||
|
return 0
|
||
|
+
|
||
|
+
|
||
|
+def deviceDestroyCallback(statusPath, ev, result):
|
||
|
+ log.debug("deviceDestroyCallback %s.", statusPath)
|
||
|
+
|
||
|
+ status = xstransact.Read(statusPath)
|
||
|
+
|
||
|
+ if status is None:
|
||
|
+ result['status'] = Disconnected
|
||
|
+ else:
|
||
|
+ return 1
|
||
|
+
|
||
|
+ log.debug("deviceDestroyCallback %d.", result['status'])
|
||
|
+
|
||
|
+ ev.set()
|
||
|
+ return 0
|
||
|
Index: xen-3.1-testing/tools/python/xen/xend/server/blkif.py
|
||
|
===================================================================
|
||
|
--- xen-3.1-testing.orig/tools/python/xen/xend/server/blkif.py
|
||
|
+++ xen-3.1-testing/tools/python/xen/xend/server/blkif.py
|
||
|
@@ -148,11 +148,23 @@ class BlkifController(DevController):
|
||
|
try:
|
||
|
DevController.destroyDevice(self, devid, force)
|
||
|
except ValueError:
|
||
|
- devid_end = type(devid) is str and devid.split('/')[-1] or None
|
||
|
+ dev = self.convertToDeviceNumber(devid)
|
||
|
|
||
|
for i in self.deviceIDs():
|
||
|
- d = self.readBackend(i, 'dev')
|
||
|
- if d == devid or (devid_end and d == devid_end):
|
||
|
+ if i == dev:
|
||
|
DevController.destroyDevice(self, i, force)
|
||
|
return
|
||
|
raise VmError("Device %s not connected" % devid)
|
||
|
+
|
||
|
+ def convertToDeviceNumber(self, devid):
|
||
|
+ try:
|
||
|
+ dev = int(devid)
|
||
|
+ except ValueError:
|
||
|
+ if type(devid) is not str:
|
||
|
+ raise VmError("devid %s is wrong type" % str(devid))
|
||
|
+ try:
|
||
|
+ dev = devid.split('/')[-1]
|
||
|
+ dev = int(dev)
|
||
|
+ except ValueError:
|
||
|
+ dev = blkif.blkdev_name_to_number(dev)
|
||
|
+ return dev
|
||
|
Index: xen-3.1-testing/tools/python/xen/xm/main.py
|
||
|
===================================================================
|
||
|
--- xen-3.1-testing.orig/tools/python/xen/xm/main.py
|
||
|
+++ xen-3.1-testing/tools/python/xen/xm/main.py
|
||
|
@@ -2129,6 +2129,7 @@ def xm_network_attach(args):
|
||
|
def detach(args, command, deviceClass):
|
||
|
arg_check(args, command, 2, 3)
|
||
|
|
||
|
+ rm_cfg = True
|
||
|
dom = args[0]
|
||
|
dev = args[1]
|
||
|
try:
|
||
|
@@ -2139,7 +2140,7 @@ def detach(args, command, deviceClass):
|
||
|
except IndexError:
|
||
|
force = None
|
||
|
|
||
|
- server.xend.domain.destroyDevice(dom, deviceClass, dev, force)
|
||
|
+ server.xend.domain.destroyDevice(dom, deviceClass, dev, force, rm_cfg)
|
||
|
|
||
|
|
||
|
def xm_block_detach(args):
|