mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
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>
This commit is contained in:
1 parent
db79ac4259
commit
b02c2e5dfc
4 files changed
+155
-19
No files matched your search
@@ -558,9 +558,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):
|
||||
@@ -574,6 +629,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.
|
||||
@@ -1321,6 +1393,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)
|
||||
|
||||
@@ -28,17 +28,19 @@ from xen.xend.xenstore.xswatch import xswatch
|
||||
|
||||
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):
|
||||
@@ -513,6 +531,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.
|
||||
|
||||
@@ -561,3 +592,19 @@ def hotplugStatusCallback(statusPath, ev, result):
|
||||
|
||||
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
|
||||
@@ -165,11 +165,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
|
||||
@@ -2186,6 +2186,7 @@ def xm_network_attach(args):
|
||||
|
||||
|
||||
def detach(args, deviceClass):
|
||||
rm_cfg = True
|
||||
dom = args[0]
|
||||
dev = args[1]
|
||||
try:
|
||||
@@ -2196,7 +2197,7 @@ def detach(args, 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):
|
||||
|
||||