[libvirt] [PATCH 1/2] blockcommit: track job type in xml
by Eric Blake
A future patch is going to wire up qemu active block commit jobs;
but as they have similar events and are canceled/pivoted in the
same way as block copy jobs, it is easiest to track all bookkeeping
for the commit job by reusing the <mirror> element. This patch
adds domain XML to track which job was responsible for creating a
mirroring situation, and adds a job='copy' attribute to all
existing uses of <mirror>. Along the way, it also massages the
qemu monitor backend to read the new field in order to generate
the correct type of libvirt job (even though it requires a
future patch to actually cause a qemu event that can be reported
as an active commit).
* docs/schemas/domaincommon.rng: Enhance schema.
* docs/formatdomain.html.in: Document it.
* src/conf/domain_conf.h (_virDomainDiskDef): Add a field.
* src/conf/domain_conf.c (virDomainBlockJobType): String conversion.
(virDomainDiskDefParseXML): Parse job type.
(virDomainDiskDefFormat): Output job type.
* src/qemu/qemu_process.c (qemuProcessHandleBlockJob): Distinguish
active from regular commit.
* src/qemu/qemu_driver.c (qemuDomainBlockCopy): Set job type.
(qemuDomainBlockPivot, qemuDomainBlockJobImpl): Clean up job type
on completion.
* tests/qemuxml2xmloutdata/qemuxml2xmlout-disk-mirror-old.xml:
Update tests.
* tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml: Likewise.
* tests/qemuxml2argvdata/qemuxml2argv-disk-active-commit.xml: New
file.
* tests/qemuxml2xmltest.c (mymain): Drive new test.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
docs/formatdomain.html.in | 21 ++++++------
docs/schemas/domaincommon.rng | 13 ++++++++
src/conf/domain_conf.c | 33 ++++++++++++++++++-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_driver.c | 3 ++
src/qemu/qemu_process.c | 18 +++++++----
.../qemuxml2argv-disk-active-commit.xml | 37 ++++++++++++++++++++++
.../qemuxml2argvdata/qemuxml2argv-disk-mirror.xml | 4 +--
.../qemuxml2xmlout-disk-mirror-old.xml | 4 +--
tests/qemuxml2xmltest.c | 1 +
10 files changed, 114 insertions(+), 21 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-active-commit.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 8950959..7593b55 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1898,16 +1898,19 @@
</dd>
<dt><code>mirror</code></dt>
<dd>
- This element is present if the hypervisor has started a block
- copy operation (via the <code>virDomainBlockRebase</code>
- API), where the mirror location in the <code>source</code>
- sub-element will eventually have the same contents as the
- source, and with the file format in the
+ This element is present if the hypervisor has started a
+ long-running block job operation, where the mirror location in
+ the <code>source</code> sub-element will eventually have the
+ same contents as the source, and with the file format in the
sub-element <code>format</code> (which might differ from the
- format of the source). The details of the <code>source</code>
- sub-element are determined by the <code>type</code> attribute
- of the mirror, similar to what is done for the
- overall <code>disk</code> device element. If
+ format of the source). The <code>job</code> attribute
+ mentions which API started the operation ("copy" for
+ the <code>virDomainBlockRebase</code> API, or "active-commit"
+ for the <code>virDomainBlockCommit</code>
+ API), <span class="since">since 1.2.7</span>. The details
+ of the <code>source</code> sub-element are determined by
+ the <code>type</code> attribute of the mirror, similar to what
+ is done for the overall <code>disk</code> device element. If
attribute <code>ready</code> is present, then it is known the
disk is ready to pivot; otherwise, the disk is probably still
copying. For now, this element only valid in output; it is
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 835bd3c..231c743 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4262,6 +4262,13 @@
</attribute>
</optional>
<optional>
+ <attribute name='job'>
+ <choice>
+ <value>copy</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
<interleave>
<ref name='diskSourceFile'/>
<optional>
@@ -4271,6 +4278,12 @@
</optional>
</group>
<group> <!-- preferred format -->
+ <attribute name='job'>
+ <choice>
+ <value>copy</value>
+ <value>active-commit</value>
+ </choice>
+ </attribute>
<interleave>
<ref name="diskSource"/>
<optional>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 1e27165..4b00280 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -761,6 +761,12 @@ VIR_ENUM_IMPL(virDomainDiskDiscard, VIR_DOMAIN_DISK_DISCARD_LAST,
"unmap",
"ignore")
+/* Internal mapping: subset of block job types that can be present in
+ * <mirror> XML (remaining types are not two-phase). */
+VIR_ENUM_DECL(virDomainBlockJob)
+VIR_ENUM_IMPL(virDomainBlockJob, VIR_DOMAIN_BLOCK_JOB_TYPE_LAST,
+ "", "", "copy", "", "active-commit")
+
#define VIR_DOMAIN_XML_WRITE_FLAGS VIR_DOMAIN_XML_SECURE
#define VIR_DOMAIN_XML_READ_FLAGS VIR_DOMAIN_XML_INACTIVE
@@ -5406,10 +5412,26 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
xmlStrEqual(cur->name, BAD_CAST "mirror") &&
!(flags & VIR_DOMAIN_XML_INACTIVE)) {
char *ready;
+ char *blockJob;
if (VIR_ALLOC(def->mirror) < 0)
goto error;
+ blockJob = virXMLPropString(cur, "job");
+ if (blockJob) {
+ def->mirrorJob = virDomainBlockJobTypeFromString(blockJob);
+ if (def->mirrorJob <= 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown mirror job type '%s'"),
+ blockJob);
+ VIR_FREE(blockJob);
+ goto error;
+ }
+ VIR_FREE(blockJob);
+ } else {
+ def->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
+ }
+
mirrorType = virXMLPropString(cur, "type");
if (mirrorType) {
def->mirror->type = virStorageTypeFromString(mirrorType);
@@ -5432,6 +5454,12 @@ virDomainDiskDefParseXML(virDomainXMLOptionPtr xmlopt,
_("mirror requires file name"));
goto error;
}
+ if (def->mirrorJob != VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("mirror without type only supported "
+ "by copy job"));
+ goto error;
+ }
mirrorFormat = virXMLPropString(cur, "format");
}
if (mirrorFormat) {
@@ -15163,10 +15191,13 @@ virDomainDiskDefFormat(virBufferPtr buf,
formatStr = virStorageFileFormatTypeToString(def->mirror->format);
virBufferAsprintf(buf, "<mirror type='%s'",
virStorageTypeToString(def->mirror->type));
- if (def->mirror->type == VIR_STORAGE_TYPE_FILE) {
+ if (def->mirror->type == VIR_STORAGE_TYPE_FILE &&
+ def->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
virBufferEscapeString(buf, " file='%s'", def->mirror->path);
virBufferEscapeString(buf, " format='%s'", formatStr);
}
+ virBufferEscapeString(buf, " job='%s'",
+ virDomainBlockJobTypeToString(def->mirrorJob));
if (def->mirroring)
virBufferAddLit(buf, " ready='yes'");
virBufferAddLit(buf, ">\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index cd3293b..f5eb031 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -614,6 +614,7 @@ struct _virDomainDiskDef {
virStorageSourcePtr mirror;
bool mirroring;
+ int mirrorJob; /* virDomainBlockJobType */
struct {
unsigned int cylinders;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 1782913..368e112 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -14872,6 +14872,7 @@ qemuDomainBlockPivot(virConnectPtr conn,
disk->mirror = NULL;
disk->mirroring = false;
+ disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
cleanup:
/* revert to original disk def on failure */
@@ -15037,6 +15038,7 @@ qemuDomainBlockJobImpl(virDomainObjPtr vm,
virStorageSourceFree(disk->mirror);
disk->mirror = NULL;
disk->mirroring = false;
+ disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
}
waitjob:
@@ -15325,6 +15327,7 @@ qemuDomainBlockCopy(virDomainObjPtr vm,
need_unlink = false;
disk->mirror = mirror;
mirror = NULL;
+ disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_COPY;
endjob:
if (need_unlink && unlink(dest))
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 8a6b384..65e9faf 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -1023,28 +1023,32 @@ qemuProcessHandleBlockJob(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
if (disk) {
/* Have to generate two variants of the event for old vs. new
* client callbacks */
+ if (type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT &&
+ disk->mirrorJob == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)
+ type = disk->mirrorJob;
path = virDomainDiskGetSource(disk);
event = virDomainEventBlockJobNewFromObj(vm, path, type, status);
event2 = virDomainEventBlockJob2NewFromObj(vm, disk->dst, type,
status);
/* XXX If we completed a block pull or commit, then recompute
* the cached backing chain to match. Better would be storing
- * the chain ourselves rather than reprobing, but this
- * requires modifying domain_conf and our XML to fully track
- * the chain across libvirtd restarts. For that matter, if
- * qemu gains support for committing the active layer, we have
- * to update disk->src. */
+ * the chain ourselves rather than reprobing, but we haven't
+ * quite completed that conversion to use our XML tracking. */
if ((type == VIR_DOMAIN_BLOCK_JOB_TYPE_PULL ||
- type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT) &&
+ type == VIR_DOMAIN_BLOCK_JOB_TYPE_COMMIT ||
+ type == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT) &&
status == VIR_DOMAIN_BLOCK_JOB_COMPLETED)
qemuDomainDetermineDiskChain(driver, vm, disk, true);
- if (disk->mirror && type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY) {
+ if (disk->mirror &&
+ (type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY ||
+ type == VIR_DOMAIN_BLOCK_JOB_TYPE_ACTIVE_COMMIT)) {
if (status == VIR_DOMAIN_BLOCK_JOB_READY) {
disk->mirroring = true;
} else if (status == VIR_DOMAIN_BLOCK_JOB_FAILED) {
virStorageSourceFree(disk->mirror);
disk->mirror = NULL;
disk->mirroring = false;
+ disk->mirrorJob = VIR_DOMAIN_BLOCK_JOB_TYPE_UNKNOWN;
}
}
}
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-active-commit.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-active-commit.xml
new file mode 100644
index 0000000..6ba5724
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-active-commit.xml
@@ -0,0 +1,37 @@
+<domain type='qemu' id='1'>
+ <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='file' device='disk'>
+ <driver name='qemu' type='qcow2'/>
+ <source file='/tmp/HostVG/QEMUGuest1-snap'/>
+ <backingStore type='block' index='1'>
+ <format type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <backingStore/>
+ </backingStore>
+ <mirror type='block' job='active-commit'>
+ <format type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ </mirror>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0' target='0' unit='0'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml
index 72b03c9..abec180 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-mirror.xml
@@ -17,7 +17,7 @@
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<backingStore/>
- <mirror type='file' file='/dev/HostVG/QEMUGuest1Copy' ready='yes'>
+ <mirror type='file' file='/dev/HostVG/QEMUGuest1Copy' job='copy' ready='yes'>
<source file='/dev/HostVG/QEMUGuest1Copy'/>
</mirror>
<target dev='hda' bus='ide'/>
@@ -33,7 +33,7 @@
<disk type='file' device='disk'>
<source file='/tmp/data.img'/>
<backingStore/>
- <mirror type='file' file='/tmp/copy.img' format='qcow2'>
+ <mirror type='file' file='/tmp/copy.img' format='qcow2' job='copy'>
<format type='qcow2'/>
<source file='/tmp/copy.img'/>
</mirror>
diff --git a/tests/qemuxml2xmloutdata/qemuxml2xmlout-disk-mirror-old.xml b/tests/qemuxml2xmloutdata/qemuxml2xmlout-disk-mirror-old.xml
index 72b03c9..abec180 100644
--- a/tests/qemuxml2xmloutdata/qemuxml2xmlout-disk-mirror-old.xml
+++ b/tests/qemuxml2xmloutdata/qemuxml2xmlout-disk-mirror-old.xml
@@ -17,7 +17,7 @@
<disk type='block' device='disk'>
<source dev='/dev/HostVG/QEMUGuest1'/>
<backingStore/>
- <mirror type='file' file='/dev/HostVG/QEMUGuest1Copy' ready='yes'>
+ <mirror type='file' file='/dev/HostVG/QEMUGuest1Copy' job='copy' ready='yes'>
<source file='/dev/HostVG/QEMUGuest1Copy'/>
</mirror>
<target dev='hda' bus='ide'/>
@@ -33,7 +33,7 @@
<disk type='file' device='disk'>
<source file='/tmp/data.img'/>
<backingStore/>
- <mirror type='file' file='/tmp/copy.img' format='qcow2'>
+ <mirror type='file' file='/tmp/copy.img' format='qcow2' job='copy'>
<format type='qcow2'/>
<source file='/tmp/copy.img'/>
</mirror>
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index cefe05b..8966b9a 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -229,6 +229,7 @@ mymain(void)
DO_TEST_DIFFERENT("disk-mirror-old");
DO_TEST_FULL("disk-mirror", false, WHEN_ACTIVE);
DO_TEST_FULL("disk-mirror", true, WHEN_INACTIVE);
+ DO_TEST_FULL("disk-active-commit", false, WHEN_ACTIVE);
DO_TEST("graphics-listen-network");
DO_TEST("graphics-vnc");
DO_TEST("graphics-vnc-websocket");
--
1.9.3
10 years, 9 months
[libvirt] ipv6 slirp network
by Vasiliy Tolstov
Hello. I have now slirp qemu network with ipv4 address, but for tests
i need also ipv6 addresses in slirp network. How can i provide this
args for qemu via libvirt or (best) via qemu args?
I found some commits about ipv6 slirp network but can't find args
needed to enable it.
--
Vasiliy Tolstov,
e-mail: v.tolstov(a)selfip.ru
jabber: vase(a)selfip.ru
10 years, 9 months
[libvirt] [PATCH] tests: Remove stale scsihostdata dir
by Michal Privoznik
In the fbd91d49 commit, new scsihostdata dir is added to EXTRA_DIST in
the tests/Makefile.am. However, the directory itself is not created
anywhere, nor in the commit.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
Notes:
Pushed under build-breaker rule.
tests/Makefile.am | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ecb2f34..3e71069 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -83,7 +83,6 @@ EXTRA_DIST = \
domainsnapshotxml2xmlin \
domainsnapshotxml2xmlout \
fchostdata \
- scsihostdata \
interfaceschemadata \
lxcconf2xmldata \
lxcxml2xmldata \
--
1.8.5.5
10 years, 9 months
[libvirt] [PATCHv2 0/2] Deal with snapshots in PMSUSPENDED state
by Peter Krempa
Peter Krempa (2):
qemu: snapshot: Forbid taking snapshot in invalid state
qemu: snapshot: Forbid taking/reverting snapshots in PMSUSPENDED state
src/qemu/qemu_driver.c | 33 +++++++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
--
2.0.0
10 years, 9 months
[libvirt] Syslog "nested job is dangerous" message
by Sam Bobroff
Hello everyone,
After performing a migration, the syslog often contains several messages like this:
"This thread seems to be the async job owner; entering monitor without asking for a nested job is dangerous"
The message makes it sound as if the user has done something dangerous but, after looking at the code that produces the message, it appears to be more to do with how the libvirt job code is used.
The commit that added the warning (6eede368bc8e3df2c94c2ec1a913885ce08e99db) doesn't explain why it might be dangerous...
qemu: Warn on possibly incorrect usage of EnterMonitor*
qemuDomainObjEnterMonitor{,WithDriver} should not be called from async
jobs, only EnterMonitorAsync variant is allowed.
... so I would appreciate some advice from people who understand that area.
Would it be appropriate to re-word the message, or perhaps change it to a debug message so that it's not normally seen by users?
Is it important to track down the cases that are generating the warning and fix them? (Could it cause some kind of significant problem?)
Cheers,
Sam.
10 years, 9 months
[libvirt] [PATCH V2 0/3] refactor virMutexInit virRWLockInit and virCondInit
by Jincheng Miao
This patchset refactors vir{Mutex,RWLock,Cond}Init by calling a Initernal function,
which has the error reporting. So that the caller no longer to write a redundant
error message after them.
V2:
removed quiet argument of vir{Mutex,RWLock,Cond}Internal.
separated argument renaming patch.
Jincheng Miao (3):
rename arguments of virthread functions
add error report for virMutexInit virRWLockInit and virCondInit
remove error message after virMutexInit virRWLockInit virCondInit
daemon/remote.c | 1 -
src/conf/interface_conf.c | 2 -
src/conf/network_conf.c | 2 -
src/conf/node_device_conf.c | 2 -
src/conf/nwfilter_conf.c | 2 -
src/conf/object_event.c | 2 -
src/conf/storage_conf.c | 2 -
src/conf/virchrdev.c | 2 -
src/esx/esx_vi.c | 15 +----
src/fdstream.c | 2 -
src/libvirt_private.syms | 7 +--
src/libxl/libxl_driver.c | 2 -
src/locking/lock_daemon.c | 5 --
src/node_device/node_device_udev.c | 1 -
src/nwfilter/nwfilter_learnipaddr.c | 2 -
src/parallels/parallels_driver.c | 5 +-
src/qemu/qemu_agent.c | 2 -
src/qemu/qemu_capabilities.c | 2 -
src/qemu/qemu_driver.c | 1 -
src/qemu/qemu_monitor.c | 6 +-
src/remote/remote_driver.c | 2 -
src/rpc/virnetclient.c | 5 +-
src/test/test_driver.c | 4 --
src/util/vireventpoll.c | 5 +-
src/util/virlockspace.c | 4 --
src/util/virobject.c | 2 -
src/util/virthread.c | 109 +++++++++++++++++-------------------
src/util/virthread.h | 50 +++++++++++------
src/xen/xen_driver.c | 2 -
tests/qemumonitortestutils.c | 2 -
30 files changed, 97 insertions(+), 153 deletions(-)
--
1.8.3.1
10 years, 9 months
[libvirt] [PATCH] leaseshelper: add enhancements to support all events
by Nehal J Wani
This patch enables the helper program to detect event(s) triggered when there
is a change in lease length or expiry and client-id. This transfers complete
control of leases database to libvirt and suppresses use of the lease database
file (<network-name>.leases). That file will not be created, read, or written.
This is achieved by adding the option --leasefile-ro to dnsmasq and applying
the symlink technique, which helps us map events related to leases with their
corresponding network bridges.
Example:
/var/lib/libvirt/dnsmasq/virbr0.helper -> /home/wani/libvirt/src/libvirt_leaseshelper
/var/lib/libvirt/dnsmasq/virbr3.helper -> /home/wani/libvirt/src/libvirt_leaseshelper
Also, this requires the addition of a new non-lease entry in our custom lease
database: "server-duid". It is required to identify a DHCPv6 server.
Now that dnsmasq doesn't maintain its own leases database, it relies on our
helper program to tell it about previous leases and server duid. Thus, this
patch makes our leases program honor an extra action: "init", in which it sends
the known info in a particular format to dnsmasq by printing it to stdout.
---
src/network/bridge_driver.c | 43 +++++++++++-
src/network/leaseshelper.c | 156 +++++++++++++++++++++++++++++++++++++-------
2 files changed, 175 insertions(+), 24 deletions(-)
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 6a2e760..1e1e53f 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -229,6 +229,16 @@ networkDnsmasqLeaseFileNameCustom(const char *bridge)
}
static char *
+networkDnsmasqPseudoLeaseHelperName(const char *bridge)
+{
+ char *pseudo_leasehelper;
+
+ ignore_value(virAsprintf(&pseudo_leasehelper, "%s/%s.helper",
+ driverState->dnsmasqStateDir, bridge));
+ return pseudo_leasehelper;
+}
+
+static char *
networkDnsmasqConfigFileName(const char *netname)
{
char *conffile;
@@ -1261,6 +1271,7 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
char *configfile = NULL;
char *configstr = NULL;
char *leaseshelper_path = NULL;
+ char *pseudo_leaseshelper_path = NULL;
network->dnsmasqPid = -1;
@@ -1273,6 +1284,11 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
if (!(configfile = networkDnsmasqConfigFileName(network->def->name)))
goto cleanup;
+ /* construct symlink name */
+ if (!(pseudo_leaseshelper_path
+ = networkDnsmasqPseudoLeaseHelperName(network->def->bridge)))
+ goto cleanup;
+
/* Write the file */
if (virFileWriteStr(configfile, configstr, 0600) < 0) {
virReportSystemError(errno,
@@ -1287,9 +1303,30 @@ networkBuildDhcpDaemonCommandLine(virNetworkObjPtr network,
LIBEXECDIR)))
goto cleanup;
+ /* Symlink technique for dnsmasq lease file is needed so that libvirt
+ * can have complete control over the handling of leases database */
+
+ /* Remove unwanted, old symlink */
+ if (unlink(pseudo_leaseshelper_path) < 0 &&
+ errno != ENOENT && errno != ENOTDIR) {
+ virReportSystemError(errno,
+ _("Failed to delete symlink '%s'"),
+ pseudo_leaseshelper_path);
+ goto cleanup;
+ }
+
+ /* Create a new symlink */
+ if (symlink(leaseshelper_path, pseudo_leaseshelper_path) < 0) {
+ virReportSystemError(errno,
+ _("Failed to create symlink '%s' to '%s'"),
+ leaseshelper_path, pseudo_leaseshelper_path);
+ goto cleanup;
+ }
+
cmd = virCommandNew(dnsmasqCapsGetBinaryPath(caps));
virCommandAddArgFormat(cmd, "--conf-file=%s", configfile);
- virCommandAddArgFormat(cmd, "--dhcp-script=%s", leaseshelper_path);
+ virCommandAddArgFormat(cmd, "--dhcp-script=%s", pseudo_leaseshelper_path);
+ virCommandAddArgFormat(cmd, "--leasefile-ro");
*cmdout = cmd;
ret = 0;
@@ -3432,6 +3469,10 @@ networkGetDHCPLeases(virNetworkPtr network,
goto error;
}
+ /* Ignore server-duid. It's not part of a lease */
+ if (virJSONValueObjectHasKey(lease_tmp, "server-duid"))
+ continue;
+
if (!(mac_tmp = virJSONValueObjectGetString(lease_tmp, "mac-address"))) {
/* leaseshelper program guarantees that lease will be stored only if
* mac-address is known otherwise not */
diff --git a/src/network/leaseshelper.c b/src/network/leaseshelper.c
index e4b5283..3d6c773 100644
--- a/src/network/leaseshelper.c
+++ b/src/network/leaseshelper.c
@@ -50,6 +50,13 @@
*/
#define VIR_NETWORK_DHCP_LEASE_FILE_SIZE_MAX (32 * 1024 * 1024)
+/*
+ * Use this when passing possibly-NULL strings to printf-a-likes.
+ * Required for unkown parameters during init call.
+ */
+# define EMPTY_STR(s) ((s) ? (s) : "*")
+
+
static const char *program_name;
/* Display version information. */
@@ -65,7 +72,7 @@ usage(int status)
if (status) {
fprintf(stderr, _("%s: try --help for more details\n"), program_name);
} else {
- printf(_("Usage: %s add|old|del mac|clientid ip [hostname]\n"
+ printf(_("Usage: %s add|old|del|init mac|clientid ip [hostname]\n"
"Designed for use with 'dnsmasq --dhcp-script'\n"
"Refer to man page of dnsmasq for more details'\n"),
program_name);
@@ -89,6 +96,7 @@ enum virLeaseActionFlags {
VIR_LEASE_ACTION_ADD, /* Create new lease */
VIR_LEASE_ACTION_OLD, /* Lease already exists, renew it */
VIR_LEASE_ACTION_DEL, /* Delete the lease */
+ VIR_LEASE_ACTION_INIT, /* Tell dnsmasq of existing leases on restart */
VIR_LEASE_ACTION_LAST
};
@@ -96,7 +104,7 @@ enum virLeaseActionFlags {
VIR_ENUM_DECL(virLeaseAction);
VIR_ENUM_IMPL(virLeaseAction, VIR_LEASE_ACTION_LAST,
- "add", "old", "del");
+ "add", "old", "del", "init");
int
main(int argc, char **argv)
@@ -105,6 +113,7 @@ main(int argc, char **argv)
char *pid_file = NULL;
char *lease_entries = NULL;
char *custom_lease_file = NULL;
+ char *server_duid = NULL;
const char *ip = NULL;
const char *mac = NULL;
const char *iaid = virGetEnvAllowSUID("DNSMASQ_IAID");
@@ -112,20 +121,26 @@ main(int argc, char **argv)
const char *interface = virGetEnvAllowSUID("DNSMASQ_INTERFACE");
const char *exptime_tmp = virGetEnvAllowSUID("DNSMASQ_LEASE_EXPIRES");
const char *hostname = virGetEnvAllowSUID("DNSMASQ_SUPPLIED_HOSTNAME");
+ const char *server_duid_env = virGetEnvAllowSUID("DNSMASQ_SERVER_DUID");
const char *leases_str = NULL;
long long currtime = 0;
long long expirytime = 0;
size_t i = 0;
+ size_t count_ipv6 = 0;
+ size_t count_ipv4 = 0;
int action = -1;
int pid_file_fd = -1;
int rv = EXIT_FAILURE;
int custom_lease_file_len = 0;
bool add = false;
+ bool init = false;
bool delete = false;
virJSONValuePtr lease_new = NULL;
virJSONValuePtr lease_tmp = NULL;
virJSONValuePtr leases_array = NULL;
virJSONValuePtr leases_array_new = NULL;
+ virJSONValuePtr *leases_ipv4 = NULL;
+ virJSONValuePtr *leases_ipv6 = NULL;
virSetErrorFunc(NULL, NULL);
virSetErrorLogPriorityFunc(NULL);
@@ -156,17 +171,19 @@ main(int argc, char **argv)
}
}
- if (argc != 4 && argc != 5) {
+ if (argc != 4 && argc != 5 && argc != 2) {
/* Refer man page of dnsmasq --dhcp-script for more details */
usage(EXIT_FAILURE);
}
/* Make sure dnsmasq knows the interface. The interface name is not known
- * when dnsmasq (re)starts and throws 'del' events for expired leases.
- * So, if any old lease has expired, it will be automatically removed the
- * next time this program is invoked */
- if (!interface)
- goto cleanup;
+ * via env variable when dnsmasq (re)starts and throws 'del' events for
+ * expired leases. Our symlink hack provides us an alternative method to
+ * find it */
+ if (!interface) {
+ interface = basename(argv[0]);
+ *(strchr(interface, '.')) = '\0';
+ }
ip = argv[3];
mac = argv[2];
@@ -185,9 +202,14 @@ main(int argc, char **argv)
exptime[strlen(exptime) - 1] = '\0';
/* Check if it is an IPv6 lease */
- if (virGetEnvAllowSUID("DNSMASQ_IAID")) {
+ if (iaid) {
mac = virGetEnvAllowSUID("DNSMASQ_MAC");
clientid = argv[2];
+
+ if (server_duid_env) {
+ if (VIR_STRDUP(server_duid, server_duid_env) < 0)
+ goto cleanup;
+ }
}
if (virAsprintf(&custom_lease_file,
@@ -264,6 +286,8 @@ main(int argc, char **argv)
goto cleanup;
}
}
+ } else if (action == VIR_LEASE_ACTION_INIT) {
+ init = true;
} else {
fprintf(stderr, _("Unsupported action: %s\n"),
virLeaseActionTypeToString(action));
@@ -294,6 +318,7 @@ main(int argc, char **argv)
i = 0;
while (i < virJSONValueArraySize(leases_array)) {
const char *ip_tmp = NULL;
+ const char *server_duid_tmp = NULL;
long long expirytime_tmp = -1;
if (!(lease_tmp = virJSONValueArrayGet(leases_array, i))) {
@@ -302,6 +327,20 @@ main(int argc, char **argv)
goto cleanup;
}
+ if ((server_duid_tmp
+ = virJSONValueObjectGetString(lease_tmp, "server-duid"))) {
+ /* Control reaches here atmost once */
+ if (!server_duid) {
+ /* Control reaches here when the action is not for an
+ * ipv6 lease or for some weird reason the env variable
+ * DNSMASQ_SERVER_DUID wasn't set*/
+ if (VIR_STRDUP(server_duid, server_duid_tmp) < 0)
+ goto cleanup;
+ }
+ i++;
+ continue;
+ }
+
if (!(ip_tmp = virJSONValueObjectGetString(lease_tmp, "ip-address")) ||
(virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp) < 0)) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
@@ -328,39 +367,110 @@ main(int argc, char **argv)
goto cleanup;
}
+ /* Store pointers to ipv4 and ipv6 leases */
+ if (strchr(ip_tmp, ':'))
+ ignore_value(VIR_APPEND_ELEMENT(leases_ipv6, count_ipv6, lease_tmp));
+ else
+ ignore_value(VIR_APPEND_ELEMENT(leases_ipv4, count_ipv4, lease_tmp));
+
ignore_value(virJSONValueArraySteal(leases_array, i));
}
}
}
- if (add) {
- if (virJSONValueArrayAppend(leases_array_new, lease_new) < 0) {
+ if (init) {
+ /* Man page of dnsmasq says: the script (helper program, in our case)
+ * should write the saved state of the lease database, in dnsmasq
+ * leasefile format, to stdout and exit with zero exit code, when
+ * called with argument init. Format:
+ * #For all ipv4 leases:
+ * Expiry_time MAC_address IP_address Hostname Client-id
+ * #If DHCPv6 is present:
+ * duid Server_DUID
+ * #For all ipv6 leases:
+ * Expiry_time IAID IP_address Hostname Client-DUID */
+ long long expirytime_tmp = -1;
+ for (i = 0; i < count_ipv4; i++) {
+ lease_tmp = leases_ipv4[i];
+ virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp);
+ printf("%lld %s %s %s %s\n",
+ expirytime_tmp,
+ virJSONValueObjectGetString(lease_tmp, "mac-address"),
+ virJSONValueObjectGetString(lease_tmp, "ip-address"),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id")));
+ }
+ if (server_duid) {
+ printf("duid %s\n", server_duid);
+ for (i = 0; i < count_ipv6; i++) {
+ lease_tmp = leases_ipv6[i];
+ virJSONValueObjectGetNumberLong(lease_tmp, "expiry-time", &expirytime_tmp);
+ printf("%lld %s %s %s %s\n",
+ expirytime_tmp,
+ virJSONValueObjectGetString(lease_tmp, "iaid"),
+ virJSONValueObjectGetString(lease_tmp, "ip-address"),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "hostname")),
+ EMPTY_STR(virJSONValueObjectGetString(lease_tmp, "client-id")));
+ }
+ }
+ }
+ else {
+ if (add) {
+ if (virJSONValueArrayAppend(leases_array_new, lease_new) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create json"));
+ goto cleanup;
+ }
+ lease_new = NULL;
+ }
+
+ if (server_duid) {
+ if (!(lease_new = virJSONValueNewObject())) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create json"));
+ goto cleanup;
+ }
+
+ if (virJSONValueObjectAppendString(lease_new,
+ "server-duid", server_duid) < 0)
+ goto cleanup;
+
+ if (virJSONValueArrayAppend(leases_array_new, lease_new) < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to create json"));
+ goto cleanup;
+ }
+ lease_new = NULL;
+ }
+
+ if (!(leases_str = virJSONValueToString(leases_array_new, true))) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to create json"));
+ _("empty json array"));
goto cleanup;
}
- lease_new = NULL;
- }
- if (!(leases_str = virJSONValueToString(leases_array_new, true))) {
- virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("empty json array"));
- goto cleanup;
+ /* Write to file */
+ if (virFileRewrite(custom_lease_file, 0644,
+ customLeaseRewriteFile, &leases_str) < 0)
+ goto cleanup;
}
- /* Write to file */
- if (virFileRewrite(custom_lease_file, 0644,
- customLeaseRewriteFile, &leases_str) < 0)
- goto cleanup;
-
rv = EXIT_SUCCESS;
cleanup:
if (pid_file_fd != -1)
virPidFileReleasePath(pid_file, pid_file_fd);
+ for (i = 0; i < count_ipv4; i++)
+ VIR_FREE(leases_ipv4);
+
+ for (i = 0; i < count_ipv6; i++)
+ VIR_FREE(leases_ipv6);
+
VIR_FREE(pid_file);
VIR_FREE(exptime);
+ VIR_FREE(server_duid);
+ VIR_FREE(lease_entries);
VIR_FREE(custom_lease_file);
virJSONValueFree(lease_new);
virJSONValueFree(leases_array);
--
1.9.3
10 years, 9 months
[libvirt] [PATCH 0/8] Add iSCSI hostdev pass-through device
by John Ferlan
https://bugzilla.redhat.com/show_bug.cgi?id=957293
Allow iSCSI <hostdev/> devices to be added similarly to the existing
<disk/> devices. Initially do a little bit of refactoring of the
hostdev subsys structures to make it easier to model an iSCSI hostdev
after the SCSI scsi_host. Although the bulk of the non-structure
changes are "technically unnecessary", it just looked nicer to see
{usb|pci|scsi}src rather than the longer "->source.subsys.u.{usb|pci|scsi}"
in many places in the code.
The end result is the guest will have /dev/sdX devices created.
I have run this code through my Coverity environment and will be
running the virttest suite over the weekend.
Patches 1-3 are repetitive moves of the various hostdev subsys types
(USB, PCI, and SCSI) into separate typedefs and then modifying code use
the Ptr instead of the long union path to each field. I think I got
most, but I'm sure there's still a few that could be cleaned up or
that were added since I started this.
Patch 4 more or less redoes patch 3 and I suppose could be combined. I
left it separate because it's showing the progression to patch 6. This
patch uses 'scsihost' to reference the specific portions while still
using 'scsisrc' to reference the shared portion (which is only sgio).
Patch 5 adds a virConnectPtr since patch 6 will need a way to get the
secret value for the iSCSI secret/auth in qemuBuildSCSIHostdevDrvStr.
Patch 6 adds the qemu code to handle a new hostdev protocol type
VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_ISCSI. The code will mimic the
network disk (VIR_STORAGE_NET_PROTOCOL_ISCSI) code when making decisions.
The new 'scsisrc' field 'protocol' will be the decision point. The
default of VIR_DOMAIN_HOSTDEV_SCSI_PROTOCOL_TYPE_NONE was chosen
over TYPE_SCSI_HOST. The changes were made in this order to reduce
the size of the patch when the XML is added (patch 8). Most of the
code was done inline using the iscsisrc->protocol (when the iSCSI code
had nothing to do). The remaining changes refactored code into "SCSIHost"
and "SCSIiSCSI" to process the differences.
Patch 7 just refactors domain_conf to add what will be a common routine
to handle the "<host/>" element network disks. The iSCSI code will
reuse the code to have it's own element.
Patch 8 adds the XML, schema, and updates the docs to describe the
<hostdev/> entry as well as of course adding new tests. The tests
are a copy/merge of the scsi_host and network iscsi tests to define
and describe the expected model.
John Ferlan (8):
hostdev: Introduce virDomainHostdevSubsysUSB
hostdev: Introduce virDomainHostdevSubsysPCI
hostdev: Introduce virDomainHostdevSubsysSCSI
hostdev: Introduce virDomainHostdevSubsysSCSIHost
Add virConnectPtr for qemuBuildSCSIHostdevDrvStr
hostdev: Introduce virDomainHostdevSubsysSCSIiSCSI
domain_conf: Common routine to handle network storage host xml def
hostdev: Add iSCSI hostdev XML
docs/formatdomain.html.in | 142 +++++--
docs/schemas/domaincommon.rng | 46 +-
src/conf/domain_audit.c | 38 +-
src/conf/domain_conf.c | 463 +++++++++++++++------
src/conf/domain_conf.h | 80 +++-
src/libxl/libxl_conf.c | 9 +-
src/libxl/libxl_domain.c | 5 +-
src/libxl/libxl_driver.c | 34 +-
src/lxc/lxc_cgroup.c | 4 +-
src/lxc/lxc_controller.c | 10 +-
src/lxc/lxc_driver.c | 16 +-
src/qemu/qemu_cgroup.c | 69 +--
src/qemu/qemu_command.c | 158 ++++---
src/qemu/qemu_command.h | 5 +-
src/qemu/qemu_conf.c | 20 +-
src/qemu/qemu_driver.c | 6 +-
src/qemu/qemu_hotplug.c | 93 +++--
src/qemu/qemu_hotplug.h | 9 +-
src/security/security_apparmor.c | 33 +-
src/security/security_dac.c | 66 +--
src/security/security_selinux.c | 64 +--
src/security/virt-aa-helper.c | 5 +-
src/util/virhostdev.c | 295 +++++++------
.../qemuxml2argv-hostdev-scsi-lsi-iscsi-auth.args | 14 +
.../qemuxml2argv-hostdev-scsi-lsi-iscsi-auth.xml | 46 ++
.../qemuxml2argv-hostdev-scsi-lsi-iscsi.args | 14 +
.../qemuxml2argv-hostdev-scsi-lsi-iscsi.xml | 40 ++
...emuxml2argv-hostdev-scsi-virtio-iscsi-auth.args | 16 +
...qemuxml2argv-hostdev-scsi-virtio-iscsi-auth.xml | 46 ++
.../qemuxml2argv-hostdev-scsi-virtio-iscsi.args | 16 +
.../qemuxml2argv-hostdev-scsi-virtio-iscsi.xml | 40 ++
tests/qemuxml2argvtest.c | 16 +
tests/qemuxml2xmltest.c | 5 +
33 files changed, 1317 insertions(+), 606 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi-auth.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-lsi-iscsi.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi-auth.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-hostdev-scsi-virtio-iscsi.xml
--
1.9.3
10 years, 9 months
[libvirt] [PATCH] storage: logical: drop useless if
by Roman Bogorodskiy
virStorageBackendLogicalCreateVol contains a piece like:
if (vol->target.path != NULL) {
/* A target path passed to CreateVol has no meaning */
VIR_FREE(vol->target.path);
}
The 'if' is useless here, but 'syntax-check' doesn't catch that
because of the comment, so drop the 'if'.
---
src/storage/storage_backend_logical.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index ed62c2f..4959985 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -742,10 +742,8 @@ virStorageBackendLogicalCreateVol(virConnectPtr conn,
vol->type = VIR_STORAGE_VOL_BLOCK;
- if (vol->target.path != NULL) {
- /* A target path passed to CreateVol has no meaning */
- VIR_FREE(vol->target.path);
- }
+ /* A target path passed to CreateVol has no meaning */
+ VIR_FREE(vol->target.path);
if (virAsprintf(&vol->target.path, "%s/%s",
pool->def->target.path,
--
1.9.0
10 years, 9 months
[libvirt] [PATCH] Fix build on non-Linux platforms
by Roman Bogorodskiy
Commit ef48a1b introduced virFindSCSIHostByPCI for Linux and
a stub for other platforms that returns -1 while the function
should return 'char *', so use 'return NULL' instead.
Commit fbd91d4 introduced virReadSCSIUniqueId with the third
argument 'int *result', however the stub for non-Linux patform
uses 'unsigned int *result', so change it to 'int *result'.
Pushed under the build breaker rule.
---
src/util/virutil.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 1c6d261..20e9f0e 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -2176,7 +2176,7 @@ virFindFCHostCapableVport(const char *sysfs_prefix)
int
virReadSCSIUniqueId(const char *sysfs_prefix ATTRIBUTE_UNUSED,
int host ATTRIBUTE_UNUSED,
- unsigned int *result ATTRIBUTE_UNUSED)
+ int *result ATTRIBUTE_UNUSED)
{
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
return -1;
@@ -2188,7 +2188,7 @@ virFindSCSIHostByPCI(const char *sysfs_prefix ATTRIBUTE_UNUSED,
unsigned int unique_id ATTRIBUTE_UNUSED)
{
virReportSystemError(ENOSYS, "%s", _("Not supported on this platform"));
- return -1;
+ return NULL;
}
int
--
1.9.0
10 years, 9 months