mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 18:21:39 +01:00
xend: Make device detach wait for detach to complete.
*-detach will wait till device is detached or time'ed out. XendConfig will be updated, if detached. Signed-off-by: Max Zhen <max.zhen@sun.com>
This commit is contained in:
1 parent
1606c2497d
commit
fbaf0773bb
3 files changed
+75
-5
No files matched your search
@@ -1268,6 +1268,21 @@ class XendConfig(dict):
|
||||
|
||||
return False
|
||||
|
||||
def device_remove(self, dev_uuid):
|
||||
"""Remove an existing device referred by dev_uuid.
|
||||
"""
|
||||
|
||||
if dev_uuid in self['devices']:
|
||||
dev_config = self['devices'].get(dev_uuid)
|
||||
dev_type = dev_config[0]
|
||||
|
||||
del self['devices'][dev_uuid]
|
||||
# Remove dev references for certain device types (see device_add)
|
||||
if dev_type in ('vif', 'vbd', 'vtpm'):
|
||||
param = '%s_refs' % dev_type
|
||||
if param in self:
|
||||
if dev_uuid in self[param]:
|
||||
self[param].remove(dev_uuid)
|
||||
|
||||
def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
|
||||
"""Get Device SXPR by either giving the device UUID or (type, config).
|
||||
|
||||
@@ -557,7 +557,23 @@ class XendDomainInfo:
|
||||
return None
|
||||
|
||||
log.debug("dev = %s", dev)
|
||||
return self.getDeviceController(deviceClass).destroyDevice(dev, force)
|
||||
|
||||
dev_control = self.getDeviceController(deviceClass)
|
||||
dev_uuid = dev_control.readBackend(dev, 'uuid')
|
||||
|
||||
ret = None
|
||||
|
||||
try:
|
||||
ret = dev_control.destroyDevice(dev, force)
|
||||
except EnvironmentError:
|
||||
# We failed to detach the device
|
||||
raise VmError("Failed to detach device %d" % dev)
|
||||
|
||||
# update XendConfig
|
||||
if dev_uuid:
|
||||
self.info.device_remove(dev_uuid)
|
||||
|
||||
return ret
|
||||
|
||||
def getDeviceSxprs(self, deviceClass):
|
||||
if self._stateGet() in (DOM_STATE_RUNNING, DOM_STATE_PAUSED):
|
||||
@@ -571,7 +587,6 @@ class XendDomainInfo:
|
||||
dev_num += 1
|
||||
return sxprs
|
||||
|
||||
|
||||
def setMemoryTarget(self, target):
|
||||
"""Set the memory target of this domain.
|
||||
@param target: In MiB.
|
||||
|
||||
@@ -29,6 +29,7 @@ from xen.xend.xenstore.xswatch import xswatch
|
||||
import os
|
||||
|
||||
DEVICE_CREATE_TIMEOUT = 100
|
||||
DEVICE_DESTROY_TIMEOUT = 10
|
||||
HOTPLUG_STATUS_NODE = "hotplug-status"
|
||||
HOTPLUG_ERROR_NODE = "hotplug-error"
|
||||
HOTPLUG_STATUS_ERROR = "error"
|
||||
@@ -211,17 +212,34 @@ class DevController:
|
||||
|
||||
devid = int(devid)
|
||||
|
||||
frontpath = self.frontendPath(devid)
|
||||
if frontpath:
|
||||
backpath = xstransact.Read(frontpath, "backend")
|
||||
|
||||
# Modify online status /before/ updating state (latter is watched by
|
||||
# drivers, so this ordering avoids a race).
|
||||
self.writeBackend(devid, 'online', "0")
|
||||
self.writeBackend(devid, 'state', str(xenbusState['Closing']))
|
||||
|
||||
if force:
|
||||
frontpath = self.frontendPath(devid)
|
||||
backpath = xstransact.Read(frontpath, "backend")
|
||||
if backpath:
|
||||
xstransact.Remove(backpath)
|
||||
xstransact.Remove(frontpath)
|
||||
if frontpath:
|
||||
xstransact.Remove(frontpath)
|
||||
return
|
||||
|
||||
# Wait till both frontpath and backpath are removed from
|
||||
# xenstore, or timed out
|
||||
if frontpath:
|
||||
status = self.waitUntilDestroyed(frontpath)
|
||||
if status == Timeout:
|
||||
# Exception will be caught by destroyDevice in XendDomainInfo.py
|
||||
raise EnvironmentError
|
||||
if backpath:
|
||||
status = self.waitUntilDestroyed(backpath)
|
||||
if status == Timeout:
|
||||
# Exception will be caught by destroyDevice in XendDomainInfo.py
|
||||
raise EnvironmentError
|
||||
|
||||
self.vm._removeVm("device/%s/%d" % (self.deviceClass, devid))
|
||||
|
||||
@@ -508,6 +526,16 @@ class DevController:
|
||||
return (Missing, None)
|
||||
|
||||
|
||||
def waitUntilDestroyed(self, path):
|
||||
ev = Event()
|
||||
result = { 'path': path, 'status': Timeout }
|
||||
|
||||
xswatch(path, destroyCallback, 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.
|
||||
|
||||
@@ -537,6 +565,18 @@ class DevController:
|
||||
self.deviceClass)
|
||||
|
||||
|
||||
def destroyCallback(devPath, ev, result):
|
||||
log.debug("destroyCallback %s.", devPath)
|
||||
|
||||
list = xstransact.List(result['path'])
|
||||
if list:
|
||||
return 1
|
||||
|
||||
result['status'] = Missing
|
||||
ev.set()
|
||||
log.debug("destroyCallback %s is destroyed", result['path'])
|
||||
return 0
|
||||
|
||||
def hotplugStatusCallback(statusPath, ev, result):
|
||||
log.debug("hotplugStatusCallback %s.", statusPath)
|
||||
|
||||
|
||||