mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
Merge with xenppc-unstable.hg
This commit is contained in:
commit
b3f09a8a4f
175 files changed
+5796
-3660
No files matched your search
@@ -239,8 +239,11 @@ def restore(xd, fd, dominfo = None, paused = False):
|
||||
|
||||
forkHelper(cmd, fd, handler.handler, True)
|
||||
|
||||
if handler.store_mfn is None or handler.console_mfn is None:
|
||||
raise XendError('Could not read store/console MFN')
|
||||
if handler.store_mfn is None:
|
||||
raise XendError('Could not read store MFN')
|
||||
|
||||
if not is_hvm and handler.console_mfn is None:
|
||||
raise XendError('Could not read console MFN')
|
||||
|
||||
dominfo.waitForDevices() # Wait for backends to set up
|
||||
if not paused:
|
||||
|
||||
@@ -1148,6 +1148,47 @@ class XendConfig(dict):
|
||||
# no valid device to add
|
||||
return ''
|
||||
|
||||
def phantom_device_add(self, dev_type, cfg_xenapi = None,
|
||||
target = None):
|
||||
"""Add a phantom tap device configuration in XenAPI struct format.
|
||||
"""
|
||||
|
||||
if target == None:
|
||||
target = self
|
||||
|
||||
if dev_type not in XendDevices.valid_devices() and \
|
||||
dev_type not in XendDevices.pseudo_devices():
|
||||
raise XendConfigError("XendConfig: %s not a valid device type" %
|
||||
dev_type)
|
||||
|
||||
if cfg_xenapi == None:
|
||||
raise XendConfigError("XendConfig: device_add requires some "
|
||||
"config.")
|
||||
|
||||
if cfg_xenapi:
|
||||
log.debug("XendConfig.phantom_device_add: %s" % str(cfg_xenapi))
|
||||
|
||||
if cfg_xenapi:
|
||||
dev_info = {}
|
||||
if dev_type in ('vbd', 'tap'):
|
||||
if dev_type == 'vbd':
|
||||
dev_info['uname'] = cfg_xenapi.get('image', '')
|
||||
dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
|
||||
elif dev_type == 'tap':
|
||||
if cfg_xenapi.get('image').find('tap:') == -1:
|
||||
dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
|
||||
dev_info['dev'] = '/dev/%s' % cfg_xenapi.get('device')
|
||||
dev_info['uname'] = cfg_xenapi.get('image')
|
||||
dev_info['mode'] = cfg_xenapi.get('mode')
|
||||
dev_info['backend'] = '0'
|
||||
dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
|
||||
dev_info['uuid'] = dev_uuid
|
||||
self['devices'][dev_uuid] = (dev_type, dev_info)
|
||||
self['vbd_refs'].append(dev_uuid)
|
||||
return dev_uuid
|
||||
|
||||
return ''
|
||||
|
||||
def console_add(self, protocol, location, other_config = {}):
|
||||
dev_uuid = uuid.createString()
|
||||
if protocol == 'vt100':
|
||||
|
||||
@@ -800,7 +800,10 @@ class XendDomain:
|
||||
"support.")
|
||||
|
||||
path = self._managed_check_point_path(dom_uuid)
|
||||
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
|
||||
oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||
if hasattr(os, "O_LARGEFILE"):
|
||||
oflags |= os.O_LARGEFILE
|
||||
fd = os.open(path, oflags)
|
||||
try:
|
||||
# For now we don't support 'live checkpoint'
|
||||
XendCheckpoint.save(fd, dominfo, False, False, path)
|
||||
@@ -840,8 +843,11 @@ class XendDomain:
|
||||
# Restore that replaces the existing XendDomainInfo
|
||||
try:
|
||||
log.debug('Current DomainInfo state: %d' % dominfo.state)
|
||||
oflags = os.O_RDONLY
|
||||
if hasattr(os, "O_LARGEFILE"):
|
||||
oflags |= os.O_LARGEFILE
|
||||
XendCheckpoint.restore(self,
|
||||
os.open(chkpath, os.O_RDONLY),
|
||||
os.open(chkpath, oflags),
|
||||
dominfo,
|
||||
paused = start_paused)
|
||||
os.unlink(chkpath)
|
||||
@@ -1009,7 +1015,10 @@ class XendDomain:
|
||||
@raise XendError: Failure to restore domain
|
||||
"""
|
||||
try:
|
||||
fd = os.open(src, os.O_RDONLY)
|
||||
oflags = os.O_RDONLY
|
||||
if hasattr(os, "O_LARGEFILE"):
|
||||
oflags |= os.O_LARGEFILE
|
||||
fd = os.open(src, oflags)
|
||||
try:
|
||||
return self.domain_restore_fd(fd, paused=paused)
|
||||
finally:
|
||||
@@ -1193,7 +1202,10 @@ class XendDomain:
|
||||
if dominfo.getDomid() == DOM0_ID:
|
||||
raise XendError("Cannot save privileged domain %i" % domid)
|
||||
|
||||
fd = os.open(dst, os.O_WRONLY | os.O_CREAT | os.O_TRUNC)
|
||||
oflags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
|
||||
if hasattr(os, "O_LARGEFILE"):
|
||||
oflags |= os.O_LARGEFILE
|
||||
fd = os.open(dst, oflags)
|
||||
try:
|
||||
# For now we don't support 'live checkpoint'
|
||||
XendCheckpoint.save(fd, dominfo, False, False, dst)
|
||||
|
||||
@@ -1416,7 +1416,7 @@ class XendDomainInfo:
|
||||
self.info['image'],
|
||||
self.info['devices'])
|
||||
|
||||
localtime = self.info.get('localtime', False)
|
||||
localtime = self.info.get('platform_localtime', False)
|
||||
if localtime:
|
||||
xc.domain_set_time_offset(self.domid)
|
||||
|
||||
@@ -1565,19 +1565,54 @@ class XendDomainInfo:
|
||||
# VM Destroy
|
||||
#
|
||||
|
||||
def _prepare_phantom_paths(self):
|
||||
# get associated devices to destroy
|
||||
# build list of phantom devices to be removed after normal devices
|
||||
plist = []
|
||||
from xen.xend.xenstore.xstransact import xstransact
|
||||
t = xstransact("%s/device/vbd" % GetDomainPath(self.domid))
|
||||
for dev in t.list():
|
||||
backend_phantom_vbd = xstransact.Read("%s/device/vbd/%s/phantom_vbd" \
|
||||
% (self.dompath, dev))
|
||||
if backend_phantom_vbd is not None:
|
||||
frontend_phantom_vbd = xstransact.Read("%s/frontend" \
|
||||
% backend_phantom_vbd)
|
||||
plist.append(backend_phantom_vbd)
|
||||
plist.append(frontend_phantom_vbd)
|
||||
return plist
|
||||
|
||||
def _cleanup_phantom_devs(self, plist):
|
||||
# remove phantom devices
|
||||
if not plist == []:
|
||||
time.sleep(2)
|
||||
for paths in plist:
|
||||
if paths.find('backend') != -1:
|
||||
from xen.xend.server import DevController
|
||||
# Modify online status /before/ updating state (latter is watched by
|
||||
# drivers, so this ordering avoids a race).
|
||||
xstransact.Write(paths, 'online', "0")
|
||||
xstransact.Write(paths, 'state', str(DevController.xenbusState['Closing']))
|
||||
# force
|
||||
xstransact.Remove(paths)
|
||||
|
||||
def destroy(self):
|
||||
"""Cleanup VM and destroy domain. Nothrow guarantee."""
|
||||
|
||||
log.debug("XendDomainInfo.destroy: domid=%s", str(self.domid))
|
||||
|
||||
paths = self._prepare_phantom_paths()
|
||||
|
||||
self._cleanupVm()
|
||||
if self.dompath is not None:
|
||||
self.destroyDomain()
|
||||
|
||||
self._cleanup_phantom_devs(paths)
|
||||
|
||||
def destroyDomain(self):
|
||||
log.debug("XendDomainInfo.destroyDomain(%s)", str(self.domid))
|
||||
|
||||
paths = self._prepare_phantom_paths()
|
||||
|
||||
try:
|
||||
if self.domid is not None:
|
||||
xc.domain_destroy(self.domid)
|
||||
@@ -1591,7 +1626,7 @@ class XendDomainInfo:
|
||||
XendDomain.instance().remove_domain(self)
|
||||
|
||||
self.cleanupDomain()
|
||||
|
||||
self._cleanup_phantom_devs(paths)
|
||||
|
||||
def resumeDomain(self):
|
||||
log.debug("XendDomainInfo.resumeDomain(%s)", str(self.domid))
|
||||
@@ -2211,6 +2246,25 @@ class XendDomainInfo:
|
||||
|
||||
return dev_uuid
|
||||
|
||||
def create_phantom_vbd_with_vdi(self, xenapi_vbd, vdi_image_path):
|
||||
"""Create a VBD using a VDI from XendStorageRepository.
|
||||
|
||||
@param xenapi_vbd: vbd struct from the Xen API
|
||||
@param vdi_image_path: VDI UUID
|
||||
@rtype: string
|
||||
@return: uuid of the device
|
||||
"""
|
||||
xenapi_vbd['image'] = vdi_image_path
|
||||
dev_uuid = self.info.phantom_device_add('tap', cfg_xenapi = xenapi_vbd)
|
||||
if not dev_uuid:
|
||||
raise XendError('Failed to create device')
|
||||
|
||||
if self.state == XEN_API_VM_POWER_STATE_RUNNING:
|
||||
_, config = self.info['devices'][dev_uuid]
|
||||
config['devid'] = self.getDeviceController('tap').createDevice(config)
|
||||
|
||||
return config['devid']
|
||||
|
||||
def create_vif(self, xenapi_vif):
|
||||
"""Create VIF device from the passed struct in Xen API format.
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
|
||||
from xen.xend.server.blkif import BlkifController
|
||||
from xen.xend.XendLogging import log
|
||||
|
||||
phantomDev = 0;
|
||||
phantomId = 0;
|
||||
|
||||
class BlktapController(BlkifController):
|
||||
def __init__(self, vm):
|
||||
@@ -12,3 +15,62 @@ class BlktapController(BlkifController):
|
||||
"""@see DevController#frontendRoot"""
|
||||
|
||||
return "%s/device/vbd" % self.vm.getDomainPath()
|
||||
|
||||
def getDeviceDetails(self, config):
|
||||
(devid, back, front) = BlkifController.getDeviceDetails(self, config)
|
||||
|
||||
phantomDevid = 0
|
||||
wrapped = False
|
||||
|
||||
try:
|
||||
imagetype = self.vm.info['image']['type']
|
||||
except:
|
||||
imagetype = ""
|
||||
|
||||
if imagetype == 'hvm':
|
||||
tdevname = back['dev']
|
||||
index = ['c', 'd', 'e', 'f', 'g', 'h', 'i', \
|
||||
'j', 'l', 'm', 'n', 'o', 'p']
|
||||
while True:
|
||||
global phantomDev
|
||||
global phantomId
|
||||
import os, stat
|
||||
|
||||
phantomId = phantomId + 1
|
||||
if phantomId == 16:
|
||||
if index[phantomDev] == index[-1]:
|
||||
if wrapped:
|
||||
raise VmError(" No loopback block \
|
||||
devices are available. ")
|
||||
wrapped = True
|
||||
phantomDev = 0
|
||||
else:
|
||||
phantomDev = phantomDev + 1
|
||||
phantomId = 1
|
||||
devname = 'xvd%s%d' % (index[phantomDev], phantomId)
|
||||
try:
|
||||
info = os.stat('/dev/%s' % devname)
|
||||
except:
|
||||
break
|
||||
|
||||
vbd = { 'mode': 'w', 'device': devname }
|
||||
fn = 'tap:%s' % back['params']
|
||||
|
||||
# recurse ... by creating the vbd, then fallthrough
|
||||
# and finish creating the original device
|
||||
|
||||
from xen.xend import XendDomain
|
||||
dom0 = XendDomain.instance().privilegedDomain()
|
||||
phantomDevid = dom0.create_phantom_vbd_with_vdi(vbd, fn)
|
||||
# we need to wait for this device at a higher level
|
||||
# the vbd that gets created will have a link to us
|
||||
# and will let them do it there
|
||||
|
||||
# add a hook to point to the phantom device,
|
||||
# root path is always the same (dom0 tap)
|
||||
if phantomDevid != 0:
|
||||
front['phantom_vbd'] = '/local/domain/0/backend/tap/0/%s' \
|
||||
% str(phantomDevid)
|
||||
|
||||
return (devid, back, front)
|
||||
|
||||
@@ -153,9 +153,9 @@ class DevController:
|
||||
log.debug("Waiting for %s.", devid)
|
||||
|
||||
if not self.hotplug:
|
||||
return
|
||||
|
||||
status = self.waitForBackend(devid)
|
||||
return
|
||||
|
||||
(status, err) = self.waitForBackend(devid)
|
||||
|
||||
if status == Timeout:
|
||||
self.destroyDevice(devid, False)
|
||||
@@ -165,25 +165,22 @@ class DevController:
|
||||
|
||||
elif status == Error:
|
||||
self.destroyDevice(devid, False)
|
||||
raise VmError("Device %s (%s) could not be connected. "
|
||||
"Backend device not found." %
|
||||
(devid, self.deviceClass))
|
||||
|
||||
if err is None:
|
||||
raise VmError("Device %s (%s) could not be connected. "
|
||||
"Backend device not found." %
|
||||
(devid, self.deviceClass))
|
||||
else:
|
||||
raise VmError("Device %s (%s) could not be connected. "
|
||||
"%s" % (devid, self.deviceClass, err))
|
||||
elif status == Missing:
|
||||
# Don't try to destroy the device; it's already gone away.
|
||||
raise VmError("Device %s (%s) could not be connected. "
|
||||
"Device not found." % (devid, self.deviceClass))
|
||||
|
||||
elif status == Busy:
|
||||
err = None
|
||||
frontpath = self.frontendPath(devid)
|
||||
backpath = xstransact.Read(frontpath, "backend")
|
||||
if backpath:
|
||||
err = xstransact.Read(backpath, HOTPLUG_ERROR_NODE)
|
||||
if not err:
|
||||
err = "Busy."
|
||||
|
||||
self.destroyDevice(devid, False)
|
||||
if err is None:
|
||||
err = "Busy."
|
||||
raise VmError("Device %s (%s) could not be connected.\n%s" %
|
||||
(devid, self.deviceClass, err))
|
||||
|
||||
@@ -476,19 +473,36 @@ class DevController:
|
||||
def waitForBackend(self, devid):
|
||||
|
||||
frontpath = self.frontendPath(devid)
|
||||
# lookup a phantom
|
||||
phantomPath = xstransact.Read(frontpath, 'phantom_vbd')
|
||||
if phantomPath is not None:
|
||||
log.debug("Waiting for %s's phantom %s.", devid, phantomPath)
|
||||
statusPath = phantomPath + '/' + HOTPLUG_STATUS_NODE
|
||||
ev = Event()
|
||||
result = { 'status': Timeout }
|
||||
xswatch(statusPath, hotplugStatusCallback, ev, result)
|
||||
ev.wait(DEVICE_CREATE_TIMEOUT)
|
||||
err = xstransact.Read(statusPath, HOTPLUG_ERROR_NODE)
|
||||
if result['status'] != 'Connected':
|
||||
return (result['status'], err)
|
||||
|
||||
backpath = xstransact.Read(frontpath, "backend")
|
||||
|
||||
|
||||
if backpath:
|
||||
statusPath = backpath + '/' + HOTPLUG_STATUS_NODE
|
||||
ev = Event()
|
||||
result = { 'status': Timeout }
|
||||
|
||||
|
||||
xswatch(statusPath, hotplugStatusCallback, ev, result)
|
||||
|
||||
ev.wait(DEVICE_CREATE_TIMEOUT)
|
||||
return result['status']
|
||||
|
||||
err = xstransact.Read(backpath, HOTPLUG_ERROR_NODE)
|
||||
|
||||
return (result['status'], err)
|
||||
else:
|
||||
return Missing
|
||||
return (Missing, None)
|
||||
|
||||
|
||||
def backendPath(self, backdom, devid):
|
||||
|
||||