Index: xen-3.2.1-testing/tools/python/xen/util/blkif.py =================================================================== --- xen-3.2.1-testing.orig/tools/python/xen/util/blkif.py +++ xen-3.2.1-testing/tools/python/xen/util/blkif.py @@ -66,23 +66,24 @@ def blkdev_segment(name): 'type' : 'Disk' } return val -def _parse_uname(uname): - fn = taptype = None +def parse_uname(uname): + fn = tpy = taptype = None if uname.find(":") != -1: (typ, fn) = uname.split(":", 1) if typ == "phy" and not fn.startswith("/"): fn = "/dev/%s" %(fn,) if typ == "tap": (taptype, fn) = fn.split(":", 1) - return (fn, taptype) + return (fn, (typ, taptype)) + return (fn, (typ,taptype)) def blkdev_uname_to_file(uname): """Take a blkdev uname and return the corresponding filename.""" - return _parse_uname(uname)[0] + return parse_uname(uname)[0] def blkdev_uname_to_taptype(uname): """Take a blkdev uname and return the blktap type.""" - return _parse_uname(uname)[1] + return parse_uname(uname)[1][0] def mount_mode(name): mode = None Index: xen-3.2.1-testing/tools/python/xen/xend/server/DevController.py =================================================================== --- xen-3.2.1-testing.orig/tools/python/xen/xend/server/DevController.py +++ xen-3.2.1-testing/tools/python/xen/xend/server/DevController.py @@ -562,6 +562,31 @@ class DevController: return result['status'] + def waitForFrontend(self, devid): + def frontendStatusCallback(statusPath, ev, result): + status = xstransact.Read(statusPath) + log.debug("frontendStatusCallback %s = %s" % (statusPath, status)) + try: + status = int(status) + if status == xenbusState['Connected']: + result['status'] = Connected + elif status == xenbusState['Closed']: + result['status'] = Error + else: + raise + except: + return 1 + ev.set() + return 0 + frontpath = self.frontendPath(devid) + statusPath = frontpath + '/state' + ev = Event() + result = { 'status': Timeout } + xswatch(statusPath, frontendStatusCallback, ev, result) + ev.wait(5) + return result['status'] + + def backendPath(self, backdom, devid): """Construct backend path given the backend domain and device id. Index: xen-3.2.1-testing/tools/python/xen/xend/XendBootloader.py =================================================================== --- xen-3.2.1-testing.orig/tools/python/xen/xend/XendBootloader.py +++ xen-3.2.1-testing/tools/python/xen/xend/XendBootloader.py @@ -12,8 +12,9 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # -import os, select, errno, stat, signal +import os, select, errno, stat, signal, time import random +import re import shlex from xen.xend import sxp @@ -38,8 +39,25 @@ def bootloader(blexec, disk, dom, quiet msg = "Bootloader isn't executable" log.error(msg) raise VmError(msg) - if not os.access(disk, os.R_OK): - msg = "Disk isn't accessible" + + # domUloader requires '--entry=foo' in blargs, which is derived from + # 'bootargs' entry in domain configuration file. Ensure it exists + # here so a reasonable error message can be returned. + if blexec.find('domUloader.py') != -1: + if blargs.find('entry') == -1: + msg = "domUloader requires specification of bootargs" + log.error(msg) + raise VmError(msg) + + avail = False + for i in xrange(1, 20): + avail = os.access(disk, os.R_OK) + if avail: + break + time.sleep(.05) + + if not avail: + msg = "Disk '%s' isn't accessible" % disk log.error(msg) raise VmError(msg) @@ -185,3 +203,14 @@ def bootloader_tidy(dom): os.kill(pid, signal.SIGKILL) +def bootfilter(bootloader, bootloader_args, vdisk): + """Is this virtual disk ok to boot from?""" + if vdisk.endswith(':disk'): + vdisk = vdisk[:-5] # temporary work-around for bug 237414 + if bootloader.endswith('domUloader.py'): + for arg in bootloader_args.split(): + if arg.startswith('--entry='): + m = re.match(r'^([hsx]v?d[a-z])[0-9]*:[^,]*(,[^,]*)?$', arg[8:]) + if m: + return vdisk == m.group(1) or vdisk == m.group(2) + return True Index: xen-3.2.1-testing/tools/python/xen/xend/XendDomainInfo.py =================================================================== --- xen-3.2.1-testing.orig/tools/python/xen/xend/XendDomainInfo.py +++ xen-3.2.1-testing/tools/python/xen/xend/XendDomainInfo.py @@ -35,14 +35,14 @@ from types import StringTypes import xen.lowlevel.xc from xen.util import asserts -from xen.util.blkif import blkdev_uname_to_file, blkdev_uname_to_taptype +from xen.util.blkif import parse_uname import xen.util.xsm.xsm as security from xen.xend import balloon, sxp, uuid, image, arch, osdep from xen.xend import XendOptions, XendNode, XendConfig from xen.xend.XendConfig import scrub_password -from xen.xend.XendBootloader import bootloader, bootloader_tidy +from xen.xend.XendBootloader import bootloader, bootloader_tidy, bootfilter from xen.xend.XendError import XendError, VmError from xen.xend.XendDevices import XendDevices from xen.xend.XendTask import XendTask @@ -1517,6 +1517,10 @@ class XendDomainInfo: deviceClass, config = self.info['devices'].get(dev_uuid) self._waitForDevice(deviceClass, config['devid']) + def _waitForDeviceFrontUUID(self, dev_uuid): + deviceClass, config = self.info['devices'].get(dev_uuid) + self.getDeviceController(deviceClass).waitForFrontend(config['devid']) + def _waitForDevice_destroy(self, deviceClass, devid, backpath): return self.getDeviceController(deviceClass).waitForDevice_destroy( devid, backpath) @@ -2098,8 +2102,11 @@ class XendDomainInfo: blexec = osdep.pygrub_path blcfg = None - disks = [x for x in self.info['vbd_refs'] - if self.info['devices'][x][1]['bootable']] + disks = [] + for x in self.info['vbd_refs']: + vdisk = self.info['devices'][x][1]['dev'] + if bootfilter(blexec, bootloader_args, vdisk): + disks.append(x) if not disks: msg = "Had a bootloader specified, but no disks are bootable" @@ -2110,13 +2117,10 @@ class XendDomainInfo: devtype = devinfo[0] disk = devinfo[1]['uname'] - fn = blkdev_uname_to_file(disk) - taptype = blkdev_uname_to_taptype(disk) - mounted = devtype == 'tap' and taptype != 'aio' and taptype != 'sync' and not os.stat(fn).st_rdev + (fn, types) = parse_uname(disk) + mounted = (types[0] not in ('file', 'phy')) if mounted: - # This is a file, not a device. pygrub can cope with a - # file if it's raw, but if it's QCOW or other such formats - # used through blktap, then we need to mount it first. + # This is not a raw file or device, so we need to mount it first. log.info("Mounting %s on %s." % (fn, BOOTLOADER_LOOPBACK_DEVICE)) @@ -2128,7 +2132,9 @@ class XendDomainInfo: from xen.xend import XendDomain dom0 = XendDomain.instance().privilegedDomain() - dom0._waitForDeviceUUID(dom0.create_vbd(vbd, disk)) + vbd_uuid = dom0.create_vbd(vbd, disk) + dom0._waitForDeviceUUID(vbd_uuid) + dom0._waitForDeviceFrontUUID(vbd_uuid) fn = BOOTLOADER_LOOPBACK_DEVICE try: @@ -2139,7 +2145,7 @@ class XendDomainInfo: log.info("Unmounting %s from %s." % (fn, BOOTLOADER_LOOPBACK_DEVICE)) - dom0.destroyDevice('tap', BOOTLOADER_LOOPBACK_DEVICE) + dom0.destroyDevice('tap', BOOTLOADER_LOOPBACK_DEVICE, rm_cfg = True) if blcfg is None: msg = "Had a bootloader specified, but can't find disk"