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.1.1-testing/tools/python/xen/xend/XendDomainInfo.py
===================================================================
--- xen-4.1.1-testing.orig/tools/python/xen/xend/XendDomainInfo.py
+++ xen-4.1.1-testing/tools/python/xen/xend/XendDomainInfo.py
@@ -74,7 +74,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()
@@ -3298,33 +3298,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);
-                vbd_uuid = dom0.create_vbd(vbd, disk)
-                dom0._waitForDeviceFrontUUID(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()
+                        vbd_uuid = dom0.create_vbd(vbd, disk)
+                        dom0._waitForDeviceFrontUUID(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))
+                             (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"
                 log.error(msg)