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:
kfraser@localhost.localdomain committed 2007-08-09 16:21:41 +01:00
1 parent db79ac4259
commit b02c2e5dfc
4 files changed
+155 -19

No files matched your search

+79 -3
View File
@@ -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)
+59 -12
View File
@@ -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
+15 -3
View File
@@ -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
+2 -1
View File
@@ -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):
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.