[libvirt] [libvirt-virshcmdref 01/10] clarify the format of XML file used in command attach-device and detach-device
by Hu Tao
---
source/attach-device.xml | 4 +++-
source/detach-device.xml | 3 ++-
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/source/attach-device.xml b/source/attach-device.xml
index 18e3262..aab8313 100644
--- a/source/attach-device.xml
+++ b/source/attach-device.xml
@@ -27,7 +27,9 @@
<value type="string" requirement="required">file</value>
<description>
<text>
- the XML file describing the device to be attached
+ the XML file describing the device to be attached, with
+ a root element of something that belongs inside <devices>
+ of domain xml
</text>
<text>
"--file" itself is optional
diff --git a/source/detach-device.xml b/source/detach-device.xml
index 85ab17b..6262d49 100644
--- a/source/detach-device.xml
+++ b/source/detach-device.xml
@@ -27,7 +27,8 @@
<value type="string" requirement="required">file</value>
<description>
<text>
- the XML file describing the device to be detached
+ the XML file describing the device to be detached, with
+ a root element of something that belongs inside <devices>
</text>
<text>
"--file" itself is optional
--
1.7.3.1
13 years, 2 months
[libvirt] [RFC PATCH] Prevent defining a domain has disk used by other domain
by Osier Yang
$subject + "If the disk is shared and readonly."
If the disk is not shared or readonly, the later started domain
will relabel the disk, thus the first domain will lose the permission
to write to the disk and be corrupt.
--
I'm not sure if it's the design to allow multiple domains use
same disk not shared and readonly. So this patch just gives a
demo of the implementation (it skips the checking of nbd disk,
and only changes qemu driver), to see whether if the pricinple
is right or not.
---
src/conf/domain_conf.c | 34 ++++++++++++++++++++++++++++++++++
src/conf/domain_conf.h | 2 ++
src/libvirt_private.syms | 1 +
src/qemu/qemu_driver.c | 24 ++++++++++++++++++++++++
4 files changed, 61 insertions(+), 0 deletions(-)
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7463d7c..b64450b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -655,6 +655,40 @@ virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
return obj;
}
+static int
+virDomainObjListSearchDiskPath(const void *payload,
+ const void *name ATTRIBUTE_UNUSED,
+ const void *data)
+{
+ virDomainObjPtr obj = (virDomainObjPtr)payload;
+ int i;
+ int want = 0;
+ const char *path = NULL;
+
+ path = (const char *)data;
+
+ virDomainObjLock(obj);
+ for (i = 0; obj->def->ndisks; i++) {
+ if (STREQ(obj->def->disks[i]->src, path)) {
+ want = 1;
+ break;
+ }
+ }
+ virDomainObjUnlock(obj);
+
+ return want;
+}
+
+virDomainObjPtr
+virDomainFindByDiskPath(const virDomainObjListPtr doms,
+ const char *path)
+{
+ virDomainObjPtr obj = NULL;
+ obj = virHashSearch(doms->objs, virDomainObjListSearchDiskPath, path);
+ if (obj)
+ virDomainObjLock(obj);
+ return obj;
+}
bool virDomainObjTaint(virDomainObjPtr obj,
enum virDomainTaintFlags taint)
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 371f270..d7d42dd 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1549,6 +1549,8 @@ virDomainObjPtr virDomainFindByUUID(const virDomainObjListPtr doms,
const unsigned char *uuid);
virDomainObjPtr virDomainFindByName(const virDomainObjListPtr doms,
const char *name);
+virDomainObjPtr virDomainFindByDiskPath(const virDomainObjListPtr doms,
+ const char *path);
bool virDomainObjTaint(virDomainObjPtr obj,
enum virDomainTaintFlags taint);
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 8235ea1..c33cb2d 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -302,6 +302,7 @@ virDomainFSTypeToString;
virDomainFindByID;
virDomainFindByName;
virDomainFindByUUID;
+virDomainFindByDiskPath;
virDomainGetRootFilesystem;
virDomainGraphicsAuthConnectedTypeFromString;
virDomainGraphicsAuthConnectedTypeToString;
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0d0bea2..a448a0b 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4796,6 +4796,7 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
virDomainPtr dom = NULL;
virDomainEventPtr event = NULL;
int dupVM;
+ int i;
qemuDriverLock(driver);
if (!(def = virDomainDefParseString(driver->caps, xml,
@@ -4809,6 +4810,29 @@ static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
goto cleanup;
+ /* Make sure no disk is used by other domain, if it's not
+ * either shareable or readonly.
+ */
+ for (i = 0; i < def->ndisks; i++) {
+ /* XXX: Do we also need to check if same host&port is used by
+ * other domain for disk of nbd type?
+ */
+ if (def->disks[i]->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+ def->disks[i]->protocol == VIR_DOMAIN_DISK_PROTOCOL_NBD)
+ continue;
+
+ if (!def->disks[i]->shared &&
+ !def->disks[i]->readonly &&
+ (vm = virDomainFindByDiskPath(&driver->domains,
+ def->disks[i]->src))) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("disk '%s' already used by domain '%s'"),
+ def->disks[i]->src,
+ vm->def->name);
+ goto cleanup;
+ }
+ }
+
if (qemudCanonicalizeMachine(driver, def) < 0)
goto cleanup;
--
1.7.6
13 years, 2 months
[libvirt] [PATCH v3 0/2] add blkio.weight_device support
by Hu Tao
This series adds support for blkio.weight_device.
changes from v2:
- fix the compatibility issue of TYPED_STRING with old clients
and old servers
- modify XML format for weight_device as danp suggested
Hu Tao (2):
Add VIR_TYPED_PARAM_STRING
add interface for blkio.weight_device
daemon/remote.c | 22 +++++
include/libvirt/libvirt.h.in | 14 +++-
src/conf/domain_conf.c | 114 ++++++++++++++++++++++++-
src/conf/domain_conf.h | 16 ++++
src/libvirt_private.syms | 1 +
src/qemu/qemu_cgroup.c | 22 +++++
src/qemu/qemu_driver.c | 191 +++++++++++++++++++++++++++++++++++++++++-
src/remote/remote_driver.c | 17 ++++
src/remote/remote_protocol.x | 2 +
src/remote_protocol-structs | 2 +
src/util/cgroup.c | 33 +++++++
src/util/cgroup.h | 3 +
tools/virsh.c | 52 ++++++++++--
tools/virsh.pod | 5 +-
14 files changed, 479 insertions(+), 15 deletions(-)
--
1.7.3.1
13 years, 2 months
[libvirt] [PATCH] storage: Do not break the whole vol lookup process in the middle
by Osier Yang
* src/storage/storage_driver.c: As virStorageVolLookupByPath lookups
all the pool objs of the drivers, breaking when failing on getting
the stable path of the pool will just breaks the lookup process, it
can cause the API fails even if the vol exists indeed. It won't get
any benifit. This patch is to fix it.
---
src/storage/storage_driver.c | 14 ++++++--------
1 files changed, 6 insertions(+), 8 deletions(-)
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index c05b74e..8a3b5be 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -1247,14 +1247,13 @@ storageVolumeLookupByPath(virConnectPtr conn,
stable_path = virStorageBackendStablePath(driver->pools.objs[i],
cleanpath);
- /*
- * virStorageBackendStablePath already does
- * virStorageReportError if it fails; we just need to keep
- * propagating the return code
- */
if (stable_path == NULL) {
- virStoragePoolObjUnlock(driver->pools.objs[i]);
- goto cleanup;
+ /* Don't break the whole lookup process if fails on
+ * getting the stabe path for some of the pool.
+ */
+ VIR_WARN("Failed to get stable path for pool '%s'",
+ driver->pools.objs[i]->def->name);
+ continue;
}
vol = virStorageVolDefFindByPath(driver->pools.objs[i],
@@ -1274,7 +1273,6 @@ storageVolumeLookupByPath(virConnectPtr conn,
virStorageReportError(VIR_ERR_NO_STORAGE_VOL,
"%s", _("no storage vol with matching path"));
-cleanup:
VIR_FREE(cleanpath);
storageDriverUnlock(driver);
return ret;
--
1.7.6
13 years, 2 months
[libvirt] [PATCH 2/2] Modify generic ethernet interface so it will work when sVirt is enabled with qemu
by Tyler Coumbes
Update code to create generic ethernet interfaces using the new
utility library tunctl making
changes to create the TAP device in libvirt and pass it to qemu as a
file descriptor.
---
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index ee4b52b..181f56c 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -396,6 +396,51 @@ qemuOpenVhostNet(virDomainDefPtr def,
}
+int qemuEthernetIfaceCreate(virDomainDefPtr def,
+ virDomainNetDefPtr net,
+ virBitmapPtr qemuCaps)
+{
+ int tapfd;
+ int err;
+ int vnet_hdr = 0;
+ unsigned char tapmac[VIR_MAC_BUFLEN];
+
+ if (qemuCapsGet(qemuCaps, QEMU_CAPS_VNET_HDR) &&
+ net->model && STREQ(net->model, "virtio"))
+ vnet_hdr = 1;
+
+ if (!net->ifname ||
+ STRPREFIX(net->ifname, "vnet") ||
+ strchr(net->ifname, '%')) {
+ VIR_FREE(net->ifname);
+ if (!(net->ifname = strdup("vnet%d"))) {
+ virReportOOMError();
+ return -1;
+ }
+ }
+
+ err = createTap(&net->ifname, vnet_hdr, &tapfd);
+ virDomainAuditNetDevice(def, net, "/dev/net/tun", tapfd >= 0);
+ if (tapfd < 0 || err)
+ return -1;
+
+ memcpy(tapmac, net->mac, VIR_MAC_BUFLEN);
+ /* Discourage bridge from using TAP dev MAC */
+ tapmac[0] = 0xFE;
+ err = tapSetInterfaceMac(net->ifname, tapmac);
+
+ if (err)
+ return -1;
+
+ err = tapSetInterfaceUp(net->ifname, 1);
+
+ if (err)
+ return -1;
+
+ return tapfd;
+}
+
+
static int qemuDomainDeviceAliasIndex(virDomainDeviceInfoPtr info,
const char *prefix)
{
@@ -2055,14 +2100,17 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
case VIR_DOMAIN_NET_TYPE_ETHERNET:
virBufferAddLit(&buf, "tap");
- if (net->ifname) {
- virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);
- type_sep = ',';
- }
if (net->data.ethernet.script) {
+ if (net->ifname) {
+ virBufferAsprintf(&buf, "%cifname=%s", type_sep, net->ifname);
+ type_sep = ',';
+ }
virBufferAsprintf(&buf, "%cscript=%s", type_sep,
net->data.ethernet.script);
type_sep = ',';
+ } else if(net->ifname) {
+ virBufferAsprintf(&buf, "%cfd=%s", type_sep, tapfd);
+ type_sep = ',';
}
is_tap = true;
break;
@@ -4064,6 +4112,18 @@ qemuBuildCommandLine(virConnectPtr conn,
if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
tapfd) >= sizeof(tapfd_name))
goto no_memory;
+ } else if (actualType == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+ !net->data.ethernet.script) {
+ int tapfd = qemuEthernetIfaceCreate(def, net, qemuCaps);
+ if (tapfd < 0)
+ goto error;
+
+ last_good_net = i;
+ virCommandTransferFD(cmd, tapfd);
+
+ if (snprintf(tapfd_name, sizeof(tapfd_name), "%d",
+ tapfd) >= sizeof(tapfd_name))
+ goto no_memory;
}
if (actualType == VIR_DOMAIN_NET_TYPE_NETWORK ||
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 00e58a2..b21eeb6 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -142,6 +142,10 @@ int qemuOpenVhostNet(virDomainDefPtr def,
virBitmapPtr qemuCaps,
int *vhostfd);
+int qemuEthernetIfaceCreate(virDomainDefPtr def,
+ virDomainNetDefPtr net,
+ virBitmapPtr qemuCaps);
+
int qemudCanonicalizeMachine(struct qemud_driver *driver,
virDomainDefPtr def);
diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
index e8b92a4..cbea145 100644
--- a/src/qemu/qemu_conf.h
+++ b/src/qemu/qemu_conf.h
@@ -29,6 +29,7 @@
# include "ebtables.h"
# include "internal.h"
# include "bridge.h"
+# include "tunctl.h"
# include "capabilities.h"
# include "network_conf.h"
# include "domain_conf.h"
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index 6cfe392..32c5edb 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -645,6 +645,12 @@ int qemuDomainAttachNetDevice(virConnectPtr conn,
iface_connected = true;
if (qemuOpenVhostNet(vm->def, net, priv->qemuCaps, &vhostfd) < 0)
goto cleanup;
+ } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+ !net->data.ethernet.script)
+ {
+ if ((tapfd = qemuEthernetIfaceCreate(vm->def, net,
priv->qemuCaps)) < 0)
+ goto cleanup;
+ iface_connected = true;
}
if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets+1) < 0)
@@ -1881,6 +1887,10 @@ int qemuDomainDetachNetDevice(struct
qemud_driver *driver,
}
#endif
+ if(detach->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+ !detach->data.ethernet.script)
+ delTap(detach->ifname);
+
if ((driver->macFilter) && (detach->ifname != NULL)) {
if ((errno = networkDisallowMacOnPort(driver,
detach->ifname,
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index 3baaa19..11e4219 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -3392,6 +3392,14 @@ void qemuProcessStop(struct qemud_driver *driver,
networkReleaseActualDevice(net);
}
+ def = vm->def;
+ for(i=0; i < def->nnets; i++) {
+ virDomainNetDefPtr net = def->nets[i];
+ if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+ !net->data.ethernet.script)
+ delTap(net->ifname);
+ }
+
retry:
if ((ret = qemuRemoveCgroup(driver, vm, 0)) < 0) {
if (ret == -EBUSY && (retries++ < 5)) {
13 years, 2 months
[libvirt] [PATCH 1/2] Modify generic ethernet interface so it will work when sVirt is enabled with qemu
by Tyler Coumbes
Add a generic utility library for working with the TUN driver (/dev/net/tun).
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 738ee91..ddd1b77 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -88,7 +88,8 @@ UTIL_SOURCES = \
util/xml.c util/xml.h \
util/virterror.c util/virterror_internal.h \
util/virkeycode.c util/virkeycode.h \
- util/virkeymaps.h
+ util/virkeymaps.h \
+ util/tunctl.c util/tunctl.h
EXTRA_DIST += $(srcdir)/util/virkeymaps.h $(srcdir)/util/keymaps.csv \
$(srcdir)/util/virkeycode-mapgen.py
@@ -1182,6 +1183,8 @@ if WITH_NETWORK
USED_SYM_FILES += libvirt_network.syms
endif
+USED_SYM_FILES += libvirt_tunctl.syms
+
EXTRA_DIST += \
libvirt_public.syms \
libvirt_private.syms \
diff --git a/src/libvirt_tunctl.syms b/src/libvirt_tunctl.syms
new file mode 100644
index 0000000..d1e00bb
--- /dev/null
+++ b/src/libvirt_tunctl.syms
@@ -0,0 +1,5 @@
+#tunctl.h
+createTap;
+delTap;
+tapSetInterfaceUp;
+tapSetInterfaceMac;
diff --git a/src/util/tunctl.c b/src/util/tunctl.c
new file mode 100644
index 0000000..e758e6d
--- /dev/null
+++ b/src/util/tunctl.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2007, 2009, 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ */
+
+# include <config.h>
+# include "tunctl.h"
+# include "virfile.h"
+
+# include <stdlib.h>
+# include <stdio.h>
+# include <string.h>
+# include <unistd.h>
+# include <fcntl.h>
+# include <errno.h>
+# include <arpa/inet.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <sys/ioctl.h>
+# include <paths.h>
+# include <sys/wait.h>
+
+# include <linux/param.h> /* HZ */
+# include <linux/sockios.h> /* SIOCBRADDBR etc. */
+# include <linux/if_bridge.h> /* SYSFS_BRIDGE_ATTR */
+# include <linux/if_tun.h> /* IFF_TUN, IFF_NO_PI */
+# include <net/if_arp.h> /* ARPHRD_ETHER */
+
+# include "internal.h"
+# include "command.h"
+# include "memory.h"
+# include "util.h"
+# include "logging.h"
+# include "network.h"
+
+/**
+ * tapProbeVnetHdr:
+ * @tapfd: a tun/tap file descriptor
+ *
+ * Check whether it is safe to enable the IFF_VNET_HDR flag on the
+ * tap interface.
+ *
+ * Setting IFF_VNET_HDR enables QEMU's virtio_net driver to allow
+ * guests to pass larger (GSO) packets, with partial checksums, to
+ * the host. This greatly increases the achievable throughput.
+ *
+ * It is only useful to enable this when we're setting up a virtio
+ * interface. And it is only *safe* to enable it when we know for
+ * sure that a) qemu has support for IFF_VNET_HDR and b) the running
+ * kernel implements the TUNGETIFF ioctl(), which qemu needs to query
+ * the supplied tapfd.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+# ifdef IFF_VNET_HDR
+static int tapProbeVnetHdr(int tapfd)
+{
+# if defined(IFF_VNET_HDR) && defined(TUNGETFEATURES) && defined(TUNGETIFF)
+ unsigned int features;
+ struct ifreq dummy;
+
+ if (ioctl(tapfd, TUNGETFEATURES, &features) != 0) {
+ VIR_INFO("Not enabling IFF_VNET_HDR; "
+ "TUNGETFEATURES ioctl() not implemented");
+ return 0;
+ }
+
+ if (!(features & IFF_VNET_HDR)) {
+ VIR_INFO("Not enabling IFF_VNET_HDR; "
+ "TUNGETFEATURES ioctl() reports no IFF_VNET_HDR");
+ return 0;
+ }
+
+ /* The kernel will always return -1 at this point.
+ * If TUNGETIFF is not implemented then errno == EBADFD.
+ */
+ if (ioctl(tapfd, TUNGETIFF, &dummy) != -1 || errno != EBADFD) {
+ VIR_INFO("Not enabling IFF_VNET_HDR; "
+ "TUNGETIFF ioctl() not implemented");
+ return 0;
+ }
+
+ VIR_INFO("Enabling IFF_VNET_HDR");
+
+ return 1;
+# else
+ (void) tapfd;
+ VIR_INFO("Not enabling IFF_VNET_HDR; disabled at build time");
+ return 0;
+# endif
+}
+# endif
+
+/**
+ * createTap:
+ * @ifname: the interface name
+ * @vnet_hr: whether to try enabling IFF_VNET_HDR
+ * @tapfd: file descriptor return value for the new tap device
+ *
+ * Creates a tap interface.
+ * If the @tapfd parameter is supplied, the open tap device file
+ * descriptor will be returned, otherwise the TAP device will be made
+ * persistent and closed. The caller must use delTap to remove
+ * a persistent TAP devices when it is no longer needed.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int createTap(char **ifname,
+ int vnet_hdr,
+ int *tapfd)
+{
+
+ int fd;
+ struct ifreq ifr;
+
+ if (!ifname)
+ return EINVAL;
+
+ if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+
+# ifdef IFF_VNET_HDR
+ if (vnet_hdr && tapProbeVnetHdr(fd))
+ ifr.ifr_flags |= IFF_VNET_HDR;
+# else
+ (void) vnet_hdr;
+# endif
+
+ if (virStrcpyStatic(ifr.ifr_name, *ifname) == NULL) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (ioctl(fd, TUNSETIFF, &ifr) < 0)
+ goto error;
+
+ if (!tapfd &&
+ (errno = ioctl(fd, TUNSETPERSIST, 1)))
+ goto error;
+ VIR_FREE(*ifname);
+ if (!(*ifname = strdup(ifr.ifr_name)))
+ goto error;
+ if(tapfd)
+ *tapfd = fd;
+ else
+ VIR_FORCE_CLOSE(fd);
+ return 0;
+
+ error:
+ VIR_FORCE_CLOSE(fd);
+
+ return errno;
+}
+
+/**
+ * delTap:
+ * @ifname the interface name
+ *
+ * Deletes the tap interface.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int delTap(const char *ifname) {
+ struct ifreq try;
+ int fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
+ return errno;
+
+ memset(&try, 0, sizeof(struct ifreq));
+ try.ifr_flags = IFF_TAP|IFF_NO_PI;
+
+ if (virStrcpyStatic(try.ifr_name, ifname) == NULL) {
+ errno = EINVAL;
+ goto error;
+ }
+
+ if (ioctl(fd, TUNSETIFF, &try) == 0) {
+ if ((errno = ioctl(fd, TUNSETPERSIST, 0)))
+ goto error;
+ }
+
+ error:
+ VIR_FORCE_CLOSE(fd);
+
+ return errno;
+}
+
+/**
+ * tapSetInterfaceUp:
+ * @ifname: the interface name
+ * @up: 1 for up, 0 for down
+ *
+ * Function to control if an interface is activated (up, 1) or not (down, 0)
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+
+int tapSetInterfaceUp(const char *ifname,
+ int up)
+{
+ struct ifreq ifr;
+ int ifflags;
+ int ctrl_fd;
+
+ if (!ifname)
+ return EINVAL;
+
+ ctrl_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctrl_fd < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+
+ if (ioctl(ctrl_fd, SIOCGIFFLAGS, &ifr) < 0)
+ return errno;
+
+ ifflags = up ? (ifr.ifr_flags | IFF_UP) : (ifr.ifr_flags & ~IFF_UP);
+
+ if (ifr.ifr_flags != ifflags) {
+ ifr.ifr_flags = ifflags;
+
+ if (ioctl(ctrl_fd, SIOCSIFFLAGS, &ifr) < 0)
+ return errno;
+ }
+ VIR_FORCE_CLOSE(ctrl_fd);
+ return 0;
+}
+
+/**
+ * tapSetInterfaceMac:
+ * @ifname: interface name to set MTU for
+ * @macaddr: MAC address (VIR_MAC_BUFLEN in size)
+ *
+ * This function sets the @macaddr for a given interface @ifname. This
+ * gets rid of the kernel's automatically assigned random MAC.
+ *
+ * Returns 0 in case of success or an errno code in case of failure.
+ */
+int tapSetInterfaceMac(const char *ifname,
+ const unsigned char *macaddr)
+{
+ struct ifreq ifr;
+ int ctrl_fd;
+ int err;
+
+ if (!ifname)
+ return EINVAL;
+
+ ctrl_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (ctrl_fd < 0)
+ return errno;
+
+ memset(&ifr, 0, sizeof(struct ifreq));
+ if (virStrcpyStatic(ifr.ifr_name, ifname) == NULL)
+ return EINVAL;
+ /* To fill ifr.ifr_hdaddr.sa_family field */
+ if (ioctl(ctrl_fd, SIOCGIFHWADDR, &ifr) != 0)
+ return errno;
+
+ memcpy(ifr.ifr_hwaddr.sa_data, macaddr, VIR_MAC_BUFLEN);
+
+ err = ioctl(ctrl_fd, SIOCSIFHWADDR, &ifr) == 0 ? 0 : errno;
+
+ VIR_FORCE_CLOSE(ctrl_fd);
+
+ return err;
+}
diff --git a/src/util/tunctl.h b/src/util/tunctl.h
new file mode 100644
index 0000000..73dd4aa
--- /dev/null
+++ b/src/util/tunctl.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Authors:
+ */
+
+#ifndef __QEMUD_TAP_H__
+# define __QEMUD_TAP_H__
+
+# include <config.h>
+# include <net/if.h>
+# include <netinet/in.h>
+# include "network.h"
+
+int createTap (char **ifname,
+ int vnet_hdr,
+ int *tapfd);
+int delTap (const char *ifname);
+int tapSetInterfaceUp (const char *ifname,
+ int up);
+int tapSetInterfaceMac (const char *ifname,
+ const unsigned char *macaddr);
+
+#endif /* __QEMUD_TAP_H__ */
13 years, 2 months
[libvirt] [PATCH] Add unsafe cache mode support for disk driver
by Oskari Saarenmaa
QEMU 0.13 introduced cache=unsafe for -drive, this patch exposes
it in the libvirt layer.
* Introduced a new QEMU capability flag ($prefix_CACHE_UNSAFE),
as even if $prefix_CACHE_V2 is set, we can't known if unsafe
is supported.
* qemuhelptest prints test case name on failure.
---
docs/formatdomain.html.in | 7 ++--
docs/schemas/domaincommon.rng | 1 +
src/conf/domain_conf.c | 3 +-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_capabilities.c | 3 ++
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 15 ++++++++-
tests/qemuargv2xmltest.c | 1 +
tests/qemuhelptest.c | 19 ++++++-----
.../qemuxml2argv-disk-drive-cache-unsafe.args | 5 +++
.../qemuxml2argv-disk-drive-cache-unsafe.xml | 33 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 3 ++
tools/virsh.pod | 4 +-
13 files changed, 80 insertions(+), 16 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 0a7abaf..8087327 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -996,9 +996,10 @@
<li>
The optional <code>cache</code> attribute controls the
cache mechanism, possible values are "default", "none",
- "writethrough", "writeback", and "directsync". "directsync"
- is like "writethrough", but it bypasses the host page
- cache.
+ "writethrough", "writeback", "directsync" (like
+ "writethrough", but it bypasses the host page cache) and
+ "unsafe" (host may cache all disk io and sync requests from
+ guest are ignored).
<span class="since">Since 0.6.0</span>
</li>
<li>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index d0da41c..be98be0 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -848,6 +848,7 @@
<value>writeback</value>
<value>writethrough</value>
<value>directsync</value>
+ <value>unsafe</value>
</choice>
</attribute>
</define>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 7476447..21f4c6b 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -164,7 +164,8 @@ VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST,
"none",
"writethrough",
"writeback",
- "directsync")
+ "directsync",
+ "unsafe")
VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST,
"default",
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 371f270..86b4c79 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -192,6 +192,7 @@ enum virDomainDiskCache {
VIR_DOMAIN_DISK_CACHE_WRITETHRU,
VIR_DOMAIN_DISK_CACHE_WRITEBACK,
VIR_DOMAIN_DISK_CACHE_DIRECTSYNC,
+ VIR_DOMAIN_DISK_CACHE_UNSAFE,
VIR_DOMAIN_DISK_CACHE_LAST
};
diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c
index 36f47a9..13f1aea 100644
--- a/src/qemu/qemu_capabilities.c
+++ b/src/qemu/qemu_capabilities.c
@@ -136,6 +136,7 @@ VIR_ENUM_IMPL(qemuCaps, QEMU_CAPS_LAST,
"pci-ohci",
"usb-redir",
"usb-hub",
+ "cache-unsafe",
);
struct qemu_feature_flags {
@@ -918,6 +919,8 @@ qemuCapsComputeCmdFlags(const char *help,
if (strstr(help, "directsync"))
qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC);
}
+ if (strstr(help, "|unsafe"))
+ qemuCapsSet(flags, QEMU_CAPS_DRIVE_CACHE_UNSAFE);
if (strstr(help, "format="))
qemuCapsSet(flags, QEMU_CAPS_DRIVE_FORMAT);
if (strstr(help, "readonly="))
diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h
index 96b7a3b..97fda0c 100644
--- a/src/qemu/qemu_capabilities.h
+++ b/src/qemu/qemu_capabilities.h
@@ -110,6 +110,7 @@ enum qemuCapsFlags {
QEMU_CAPS_PCI_OHCI = 71, /* -device pci-ohci */
QEMU_CAPS_USB_REDIR = 72, /* -device usb-redir */
QEMU_CAPS_USB_HUB = 73, /* -device usb-hub */
+ QEMU_CAPS_DRIVE_CACHE_UNSAFE = 74, /* Is cache=unsafe supported? */
QEMU_CAPS_LAST, /* this must always be the last item */
};
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index e8b1157..372f9fb 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -66,14 +66,16 @@ VIR_ENUM_IMPL(qemuDiskCacheV1, VIR_DOMAIN_DISK_CACHE_LAST,
"off",
"off", /* writethrough not supported, so for safety, disable */
"on", /* Old 'on' was equivalent to 'writeback' */
- "off"); /* directsync not supported, for safety, disable */
+ "off", /* directsync not supported, for safety, disable */
+ "off"); /* unsafe not supported, for safety, disable */
VIR_ENUM_IMPL(qemuDiskCacheV2, VIR_DOMAIN_DISK_CACHE_LAST,
"default",
"none",
"writethrough",
"writeback",
- "directsync");
+ "directsync",
+ "unsafe");
VIR_ENUM_DECL(qemuVideo)
@@ -1623,6 +1625,13 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
"supported by this QEMU"));
goto error;
}
+ else if (disk->cachemode == VIR_DOMAIN_DISK_CACHE_UNSAFE &&
+ !qemuCapsGet(qemuCaps, QEMU_CAPS_DRIVE_CACHE_UNSAFE)) {
+ qemuReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("disk cache mode 'unsafe' is not "
+ "supported by this QEMU"));
+ goto error;
+ }
} else {
mode = qemuDiskCacheV1TypeToString(disk->cachemode);
}
@@ -5536,6 +5545,8 @@ qemuParseCommandLineDisk(virCapsPtr caps,
def->cachemode = VIR_DOMAIN_DISK_CACHE_WRITETHRU;
else if (STREQ(values[i], "directsync"))
def->cachemode = VIR_DOMAIN_DISK_CACHE_DIRECTSYNC;
+ else if (STREQ(values[i], "unsafe"))
+ def->cachemode = VIR_DOMAIN_DISK_CACHE_UNSAFE;
} else if (STREQ(keywords[i], "werror") ||
STREQ(keywords[i], "rerror")) {
if (STREQ(values[i], "stop"))
diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c
index 91f15af..6a79630 100644
--- a/tests/qemuargv2xmltest.c
+++ b/tests/qemuargv2xmltest.c
@@ -169,6 +169,7 @@ mymain(void)
DO_TEST("disk-drive-cache-v2-wb");
DO_TEST("disk-drive-cache-v2-none");
DO_TEST("disk-drive-cache-directsync");
+ DO_TEST("disk-drive-cache-unsafe");
DO_TEST("disk-drive-network-nbd");
DO_TEST("disk-drive-network-rbd");
DO_TEST("disk-drive-network-sheepdog");
diff --git a/tests/qemuhelptest.c b/tests/qemuhelptest.c
index ffd30e2..4d757e5 100644
--- a/tests/qemuhelptest.c
+++ b/tests/qemuhelptest.c
@@ -77,8 +77,8 @@ static int testHelpStrParsing(const void *data)
if (STRNEQ(got, expected)) {
fprintf(stderr,
- "Computed flags do not match: got %s, expected %s\n",
- got, expected);
+ "%s: computed flags do not match: got %s, expected %s\n",
+ info->name, got, expected);
if (getenv("VIR_TEST_DEBUG"))
printMismatchedFlags(flags, info->flags);
@@ -87,22 +87,22 @@ static int testHelpStrParsing(const void *data)
}
if (version != info->version) {
- fprintf(stderr, "Parsed versions do not match: got %u, expected %u\n",
- version, info->version);
+ fprintf(stderr, "%s: parsed versions do not match: got %u, expected %u\n",
+ info->name, version, info->version);
goto cleanup;
}
if (is_kvm != info->is_kvm) {
fprintf(stderr,
- "Parsed is_kvm flag does not match: got %u, expected %u\n",
- is_kvm, info->is_kvm);
+ "%s: parsed is_kvm flag does not match: got %u, expected %u\n",
+ info->name, is_kvm, info->is_kvm);
goto cleanup;
}
if (kvm_version != info->kvm_version) {
fprintf(stderr,
- "Parsed KVM versions do not match: got %u, expected %u\n",
- kvm_version, info->kvm_version);
+ "%s: parsed KVM versions do not match: got %u, expected %u\n",
+ info->name, kvm_version, info->kvm_version);
goto cleanup;
}
@@ -164,6 +164,7 @@ mymain(void)
QEMU_CAPS_MIGRATE_QEMU_TCP,
QEMU_CAPS_MIGRATE_QEMU_EXEC,
QEMU_CAPS_DRIVE_CACHE_V2,
+ QEMU_CAPS_DRIVE_CACHE_UNSAFE,
QEMU_CAPS_KVM,
QEMU_CAPS_DRIVE_FORMAT,
QEMU_CAPS_DRIVE_SERIAL,
@@ -399,6 +400,7 @@ mymain(void)
QEMU_CAPS_MIGRATE_QEMU_TCP,
QEMU_CAPS_MIGRATE_QEMU_EXEC,
QEMU_CAPS_DRIVE_CACHE_V2,
+ QEMU_CAPS_DRIVE_CACHE_UNSAFE,
QEMU_CAPS_KVM,
QEMU_CAPS_DRIVE_FORMAT,
QEMU_CAPS_DRIVE_SERIAL,
@@ -450,6 +452,7 @@ mymain(void)
QEMU_CAPS_MIGRATE_QEMU_TCP,
QEMU_CAPS_MIGRATE_QEMU_EXEC,
QEMU_CAPS_DRIVE_CACHE_V2,
+ QEMU_CAPS_DRIVE_CACHE_UNSAFE,
QEMU_CAPS_KVM,
QEMU_CAPS_DRIVE_FORMAT,
QEMU_CAPS_DRIVE_SERIAL,
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.args
new file mode 100644
index 0000000..f8ddcd8
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.args
@@ -0,0 +1,5 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \
+pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \
+-no-acpi -boot c -drive file=/dev/HostVG/QEMUGuest1,if=ide,bus=0,unit=0,\
+format=qcow2,cache=unsafe -drive file=/dev/HostVG/QEMUGuest2,if=ide,\
+media=cdrom,bus=1,unit=0,format=raw -net none -serial none -parallel none -usb
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.xml
new file mode 100644
index 0000000..37185f6
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-cache-unsafe.xml
@@ -0,0 +1,33 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219136</memory>
+ <currentMemory>219136</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'>
+ <driver name='qemu' type='qcow2' cache='unsafe'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0' unit='0'/>
+ </disk>
+ <disk type='block' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1' unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index fcb20bb..97b61d1 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -341,6 +341,9 @@ mymain(void)
DO_TEST("disk-drive-cache-directsync", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2,
QEMU_CAPS_DRIVE_CACHE_DIRECTSYNC, QEMU_CAPS_DRIVE_FORMAT);
+ DO_TEST("disk-drive-cache-unsafe", false,
+ QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2,
+ QEMU_CAPS_DRIVE_CACHE_UNSAFE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-nbd", false,
QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_FORMAT);
DO_TEST("disk-drive-network-rbd", false,
diff --git a/tools/virsh.pod b/tools/virsh.pod
index 02726f3..73ed045 100644
--- a/tools/virsh.pod
+++ b/tools/virsh.pod
@@ -1173,8 +1173,8 @@ floppy device; consider using B<update-device> for this usage instead.
I<mode> can specify the two specific mode I<readonly> or I<shareable>.
I<persistent> indicates the changes will affect the next boot of the domain.
I<sourcetype> can indicate the type of source (block|file)
-I<cache> can be one of "default", "none", "writethrough", "writeback", or
-"directsync".
+I<cache> can be one of "default", "none", "writethrough", "writeback",
+"directsync" or "unsafe".
I<serial> is the serial of disk device. I<shareable> indicates the disk device
is shareable between domains.
I<address> is the address of disk device in the form of pci:domain.bus.slot.function,
--
1.7.6.2
13 years, 2 months
[libvirt] [PATCH] selinux: Correctly report warning if virt_use_nfs not set
by Michal Privoznik
Previous patch c9b37fee tried to deal with virt_use_nfs. But
setfilecon() returns EOPNOTSUPP on NFS so we need to move the
warning to else branch.
---
src/security/security_selinux.c | 27 +++++++++++++++------------
1 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/src/security/security_selinux.c b/src/security/security_selinux.c
index 028f5b2..9a9a305 100644
--- a/src/security/security_selinux.c
+++ b/src/security/security_selinux.c
@@ -420,23 +420,26 @@ SELinuxSetFilecon(const char *path, char *tcon)
* virt_use_{nfs,usb,pci} boolean tunables to allow it...
*/
if (setfilecon_errno != EOPNOTSUPP) {
- const char *errmsg;
- if ((virStorageFileIsSharedFSType(path,
- VIR_STORAGE_FILE_SHFS_NFS) == 1) &&
- security_get_boolean_active("virt_use_nfs") != 1) {
- errmsg = _("unable to set security context '%s' on '%s'. "
- "Consider setting virt_use_nfs");
- } else {
- errmsg = _("unable to set security context '%s' on '%s'");
- }
virReportSystemError(setfilecon_errno,
- errmsg,
+ _("unable to set security context '%s' on '%s'"),
tcon, path);
if (security_getenforce() == 1)
return -1;
} else {
- VIR_INFO("Setting security context '%s' on '%s' not supported",
- tcon, path);
+ const char *msg;
+ if ((virStorageFileIsSharedFSType(path,
+ VIR_STORAGE_FILE_SHFS_NFS) == 1) &&
+ security_get_boolean_active("virt_use_nfs") != 1) {
+ msg = _("Setting security context '%s' on '%s' not supported. "
+ "Consider setting virt_use_nfs");
+ if (security_getenforce() == 1)
+ VIR_WARN(msg, tcon, path);
+ else
+ VIR_INFO(msg, tcon, path);
+ } else {
+ VIR_INFO(_("Setting security context '%s' "
+ "on '%s' not supported"), tcon, path);
+ }
}
}
return 0;
--
1.7.3.4
13 years, 2 months
[libvirt] [PATCH] storage: Do not use comma as seperator for lvs output
by Osier Yang
* src/storage/storage_backend_logical.c:
If a logical vol is created with multiple stripes. (e.g. --stripes 3),
the "device" field of lvs output will have multiple fileds which are
seperated by comma. It means the RE we write in the codes will not
work well anymore. E.g. (lvs output for a stripped vol, uses "#" as
seperator here):
test_stripes##fSLSZH-zAS2-yAIb-n4mV-Al9u-HA3V-oo9K1B#\
/dev/sdc1(10240),/dev/sdd1(0)#42949672960#4194304
The RE we uses:
const char *regexes[] = {
"^\\s*(\\S+),(\\S*),(\\S+),(\\S+)\\((\\S+)\\),(\\S+),([0-9]+),?\\s*$"
};
This patch changes the seperator into "#" to fix the problem.
Related RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=727474
---
src/storage/storage_backend_logical.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/storage/storage_backend_logical.c b/src/storage/storage_backend_logical.c
index 4f42047..6c13a6b 100644
--- a/src/storage/storage_backend_logical.c
+++ b/src/storage/storage_backend_logical.c
@@ -199,7 +199,7 @@ virStorageBackendLogicalFindLVs(virStoragePoolObjPtr pool,
7
};
const char *prog[] = {
- LVS, "--separator", ",", "--noheadings", "--units", "b",
+ LVS, "--separator", "#", "--noheadings", "--units", "b",
"--unbuffered", "--nosuffix", "--options",
"lv_name,origin,uuid,devices,seg_size,vg_extent_size",
pool->def->source.name, NULL
--
1.7.6
13 years, 2 months