Allow multiple bootloader loopback devices

Starting several domains concurrently can fail due to using a single
bootloader loopback device.  This patch creates a list of bootloader
loopback devices so more than one instance of bootloader can be run
concurrently.

Index: xen-4.0.3-testing/tools/python/xen/util/blkif.py
===================================================================
--- xen-4.0.3-testing.orig/tools/python/xen/util/blkif.py
+++ xen-4.0.3-testing/tools/python/xen/util/blkif.py
@@ -19,11 +19,6 @@ def blkdev_name_to_number(name):
     devname = 'virtual-device'
     devnum = None
 
-    try:
-        return (devname, os.stat(n).st_rdev)
-    except Exception, ex:
-        pass
-
     scsi_major = [ 8, 65, 66, 67, 68, 69, 70, 71, 128, 129, 130, 131, 132, 133, 134, 135 ]
     if re.match( '/dev/sd[a-z]([1-9]|1[0-5])?$', n):
         major = scsi_major[(ord(n[7:8]) - ord('a')) / 16]
Index: xen-4.0.3-testing/tools/python/xen/xend/XendDomainInfo.py
===================================================================
--- xen-4.0.3-testing.orig/tools/python/xen/xend/XendDomainInfo.py
+++ xen-4.0.3-testing/tools/python/xen/xend/XendDomainInfo.py
@@ -73,7 +73,7 @@ from xen.xend.XendPSCSI import XendPSCSI
 from xen.xend.XendDSCSI import XendDSCSI, XendDSCSI_HBA
 
 MIGRATE_TIMEOUT = 30.0
-BOOTLOADER_LOOPBACK_DEVICE = '/dev/xvdp'
+BOOTLOADER_LOOPBACK_DEVICES = ['/dev/xvd' + chr(x) for x in range(ord('z'), ord('d'), -1)]
 
 xc = xen.lowlevel.xc.xc()
 xoptions = XendOptions.instance()
@@ -3311,32 +3311,38 @@ class XendDomainInfo:
                 # 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.
-
-                log.info("Mounting %s on %s." %
-                         (fn, BOOTLOADER_LOOPBACK_DEVICE))
-
-                vbd = {
-                    'mode': 'RW',
-                    'device': BOOTLOADER_LOOPBACK_DEVICE,
-                    }
-
-                from xen.xend import XendDomain
-                dom0 = XendDomain.instance().privilegedDomain()
-                mounted_vbd_uuid = dom0.create_vbd(vbd, disk);
-                dom0._waitForDeviceFrontUUID(mounted_vbd_uuid)
-                fn = BOOTLOADER_LOOPBACK_DEVICE
+                # Try all possible loopback_devices
+                for loopback_device in BOOTLOADER_LOOPBACK_DEVICES:
+                    log.info("Mounting %s on %s." % (fn, loopback_device))
+                    vbd = { 'mode' : 'RW', 'device' : loopback_device, }
+                    try:
+                        from xen.xend import XendDomain
+                        dom0 = XendDomain.instance().privilegedDomain()
+                        mounted_vbd_uuid = dom0.create_vbd(vbd, disk)
+                        dom0._waitForDeviceFrontUUID(mounted_vbd_uuid)
+                        fn = loopback_device
+                        break
+                    except VmError, e:
+                        if str(e).find('already connected.') != -1:
+                            continue
+                        elif str(e).find('isn\'t accessible') != -1:
+                            dom0.destroyDevice('vbd', loopback_device, force = True, rm_cfg = True)
+                            continue
+                        else:
+                            raise
+                else:
+                    raise
 
             try:
                 blcfg = bootloader(blexec, fn, self, False,
                                    bootloader_args, kernel, ramdisk, args)
             finally:
                 if mounted:
-                    log.info("Unmounting %s from %s." %
-                             (fn, BOOTLOADER_LOOPBACK_DEVICE))
+                    log.info("Unmounting %s from %s." % (fn, loopback_device))
                     if devtype in ['tap', 'tap2']:
-                        dom0.destroyDevice('tap', BOOTLOADER_LOOPBACK_DEVICE, rm_cfg = True)
+                        dom0.destroyDevice('tap', loopback_device, rm_cfg = True)
                     else:
-                        dom0.destroyDevice('vbd', BOOTLOADER_LOOPBACK_DEVICE, rm_cfg = True)
+                        dom0.destroyDevice('vbd', loopback_device, rm_cfg = True)
 
             if blcfg is None:
                 msg = "Had a bootloader specified, but can't find disk"
