[libvirt] ANNOUNCE: virt-tools.org website
by Richard W.M. Jones
I'm pleased to announce the virt-tools.org website:
http://virt-tools.org/
The "virt tools" are an informal group of system administration tools
for small-scale Linux virtualization, including virt-manager,
virt-install, libvirt, virt-v2v, libguestfs, virt-df, virt-top and
more.
The virt tools website is an umbrella project to provide
documentation, tutorials, online help and roadmaps for these tools.
The website does *not* replace the existing upstream websites, but
hopes to complement those sites by providing documentation that
crosses tool boundaries and help to get started.
The site is open source and we welcome your contributions. Get the
git repository here:
http://git.fedorahosted.org/git/?p=virt-tools.git
and send patches to the mailing list:
http://virt-tools.org/contact/#mailing-list
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
14 years, 1 month
[libvirt] [PATCH 8/8] virsh: add -- support
by Lai Jiangshan
"--" means no option at the following arguments.
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
diff --git a/tools/virsh.c b/tools/virsh.c
index a5b438b..d01091f 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10305,6 +10305,7 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
vshCmdOpt *last = NULL;
const vshCmdDef *cmd = NULL;
int tk;
+ bool data_only = false;
int data_ct = 0;
first = NULL;
@@ -10327,6 +10328,8 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
goto syntaxError; /* ... or ignore this command only? */
}
VIR_FREE(tkdata);
+ } else if (data_only) {
+ goto get_data;
} else if (*tkdata == '-' && *(tkdata + 1) == '-' && *(tkdata + 2)
&& c_isalnum(*(tkdata + 2))) {
char *optstr = strchr(tkdata + 2, '=');
@@ -10368,7 +10371,12 @@ vshCommandParse(vshControl *ctl, vshCommandParser *parser)
goto syntaxError;
}
}
+ } else if (*tkdata == '-' && *(tkdata + 1) == '-'
+ && *(tkdata + 2) == '\0') {
+ data_only = true;
+ continue;
} else {
+get_data:
if (!(opt = vshCmddefGetData(cmd, data_ct++))) {
vshError(ctl, _("unexpected data '%s'"), tkdata);
goto syntaxError;
14 years, 1 month
[libvirt] [PATCH] [RFC] nwfilter: resolve deadlock between VM operations and filter update
by Stefan Berger
V2:
remove the locks from qemudVMFilterRebuild & umlVMFilterRebuild
This is from a bug report and conversation on IRC where Soren reported
that while a filter update is occurring on one or more VMs (due to a
rule having been edited for example), a deadlock can occur when a VM
referencing a filter is started.
The problem is caused by the two locking sequences of
qemu driver, qemu domain, filter # for the VM start operation
filter, qemu_driver, qemu_domain # for the filter update
operation
that obviously don't lock in the same order. The problem is the 2nd lock
sequence. Here the qemu_driver lock is being grabbed in
qemu_driver:qemudVMFilterRebuild()
The following solution is based on the idea of trying to re-arrange the
2nd sequence of locks as follows:
qemu_driver, filter, qemu_driver, qemu_domain
and making the qemu driver recursively lockable so that a second lock
can occur, this would then lead to the following net-locking sequence
qemu_driver, filter, qemu_domain
where the 2nd qemu_driver lock has been ( logically ) eliminated.
The 2nd part of the idea is that the sequence of locks (filter,
qemu_domain) and (qemu_domain, filter) becomes interchangeable if all
code paths where filter AND qemu_domain are locked have a preceding
qemu_domain lock that basically blocks their concurrent execution
So, the following code paths exist towards
qemu_driver:qemudVMFilterRebuild where we now want to put a qemu_driver
lock in front of the filter lock.
-> nwfilterUndefine() [ locks the filter ]
-> virNWFilterTestUnassignDef()
-> virNWFilterTriggerVMFilterRebuild()
-> qemudVMFilterRebuild()
-> nwfilterDefine()
-> virNWFilterPoolAssignDef() [ locks the filter ]
-> virNWFilterTriggerVMFilterRebuild()
-> qemudVMFilterRebuild()
-> nwfilterDriverReload()
-> virNWFilterPoolLoadAllConfigs()
->virNWFilterPoolObjLoad()
-> virNWFilterPoolAssignDef() [ locks the filter ]
-> virNWFilterTriggerVMFilterRebuild()
-> qemudVMFilterRebuild()
-> nwfilterDriverStartup()
-> virNWFilterPoolLoadAllConfigs()
->virNWFilterPoolObjLoad()
-> virNWFilterPoolAssignDef() [ locks the filter ]
-> virNWFilterTriggerVMFilterRebuild()
-> qemudVMFilterRebuild()
Qemu is not the only driver using the nwfilter driver, but also the UML
driver calls into it. Therefore qemuVMFilterRebuild() can be exchanged
with umlVMFilterRebuild() along with the driver lock of qemu_driver that
can now be a uml_driver. Further, since UML and Qemu domains can be
running on the same machine, the triggering of a rebuild of the filter
can touch both types of drivers and their domains.
In the patch below I am now extending each nwfilter callback driver with
functions for locking and unlocking the (VM) driver (UML, QEMU) and
introduce new functions for locking all registered callback drivers and
unlocking them. Then I am distributing the
lock-all-cbdrivers/unlock-all-cbdrivers call into the above call paths.
The last shown callpath starting with nwfilterDriverStart() is
problematic since it is initialize before the Qemu and UML drives are
and thus a lock in the path would result in a NULL pointer attempted to
be locked -- the call to virNWFilterTriggerVMFilterRebuild() is never
called, so we never lock either the qemu_driver or the uml_driver in
that path. Therefore, only the first 3 paths now receive calls to lock
and unlock all callback drivers. Now that the locks are distributed
where it matters I can remove the qemu_driver and uml_driver lock from
qemudVMFilterRebuild() and umlVMFilterRebuild() and not requiring the
recursive locks.
For now I want to put this out as an RFC patch. I have tested it by
'stretching' the critical section after the define/undefine functions
each lock the filter so I can (easily) concurrently execute another VM
operation (suspend,start). That code is in this patch and if you want
you can de-activate it. It seems to work ok and operations are being
blocked while the update is being done.
I still also want to verify the other assumption above that locking
filter and qemu_domain always has a preceding qemu_driver lock.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
src/conf/nwfilter_conf.c | 18 ++++++++++++++++++
src/conf/nwfilter_conf.h | 6 ++++++
src/libvirt_private.syms | 2 ++
src/nwfilter/nwfilter_driver.c | 26 ++++++++++++++++++++++++++
src/qemu/qemu_driver.c | 19 +++++++++++++++----
src/uml/uml_driver.c | 18 ++++++++++++++----
6 files changed, 81 insertions(+), 8 deletions(-)
Index: libvirt-acl/src/conf/nwfilter_conf.h
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.h
+++ libvirt-acl/src/conf/nwfilter_conf.h
@@ -639,6 +639,8 @@ void virNWFilterConfLayerShutdown(void);
typedef int (*virNWFilterRebuild)(virConnectPtr conn,
virHashIterator, void *data);
+typedef void (*virNWFilterVoidCall)(void);
+
typedef struct _virNWFilterCallbackDriver virNWFilterCallbackDriver;
typedef virNWFilterCallbackDriver *virNWFilterCallbackDriverPtr;
@@ -646,9 +648,13 @@ struct _virNWFilterCallbackDriver {
const char *name;
virNWFilterRebuild vmFilterRebuild;
+ virNWFilterVoidCall vmDriverLock;
+ virNWFilterVoidCall vmDriverUnlock;
};
void virNWFilterRegisterCallbackDriver(virNWFilterCallbackDriverPtr);
+void virNWFilterCallbackDriversLock(void);
+void virNWFilterCallbackDriversUnlock(void);
VIR_ENUM_DECL(virNWFilterRuleAction);
Index: libvirt-acl/src/qemu/qemu_driver.c
===================================================================
--- libvirt-acl.orig/src/qemu/qemu_driver.c
+++ libvirt-acl/src/qemu/qemu_driver.c
@@ -12725,11 +12725,7 @@ static int
qemudVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
virHashIterator iter, void *data)
{
- struct qemud_driver *driver = qemu_driver;
-
- qemuDriverLock(driver);
virHashForEach(qemu_driver->domains.objs, iter, data);
- qemuDriverUnlock(driver);
return 0;
}
@@ -12757,9 +12753,24 @@ qemudVMFiltersInstantiate(virConnectPtr
return err;
}
+
+static void
+qemudVMDriverLock(void) {
+ qemuDriverLock(qemu_driver);
+};
+
+
+static void
+qemudVMDriverUnlock(void) {
+ qemuDriverUnlock(qemu_driver);
+};
+
+
static virNWFilterCallbackDriver qemuCallbackDriver = {
.name = "QEMU",
.vmFilterRebuild = qemudVMFilterRebuild,
+ .vmDriverLock = qemudVMDriverLock,
+ .vmDriverUnlock = qemudVMDriverUnlock,
};
int qemuRegister(void) {
Index: libvirt-acl/src/uml/uml_driver.c
===================================================================
--- libvirt-acl.orig/src/uml/uml_driver.c
+++ libvirt-acl/src/uml/uml_driver.c
@@ -2202,11 +2202,7 @@ static int
umlVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
virHashIterator iter, void *data)
{
- struct uml_driver *driver = uml_driver;
-
- umlDriverLock(driver);
virHashForEach(uml_driver->domains.objs, iter, data);
- umlDriverUnlock(driver);
return 0;
}
@@ -2219,9 +2215,23 @@ static virStateDriver umlStateDriver = {
.active = umlActive,
};
+static void
+umlVMDriverLock(void)
+{
+ umlDriverLock(uml_driver);
+}
+
+static void
+umlVMDriverUnlock(void)
+{
+ umlDriverUnlock(uml_driver);
+}
+
static virNWFilterCallbackDriver umlCallbackDriver = {
.name = "UML",
.vmFilterRebuild = umlVMFilterRebuild,
+ .vmDriverLock = umlVMDriverLock,
+ .vmDriverUnlock = umlVMDriverUnlock,
};
int umlRegister(void) {
Index: libvirt-acl/src/conf/nwfilter_conf.c
===================================================================
--- libvirt-acl.orig/src/conf/nwfilter_conf.c
+++ libvirt-acl/src/conf/nwfilter_conf.c
@@ -2161,6 +2161,24 @@ virNWFilterRegisterCallbackDriver(virNWF
}
}
+void
+virNWFilterCallbackDriversLock(void)
+{
+ int i;
+
+ for (i = 0; i < nCallbackDriver; i++)
+ callbackDrvArray[i]->vmDriverLock();
+}
+
+void
+virNWFilterCallbackDriversUnlock(void)
+{
+ int i;
+
+ for (i = 0; i < nCallbackDriver; i++)
+ callbackDrvArray[i]->vmDriverUnlock();
+}
+
static virHashIterator virNWFilterDomainFWUpdateCB;
Index: libvirt-acl/src/libvirt_private.syms
===================================================================
--- libvirt-acl.orig/src/libvirt_private.syms
+++ libvirt-acl/src/libvirt_private.syms
@@ -534,6 +534,8 @@ virNWFilterConfLayerInit;
virNWFilterConfLayerShutdown;
virNWFilterLockFilterUpdates;
virNWFilterUnlockFilterUpdates;
+virNWFilterCallbackDriversLock;
+virNWFilterCallbackDriversUnlock;
# nwfilter_params.h
Index: libvirt-acl/src/nwfilter/nwfilter_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_driver.c
@@ -34,6 +34,7 @@
#include "memory.h"
#include "domain_conf.h"
#include "domain_nwfilter.h"
+#include "nwfilter_conf.h"
#include "nwfilter_driver.h"
#include "nwfilter_gentech_driver.h"
@@ -152,9 +153,13 @@ nwfilterDriverReload(void) {
virNWFilterLearnThreadsTerminate(true);
nwfilterDriverLock(driverState);
+ virNWFilterCallbackDriversLock();
+
virNWFilterPoolLoadAllConfigs(conn,
&driverState->pools,
driverState->configDir);
+
+ virNWFilterCallbackDriversUnlock();
nwfilterDriverUnlock(driverState);
virConnectClose(conn);
@@ -328,12 +333,21 @@ nwfilterDefine(virConnectPtr conn,
virNWFilterPtr ret = NULL;
nwfilterDriverLock(driver);
+ virNWFilterCallbackDriversLock();
+
if (!(def = virNWFilterDefParseString(conn, xml)))
goto cleanup;
if (!(pool = virNWFilterPoolObjAssignDef(conn, &driver->pools, def)))
goto cleanup;
+#define CRITICAL_SECTION_STRETCH 0
+if (true) {
+ fprintf(stderr,"sleep in %s\n", __FUNCTION__);
+ sleep(CRITICAL_SECTION_STRETCH);
+ fprintf(stderr,"continue in %s\n", __FUNCTION__);
+}
+
if (virNWFilterPoolObjSaveDef(driver, pool, def) < 0) {
virNWFilterPoolObjRemove(&driver->pools, pool);
def = NULL;
@@ -347,6 +361,8 @@ cleanup:
virNWFilterDefFree(def);
if (pool)
virNWFilterPoolObjUnlock(pool);
+
+ virNWFilterCallbackDriversUnlock();
nwfilterDriverUnlock(driver);
return ret;
}
@@ -359,6 +375,8 @@ nwfilterUndefine(virNWFilterPtr obj) {
int ret = -1;
nwfilterDriverLock(driver);
+ virNWFilterCallbackDriversLock();
+
pool = virNWFilterPoolObjFindByUUID(&driver->pools, obj->uuid);
if (!pool) {
virNWFilterReportError(VIR_ERR_INVALID_NWFILTER,
@@ -366,6 +384,12 @@ nwfilterUndefine(virNWFilterPtr obj) {
goto cleanup;
}
+if (true) {
+ fprintf(stderr,"sleep in %s\n", __FUNCTION__);
+ sleep(CRITICAL_SECTION_STRETCH);
+ fprintf(stderr,"continue in %s\n", __FUNCTION__);
+}
+
if (virNWFilterTestUnassignDef(obj->conn, pool)) {
virNWFilterReportError(VIR_ERR_INVALID_NWFILTER,
"%s",
@@ -385,6 +409,8 @@ nwfilterUndefine(virNWFilterPtr obj) {
cleanup:
if (pool)
virNWFilterPoolObjUnlock(pool);
+
+ virNWFilterCallbackDriversUnlock();
nwfilterDriverUnlock(driver);
return ret;
}
14 years, 1 month
[libvirt] [libvirt-tck] [RFC] 802.1Qbg test scripts
by Gerhard Stenzel
Hi Daniel,
I am currently looking into TCK test cases to verify setting 802.1Qbg
functionality from libvirt. My current approach requires changes to some
library functions in lib/Sys/Virt/TCK/.
I would appreciate your feedback about these changes before continuing
much further.
I also attach the test case.
Thanks in advance.
--
Best regards,
Gerhard Stenzel,
-----------------------------------------------------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
14 years, 1 month
[libvirt] [PATCH] Don't fail if D-Bus isn't available
by Guido Günther
Hi,
when using HAL instead of udev for nodeinfo we don't fail if HAL isn't
available. We also shouldn't fail if D-Bus is missing thenn either.
Attached patch fixes this. O.k. to apply?
Cheers,
-- Guido
14 years, 1 month
[libvirt] [PATCH] Enable support for nested SVM
by Daniel P. Berrange
This enables support for nested SVM using the regular CPU
model/features block. If the CPU model or features include
'svm', then the '-enable-nesting' flag will be added to the
QEMU command line. Latest out of tree patches for nested
'vmx', no longer require the '-enable-nesting' flag. They
instead just look at the cpu features. Several of the models
already include svm support, but QEMU was just masking out
the svm bit silently. So this will enable SVM on such
models
* src/qemu/qemu_conf.h: flag for -enable-nesting
* src/qemu/qemu_conf.c: Use -enable-nesting if VMX or SVM are in
the CPUID
* src/cpu/cpu.h, src/cpu/cpu.c: API to check for a named feature
* src/cpu/cpu_x86.c: x86 impl of feature check
* src/libvirt_private.syms: Add cpuHasFeature
* src/qemuhelptest.c: Add nesting flag where required
---
src/cpu/cpu.c | 24 ++++++++++++++++++++++++
src/cpu/cpu.h | 11 +++++++++++
src/cpu/cpu_x86.c | 29 +++++++++++++++++++++++++++++
src/libvirt_private.syms | 1 +
src/qemu/qemu_conf.c | 21 +++++++++++++++++++--
src/qemu/qemu_conf.h | 1 +
tests/qemuhelptest.c | 12 ++++++++----
7 files changed, 93 insertions(+), 6 deletions(-)
diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c
index def6974..f509e1c 100644
--- a/src/cpu/cpu.c
+++ b/src/cpu/cpu.c
@@ -424,3 +424,27 @@ cpuUpdate(virCPUDefPtr guest,
return driver->update(guest, host);
}
+
+bool
+cpuHasFeature(const char *arch,
+ const union cpuData *data,
+ const char *feature)
+{
+ struct cpuArchDriver *driver;
+
+ VIR_DEBUG("arch=%s, data=%p, feature=%s",
+ arch, data, feature);
+
+ if ((driver = cpuGetSubDriver(arch)) == NULL)
+ return -1;
+
+ if (driver->hasFeature == NULL) {
+ virCPUReportError(VIR_ERR_NO_SUPPORT,
+ _("cannot check guest CPU data for %s architecture"),
+ arch);
+ return -1;
+ }
+
+ return driver->hasFeature(data, feature);
+}
+
diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h
index a745917..3a7b996 100644
--- a/src/cpu/cpu.h
+++ b/src/cpu/cpu.h
@@ -82,6 +82,10 @@ typedef int
(*cpuArchUpdate) (virCPUDefPtr guest,
const virCPUDefPtr host);
+typedef bool
+(*cpuArchHasFeature) (const union cpuData *data,
+ const char *feature);
+
struct cpuArchDriver {
const char *name;
@@ -95,6 +99,7 @@ struct cpuArchDriver {
cpuArchGuestData guestData;
cpuArchBaseline baseline;
cpuArchUpdate update;
+ cpuArchHasFeature hasFeature;
};
@@ -151,4 +156,10 @@ extern int
cpuUpdate (virCPUDefPtr guest,
const virCPUDefPtr host);
+extern bool
+cpuHasFeature(const char *arch,
+ const union cpuData *data,
+ const char *feature);
+
+
#endif /* __VIR_CPU_H__ */
diff --git a/src/cpu/cpu_x86.c b/src/cpu/cpu_x86.c
index 1937901..42349f0 100644
--- a/src/cpu/cpu_x86.c
+++ b/src/cpu/cpu_x86.c
@@ -1754,6 +1754,34 @@ cleanup:
return ret;
}
+static bool x86HasFeature(const union cpuData *data,
+ const char *name)
+{
+ struct x86_map *map;
+ struct x86_feature *feature;
+ bool ret = false;
+ int i;
+
+ if (!(map = x86LoadMap()))
+ return false;
+
+ if (!(feature = x86FeatureFind(map, name)))
+ goto cleanup;
+
+ for (i = 0 ; i < feature->ncpuid ; i++) {
+ struct cpuX86cpuid *cpuid;
+
+ cpuid = x86DataCpuid(data, feature->cpuid[i].function);
+ if (cpuid && x86cpuidMatchMasked(cpuid, feature->cpuid + i)) {
+ ret = true;
+ goto cleanup;
+ }
+ }
+
+cleanup:
+ x86MapFree(map);
+ return ret;
+}
struct cpuArchDriver cpuDriverX86 = {
.name = "x86",
@@ -1771,4 +1799,5 @@ struct cpuArchDriver cpuDriverX86 = {
.guestData = x86GuestData,
.baseline = x86Baseline,
.update = x86Update,
+ .hasFeature = x86HasFeature,
};
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 301b0ef..0189183 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -90,6 +90,7 @@ cpuEncode;
cpuGuestData;
cpuNodeData;
cpuUpdate;
+cpuHasFeature;
# cpu_conf.h
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 737b255..429c399 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1210,6 +1210,8 @@ static unsigned long long qemudComputeCmdFlags(const char *help,
flags |= QEMUD_CMD_FLAG_NO_KVM_PIT;
if (strstr(help, "-tdf"))
flags |= QEMUD_CMD_FLAG_TDF;
+ if (strstr(help, "-enable-nesting"))
+ flags |= QEMUD_CMD_FLAG_NESTING;
if (strstr(help, ",menu=on"))
flags |= QEMUD_CMD_FLAG_BOOT_MENU;
@@ -3503,7 +3505,8 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
const char *emulator,
unsigned long long qemuCmdFlags,
const struct utsname *ut,
- char **opt)
+ char **opt,
+ bool *hasHwVirt)
{
const virCPUDefPtr host = driver->caps->host.cpu;
virCPUDefPtr guest = NULL;
@@ -3514,6 +3517,8 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
virBuffer buf = VIR_BUFFER_INITIALIZER;
int i;
+ *hasHwVirt = false;
+
if (def->cpu && def->cpu->model) {
if (qemudProbeCPUModels(emulator, qemuCmdFlags, ut->machine,
&ncpus, &cpus) < 0)
@@ -3555,6 +3560,12 @@ qemuBuildCpuArgStr(const struct qemud_driver *driver,
if (cpuDecode(guest, data, cpus, ncpus, preferred) < 0)
goto cleanup;
+ /* Only 'svm' requires --enable-nesting. The out-of-tree
+ * 'vmx' patches now simply hook off the CPU features
+ */
+ *hasHwVirt =
+ cpuHasFeature(guest->arch, data, "svm");
+
virBufferVSprintf(&buf, "%s", guest->model);
for (i = 0; i < guest->nfeatures; i++) {
char sign;
@@ -3681,6 +3692,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
char *cpu;
char *smp;
int last_good_net = -1;
+ bool hasHwVirt = false;
uname_normalize(&ut);
@@ -3874,13 +3886,18 @@ int qemudBuildCommandLine(virConnectPtr conn,
ADD_ARG_LIT(def->os.machine);
}
- if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags, &ut, &cpu) < 0)
+ if (qemuBuildCpuArgStr(driver, def, emulator, qemuCmdFlags,
+ &ut, &cpu, &hasHwVirt) < 0)
goto error;
if (cpu) {
ADD_ARG_LIT("-cpu");
ADD_ARG_LIT(cpu);
VIR_FREE(cpu);
+
+ if ((qemuCmdFlags & QEMUD_CMD_FLAG_NESTING) &&
+ hasHwVirt)
+ ADD_ARG_LIT("-enable-nesting");
}
if (disableKQEMU)
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 2c9e608..16f72f5 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -93,6 +93,7 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_NODEFCONFIG = (1LL << 37), /* -nodefconfig */
QEMUD_CMD_FLAG_BOOT_MENU = (1LL << 38), /* -boot menu=on support */
QEMUD_CMD_FLAG_ENABLE_KQEMU = (1LL << 39), /* -enable-kqemu flag */
+ QEMUD_CMD_FLAG_NESTING = (1LL << 40), /* -enable-nesting (SVM/VMX) */
};
/* Main driver state */
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index 56a49fd..d072cb0 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -171,7 +171,8 @@ mymain(int argc, char **argv)
QEMUD_CMD_FLAG_RTC_TD_HACK |
QEMUD_CMD_FLAG_NO_HPET |
QEMUD_CMD_FLAG_NO_KVM_PIT |
- QEMUD_CMD_FLAG_TDF,
+ QEMUD_CMD_FLAG_TDF |
+ QEMUD_CMD_FLAG_NESTING,
10005, 1, 0);
DO_TEST("kvm-86",
QEMUD_CMD_FLAG_VNC_COLON |
@@ -194,7 +195,8 @@ mymain(int argc, char **argv)
QEMUD_CMD_FLAG_RTC_TD_HACK |
QEMUD_CMD_FLAG_NO_HPET |
QEMUD_CMD_FLAG_NO_KVM_PIT |
- QEMUD_CMD_FLAG_TDF,
+ QEMUD_CMD_FLAG_TDF |
+ QEMUD_CMD_FLAG_NESTING,
10050, 1, 0);
DO_TEST("qemu-kvm-0.11.0-rc2",
QEMUD_CMD_FLAG_VNC_COLON |
@@ -221,7 +223,8 @@ mymain(int argc, char **argv)
QEMUD_CMD_FLAG_NO_HPET |
QEMUD_CMD_FLAG_NO_KVM_PIT |
QEMUD_CMD_FLAG_TDF |
- QEMUD_CMD_FLAG_BOOT_MENU,
+ QEMUD_CMD_FLAG_BOOT_MENU |
+ QEMUD_CMD_FLAG_NESTING,
10092, 1, 0);
DO_TEST("qemu-0.12.1",
QEMUD_CMD_FLAG_VNC_COLON |
@@ -277,7 +280,8 @@ mymain(int argc, char **argv)
QEMUD_CMD_FLAG_NO_HPET |
QEMUD_CMD_FLAG_NO_KVM_PIT |
QEMUD_CMD_FLAG_TDF |
- QEMUD_CMD_FLAG_BOOT_MENU,
+ QEMUD_CMD_FLAG_BOOT_MENU |
+ QEMUD_CMD_FLAG_NESTING,
12003, 1, 0);
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
--
1.7.2.3
14 years, 1 month
[libvirt] [PATCH 5/8] virsh: rework command parsing
by Lai Jiangshan
Old virsh command parsing mashes all the args back into a string and
miss the quotes, this patches fix it. It is also needed for introducing
qemu-monitor-command which is very useful.
This patches uses the new vrshCommandParser abstraction and adds
vshCommandArgvParse() for arguments vector, so we don't need
to mash arguments vector into a command sting.
And the usage was changed:
old:
virsh [options] [commands]
new:
virsh [options]... [<command_string>]
virsh [options]... <command> [args...]
So we still support commands like:
# virsh "define D.xml; dumpxml D"
"define D.xml; dumpxml D" was parsed as a commands-string.
and support commands like:
# virsh qemu-monitor-command f13guest "info cpus"
we will not mash them into a string, we use new argv parser for it.
But we don't support the command like:
# virsh "define D.xml; dumpxml" D
"define D.xml; dumpxml" was parsed as a command-name, but we have no such command-name.
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
virsh.c | 63 +++++++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 43 insertions(+), 20 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c
index 27321a5..9fd0602 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10165,12 +10165,47 @@ vshCommandRun(vshControl *ctl, const vshCmd *cmd)
typedef struct __vshCommandParser {
int (*getNextArg)(vshControl *, struct __vshCommandParser *, char **);
+ /* vshCommandStringGetArg() */
char *pos;
+ /* vshCommandArgvGetArg() */
+ char **arg_pos;
+ char **arg_end;
} vshCommandParser;
static int vshCommandParse(vshControl *ctl, vshCommandParser *parser);
/* ---------------
+ * Command argv parsing
+ * ---------------
+ */
+
+static int
+vshCommandArgvGetArg(vshControl *ctl, vshCommandParser *parser, char **res)
+{
+ if (parser->arg_pos == parser->arg_end) {
+ *res = NULL;
+ return VSH_TK_END;
+ }
+
+ *res = vshStrdup(ctl, *parser->arg_pos);
+ parser->arg_pos++;
+ return VSH_TK_ARG;
+}
+
+static int vshCommandArgvParse(vshControl *ctl, int nargs, char **argv)
+{
+ vshCommandParser parser;
+
+ if (nargs <= 0)
+ return FALSE;
+
+ parser.arg_pos = argv;
+ parser.arg_end = argv + nargs;
+ parser.getNextArg = vshCommandArgvGetArg;
+ return vshCommandParse(ctl, &parser);
+}
+
+/* ---------------
* Command string parsing
* ---------------
*/
@@ -10939,7 +10974,8 @@ static void
vshUsage(void)
{
const vshCmdDef *cmd;
- fprintf(stdout, _("\n%s [options] [commands]\n\n"
+ fprintf(stdout, _("\n%s [options]... [<command_string>]"
+ "\n%s [options]... <command> [args...]\n\n"
" options:\n"
" -c | --connect <uri> hypervisor connection URI\n"
" -r | --readonly connect readonly\n"
@@ -10949,7 +10985,7 @@ vshUsage(void)
" -t | --timing print timing information\n"
" -l | --log <file> output logging to file\n"
" -v | --version program version\n\n"
- " commands (non interactive mode):\n"), progname);
+ " commands (non interactive mode):\n"), progname, progname);
for (cmd = commands; cmd->name; cmd++)
fprintf(stdout,
@@ -11069,26 +11105,13 @@ vshParseArgv(vshControl *ctl, int argc, char **argv)
if (argc > end) {
/* parse command */
- char *cmdstr;
- int sz = 0, ret;
-
ctl->imode = FALSE;
-
- for (i = end; i < argc; i++)
- sz += strlen(argv[i]) + 1; /* +1 is for blank space between items */
-
- cmdstr = vshCalloc(ctl, sz + 1, 1);
-
- for (i = end; i < argc; i++) {
- strncat(cmdstr, argv[i], sz);
- sz -= strlen(argv[i]);
- strncat(cmdstr, " ", sz--);
+ if (argc - end == 1) {
+ vshDebug(ctl, 2, "commands: \"%s\"\n", argv[end]);
+ return vshCommandStringParse(ctl, argv[end]);
+ } else {
+ return vshCommandArgvParse(ctl, argc - end, argv + end);
}
- vshDebug(ctl, 2, "command: \"%s\"\n", cmdstr);
- ret = vshCommandStringParse(ctl, cmdstr);
-
- VIR_FREE(cmdstr);
- return ret;
}
return TRUE;
}
14 years, 1 month
[libvirt] [PATCH 1/8] virsh: better support double quote
by Lai Jiangshan
In origin code, double quote is only allowed at the begin or end
"complicated argument"
--some_opt="complicated string" (we split this argument into 2 parts,
option and data, the data is "complicated string").
This patch makes it allow double quote at any position of
an argument:
complicated" argument"
complicated" "argument
--"some opt=complicated string"
This patch is also needed for the following patches,
the following patches will not split option argument into 2 parts,
so we have to allow double quote at any position of an argument.
Signed-off-by: Lai Jiangshan <laijs(a)cn.fujitsu.com>
---
diff --git a/tools/virsh.c b/tools/virsh.c
index 57ea618..7b6f2b6 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -10172,9 +10172,9 @@ static int
vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
{
int tk = VSH_TK_NONE;
- int quote = FALSE;
+ bool double_quote = false;
int sz = 0;
- char *p = str;
+ char *p = str, *q;
char *tkstr = NULL;
*end = NULL;
@@ -10188,9 +10188,13 @@ vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
*end = ++p; /* = \0 or begin of next command */
return VSH_TK_END;
}
+
+ q = p;
+ *res = NULL;
+copy:
while (*p) {
/* end of token is blank space or ';' */
- if ((quote == FALSE && (*p == ' ' || *p == '\t')) || *p == ';')
+ if (!double_quote && (*p == ' ' || *p == '\t' || *p == ';'))
break;
/* end of option name could be '=' */
@@ -10206,23 +10210,22 @@ vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
p += 2;
} else {
tk = VSH_TK_DATA;
- if (*p == '"') {
- quote = TRUE;
- p++;
- } else {
- quote = FALSE;
- }
}
tkstr = p; /* begin of token */
- } else if (quote && *p == '"') {
- quote = FALSE;
+ }
+
+ if (*p == '"') {
+ double_quote = !double_quote;
p++;
- break; /* end of "..." token */
+ continue;
}
+
+ if (*res)
+ (*res)[sz] = *p;
p++;
sz++;
}
- if (quote) {
+ if (double_quote) {
vshError(ctl, "%s", _("missing \""));
return VSH_TK_ERROR;
}
@@ -10231,8 +10234,12 @@ vshCommandGetToken(vshControl *ctl, char *str, char **end, char **res)
if (sz == 0)
return VSH_TK_END;
- *res = vshMalloc(ctl, sz + 1);
- memcpy(*res, tkstr, sz);
+ if (!*res) {
+ *res = vshMalloc(ctl, sz + 1);
+ sz = 0;
+ p = q;
+ goto copy;
+ }
*(*res + sz) = '\0';
*end = p;
14 years, 1 month
[libvirt] [PATCH] Implement support for virtio plan9fs filesystem passthrough in QEMU (v2)
by Daniel P. Berrange
Rebased version of my original patch, changing to use 'passthrough'
security model by default. Support for other models can be added
in a follow up patch
Make use of the existing <filesystem> element to support plan9fs
filesystem passthrough in the QEMU driver
<filesystem type='mount'>
<source dir='/export/to/guest'/>
<target dir='/import/from/host'/>
</filesystem>
NB, the target is not actually a directory, it is merely a arbitrary
string tag that is exported to the guest as a hint for where to mount
it.
---
src/qemu/qemu_conf.c | 96 +++++++++++++++++++++++++
src/qemu/qemu_conf.h | 5 ++
tests/qemuxml2argvdata/qemuxml2argv-fs9p.args | 1 +
tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml | 28 +++++++
tests/qemuxml2argvtest.c | 2 +
5 files changed, 132 insertions(+), 0 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-fs9p.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml
diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
index 7a37c70..18a302a 100644
--- a/src/qemu/qemu_conf.c
+++ b/src/qemu/qemu_conf.c
@@ -1212,6 +1212,8 @@ static unsigned long long qemudComputeCmdFlags(const char *help,
flags |= QEMUD_CMD_FLAG_TDF;
if (strstr(help, ",menu=on"))
flags |= QEMUD_CMD_FLAG_BOOT_MENU;
+ if (strstr(help, "-fsdev"))
+ flags |= QEMUD_CMD_FLAG_FSDEV;
/* Keep disabled till we're actually ready to turn on netdev mode
* The plan is todo it in 0.13.0 QEMU, but lets wait & see... */
@@ -2008,6 +2010,10 @@ qemuAssignDeviceAliases(virDomainDefPtr def, unsigned long long qemuCmdFlags)
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE))
return 0;
+ for (i = 0; i < def->nfss ; i++) {
+ if (virAsprintf(&def->fss[i]->info.alias, "fs%d", i) < 0)
+ goto no_memory;
+ }
for (i = 0; i < def->nsounds ; i++) {
if (virAsprintf(&def->sounds[i]->info.alias, "sound%d", i) < 0)
goto no_memory;
@@ -2371,6 +2377,15 @@ qemuAssignDevicePCISlots(virDomainDefPtr def, qemuDomainPCIAddressSetPtr addrs)
goto error;
}
}
+ for (i = 0; i < def->nfss ; i++) {
+ if (def->fss[i]->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
+ continue;
+
+ /* Only support VirtIO-9p-pci so far. If that changes,
+ * we might need to skip devices here */
+ if (qemuDomainPCIAddressSetNextAddr(addrs, &def->fss[i]->info) < 0)
+ goto error;
+ }
/* Network interfaces */
for (i = 0; i < def->nnets ; i++) {
@@ -2761,6 +2776,64 @@ error:
}
+char *qemuBuildFSStr(virDomainFSDefPtr fs,
+ unsigned long long qemuCmdFlags ATTRIBUTE_UNUSED)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+
+ if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("can only passthrough directories"));
+ goto error;
+ }
+
+ virBufferAddLit(&opt, "local,security_model=passthrough");
+ virBufferVSprintf(&opt, ",id=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
+ virBufferVSprintf(&opt, ",path=%s", fs->src);
+
+ if (virBufferError(&opt)) {
+ virReportOOMError();
+ goto error;
+ }
+
+ return virBufferContentAndReset(&opt);
+
+error:
+ virBufferFreeAndReset(&opt);
+ return NULL;
+}
+
+
+char *
+qemuBuildFSDevStr(virDomainFSDefPtr fs)
+{
+ virBuffer opt = VIR_BUFFER_INITIALIZER;
+
+ if (fs->type != VIR_DOMAIN_FS_TYPE_MOUNT) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("can only passthrough directories"));
+ goto error;
+ }
+
+ virBufferAddLit(&opt, "virtio-9p-pci");
+ virBufferVSprintf(&opt, ",id=%s", fs->info.alias);
+ virBufferVSprintf(&opt, ",fsdev=%s%s", QEMU_FSDEV_HOST_PREFIX, fs->info.alias);
+ virBufferVSprintf(&opt, ",mount_tag=%s", fs->dst);
+ qemuBuildDeviceAddressStr(&opt, &fs->info);
+
+ if (virBufferError(&opt)) {
+ virReportOOMError();
+ goto error;
+ }
+
+ return virBufferContentAndReset(&opt);
+
+error:
+ virBufferFreeAndReset(&opt);
+ return NULL;
+}
+
+
char *
qemuBuildControllerDevStr(virDomainControllerDefPtr def)
{
@@ -4377,6 +4450,29 @@ int qemudBuildCommandLine(virConnectPtr conn,
}
}
+ if (qemuCmdFlags & QEMUD_CMD_FLAG_FSDEV) {
+ for (i = 0 ; i < def->nfss ; i++) {
+ char *optstr;
+ virDomainFSDefPtr fs = def->fss[i];
+
+ ADD_ARG_LIT("-fsdev");
+ if (!(optstr = qemuBuildFSStr(fs, qemuCmdFlags)))
+ goto error;
+ ADD_ARG(optstr);
+
+ ADD_ARG_LIT("-device");
+ if (!(optstr = qemuBuildFSDevStr(fs)))
+ goto error;
+ ADD_ARG(optstr);
+ }
+ } else {
+ if (def->nfss) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("filesystem passthrough not supported by this QEMU"));
+ goto error;
+ }
+ }
+
if (!def->nnets) {
/* If we have -device, then we set -nodefault already */
if (!(qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE)) {
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index 2c9e608..fbd89de 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -93,6 +93,7 @@ enum qemud_cmd_flags {
QEMUD_CMD_FLAG_NODEFCONFIG = (1LL << 37), /* -nodefconfig */
QEMUD_CMD_FLAG_BOOT_MENU = (1LL << 38), /* -boot menu=on support */
QEMUD_CMD_FLAG_ENABLE_KQEMU = (1LL << 39), /* -enable-kqemu flag */
+ QEMUD_CMD_FLAG_FSDEV = (1LL << 40), /* -fstype filesystem passthrough */
};
/* Main driver state */
@@ -188,6 +189,7 @@ struct _qemuDomainCmdlineDef {
# define QEMU_DRIVE_HOST_PREFIX "drive-"
# define QEMU_VIRTIO_SERIAL_PREFIX "virtio-serial"
+# define QEMU_FSDEV_HOST_PREFIX "fsdev-"
# define qemuReportError(code, ...) \
virReportErrorHelper(NULL, VIR_FROM_QEMU, code, __FILE__, \
@@ -248,9 +250,12 @@ char *qemuDeviceDriveHostAlias(virDomainDiskDefPtr disk,
char *qemuBuildDriveStr(virDomainDiskDefPtr disk,
int bootable,
unsigned long long qemuCmdFlags);
+char *qemuBuildFSStr(virDomainFSDefPtr fs,
+ unsigned long long qemuCmdFlags);
/* Current, best practice */
char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk);
+char * qemuBuildFSDevStr(virDomainFSDefPtr fs);
/* Current, best practice */
char * qemuBuildControllerDevStr(virDomainControllerDefPtr def);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-fs9p.args b/tests/qemuxml2argvdata/qemuxml2argv-fs9p.args
new file mode 100644
index 0000000..995ffc0
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-fs9p.args
@@ -0,0 +1 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults -monitor unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda /dev/HostVG/QEMUGuest1 -fsdev local,security_model=passthrough,id=fsdev-fs0,path=/export/to/guest -device virtio-9p-pci,id=fs0,fsdev=fsdev-fs0,mount_tag=/import/from/host,bus=pci.0,addr=0x2 -usb -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml b/tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml
new file mode 100644
index 0000000..9072ead
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-fs9p.xml
@@ -0,0 +1,28 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219200</memory>
+ <currentMemory>219200</currentMemory>
+ <vcpu>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='block' device='disk'>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <filesystem type='mount'>
+ <source dir='/export/to/guest'/>
+ <target dir='/import/from/host'/>
+ </filesystem>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 7b9df09..92d5b18 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -368,6 +368,8 @@ mymain(int argc, char **argv)
DO_TEST("sound", 0);
DO_TEST("sound-device", QEMUD_CMD_FLAG_DEVICE |
QEMUD_CMD_FLAG_NODEFCONFIG);
+ DO_TEST("fs9p", QEMUD_CMD_FLAG_DEVICE |
+ QEMUD_CMD_FLAG_NODEFCONFIG | QEMUD_CMD_FLAG_FSDEV);
DO_TEST("hostdev-usb-address", 0);
DO_TEST("hostdev-usb-address-device", QEMUD_CMD_FLAG_DEVICE |
--
1.7.2.3
14 years, 1 month