qemu: Add RBD support and some network disk fixes

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>
This commit is contained in:
Josh Durgin 2010-12-07 11:56:34 -08:00 committed by Eric Blake
parent 036ad5052b
commit 85400fb992
5 changed files with 166 additions and 15 deletions

View File

@ -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....]

View File

@ -626,11 +626,13 @@
<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"/>
@ -2024,6 +2026,11 @@
<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>

View 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);

View 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);

View 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;