[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [blktap] Allow HVM booting from blktap device(s)



# HG changeset patch
# User wim@xxxxxxxxxxxx
# Date 1170895981 28800
# Node ID 6524e02edbeb8aebe65aa5400af4b09dfccb8729
# Parent  780f097b54c5f9161f7c6cf3f86b2bb72cc43587
[blktap] Allow HVM booting from blktap device(s)

Signed-off-by: wim colgate <wim@xxxxxxxxxxxxx>
---
 tools/ioemu/xenstore.c                           |   60 +++++++++++++++++++++-
 tools/python/xen/xend/XendConfig.py              |   41 +++++++++++++++
 tools/python/xen/xend/XendDomainInfo.py          |   56 ++++++++++++++++++++
 tools/python/xen/xend/server/BlktapController.py |   62 +++++++++++++++++++++++
 tools/python/xen/xend/server/DevController.py    |   13 ++++
 5 files changed, 230 insertions(+), 2 deletions(-)

diff -r 780f097b54c5 -r 6524e02edbeb tools/ioemu/xenstore.c
--- a/tools/ioemu/xenstore.c    Wed Feb 07 17:29:52 2007 +0000
+++ b/tools/ioemu/xenstore.c    Wed Feb 07 16:53:01 2007 -0800
@@ -10,6 +10,7 @@
 
 #include "vl.h"
 #include "block_int.h"
+#include <unistd.h>
 
 static struct xs_handle *xsh = NULL;
 static char *hd_filename[MAX_DISKS];
@@ -52,11 +53,40 @@ void xenstore_check_new_media_present(in
     qemu_mod_timer(insert_timer, qemu_get_clock(rt_clock) + timeout);
 }
 
+static int waitForDevice(char *path, char *field, char *desired)
+{ 
+    char *buf = NULL, *stat = NULL;
+    unsigned int len;
+    int val = 1;
+
+    /* loop until we find a value in xenstore, return 
+     * if it was what we wanted, or not
+     */
+    while (1) {
+        if (pasprintf(&buf, "%s/%s", path, field) == -1)
+            goto done;
+        free(stat);
+        stat = xs_read(xsh, XBT_NULL, buf, &len);
+        if (stat == NULL) {
+            usleep(100000); /* 1/10th second, no path found */
+        } else {
+            val = strcmp(stat, desired);
+            goto done;
+        }
+    }
+
+done:
+    free(stat);
+    free(buf);
+    return val;
+}
+
 void xenstore_parse_domain_config(int domid)
 {
     char **e = NULL;
     char *buf = NULL, *path;
-    char *bpath = NULL, *dev = NULL, *params = NULL, *type = NULL;
+    char *fpath = NULL, *bpath = NULL,
+         *dev = NULL, *params = NULL, *type = NULL;
     int i;
     unsigned int len, num, hd_index;
 
@@ -120,7 +150,35 @@ void xenstore_parse_domain_config(int do
            hd_filename[hd_index] = params;     /* strdup() */
            params = NULL;              /* don't free params on re-use */
        }
+        /* 
+         * check if device has a phantom vbd; the phantom is hooked
+         * to the frontend device (for ease of cleanup), so lookup 
+         * the frontend device, and see if there is a phantom_vbd
+         * if there is, we will use resolution as the filename
+         */
+       if (pasprintf(&buf, "%s/device/vbd/%s/phantom_vbd", path, e[i]) == -1)
+           continue;
+       free(fpath);
+        fpath = xs_read(xsh, XBT_NULL, buf, &len);
+       if (fpath != NULL) {
+
+            if (waitForDevice(fpath, "hotplug-status", "connected")) {
+               continue;
+            }
+
+           if (pasprintf(&buf, "%s/dev", fpath) == -1)
+               continue;
+            params = xs_read(xsh, XBT_NULL, buf , &len);
+           if (params != NULL) {
+                free(hd_filename[hd_index]);
+                hd_filename[hd_index] = params;
+                params = NULL;              /* don't free params on re-use */
+            }
+        }
        bs_table[hd_index] = bdrv_new(dev);
+        /* re-establish buf */
+       if (pasprintf(&buf, "%s/params", bpath) == -1)
+           continue;
        /* check if it is a cdrom */
        if (type && !strcmp(type, "cdrom")) {
            bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM);
diff -r 780f097b54c5 -r 6524e02edbeb tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Wed Feb 07 17:29:52 2007 +0000
+++ b/tools/python/xen/xend/XendConfig.py       Wed Feb 07 16:53:01 2007 -0800
@@ -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':
diff -r 780f097b54c5 -r 6524e02edbeb tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Wed Feb 07 17:29:52 2007 +0000
+++ b/tools/python/xen/xend/XendDomainInfo.py   Wed Feb 07 16:53:01 2007 -0800
@@ -1565,18 +1565,53 @@ 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:
@@ -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.
 
diff -r 780f097b54c5 -r 6524e02edbeb 
tools/python/xen/xend/server/BlktapController.py
--- a/tools/python/xen/xend/server/BlktapController.py  Wed Feb 07 17:29:52 
2007 +0000
+++ b/tools/python/xen/xend/server/BlktapController.py  Wed Feb 07 16:53:01 
2007 -0800
@@ -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)
+
diff -r 780f097b54c5 -r 6524e02edbeb 
tools/python/xen/xend/server/DevController.py
--- a/tools/python/xen/xend/server/DevController.py     Wed Feb 07 17:29:52 
2007 +0000
+++ b/tools/python/xen/xend/server/DevController.py     Wed Feb 07 16:53:01 
2007 -0800
@@ -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")
 
 

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.