]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: Add RBD support and some network disk fixes
authorJosh Durgin <joshd@hq.newdream.net>
Tue, 7 Dec 2010 19:56:34 +0000 (11:56 -0800)
committerEric Blake <eblake@redhat.com>
Thu, 9 Dec 2010 21:20:53 +0000 (14:20 -0700)
Changes common to all network disks:
-Make source name optional in the domain schema, since NBD doesn't use it
-Add a hostName type to the domain schema, and use it instead of genericName, which doesn't include .
-Don't leak host names or ports
-Set the source protocol in qemuParseCommandline

Signed-off-by: Josh Durgin <joshd@hq.newdream.net>
AUTHORS
docs/schemas/domain.rng
src/conf/domain_conf.c
src/conf/domain_conf.h
src/qemu/qemu_conf.c

diff --git a/AUTHORS b/AUTHORS
index 7f5a87d5fb703d28cca23831e4d04c027cbc309f..2ee4f980c7662c59b3c63ef100c44e63bc9c5eb5 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -139,6 +139,7 @@ Patches have also been contributed by:
   Hu Tao               <hutao@cn.fujitsu.com>
   Laurent LĂ©onard      <laurent@open-minds.org>
   MORITA Kazutaka      <morita.kazutaka@lab.ntt.co.jp>
+  Josh Durgin          <joshd@hq.newdream.net>
 
   [....send patches to get your name here....]
 
index 44638841d14b450a0c86ef0e2257118c417fe8ba..51aae14791b210768be05f645fd887eba55efbfb 100644 (file)
                     <value>sheepdog</value>
                   </choice>
                 </attribute>
-                <attribute name="name"/>
+                <optional>
+                  <attribute name="name"/>
+                </optional>
                 <zeroOrMore>
                   <element name="host">
                     <attribute name="name">
-                      <ref name="genericName"/>
+                      <ref name="hostName"/>
                     </attribute>
                     <attribute name="port">
                       <ref name="unsignedInt"/>
       <param name="minInclusive">1</param>
     </data>
   </define>
+  <define name="hostName">
+    <data type="string">
+      <param name="pattern">[a-zA-Z0-9\.\-]+</param>
+    </data>
+  </define>
   <define name="PortNumber">
     <data type="short">
       <param name="minInclusive">-1</param>
index 4d11856e9631c643c92035d59de5e85adfc2558a..5b0fd5572003b2d16445946b7d1f6ff2c1d4d443 100644 (file)
@@ -509,21 +509,34 @@ void virDomainInputDefFree(virDomainInputDefPtr def)
 
 void virDomainDiskDefFree(virDomainDiskDefPtr def)
 {
+    unsigned int i;
+
     if (!def)
         return;
 
     VIR_FREE(def->serial);
     VIR_FREE(def->src);
-    VIR_FREE(def->hosts);
     VIR_FREE(def->dst);
     VIR_FREE(def->driverName);
     VIR_FREE(def->driverType);
     virStorageEncryptionFree(def->encryption);
     virDomainDeviceInfoClear(&def->info);
 
+    for (i = 0 ; i < def->nhosts ; i++)
+        virDomainDiskHostDefFree(&def->hosts[i]);
+
     VIR_FREE(def);
 }
 
+void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def)
+{
+    if (!def)
+        return;
+
+    VIR_FREE(def->name);
+    VIR_FREE(def->port);
+}
+
 void virDomainControllerDefFree(virDomainControllerDefPtr def)
 {
     if (!def)
@@ -1644,7 +1657,12 @@ virDomainDiskDefParseXML(virCapsPtr caps,
                                              protocol);
                         goto error;
                     }
-                    source = virXMLPropString(cur, "name");
+                    if (!(source = virXMLPropString(cur, "name")) &&
+                        def->protocol != VIR_DOMAIN_DISK_PROTOCOL_NBD) {
+                        virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+                                             _("missing name for disk source"));
+                        goto error;
+                    }
                     host = cur->children;
                     while (host != NULL) {
                         if (host->type == XML_ELEMENT_NODE &&
@@ -1877,8 +1895,7 @@ cleanup:
     VIR_FREE(target);
     VIR_FREE(source);
     while (nhosts > 0) {
-        VIR_FREE(hosts[nhosts - 1].name);
-        VIR_FREE(hosts[nhosts - 1].port);
+        virDomainDiskHostDefFree(&hosts[nhosts - 1]);
         nhosts--;
     }
     VIR_FREE(hosts);
index e62320db8b7a08586e23898a0c2c2200ef4f967f..a459a22fa631b6b3309f1d20acb4401e5d6ac9c5 100644 (file)
@@ -1071,6 +1071,7 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
 void virDomainGraphicsDefFree(virDomainGraphicsDefPtr def);
 void virDomainInputDefFree(virDomainInputDefPtr def);
 void virDomainDiskDefFree(virDomainDiskDefPtr def);
+void virDomainDiskHostDefFree(virDomainDiskHostDefPtr def);
 void virDomainControllerDefFree(virDomainControllerDefPtr def);
 void virDomainFSDefFree(virDomainFSDefPtr def);
 void virDomainNetDefFree(virDomainNetDefPtr def);
index c14005eb26a081d1f948f200726a680eadfce761..fb0b29a244b24ba30a9920e06ec22c1ab750d2c3 100644 (file)
@@ -4026,6 +4026,8 @@ qemudBuildCommandLine(virConnectPtr conn,
     int last_good_net = -1;
     bool hasHwVirt = false;
     virCommandPtr cmd;
+    bool has_rbd_hosts = false;
+    virBuffer rbd_hosts = VIR_BUFFER_INITIALIZER;
 
     uname_normalize(&ut);
 
@@ -4566,6 +4568,7 @@ qemudBuildCommandLine(virConnectPtr conn,
             int bootable = 0;
             virDomainDiskDefPtr disk = def->disks[i];
             int withDeviceArg = 0;
+            int j;
 
             /* Unless we have -device, then USB disks need special
                handling */
@@ -4615,6 +4618,27 @@ qemudBuildCommandLine(virConnectPtr conn,
             virCommandAddArg(cmd, optstr);
             VIR_FREE(optstr);
 
+            if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+                disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
+                for (j = 0 ; j < disk->nhosts ; j++) {
+                    if (!has_rbd_hosts) {
+                        virBufferAddLit(&rbd_hosts, "-m ");
+                        has_rbd_hosts = true;
+                    } else {
+                        virBufferAddLit(&rbd_hosts, ",");
+                    }
+                    virDomainDiskHostDefPtr host = &disk->hosts[j];
+                    if (host->port) {
+                        virBufferVSprintf(&rbd_hosts, "%s:%s",
+                                          host->name,
+                                          host->port);
+                    } else {
+                        virBufferVSprintf(&rbd_hosts, "%s",
+                                          host->name);
+                    }
+                }
+            }
+
             if (withDeviceArg) {
                 if (disk->bus == VIR_DOMAIN_DISK_BUS_FDC) {
                     virCommandAddArg(cmd, "-global");
@@ -4637,6 +4661,7 @@ qemudBuildCommandLine(virConnectPtr conn,
             char dev[NAME_MAX];
             char file[PATH_MAX];
             virDomainDiskDefPtr disk = def->disks[i];
+            int j;
 
             if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
                 if (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
@@ -4700,6 +4725,23 @@ qemudBuildCommandLine(virConnectPtr conn,
                     break;
                 case VIR_DOMAIN_DISK_PROTOCOL_RBD:
                     snprintf(file, PATH_MAX, "rbd:%s,", disk->src);
+                    for (j = 0 ; j < disk->nhosts ; j++) {
+                        if (!has_rbd_hosts) {
+                            virBufferAddLit(&rbd_hosts, "-m ");
+                            has_rbd_hosts = true;
+                        } else {
+                            virBufferAddLit(&rbd_hosts, ",");
+                        }
+                        virDomainDiskHostDefPtr host = &disk->hosts[j];
+                        if (host->port) {
+                            virBufferVSprintf(&rbd_hosts, "%s:%s",
+                                              host->name,
+                                              host->port);
+                        } else {
+                            virBufferVSprintf(&rbd_hosts, "%s",
+                                              host->name);
+                        }
+                    }
                     break;
                 case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
                     if (disk->nhosts == 0)
@@ -4719,6 +4761,13 @@ qemudBuildCommandLine(virConnectPtr conn,
         }
     }
 
+    if (virBufferError(&rbd_hosts)) {
+        virBufferFreeAndReset(&rbd_hosts);
+        goto no_memory;
+    }
+    if (has_rbd_hosts)
+        virCommandAddEnvPair(cmd, "CEPH_ARGS", virBufferContentAndReset(&rbd_hosts));
+
     if (qemuCmdFlags & QEMUD_CMD_FLAG_FSDEV) {
         for (i = 0 ; i < def->nfss ; i++) {
             char *optstr;
@@ -5488,6 +5537,7 @@ static int qemuStringToArgvEnv(const char *args,
     int envend;
     int i;
     const char *curr = args;
+    const char *start;
     const char **progenv = NULL;
     const char **progargv = NULL;
 
@@ -5495,14 +5545,22 @@ static int qemuStringToArgvEnv(const char *args,
     while (curr && *curr != '\0') {
         char *arg;
         const char *next;
-        if (*curr == '\'') {
-            curr++;
-            next = strchr(curr, '\'');
-        } else if (*curr == '"') {
-            curr++;
-            next = strchr(curr, '"');
+
+        start = curr;
+        /* accept a space in CEPH_ARGS */
+        if (STRPREFIX(curr, "CEPH_ARGS=-m ")) {
+            start += strlen("CEPH_ARGS=-m ");
+        }
+        if (*start == '\'') {
+            if (start == curr)
+                curr++;
+            next = strchr(start + 1, '\'');
+        } else if (*start == '"') {
+            if (start == curr)
+                curr++;
+            next = strchr(start + 1, '"');
         } else {
-            next = strchr(curr, ' ');
+            next = strchr(start, ' ');
         }
         if (!next)
             next = strchr(curr, '\n');
@@ -5732,6 +5790,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
                     char *host, *port;
 
                     def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_NBD;
                     host = def->src + strlen("nbd:");
                     port = strchr(host, ':');
                     if (!port) {
@@ -5763,6 +5822,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
                     char *p = def->src;
 
                     def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_RBD;
                     def->src = strdup(p + strlen("rbd:"));
                     if (!def->src) {
                         virReportOOMError();
@@ -5775,6 +5835,7 @@ qemuParseCommandLineDisk(virCapsPtr caps,
                     char *port, *vdi;
 
                     def->type = VIR_DOMAIN_DISK_TYPE_NETWORK;
+                    def->protocol = VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG;
                     def->src = strdup(p + strlen("sheepdog:"));
                     if (!def->src) {
                         virReportOOMError();
@@ -5890,7 +5951,8 @@ qemuParseCommandLineDisk(virCapsPtr caps,
     }
 
     if (!def->src &&
-        def->device == VIR_DOMAIN_DISK_DEVICE_DISK) {
+        def->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+        def->type != VIR_DOMAIN_DISK_TYPE_NETWORK) {
         qemuReportError(VIR_ERR_INTERNAL_ERROR,
                         _("missing file parameter in drive '%s'"), val);
         virDomainDiskDefFree(def);
@@ -6810,7 +6872,7 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
                     disk->src = NULL;
                     break;
                 case VIR_DOMAIN_DISK_PROTOCOL_RBD:
-                    /* TODO: set monitor hostnames */
+                    /* handled later since the hosts for all disks are in CEPH_ARGS */
                     break;
                 case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
                     /* disk->src must be [vdiname] or [host]:[port]:[vdiname] */
@@ -7137,6 +7199,69 @@ virDomainDefPtr qemuParseCommandLine(virCapsPtr caps,
     }
 
 #undef WANT_VALUE
+    if (def->ndisks > 0) {
+        const char *ceph_args = qemuFindEnv(progenv, "CEPH_ARGS");
+        if (ceph_args) {
+            char *hosts, *port, *saveptr, *token;
+            virDomainDiskDefPtr first_rbd_disk = NULL;
+            for (i = 0 ; i < def->ndisks ; i++) {
+                virDomainDiskDefPtr disk = def->disks[i];
+                if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+                    disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD) {
+                    first_rbd_disk = disk;
+                    break;
+                }
+            }
+
+            if (!first_rbd_disk) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("CEPH_ARGS was set without an rbd disk"));
+                goto error;
+            }
+
+            /* CEPH_ARGS should be: -m host1[:port1][,host2[:port2]]... */
+            if (!STRPREFIX(ceph_args, "-m ")) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("could not parse CEPH_ARGS '%s'"), ceph_args);
+                goto error;
+            }
+            hosts = strdup(strchr(ceph_args, ' ') + 1);
+            if (!hosts)
+                goto no_memory;
+            first_rbd_disk->nhosts = 0;
+            token = strtok_r(hosts, ",", &saveptr);
+            while (token != NULL) {
+                if (VIR_REALLOC_N(first_rbd_disk->hosts, first_rbd_disk->nhosts + 1) < 0) {
+                    VIR_FREE(hosts);
+                    goto no_memory;
+                }
+                port = strchr(token, ':');
+                if (port) {
+                    *port++ = '\0';
+                    port = strdup(port);
+                    if (!port) {
+                        VIR_FREE(hosts);
+                        goto no_memory;
+                    }
+                }
+                first_rbd_disk->hosts[first_rbd_disk->nhosts].port = port;
+                first_rbd_disk->hosts[first_rbd_disk->nhosts].name = strdup(token);
+                if (!first_rbd_disk->hosts[first_rbd_disk->nhosts].name) {
+                    VIR_FREE(hosts);
+                    goto no_memory;
+                }
+                first_rbd_disk->nhosts++;
+                token = strtok_r(NULL, ",", &saveptr);
+            }
+            VIR_FREE(hosts);
+
+            if (first_rbd_disk->nhosts == 0) {
+                qemuReportError(VIR_ERR_INTERNAL_ERROR,
+                                _("found no rbd hosts in CEPH_ARGS '%s'"), ceph_args);
+                goto error;
+            }
+        }
+    }
 
     if (!nographics && def->ngraphics == 0) {
         virDomainGraphicsDefPtr sdl;