On 01/30/2013 01:11 PM, Osier Yang wrote: > With this patch, one can specify the disk source using libvirt > storage like: > > <disk type='volume' device='disk'> > <driver name='qemu' type='raw' cache='none'/> > <source pool='default' volume='fc18.img'/> > <target dev='vdb' bus='virtio'/> > </disk> > > "seclables" and "startupPolicy" are not supported for this new > disk type ("volume"). They will be supported in later patches. > > docs/formatdomain.html.in: > * Add documents for new XMLs > docs/schemas/domaincommon.rng: > * Add rng for new XMLs; > src/conf/domain_conf.h: > * New struct for 'volume' type disk source (virDomainDiskSourcePoolDef) > * Add VIR_DOMAIN_DISK_TYPE_VOLUME for enum virDomainDiskType > src/conf/domain_conf.c: > * New helper virDomainDiskSourcePoolDefParse to parse the 'volume' > type disk source. > * New helper virDomainDiskSourcePoolDefFree to free the source def > if 'volume' type disk. > * New helper virDomainDiskSourceDefFormat to format the disk source. > tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml: > tests/qemuxml2xmltest.c: > * New test > > --- > The data struct for disk source should be tidied up. It's a mess > now, but it will be later patches. > --- > docs/formatdomain.html.in | 17 +- > docs/schemas/domaincommon.rng | 18 ++ > src/conf/domain_conf.c | 259 +++++++++++++------- > src/conf/domain_conf.h | 9 + > .../qemuxml2argv-disk-source-pool.xml | 33 +++ > tests/qemuxml2xmltest.c | 1 + > 6 files changed, 247 insertions(+), 90 deletions(-) > create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml > > diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in > index 7ad8aea..ac5657a 100644 > --- a/docs/formatdomain.html.in > +++ b/docs/formatdomain.html.in > @@ -1367,6 +1367,11 @@ > <blockio logical_block_size='512' physical_block_size='4096'/> > <target dev='hda' bus='ide'/> > </disk> > + <disk type='volume' device='disk'> > + <driver name='qemu' type='raw'/> > + <source pool='blk-pool0' volume='blk-pool0-vol0'/> > + <target dev='hda' bus='ide'/> > + </disk> > </devices> > ...</pre> > > @@ -1374,7 +1379,7 @@ > <dt><code>disk</code></dt> > <dd>The <code>disk</code> element is the main container for describing > disks. The <code>type</code> attribute is either "file", > - "block", "dir", or "network" > + "block", "dir", "network", or "volume". > and refers to the underlying source for the disk. The optional > <code>device</code> attribute indicates how the disk is to be exposed > to the guest OS. Possible values for this attribute are > @@ -1444,9 +1449,15 @@ > volume/image will be used. When the disk <code>type</code> is > "network", the <code>source</code> may have zero or > more <code>host</code> sub-elements used to specify the hosts > - to connect. > + to connect. If the disk <code>type</code> is "volume", the underlying > + disk source is represented by attributes <code>pool</code> and > + <code>volume</code>. Attribute <code>pool</code> specifies the > + name of storage pool (managed by libvirt) where the disk source resides, > + and attribute <code>volume</code> specifies the name of storage volume > + (managed by libvirt) used as the disk source. > <span class="since">Since 0.0.3; <code>type='dir'</code> since > - 0.7.5; <code>type='network'</code> since 0.8.7</span><br/> > + 0.7.5; <code>type='network'</code> since 0.8.7; > + <code>type='volume'</code> since 1.0.3</span><br/> > For a "file" disk type which represents a cdrom or floppy > (the <code>device</code> attribute), it is possible to define > policy what to do with the disk if the source file is not accessible. > diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng > index 87653ce..88612ae 100644 > --- a/docs/schemas/domaincommon.rng > +++ b/docs/schemas/domaincommon.rng > @@ -1081,6 +1081,24 @@ > <ref name="diskspec"/> > </interleave> > </group> > + <group> > + <attribute name="type"> > + <value>volume</value> > + </attribute> > + <interleave> > + <optional> > + <element name="source"> > + <attribute name="pool"> > + <ref name="genericName"/> > + </attribute> > + <attribute name="volume"> > + <ref name="volName"/> > + </attribute> > + </element> > + </optional> > + <ref name="diskspec"/> > + </interleave> > + </group> > <ref name="diskspec"/> > </choice> > </element> > diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c > index 8dbfb96..5e65406 100644 > --- a/src/conf/domain_conf.c > +++ b/src/conf/domain_conf.c > @@ -182,7 +182,8 @@ VIR_ENUM_IMPL(virDomainDisk, VIR_DOMAIN_DISK_TYPE_LAST, > "block", > "file", > "dir", > - "network") > + "network", > + "volume") > > VIR_ENUM_IMPL(virDomainDiskDevice, VIR_DOMAIN_DISK_DEVICE_LAST, > "disk", > @@ -985,6 +986,18 @@ void virDomainLeaseDefFree(virDomainLeaseDefPtr def) > VIR_FREE(def); > } > > +static void > +virDomainDiskSourcePoolDefFree(virDomainDiskSourcePoolDefPtr def) > +{ > + if (!def) > + return; > + > + VIR_FREE(def->pool); > + VIR_FREE(def->volume); > + > + VIR_FREE(def); > +} > + > void virDomainDiskDefFree(virDomainDiskDefPtr def) > { > unsigned int i; > @@ -994,6 +1007,7 @@ void virDomainDiskDefFree(virDomainDiskDefPtr def) > > VIR_FREE(def->serial); > VIR_FREE(def->src); > + virDomainDiskSourcePoolDefFree(def->srcpool); > VIR_FREE(def->dst); > VIR_FREE(def->driverName); > virStorageFileFreeMetadata(def->backingChain); > @@ -3573,6 +3587,46 @@ cleanup: > goto cleanup; > } > > +static int > +virDomainDiskSourcePoolDefParse(xmlNodePtr node, > + virDomainDiskDefPtr def) > +{ > + char *pool = NULL; > + char *volume = NULL; > + int ret = -1; > + > + pool = virXMLPropString(node, "pool"); > + volume = virXMLPropString(node, "volume"); > + > + /* CD-ROM and Floppy allows no source */ > + if (!pool && !volume) > + return 0; > + > + if ((!pool && volume) || (pool && !volume)) { > + virReportError(VIR_ERR_XML_ERROR, "%s", > + _("'pool' and 'volume' must be specified together " > + "for 'pool' type source")); > + goto cleanup; > + } Couldn't this be simplified to "if (!pool || !volume) {"? > + > + if (VIR_ALLOC(def->srcpool) < 0) { > + virReportOOMError(); > + goto cleanup; > + } > + > + def->srcpool->pool = pool; > + pool = NULL; > + def->srcpool->volume = volume; > + volume = NULL; > + > + ret = 0; > + > +cleanup: > + VIR_FREE(pool); > + VIR_FREE(volume); > + return ret; > +} > + > #define VENDOR_LEN 8 > #define PRODUCT_LEN 16 > > @@ -3666,7 +3720,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, > cur = node->children; > while (cur != NULL) { > if (cur->type == XML_ELEMENT_NODE) { > - if (!source && !hosts && > + if (!source && !hosts && !def->srcpool && > xmlStrEqual(cur->name, BAD_CAST "source")) { > > sourceNode = cur; > @@ -3760,6 +3814,10 @@ virDomainDiskDefParseXML(virCapsPtr caps, > child = child->next; > } > break; > + case VIR_DOMAIN_DISK_TYPE_VOLUME: > + if (virDomainDiskSourcePoolDefParse(cur, def) < 0) > + goto error; > + break; > default: > virReportError(VIR_ERR_INTERNAL_ERROR, > _("unexpected disk type %s"), > @@ -4050,7 +4108,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, > > /* Only CDROM and Floppy devices are allowed missing source path > * to indicate no media present */ > - if (source == NULL && hosts == NULL && > + if (!source && !hosts && !def->srcpool && > def->device != VIR_DOMAIN_DISK_DEVICE_CDROM && > def->device != VIR_DOMAIN_DISK_DEVICE_FLOPPY) { > virReportError(VIR_ERR_NO_SOURCE, > @@ -4072,8 +4130,19 @@ virDomainDiskDefParseXML(virCapsPtr caps, > } > > if (target == NULL) { > - virReportError(VIR_ERR_NO_TARGET, > - source ? "%s" : NULL, source); > + if (def->srcpool) { > + char *tmp; > + if (virAsprintf(&tmp, "pool = '%s', volume = '%s'", > + def->srcpool->pool, def->srcpool->volume) < 0) { > + virReportOOMError(); > + goto error; > + } > + > + virReportError(VIR_ERR_NO_TARGET, "%s", tmp); > + VIR_FREE(tmp); > + } else { > + virReportError(VIR_ERR_NO_TARGET, source ? "%s" : NULL, source); > + } > goto error; > } > > @@ -12168,6 +12237,102 @@ static void virDomainDiskBlockIoDefFormat(virBufferPtr buf, > } > } > > +static int > +virDomainDiskSourceDefFormat(virBufferPtr buf, > + virDomainDiskDefPtr def) > +{ > + int n; > + const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy); > + > + if (def->src || def->nhosts > 0 || def->srcpool || > + def->startupPolicy) { > + switch (def->type) { > + case VIR_DOMAIN_DISK_TYPE_FILE: What happened to virBufferAddLit() here? > + if (def->src) > + virBufferEscapeString(buf, " <source file='%s'", def->src); If (!def->src), then startupPolicy and nseclabels won't have "<source " - whether that's realistic I'm not sure (still learning). If def->src cannot be NULL like other case labels, then no need to check. It seems from other code I read that it must be set. > + if (def->startupPolicy) > + virBufferEscapeString(buf, " startupPolicy='%s'", > + startupPolicy); > + if (def->nseclabels) { > + virBufferAddLit(buf, ">\n"); > + virBufferAdjustIndent(buf, 8); > + for (n = 0; n < def->nseclabels; n++) > + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); > + virBufferAdjustIndent(buf, -8); > + virBufferAddLit(buf, " </source>\n"); > + } else { > + virBufferAddLit(buf, "/>\n"); > + } > + break; > + case VIR_DOMAIN_DISK_TYPE_BLOCK: > + virBufferEscapeString(buf, " <source dev='%s'", > + def->src); > + if (def->nseclabels) { > + virBufferAddLit(buf, ">\n"); > + virBufferAdjustIndent(buf, 8); > + for (n = 0; n < def->nseclabels; n++) > + virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); > + virBufferAdjustIndent(buf, -8); > + virBufferAddLit(buf, " </source>\n"); > + } else { > + virBufferAddLit(buf, "/>\n"); > + } > + break; > + case VIR_DOMAIN_DISK_TYPE_DIR: > + virBufferEscapeString(buf, " <source dir='%s'/>\n", > + def->src); > + break; > + case VIR_DOMAIN_DISK_TYPE_NETWORK: > + virBufferAsprintf(buf, " <source protocol='%s'", > + virDomainDiskProtocolTypeToString(def->protocol)); > + if (def->src) { > + virBufferEscapeString(buf, " name='%s'", def->src); > + } > + if (def->nhosts == 0) { > + virBufferAddLit(buf, "/>\n"); > + } else { > + int i; > + > + virBufferAddLit(buf, ">\n"); > + for (i = 0; i < def->nhosts; i++) { > + virBufferAddLit(buf, " <host"); > + if (def->hosts[i].name) { > + virBufferEscapeString(buf, " name='%s'", def->hosts[i].name); > + } > + if (def->hosts[i].port) { > + virBufferEscapeString(buf, " port='%s'", > + def->hosts[i].port); > + } > + if (def->hosts[i].transport) { > + virBufferAsprintf(buf, " transport='%s'", > + virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport)); > + } > + if (def->hosts[i].socket) { > + virBufferEscapeString(buf, " socket='%s'", def->hosts[i].socket); > + } > + virBufferAddLit(buf, "/>\n"); > + } > + virBufferAddLit(buf, " </source>\n"); > + } > + break; > + case VIR_DOMAIN_DISK_TYPE_VOLUME: > + /* Parsing guarantees the def->srcpool->volume cannot be NULL > + * if def->srcpool->pool is not NULL. > + */ > + if (def->srcpool->pool) > + virBufferAsprintf(buf, " <source pool='%s' volume='%s'/>\n", > + def->srcpool->pool, def->srcpool->volume); > + break; > + default: > + virReportError(VIR_ERR_INTERNAL_ERROR, > + _("unexpected disk type %s"), > + virDomainDiskTypeToString(def->type)); > + return -1; > + } > + } > + > + return 0; > +} > > static int > virDomainDiskDefFormat(virBufferPtr buf, > @@ -12184,10 +12349,8 @@ virDomainDiskDefFormat(virBufferPtr buf, > const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd); > const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx); > const char *copy_on_read = virDomainVirtioEventIdxTypeToString(def->copy_on_read); > - const char *startupPolicy = virDomainStartupPolicyTypeToString(def->startupPolicy); > const char *sgio = virDomainDiskSGIOTypeToString(def->sgio); > > - int n; > char uuidstr[VIR_UUID_STRING_BUFLEN]; > > if (!type) { > @@ -12283,86 +12446,8 @@ virDomainDiskDefFormat(virBufferPtr buf, > virBufferAddLit(buf, " </auth>\n"); > } > > - if (def->src || def->nhosts > 0 || > - def->startupPolicy) { > - switch (def->type) { > - case VIR_DOMAIN_DISK_TYPE_FILE: > - virBufferAddLit(buf," <source"); > - if (def->src) > - virBufferEscapeString(buf, " file='%s'", def->src); > - if (def->startupPolicy) > - virBufferEscapeString(buf, " startupPolicy='%s'", > - startupPolicy); > - if (def->nseclabels) { > - virBufferAddLit(buf, ">\n"); > - virBufferAdjustIndent(buf, 8); > - for (n = 0; n < def->nseclabels; n++) > - virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); > - virBufferAdjustIndent(buf, -8); > - virBufferAddLit(buf, " </source>\n"); > - } else { > - virBufferAddLit(buf, "/>\n"); > - } > - break; > - case VIR_DOMAIN_DISK_TYPE_BLOCK: > - virBufferEscapeString(buf, " <source dev='%s'", > - def->src); > - if (def->nseclabels) { > - virBufferAddLit(buf, ">\n"); > - virBufferAdjustIndent(buf, 8); > - for (n = 0; n < def->nseclabels; n++) > - virSecurityDeviceLabelDefFormat(buf, def->seclabels[n]); > - virBufferAdjustIndent(buf, -8); > - virBufferAddLit(buf, " </source>\n"); > - } else { > - virBufferAddLit(buf, "/>\n"); > - } > - break; > - case VIR_DOMAIN_DISK_TYPE_DIR: > - virBufferEscapeString(buf, " <source dir='%s'/>\n", > - def->src); > - break; > - case VIR_DOMAIN_DISK_TYPE_NETWORK: > - virBufferAsprintf(buf, " <source protocol='%s'", > - virDomainDiskProtocolTypeToString(def->protocol)); > - if (def->src) { > - virBufferEscapeString(buf, " name='%s'", def->src); > - } > - if (def->nhosts == 0) { > - virBufferAddLit(buf, "/>\n"); > - } else { > - int i; > - > - virBufferAddLit(buf, ">\n"); > - for (i = 0; i < def->nhosts; i++) { > - virBufferAddLit(buf, " <host"); > - if (def->hosts[i].name) { > - virBufferEscapeString(buf, " name='%s'", def->hosts[i].name); > - } > - if (def->hosts[i].port) { > - virBufferEscapeString(buf, " port='%s'", > - def->hosts[i].port); > - } > - if (def->hosts[i].transport) { > - virBufferAsprintf(buf, " transport='%s'", > - virDomainDiskProtocolTransportTypeToString(def->hosts[i].transport)); > - } > - if (def->hosts[i].socket) { > - virBufferEscapeString(buf, " socket='%s'", def->hosts[i].socket); > - } > - virBufferAddLit(buf, "/>\n"); > - } > - virBufferAddLit(buf, " </source>\n"); > - } > - break; > - default: > - virReportError(VIR_ERR_INTERNAL_ERROR, > - _("unexpected disk type %s"), > - virDomainDiskTypeToString(def->type)); > - return -1; > - } > - } > - > + if (virDomainDiskSourceDefFormat(buf, def) < 0) > + return -1; > virDomainDiskGeometryDefFormat(buf, def); > virDomainDiskBlockIoDefFormat(buf, def); > > diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h > index 9a9e0b1..9919db3 100644 > --- a/src/conf/domain_conf.h > +++ b/src/conf/domain_conf.h > @@ -427,6 +427,7 @@ enum virDomainDiskType { > VIR_DOMAIN_DISK_TYPE_FILE, > VIR_DOMAIN_DISK_TYPE_DIR, > VIR_DOMAIN_DISK_TYPE_NETWORK, > + VIR_DOMAIN_DISK_TYPE_VOLUME, > > VIR_DOMAIN_DISK_TYPE_LAST > }; > @@ -585,6 +586,13 @@ struct _virDomainBlockIoTuneInfo { > }; > typedef virDomainBlockIoTuneInfo *virDomainBlockIoTuneInfoPtr; > > +typedef struct _virDomainDiskSourcePoolDef virDomainDiskSourcePoolDef; > +struct _virDomainDiskSourcePoolDef { > + char *pool; /* pool name */ > + char *volume; /* volume name */ > +}; > +typedef virDomainDiskSourcePoolDef *virDomainDiskSourcePoolDefPtr; > + > /* Stores the virtual disk configuration */ > struct _virDomainDiskDef { > int type; > @@ -596,6 +604,7 @@ struct _virDomainDiskDef { > int protocol; > size_t nhosts; > virDomainDiskHostDefPtr hosts; > + virDomainDiskSourcePoolDefPtr srcpool; > struct { > char *username; > int secretType; /* enum virDomainDiskSecretType */ > diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml > new file mode 100644 > index 0000000..876eebe > --- /dev/null > +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-source-pool.xml > @@ -0,0 +1,33 @@ > +<domain type='qemu'> > + <name>QEMUGuest1</name> > + <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid> > + <memory unit='KiB'>219136</memory> > + <currentMemory unit='KiB'>219136</currentMemory> > + <vcpu placement='static'>1</vcpu> > + <os> > + <type arch='i686' machine='pc'>hvm</type> > + <boot dev='hd'/> > + </os> > + <clock offset='utc'/> > + <on_poweroff>destroy</on_poweroff> > + <on_reboot>restart</on_reboot> > + <on_crash>destroy</on_crash> > + <devices> > + <emulator>/usr/bin/qemu</emulator> > + <disk type='volume' device='cdrom'> > + <source pool='blk-pool0' volume='blk-pool0-vol0'/> > + <target dev='hda' bus='ide'/> > + <readonly/> > + <address type='drive' controller='0' bus='0' target='0' unit='1'/> > + </disk> > + <disk type='file' device='disk'> > + <source file='/tmp/idedisk.img'/> > + <target dev='hdc' bus='ide'/> > + <address type='drive' controller='0' bus='0' target='0' unit='2'/> > + </disk> > + <controller type='usb' index='0'/> > + <controller type='ide' index='0'/> > + <controller type='ide' index='1'/> > + <memballoon model='virtio'/> > + </devices> > +</domain> > diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c > index 160e958..7e174dd 100644 > --- a/tests/qemuxml2xmltest.c > +++ b/tests/qemuxml2xmltest.c > @@ -241,6 +241,7 @@ mymain(void) > DO_TEST("disk-scsi-lun-passthrough-sgio"); > > DO_TEST("disk-scsi-disk-vpd"); > + DO_TEST("disk-source-pool"); > > /* These tests generate different XML */ > DO_TEST_DIFFERENT("balloon-device-auto"); > ACK - although my knowledge of the xml format/parse is still getting up to speed. -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list