mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
[blktap] Allow HVM booting from blktap device(s)
Signed-off-by: wim colgate <wim@xensource.com>
This commit is contained in:
1 parent
2b30444fe2
commit
51efffe712
5 files changed
+230
-2
No files matched your search
@@ -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':
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -473,6 +473,19 @@ 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")
|
||||
|
||||
|
||||
|
||||