[libvirt] Add virStorageVolResize()
by Zeeshan Ali (Khattak)
From: "Zeeshan Ali (Khattak)" <zeeshanak(a)gnome.org>
Add a new function to allow changing of capacity of storage volumes.
---
include/libvirt/libvirt.h.in | 5 ++
src/driver.h | 5 ++
src/libvirt.c | 50 +++++++++++++++++++++++
src/libvirt_public.syms | 1 +
src/remote/remote_driver.c | 1 +
src/remote/remote_protocol.x | 9 ++++-
src/remote_protocol-structs | 6 +++
src/storage/storage_backend.h | 6 +++
src/storage/storage_backend_fs.c | 59 ++++++++++++++++++++++++++++
src/storage/storage_driver.c | 80 ++++++++++++++++++++++++++++++++++++++
src/util/storage_file.c | 16 ++++++++
src/util/storage_file.h | 2 +
tools/virsh.c | 53 +++++++++++++++++++++++++
13 files changed, 292 insertions(+), 1 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index e99cd00..b169592 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2386,6 +2386,11 @@ char * virStorageVolGetXMLDesc (virStorageVolPtr pool,
char * virStorageVolGetPath (virStorageVolPtr vol);
+int virStorageVolResize (virStorageVolPtr vol,
+ unsigned long long capacity,
+ unsigned int flags);
+
+
/**
* virKeycodeSet:
*
diff --git a/src/driver.h b/src/driver.h
index df2aa60..c850926 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -1261,6 +1261,10 @@ typedef int
unsigned long long offset,
unsigned long long length,
unsigned int flags);
+typedef int
+ (*virDrvStorageVolResize) (virStorageVolPtr vol,
+ unsigned long long capacity,
+ unsigned int flags);
typedef int
(*virDrvStoragePoolIsActive)(virStoragePoolPtr pool);
@@ -1323,6 +1327,7 @@ struct _virStorageDriver {
virDrvStorageVolGetInfo volGetInfo;
virDrvStorageVolGetXMLDesc volGetXMLDesc;
virDrvStorageVolGetPath volGetPath;
+ virDrvStorageVolResize volResize;
virDrvStoragePoolIsActive poolIsActive;
virDrvStoragePoolIsPersistent poolIsPersistent;
};
diff --git a/src/libvirt.c b/src/libvirt.c
index e9d638b..d1962a2 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -12927,6 +12927,56 @@ error:
return NULL;
}
+/**
+ * virStorageVolResize:
+ * @vol: pointer to storage volume
+ * @capacity: new capacity
+ * @flags: extra flags; not used yet, so callers should always pass 0
+ *
+ * Changes the capacity of the storage volume @vol to @capacity. The new
+ * capacity must not exceed the sum of current capacity of the volume and
+ * remainining free space of its parent pool. Also the new capacity must
+ * be greater than or equal to current allocation of the volume.
+ *
+ * Returns 0 on success, or -1 on error.
+ */
+int
+virStorageVolResize(virStorageVolPtr vol,
+ unsigned long long capacity,
+ unsigned int flags)
+{
+ virConnectPtr conn;
+ VIR_DEBUG("vol=%p capacity=%llu flags=%x", vol, capacity, flags);
+
+ virResetLastError();
+
+ if (!VIR_IS_STORAGE_VOL(vol)) {
+ virLibStorageVolError(VIR_ERR_INVALID_STORAGE_VOL, __FUNCTION__);
+ virDispatchError(NULL);
+ return -1;
+ }
+
+ conn = vol->conn;
+
+ if (conn->flags & VIR_CONNECT_RO) {
+ virLibConnError(VIR_ERR_OPERATION_DENIED, __FUNCTION__);
+ goto error;
+ }
+
+ if (conn->storageDriver && conn->storageDriver->volResize) {
+ int ret;
+ ret = conn->storageDriver->volResize(vol, capacity, flags);
+ if (ret < 0)
+ goto error;
+ return ret;
+ }
+
+ virLibConnError(VIR_ERR_NO_SUPPORT, __FUNCTION__);
+
+error:
+ virDispatchError(vol->conn);
+ return -1;
+}
/**
* virNodeNumOfDevices:
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index 1340b0c..54a4f2c 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -520,6 +520,7 @@ LIBVIRT_0.9.10 {
global:
virDomainShutdownFlags;
virStorageVolWipePattern;
+ virStorageVolResize;
} LIBVIRT_0.9.9;
# .... define new API here using predicted next version number ....
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index f79f53e..2bb4cbf 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -4837,6 +4837,7 @@ static virStorageDriver storage_driver = {
.volGetInfo = remoteStorageVolGetInfo, /* 0.4.1 */
.volGetXMLDesc = remoteStorageVolGetXMLDesc, /* 0.4.1 */
.volGetPath = remoteStorageVolGetPath, /* 0.4.1 */
+ .volResize = remoteStorageVolResize, /* 0.9.10 */
.poolIsActive = remoteStoragePoolIsActive, /* 0.7.3 */
.poolIsPersistent = remoteStoragePoolIsPersistent, /* 0.7.3 */
};
diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x
index 0f354bb..29f98fc 100644
--- a/src/remote/remote_protocol.x
+++ b/src/remote/remote_protocol.x
@@ -1676,6 +1676,12 @@ struct remote_storage_vol_get_path_ret {
remote_nonnull_string name;
};
+struct remote_storage_vol_resize_args {
+ remote_nonnull_storage_vol vol;
+ unsigned hyper capacity;
+ unsigned int flags;
+};
+
/* Node driver calls: */
struct remote_node_num_of_devices_args {
@@ -2667,7 +2673,8 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_SET_INTERFACE_PARAMETERS = 256, /* autogen autogen */
REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257, /* skipgen skipgen */
REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258, /* autogen autogen */
- REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN = 259 /* autogen autogen */
+ REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN = 259, /* autogen autogen */
+ REMOTE_PROC_STORAGE_VOL_RESIZE = 300 /* autogen autogen */
/*
* Notice how the entries are grouped in sets of 10 ?
diff --git a/src/remote_protocol-structs b/src/remote_protocol-structs
index de85862..9a60fc2 100644
--- a/src/remote_protocol-structs
+++ b/src/remote_protocol-structs
@@ -1260,6 +1260,11 @@ struct remote_storage_vol_get_path_args {
struct remote_storage_vol_get_path_ret {
remote_nonnull_string name;
};
+struct remote_storage_vol_resize_args {
+ remote_nonnull_storage_vol vol;
+ uint64_t capacity;
+ u_int flags;
+};
struct remote_node_num_of_devices_args {
remote_string cap;
u_int flags;
@@ -2101,4 +2106,5 @@ enum remote_procedure {
REMOTE_PROC_DOMAIN_GET_INTERFACE_PARAMETERS = 257,
REMOTE_PROC_DOMAIN_SHUTDOWN_FLAGS = 258,
REMOTE_PROC_STORAGE_VOL_WIPE_PATTERN = 259,
+ REMOTE_PROC_STORAGE_VOL_RESIZE = 300,
};
diff --git a/src/storage/storage_backend.h b/src/storage/storage_backend.h
index 75ed676..a37bf7c 100644
--- a/src/storage/storage_backend.h
+++ b/src/storage/storage_backend.h
@@ -44,6 +44,11 @@ typedef int (*virStorageBackendDeleteVol)(virConnectPtr conn, virStoragePoolObjP
typedef int (*virStorageBackendBuildVolFrom)(virConnectPtr conn, virStoragePoolObjPtr pool,
virStorageVolDefPtr origvol, virStorageVolDefPtr newvol,
unsigned int flags);
+typedef int (*virStorageBackendVolumeResize)(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned long long capacity,
+ unsigned int flags);
/* File creation/cloning functions used for cloning between backends */
int virStorageBackendCreateRaw(virConnectPtr conn,
@@ -78,6 +83,7 @@ struct _virStorageBackend {
virStorageBackendCreateVol createVol;
virStorageBackendRefreshVol refreshVol;
virStorageBackendDeleteVol deleteVol;
+ virStorageBackendVolumeResize resizeVol;
};
virStorageBackendPtr virStorageBackendForType(int type);
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index d8dc29c..31f7c0a 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -1187,6 +1187,62 @@ virStorageBackendFileSystemVolRefresh(virConnectPtr conn,
return 0;
}
+static int
+virStorageBackendFilesystemResizeQemuImg(const char *path,
+ unsigned long long capacity)
+{
+ int ret = -1;
+ char *img_tool;
+ virCommandPtr cmd = NULL;
+
+ /* KVM is usually ahead of qemu on features, so try that first */
+ img_tool = virFindFileInPath("kvm-img");
+ if (!img_tool)
+ img_tool = virFindFileInPath("qemu-img");
+
+ if (!img_tool) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ "%s", _("unable to find kvm-img or qemu-img"));
+ return -1;
+ }
+
+ cmd = virCommandNew(img_tool);
+ virCommandAddArgList(cmd, "resize", path, NULL);
+ virCommandAddArgFormat(cmd, "%llu", capacity);
+
+ ret = virCommandRun(cmd, NULL);
+
+ VIR_FREE(img_tool);
+ virCommandFree(cmd);
+
+ return ret;
+}
+
+/**
+ * Resize a volume
+ */
+static int
+virStorageBackendFileSystemVolResize(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol,
+ unsigned long long capacity,
+ unsigned int flags)
+{
+ virCheckFlags(0, -1);
+
+ if (vol->target.format == VIR_STORAGE_FILE_RAW) {
+ return virStorageFileResize(vol->target.path, capacity);
+ } else if (vol->target.format == VIR_STORAGE_FILE_DIR) {
+ virStorageReportError(VIR_ERR_NO_SUPPORT,
+ "%s", _("Changing size of directory based "
+ "volumes is not supported"));
+ return -1;
+ } else {
+ return virStorageBackendFilesystemResizeQemuImg(vol->target.path,
+ capacity);
+ }
+}
+
virStorageBackend virStorageBackendDirectory = {
.type = VIR_STORAGE_POOL_DIR,
@@ -1199,6 +1255,7 @@ virStorageBackend virStorageBackendDirectory = {
.createVol = virStorageBackendFileSystemVolCreate,
.refreshVol = virStorageBackendFileSystemVolRefresh,
.deleteVol = virStorageBackendFileSystemVolDelete,
+ .resizeVol = virStorageBackendFileSystemVolResize,
};
#if WITH_STORAGE_FS
@@ -1216,6 +1273,7 @@ virStorageBackend virStorageBackendFileSystem = {
.createVol = virStorageBackendFileSystemVolCreate,
.refreshVol = virStorageBackendFileSystemVolRefresh,
.deleteVol = virStorageBackendFileSystemVolDelete,
+ .resizeVol = virStorageBackendFileSystemVolResize,
};
virStorageBackend virStorageBackendNetFileSystem = {
.type = VIR_STORAGE_POOL_NETFS,
@@ -1232,5 +1290,6 @@ virStorageBackend virStorageBackendNetFileSystem = {
.createVol = virStorageBackendFileSystemVolCreate,
.refreshVol = virStorageBackendFileSystemVolRefresh,
.deleteVol = virStorageBackendFileSystemVolDelete,
+ .resizeVol = virStorageBackendFileSystemVolResize,
};
#endif /* WITH_STORAGE_FS */
diff --git a/src/storage/storage_driver.c b/src/storage/storage_driver.c
index a332ada..76730b4 100644
--- a/src/storage/storage_driver.c
+++ b/src/storage/storage_driver.c
@@ -1695,7 +1695,86 @@ out:
return ret;
}
+static int
+storageVolumeResize(virStorageVolPtr obj,
+ unsigned long long capacity,
+ unsigned int flags)
+{
+ virStorageDriverStatePtr driver = obj->conn->storagePrivateData;
+ virStorageBackendPtr backend;
+ virStoragePoolObjPtr pool = NULL;
+ virStorageVolDefPtr vol = NULL;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ storageDriverLock(driver);
+ pool = virStoragePoolObjFindByName(&driver->pools, obj->pool);
+ storageDriverUnlock(driver);
+
+ if (!pool) {
+ virStorageReportError(VIR_ERR_NO_STORAGE_POOL,
+ _("no storage pool with matching uuid"));
+ goto out;
+ }
+
+ if (!virStoragePoolObjIsActive(pool)) {
+ virStorageReportError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool is not active"));
+ goto out;
+ }
+
+ if ((backend = virStorageBackendForType(pool->def->type)) == NULL)
+ goto out;
+
+ vol = virStorageVolDefFindByName(pool, obj->name);
+
+ if (vol == NULL) {
+ virStorageReportError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ obj->name);
+ goto out;
+ }
+
+ if (vol->building) {
+ virStorageReportError(VIR_ERR_OPERATION_INVALID,
+ _("volume '%s' is still being allocated."),
+ vol->name);
+ goto out;
+ }
+
+ if (capacity < vol->allocation) {
+ virStorageReportError(VIR_ERR_INVALID_ARG,
+ _("can't shrink capacity below "
+ "existing allocation"));
+ goto out;
+ }
+
+ if (capacity > vol->allocation + pool->def->available) {
+ virStorageReportError(VIR_ERR_INVALID_ARG,
+ _("Not enough space left on storage pool"));
+ goto out;
+ }
+
+ if (!backend->resizeVol) {
+ virStorageReportError(VIR_ERR_NO_SUPPORT,
+ _("storage pool does not support changing of "
+ "volume capacity"));
+ goto out;
+ }
+
+ if (backend->resizeVol(obj->conn, pool, vol, capacity, flags) < 0)
+ goto out;
+
+ vol->capacity = capacity;
+ ret = 0;
+
+out:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
/* If the volume we're wiping is already a sparse file, we simply
* truncate and extend it to its original size, filling it with
@@ -2243,6 +2322,7 @@ static virStorageDriver storageDriver = {
.volGetInfo = storageVolumeGetInfo, /* 0.4.0 */
.volGetXMLDesc = storageVolumeGetXMLDesc, /* 0.4.0 */
.volGetPath = storageVolumeGetPath, /* 0.4.0 */
+ .volResize = storageVolumeResize, /* 0.9.10 */
.poolIsActive = storagePoolIsActive, /* 0.7.3 */
.poolIsPersistent = storagePoolIsPersistent, /* 0.7.3 */
diff --git a/src/util/storage_file.c b/src/util/storage_file.c
index ba9cfc5..8260adb 100644
--- a/src/util/storage_file.c
+++ b/src/util/storage_file.c
@@ -931,6 +931,22 @@ virStorageFileFreeMetadata(virStorageFileMetadata *meta)
VIR_FREE(meta);
}
+/**
+ * virStorageFileResize:
+ *
+ * Change the capacity of the raw storage file at 'path'.
+ */
+int
+virStorageFileResize(const char *path, unsigned long long capacity)
+{
+ if (truncate(path, capacity) < 0) {
+ virReportSystemError(errno, _("Failed to truncate file '%s'"), path);
+ return -1;
+ }
+
+ return 0;
+}
+
#ifdef __linux__
# ifndef NFS_SUPER_MAGIC
diff --git a/src/util/storage_file.h b/src/util/storage_file.h
index b8920d0..96afb12 100644
--- a/src/util/storage_file.h
+++ b/src/util/storage_file.h
@@ -72,6 +72,8 @@ int virStorageFileGetMetadataFromFD(const char *path,
void virStorageFileFreeMetadata(virStorageFileMetadata *meta);
+int virStorageFileResize(const char *path, unsigned long long capacity);
+
enum {
VIR_STORAGE_FILE_SHFS_NFS = (1 << 0),
VIR_STORAGE_FILE_SHFS_GFS2 = (1 << 1),
diff --git a/tools/virsh.c b/tools/virsh.c
index 74655c2..20d4bd0 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -11279,6 +11279,58 @@ cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
return ret;
}
+/*
+ * "vol-resize" command
+ */
+static const vshCmdInfo info_vol_resize[] = {
+ {"help", N_("resize a vol")},
+ {"desc", N_("Resizes a storage vol.")},
+ {NULL, NULL}
+};
+
+static const vshCmdOptDef opts_vol_resize[] = {
+ {"vol", VSH_OT_DATA, VSH_OFLAG_REQ, N_("vol name, key or path")},
+ {"capacity", VSH_OT_DATA, VSH_OFLAG_REQ, N_("new capacity for the vol with optional k,M,G,T suffix")},
+ {"pool", VSH_OT_STRING, 0, N_("pool name or uuid")},
+ {NULL, 0, 0, NULL}
+};
+
+static bool
+cmdVolResize(vshControl *ctl, const vshCmd *cmd)
+{
+ virStorageVolPtr vol;
+ const char *capacityStr = NULL;
+ unsigned long long capacity = 0;
+ bool ret = true;
+
+ if (!vshConnectionUsability(ctl, ctl->conn))
+ return false;
+
+ if (!(vol = vshCommandOptVol(ctl, cmd, "vol", "pool", NULL)))
+ return false;
+
+ if (vshCommandOptString(cmd, "capacity", &capacityStr) <= 0)
+ goto cleanup;
+ if (cmdVolSize(capacityStr, &capacity) < 0) {
+ vshError(ctl, _("Malformed size %s"), capacityStr);
+ goto cleanup;
+ }
+
+ if (virStorageVolResize(vol, capacity, 0) == 0) {
+ vshPrint(ctl, "Size of volume '%s' successfully changed to %s\n",
+ virStorageVolGetName(vol), capacityStr);
+ ret = true;
+ } else {
+ vshError(ctl, "Failed to change size of volume '%s' to %s\n",
+ virStorageVolGetName(vol), capacityStr);
+ ret = false;
+ }
+
+cleanup:
+ virStorageVolFree(vol);
+ return ret;
+}
+
/*
* "vol-dumpxml" command
@@ -16141,6 +16193,7 @@ static const vshCmdDef storageVolCmds[] = {
{"vol-pool", cmdVolPool, opts_vol_pool, info_vol_pool, 0},
{"vol-upload", cmdVolUpload, opts_vol_upload, info_vol_upload, 0},
{"vol-wipe", cmdVolWipe, opts_vol_wipe, info_vol_wipe, 0},
+ {"vol-resize", cmdVolResize, opts_vol_resize, info_vol_resize, 0},
{NULL, NULL, NULL, NULL, 0}
};
--
1.7.7.5
12 years, 10 months
[libvirt] [PATCH libvirt-java] Return a byte[] array with secretGetValue
by Wido den Hollander
Signed-off-by: Wido den Hollander <wido(a)widodh.nl>
---
src/main/java/org/libvirt/Secret.java | 11 +++++++++--
src/main/java/org/libvirt/jna/Libvirt.java | 2 +-
2 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/src/main/java/org/libvirt/Secret.java b/src/main/java/org/libvirt/Secret.java
index e536cf4..a874925 100644
--- a/src/main/java/org/libvirt/Secret.java
+++ b/src/main/java/org/libvirt/Secret.java
@@ -5,6 +5,9 @@ import org.libvirt.jna.SecretPointer;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
+import com.sun.jna.ptr.LongByReference;
+import com.sun.jna.Pointer;
+import java.nio.ByteBuffer;
/**
* A secret defined by libvirt
@@ -109,9 +112,13 @@ public class Secret {
*
* @return the value of the secret, or null on failure.
*/
- public String getValue() throws LibvirtException {
- String returnValue = libvirt.virSecretGetValue(VSP, new NativeLong(), 0);
+ public byte[] getValue() throws LibvirtException {
+ LongByReference value_size = new LongByReference();
+ Pointer value = libvirt.virSecretGetValue(VSP, value_size, 0);
processError();
+ ByteBuffer bb = value.getByteBuffer(0, value_size.getValue());
+ byte[] returnValue = new byte[bb.remaining()];
+ bb.get(returnValue);
return returnValue;
}
diff --git a/src/main/java/org/libvirt/jna/Libvirt.java b/src/main/java/org/libvirt/jna/Libvirt.java
index 2c8c03d..3804d55 100644
--- a/src/main/java/org/libvirt/jna/Libvirt.java
+++ b/src/main/java/org/libvirt/jna/Libvirt.java
@@ -330,7 +330,7 @@ public interface Libvirt extends Library {
public int virSecretGetUUID(SecretPointer virSecretPtr, byte[] uuidString);
public int virSecretGetUUIDString(SecretPointer virSecretPtr, byte[] uuidString);
public String virSecretGetUsageID(SecretPointer virSecretPtr);
- public String virSecretGetValue(SecretPointer virSecretPtr, NativeLong value_size, int flags);
+ public Pointer virSecretGetValue(SecretPointer virSecretPtr, LongByReference value_size, int flags);
public String virSecretGetXMLDesc(SecretPointer virSecretPtr, int flags);
public SecretPointer virSecretLookupByUsage(ConnectionPointer virConnectPtr, int usageType, String usageID);
public SecretPointer virSecretLookupByUUID(ConnectionPointer virConnectPtr, byte[] uuidBytes);
--
1.7.5.4
12 years, 10 months
[libvirt] serial console/events example script
by Dave Allan
Hi all,
A while back I wrote the attached code to demonstrate how to use
events and serial console to create a serial console that stays up
even when the VM is down. Is it worth adding to the examples? It
might need some work, as I am not terribly strong with Python.
Dave
12 years, 10 months
[libvirt] [PATCH] qemu: allow snapshotting of sheepdog and rbd disks
by Josh Durgin
Signed-off-by: Josh Durgin <josh.durgin(a)dreamhost.com>
---
.gnulib | 2 +-
src/qemu/qemu_driver.c | 14 ++++++++++----
2 files changed, 11 insertions(+), 5 deletions(-)
diff --git a/.gnulib b/.gnulib
index d5612c7..6b93d00 160000
--- a/.gnulib
+++ b/.gnulib
@@ -1 +1 @@
-Subproject commit d5612c714c87555f1059d71d347e20271dced322
+Subproject commit 6b93d00f5410ec183e3a70ebf8e418e3b1bb0191
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 7e6d59c..fc537df 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -9571,12 +9571,18 @@ qemuDomainSnapshotIsAllowed(virDomainObjPtr vm)
* that succeed as well
*/
for (i = 0; i < vm->def->ndisks; i++) {
- if ((vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_LUN) ||
- (vm->def->disks[i]->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
- STRNEQ_NULLABLE(vm->def->disks[i]->driverType, "qcow2"))) {
+ virDomainDiskDefPtr disk = vm->def->disks[i];
+ if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
+ (disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
+ disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD))
+ continue;
+
+ if ((disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) ||
+ (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
+ STRNEQ_NULLABLE(disk->driverType, "qcow2"))) {
qemuReportError(VIR_ERR_OPERATION_INVALID,
_("Disk '%s' does not support snapshotting"),
- vm->def->disks[i]->src);
+ disk->src);
return false;
}
}
--
1.7.5.4
12 years, 10 months
[libvirt] [PATCH 0/3 v4] use qemu's dump-guest-meory when vm uses host device
by Wen Congyang
Currently, we use migrate to dump guest's memory. There is one
restriction in migrate command: the device's status should be
stored in qemu because the device's status should be passed to
target machine.
If we passthrough a host device to guest, the device's status
is stored in the real device. So migrate command will fail.
We usually use dump when guest is panicked. So there is no need
to store device's status in the vmcore.
qemu will have a new monitor command dump-guest-memory to dump
guest memory, but it doesn't support async now(it will support
later when the common async API is implemented).
So I use dump-guest-memory only when the guest uses host device
in this patchset.
Note: the patchset for qemu is still queued. Luiz has acked,
but he said he does not wait an ACK from Jan and/or Anthony.
Changes from v3 to v4:
1. allow the user to specify the core file's format
Changes from v2 to v3:
1. qemu supports the fd that is associated with a pipe, socket, or FIFO.
So pass a pipe fd to qemu and O_DIRECT can work now.
Change from v1 to v2:
1. remove the implemention for text mode.
Wen Congyang (3):
qemu: implement qemu's dump-guest-memory
qemu: allow the client to choose the vmcore's format
virsh: allow the user to specify vmcore's format
include/libvirt/libvirt.h.in | 1 +
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain.h | 1 +
src/qemu/qemu_driver.c | 54 +++++++++++++++++++++++++++++++----------
src/qemu/qemu_monitor.c | 38 +++++++++++++++++++++++++++++
src/qemu/qemu_monitor.h | 12 +++++++++
src/qemu/qemu_monitor_json.c | 35 +++++++++++++++++++++++++++
src/qemu/qemu_monitor_json.h | 6 ++++
tools/virsh.c | 3 ++
tools/virsh.pod | 5 +++-
10 files changed, 142 insertions(+), 14 deletions(-)
12 years, 10 months
[libvirt] [PATCH v2] [TCK] nwfilter: Add test cases for ipset
by Stefan Berger
Add test cases for ipset support.
Since ipset may not be available on all system, the first line of the XML
file containing the test filter has been extended with a specially formatted
XML comment containing a command line test for whether the test case can be
run at all. The format of that line is:
<!-- #<command line test># -->
If the tests in this line don't succeed, the test case is skipped.
Also add a test case cleaning up the created ipset. Run this test after all
other tests using alphabetical ordering.
---
v2:
- addressed Eric Blake's comments
---
scripts/nwfilter/nwfilter2vmtest.sh | 36
+++++++--
scripts/nwfilter/nwfilterxml2fwallout/ipset-test.fwall | 39
++++++++++
scripts/nwfilter/nwfilterxml2fwallout/zzz-ipset-cleanup.fwall | 1
scripts/nwfilter/nwfilterxml2xmlin/ipset-test.xml | 25
++++++
scripts/nwfilter/nwfilterxml2xmlin/zzz-ipset-cleanup.xml | 5 +
5 files changed, 99 insertions(+), 7 deletions(-)
Index: libvirt-tck/scripts/nwfilter/nwfilterxml2xmlin/ipset-test.xml
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/nwfilter/nwfilterxml2xmlin/ipset-test.xml
@@ -0,0 +1,25 @@
+<!-- #ipset help && iptables -t match-set -h && ipset list tck_test ||
ipset create tck_test hash:ip# -->
+<filter name='tck-testcase' chain='root'>
+ <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid>
+ <rule action='accept' direction='out'>
+ <all ipset='tck_test' ipsetflags='src,dst' />
+ </rule>
+ <rule action='accept' direction='in'>
+ <all state='NONE' ipset='tck_test' ipsetflags='src,dst'
comment='in+NONE'/>
+ </rule>
+ <rule action='accept' direction='out'>
+ <all state='NONE' ipset='tck_test' ipsetflags='src,dst'
comment='out+NONE'/>
+ </rule>
+ <rule action='accept' direction='in'>
+ <all ipset='tck_test' ipsetflags='SRC,DST,SRC' />
+ </rule>
+ <rule action='accept' direction='in'>
+ <all ipset='tck_test' ipsetflags='SRC,dSt,SRC' />
+ </rule>
+ <rule action='accept' direction='in'>
+ <all ipset='$IPSETNAME' ipsetflags='src,dst' />
+ </rule>
+ <rule action='accept' direction='inout'>
+ <all ipset='$IPSETNAME' ipsetflags='src,dst' comment='inout'/>
+ </rule>
+</filter>
Index: libvirt-tck/scripts/nwfilter/nwfilter2vmtest.sh
===================================================================
--- libvirt-tck.orig/scripts/nwfilter/nwfilter2vmtest.sh
+++ libvirt-tck/scripts/nwfilter/nwfilter2vmtest.sh
@@ -107,6 +107,7 @@ checkExpectedOutput() {
ifname="$3"
flags="$4"
skipregex="$5"
+ skiptest="$6"
regex="s/${ORIG_IFNAME}/${ifname}/g"
tmpdir=$(mktmpdir)
@@ -147,6 +148,18 @@ checkExpectedOutput() {
break
fi
+ if [ -n "${skiptest}" ]; then
+ # treat all skips as passes
+ passctr=$(($passctr + 1))
+ [ $(($flags & $FLAG_VERBOSE)) -ne 0 ] && \
+ echo "SKIP ${xmlfile} : ${cmd}"
+ [ $(($flags & $FLAG_LIBVIRT_TEST)) -ne 0 ] && \
+ test_result $(($passctr + $failctr)) "" 0
+ [ $(($flags & $FLAG_TAP_TEST)) -ne 0 ] && \
+ tap_pass $(($passctr + $failctr)) "SKIP: ${xmlfile} :
${skiptest}"
+ break
+ fi
+
diff -w ${tmpfile} ${tmpfile2} >/dev/null
if [ $? -ne 0 ]; then
@@ -197,19 +210,27 @@ doTest() {
flags="$5"
testnum="$6"
ctr=0
+ skiptest=""
if [ ! -r "${xmlfile}" ]; then
echo "FAIL : Cannot access filter XML file ${xmlfile}."
return 1
fi
- ${VIRSH} nwfilter-define "${xmlfile}" > /dev/null
+ # Check whether we can run this test at all
+ cmd=$(sed -n '1 s/^<\!--[ ]*#\(.*\)#[ ]*-->/\1/p' ${xmlfile})
+ if [ -n "${cmd}" ]; then
+ eval "${cmd}" 2>/dev/null 1>/dev/null
+ [ $? -ne 0 ] && skiptest="${cmd}"
+ fi
+
+ [ -z "${skiptest}" ] && ${VIRSH} nwfilter-define "${xmlfile}" > /dev/null
checkExpectedOutput "${xmlfile}" "${fwallfile}" "${vm1name}"
"${flags}" \
- ""
+ "" "${skiptest}"
checkExpectedOutput "${TESTFILTERNAME}" "${TESTVM2FWALLDATA}" \
- "${vm2name}" "${flags}" ""
+ "${vm2name}" "${flags}" "" "${skiptest}"
if [ $(($flags & $FLAG_ATTACH)) -ne 0 ]; then
@@ -234,9 +255,9 @@ EOF
if [ $rc -eq 0 ]; then
checkExpectedOutput "${xmlfile}" "${fwallfile}" "${ATTACH_IFNAME}" \
- "${flags}" "(PRE|POST)ROUTING"
+ "${flags}" "(PRE|POST)ROUTING" "${skiptest}"
checkExpectedOutput "${TESTFILTERNAME}" "${TESTVM2FWALLDATA}" \
- "${vm2name}" "${flags}" "(PRE|POST)ROUTING"
+ "${vm2name}" "${flags}" "(PRE|POST)ROUTING" "${skiptest}"
msg=`${VIRSH} detach-device "${vm1name}" "${tmpfile}"`
if [ $? -ne 0 ]; then
echo "FAIL: Detach of interface failed."
@@ -246,9 +267,9 @@ EOF
# In case of TAP, run the test anyway so we get to the full number
# of tests
checkExpectedOutput "${xmlfile}" "${fwallfile}"
"${ATTACH_IFNAME}" \
- "${flags}" "" #"(PRE|POST)ROUTING"
+ "${flags}" "" "${skiptest}" #"(PRE|POST)ROUTING"
checkExpectedOutput "${TESTFILTERNAME}" "${TESTVM2FWALLDATA}" \
- "${vm2name}" "${flags}" #"(PRE|POST)ROUTING"
+ "${vm2name}" "${flags}" "${skiptest}" #"(PRE|POST)ROUTING"
fi
attachfailctr=$(($attachfailctr + 1))
@@ -357,6 +378,7 @@ createVM() {
<parameter name='C' value='1090'/>
<parameter name='C' value='1100'/>
<parameter name='C' value='1110'/>
+ <parameter name='IPSETNAME' value='tck_test'/>
</filterref>
<target dev='${vmname}'/>
</interface>
Index: libvirt-tck/scripts/nwfilter/nwfilterxml2fwallout/ipset-test.fwall
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/nwfilter/nwfilterxml2fwallout/ipset-test.fwall
@@ -0,0 +1,39 @@
+#iptables -L FI-vnet0 -n
+Chain FI-vnet0 (1 references)
+target prot opt source destination
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
NEW,ESTABLISHED ctdir REPLY match-set tck_test src,dst
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 match-set
tck_test src,dst /* out+NONE */
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src,dst
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src,dst
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 match-set
tck_test dst,src /* inout */
+#iptables -L FO-vnet0 -n
+Chain FO-vnet0 (1 references)
+target prot opt source destination
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set
tck_test src,dst /* in+NONE */
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state
NEW,ESTABLISHED ctdir REPLY match-set tck_test src,dst,src
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state
NEW,ESTABLISHED ctdir REPLY match-set tck_test src,dst,src
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state
NEW,ESTABLISHED ctdir REPLY match-set tck_test src,dst
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 match-set
tck_test src,dst /* inout */
+#iptables -L HI-vnet0 -n
+Chain HI-vnet0 (1 references)
+target prot opt source destination
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
NEW,ESTABLISHED ctdir REPLY match-set tck_test src,dst
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 match-set
tck_test src,dst /* out+NONE */
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src,dst
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src,dst
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 state
ESTABLISHED ctdir ORIGINAL match-set tck_test dst,src
+RETURN all -- 0.0.0.0/0 0.0.0.0/0 match-set
tck_test dst,src /* inout */
+#iptables -L libvirt-host-in -n | grep vnet0 | tr -s " "
+HI-vnet0 all -- 0.0.0.0/0 0.0.0.0/0 [goto] PHYSDEV match --physdev-in vnet0
+#iptables -L libvirt-in -n | grep vnet0 | tr -s " "
+FI-vnet0 all -- 0.0.0.0/0 0.0.0.0/0 [goto] PHYSDEV match --physdev-in vnet0
+#iptables -L libvirt-in-post -n | grep vnet0
+ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 PHYSDEV
match --physdev-in vnet0
+#iptables -L libvirt-out -n | grep vnet0 | tr -s " "
+FO-vnet0 all -- 0.0.0.0/0 0.0.0.0/0 [goto] PHYSDEV match --physdev-out
vnet0
+#ebtables -t nat -L libvirt-O-vnet0 2>/dev/null | grep -v "table:" |
grep -v "^$"
+#ebtables -t nat -L libvirt-I-vnet0 2>/dev/null | grep -v "table:" |
grep -v "^$"
+#ebtables -t nat -L PREROUTING | grep vnet0
+#ebtables -t nat -L POSTROUTING | grep vnet0
Index:
libvirt-tck/scripts/nwfilter/nwfilterxml2fwallout/zzz-ipset-cleanup.fwall
===================================================================
--- /dev/null
+++
libvirt-tck/scripts/nwfilter/nwfilterxml2fwallout/zzz-ipset-cleanup.fwall
@@ -0,0 +1 @@
+#ipset destroy tck_test 2>&1 1>/dev/null
Index: libvirt-tck/scripts/nwfilter/nwfilterxml2xmlin/zzz-ipset-cleanup.xml
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/nwfilter/nwfilterxml2xmlin/zzz-ipset-cleanup.xml
@@ -0,0 +1,5 @@
+<!-- #ipset help && iptables -t match-set -h# -->
+<filter name='tck-testcase' chain='root'>
+ <uuid>5c6d49af-b071-6127-b4ec-6f8ed4b55335</uuid>
+ <!-- used only to cleanup ipset -->
+</filter>
12 years, 10 months
[libvirt] [PATCH] storage backend: Add RBD (RADOS Block Device) support
by Wido den Hollander
This patch adds support for a new storage backend with RBD support.
RBD is the RADOS Block Device and is part of the Ceph distributed storage system.
It comes in two flavours: Qemu-RBD and Kernel RBD, this storage backend only supports
Qemu-RBD, thus limiting the use of this storage driver to Qemu only.
To function this backend relies on librbd and librados being present on the local system.
The backend also supports Cephx authentication for safe authentication with the Ceph cluster.
For storing credentials it uses the build-in secret mechanism of libvirt.
Signed-off-by: Wido den Hollander <wido(a)widodh.nl>
---
configure.ac | 20 ++
include/libvirt/libvirt.h.in | 1 +
src/Makefile.am | 9 +
src/conf/storage_conf.c | 197 ++++++++++---
src/conf/storage_conf.h | 16 +
src/storage/storage_backend.c | 6 +
src/storage/storage_backend_rbd.c | 465 ++++++++++++++++++++++++++++++
src/storage/storage_backend_rbd.h | 30 ++
tests/storagepoolxml2xmlin/pool-rbd.xml | 11 +
tests/storagepoolxml2xmlout/pool-rbd.xml | 15 +
tools/virsh.c | 7 +
11 files changed, 734 insertions(+), 43 deletions(-)
create mode 100644 src/storage/storage_backend_rbd.c
create mode 100644 src/storage/storage_backend_rbd.h
create mode 100644 tests/storagepoolxml2xmlin/pool-rbd.xml
create mode 100644 tests/storagepoolxml2xmlout/pool-rbd.xml
diff --git a/configure.ac b/configure.ac
index 32cc8d0..b693e5b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1743,6 +1743,8 @@ AC_ARG_WITH([storage-mpath],
AC_HELP_STRING([--with-storage-mpath], [with mpath backend for the storage driver @<:@default=check@:>@]),[],[with_storage_mpath=check])
AC_ARG_WITH([storage-disk],
AC_HELP_STRING([--with-storage-disk], [with GPartd Disk backend for the storage driver @<:@default=check@:>@]),[],[with_storage_disk=check])
+AC_ARG_WITH([storage-rbd],
+ AC_HELP_STRING([--with-storage-rbd], [with RADOS Block Device backend for the storage driver @<:@default=check@:>@]),[],[with_storage_rbd=check])
if test "$with_libvirtd" = "no"; then
with_storage_dir=no
@@ -1752,6 +1754,7 @@ if test "$with_libvirtd" = "no"; then
with_storage_scsi=no
with_storage_mpath=no
with_storage_disk=no
+ with_storage_rbd=no
fi
if test "$with_storage_dir" = "yes" ; then
AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled])
@@ -1910,6 +1913,22 @@ if test "$with_storage_mpath" = "check"; then
fi
AM_CONDITIONAL([WITH_STORAGE_MPATH], [test "$with_storage_mpath" = "yes"])
+if test "$with_storage_rbd" = "yes" || test "$with_storage_rbd" = "check"; then
+ AC_CHECK_HEADER([rbd/librbd.h], [LIBRBD_FOUND=yes; break;])
+
+ LIBRBD_LIBS="-lrbd -lrados -lcrypto"
+
+ if test "$LIBRBD_FOUND" = "yes"; then
+ with_storage_rbd=yes
+ LIBS="$LIBS $LIBRBD_LIBS"
+ else
+ with_storage_rbd=no
+ fi
+
+ AC_DEFINE_UNQUOTED([WITH_STORAGE_RBD], 1, [wether RBD backend for storage driver is enabled])
+fi
+AM_CONDITIONAL([WITH_STORAGE_RBD], [test "$with_storage_rbd" = "yes"])
+
LIBPARTED_CFLAGS=
LIBPARTED_LIBS=
if test "$with_storage_disk" = "yes" ||
@@ -2673,6 +2692,7 @@ AC_MSG_NOTICE([ iSCSI: $with_storage_iscsi])
AC_MSG_NOTICE([ SCSI: $with_storage_scsi])
AC_MSG_NOTICE([ mpath: $with_storage_mpath])
AC_MSG_NOTICE([ Disk: $with_storage_disk])
+AC_MSG_NOTICE([ RBD: $with_storage_rbd])
AC_MSG_NOTICE([])
AC_MSG_NOTICE([Security Drivers])
AC_MSG_NOTICE([])
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 499dcd4..ee1d5ec 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -2324,6 +2324,7 @@ typedef enum {
VIR_STORAGE_VOL_FILE = 0, /* Regular file based volumes */
VIR_STORAGE_VOL_BLOCK = 1, /* Block based volumes */
VIR_STORAGE_VOL_DIR = 2, /* Directory-passthrough based volume */
+ VIR_STORAGE_VOL_NETWORK = 3, /* Network volumes like RBD (RADOS Block Device) */
#ifdef VIR_ENUM_SENTINELS
VIR_STORAGE_VOL_LAST
diff --git a/src/Makefile.am b/src/Makefile.am
index a2aae9d..e4457c3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -498,6 +498,9 @@ STORAGE_DRIVER_MPATH_SOURCES = \
STORAGE_DRIVER_DISK_SOURCES = \
storage/storage_backend_disk.h storage/storage_backend_disk.c
+STORAGE_DRIVER_RBD_SOURCES = \
+ storage/storage_backend_rbd.h storage/storage_backend_rbd.c
+
STORAGE_HELPER_DISK_SOURCES = \
storage/parthelper.c
@@ -1040,6 +1043,11 @@ if WITH_STORAGE_DISK
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_DISK_SOURCES)
endif
+if WITH_STORAGE_RBD
+libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_RBD_SOURCES)
+libvirt_la_LIBADD += $(LIBRBD_LIBS)
+endif
+
if WITH_NODE_DEVICES
# Needed to keep automake quiet about conditionals
if WITH_DRIVER_MODULES
@@ -1139,6 +1147,7 @@ EXTRA_DIST += \
$(STORAGE_DRIVER_SCSI_SOURCES) \
$(STORAGE_DRIVER_MPATH_SOURCES) \
$(STORAGE_DRIVER_DISK_SOURCES) \
+ $(STORAGE_DRIVER_RBD_SOURCES) \
$(NODE_DEVICE_DRIVER_SOURCES) \
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
diff --git a/src/conf/storage_conf.c b/src/conf/storage_conf.c
index bdf6218..2a0b5eb 100644
--- a/src/conf/storage_conf.c
+++ b/src/conf/storage_conf.c
@@ -52,7 +52,7 @@ VIR_ENUM_IMPL(virStoragePool,
VIR_STORAGE_POOL_LAST,
"dir", "fs", "netfs",
"logical", "disk", "iscsi",
- "scsi", "mpath")
+ "scsi", "mpath", "rbd")
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
VIR_STORAGE_POOL_FS_LAST,
@@ -110,6 +110,7 @@ enum {
VIR_STORAGE_POOL_SOURCE_ADAPTER = (1<<3),
VIR_STORAGE_POOL_SOURCE_NAME = (1<<4),
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN = (1<<5),
+ VIR_STORAGE_POOL_SOURCE_NETWORK = (1<<6),
};
@@ -194,6 +195,15 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
.formatToString = virStoragePoolFormatDiskTypeToString,
}
},
+ { .poolType = VIR_STORAGE_POOL_RBD,
+ .poolOptions = {
+ .flags = (VIR_STORAGE_POOL_SOURCE_NETWORK |
+ VIR_STORAGE_POOL_SOURCE_NAME),
+ },
+ .volOptions = {
+ .formatToString = virStoragePoolFormatDiskTypeToString,
+ }
+ },
{ .poolType = VIR_STORAGE_POOL_MPATH,
.volOptions = {
.formatToString = virStoragePoolFormatDiskTypeToString,
@@ -277,6 +287,11 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
return;
VIR_FREE(source->host.name);
+ for (i = 0 ; i < source->nhost ; i++) {
+ VIR_FREE(source->hosts[i].name);
+ }
+ VIR_FREE(source->hosts);
+
for (i = 0 ; i < source->ndevice ; i++) {
VIR_FREE(source->devices[i].freeExtents);
VIR_FREE(source->devices[i].path);
@@ -293,6 +308,12 @@ virStoragePoolSourceClear(virStoragePoolSourcePtr source)
VIR_FREE(source->auth.chap.login);
VIR_FREE(source->auth.chap.passwd);
}
+
+ if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+ VIR_FREE(source->auth.cephx.username);
+ VIR_FREE(source->auth.cephx.secret.uuid);
+ VIR_FREE(source->auth.cephx.secret.usage);
+ }
}
void
@@ -395,6 +416,27 @@ virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
}
static int
+virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
+ virStoragePoolAuthCephxPtr auth) {
+ auth->username = virXPathString("string(./auth/@username)", ctxt);
+ if (auth->username == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing auth username attribute"));
+ return -1;
+ }
+
+ auth->secret.uuid = virXPathString("string(./auth/secret/@uuid)", ctxt);
+ auth->secret.usage = virXPathString("string(./auth/secret/@usage)", ctxt);
+ if (auth->secret.uuid == NULL && auth->secret.usage == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing auth secret uuid or usage attribute"));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
virStoragePoolSourcePtr source,
int pool_type,
@@ -414,6 +456,12 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
}
source->name = virXPathString("string(./name)", ctxt);
+ if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ _("%s"), "missing mandatory 'name' field for RBD pool name");
+ VIR_FREE(source->name);
+ goto cleanup;
+ }
if (options->formatFromString) {
char *format = virXPathString("string(./format/@type)", ctxt);
@@ -431,17 +479,39 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
VIR_FREE(format);
}
- source->host.name = virXPathString("string(./host/@name)", ctxt);
- port = virXPathString("string(./host/@port)", ctxt);
- if (port) {
- if (virStrToLong_i(port, NULL, 10, &source->host.port) < 0) {
- virStorageReportError(VIR_ERR_XML_ERROR,
- _("Invalid port number: %s"),
- port);
+ source->nhost = virXPathNodeSet("./host", ctxt, &nodeset);
+
+ if (source->nhost) {
+ if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
+ virReportOOMError();
goto cleanup;
}
- }
+ for (i = 0 ; i < source->nhost ; i++) {
+ char *name = virXMLPropString(nodeset[i], "name");
+ if (name == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing storage pool host name"));
+ goto cleanup;
+ }
+ source->hosts[i].name = name;
+ if(i == 0 && source->nhost == 1)
+ source->host.name = name;
+
+ port = virXMLPropString(nodeset[i], "port");
+ if (port) {
+ if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ _("Invalid port number: %s"),
+ port);
+ goto cleanup;
+ } else {
+ if (i == 0 && source->nhost == 1)
+ virStrToLong_i(port, NULL, 10, &source->host.port);
+ }
+ }
+ }
+ }
source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
@@ -478,6 +548,8 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
} else {
if (STREQ(authType, "chap")) {
source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
+ } else if (STREQ(authType, "ceph")) {
+ source->authType = VIR_STORAGE_POOL_AUTH_CEPHX;
} else {
virStorageReportError(VIR_ERR_XML_ERROR,
_("unknown auth type '%s'"),
@@ -491,6 +563,11 @@ virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
goto cleanup;
}
+ if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+ if (virStoragePoolDefParseAuthCephx(ctxt, &source->auth.cephx) < 0)
+ goto cleanup;
+ }
+
source->vendor = virXPathString("string(./vendor/@name)", ctxt);
source->product = virXPathString("string(./product/@name)", ctxt);
@@ -682,6 +759,15 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
}
}
+ if (options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK) {
+ if (!ret->source.host.name && ret->source.nhost < 1) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s",
+ _("missing storage pool source network host name"));
+ goto cleanup;
+ }
+ }
+
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
if (!ret->source.dir) {
virStorageReportError(VIR_ERR_XML_ERROR,
@@ -717,20 +803,22 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt) {
}
}
- if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
- virStorageReportError(VIR_ERR_XML_ERROR,
- "%s", _("missing storage pool target path"));
- goto cleanup;
- }
- ret->target.path = virFileSanitizePath(tmppath);
- VIR_FREE(tmppath);
- if (!ret->target.path)
- goto cleanup;
-
+ /* When we are working with a virtual disk we can skip the target path and permissions */
+ if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
+ if ((tmppath = virXPathString("string(./target/path)", ctxt)) == NULL) {
+ virStorageReportError(VIR_ERR_XML_ERROR,
+ "%s", _("missing storage pool target path"));
+ goto cleanup;
+ }
+ ret->target.path = virFileSanitizePath(tmppath);
+ VIR_FREE(tmppath);
+ if (!ret->target.path)
+ goto cleanup;
- if (virStorageDefParsePerms(ctxt, &ret->target.perms,
- "./target/permissions", 0700) < 0)
- goto cleanup;
+ if (virStorageDefParsePerms(ctxt, &ret->target.perms,
+ "./target/permissions", 0700) < 0)
+ goto cleanup;
+ }
return ret;
@@ -800,12 +888,15 @@ virStoragePoolSourceFormat(virBufferPtr buf,
int i, j;
virBufferAddLit(buf," <source>\n");
- if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) &&
- src->host.name) {
- virBufferAsprintf(buf, " <host name='%s'", src->host.name);
- if (src->host.port)
- virBufferAsprintf(buf, " port='%d'", src->host.port);
- virBufferAddLit(buf, "/>\n");
+ if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST ||
+ options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK) &&
+ src->nhost) {
+ for (i = 0; i < src->nhost; i++) {
+ virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name);
+ if (src->hosts[i].port)
+ virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
+ virBufferAddLit(buf, "/>\n");
+ }
}
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
@@ -860,6 +951,23 @@ virStoragePoolSourceFormat(virBufferPtr buf,
src->auth.chap.login,
src->auth.chap.passwd);
+ if (src->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
+ virBufferAsprintf(buf," <auth username='%s' type='ceph'>\n",
+ src->auth.cephx.username);
+
+ virBufferAsprintf(buf," %s", "<secret");
+ if (src->auth.cephx.secret.uuid != NULL) {
+ virBufferAsprintf(buf," uuid='%s'", src->auth.cephx.secret.uuid);
+ }
+
+ if (src->auth.cephx.secret.usage != NULL) {
+ virBufferAsprintf(buf," usage='%s'", src->auth.cephx.secret.usage);
+ }
+ virBufferAsprintf(buf,"%s", "/>\n");
+
+ virBufferAsprintf(buf," %s", "</auth>\n");
+ }
+
if (src->vendor != NULL) {
virBufferEscapeString(buf," <vendor name='%s'/>\n", src->vendor);
}
@@ -907,25 +1015,28 @@ virStoragePoolDefFormat(virStoragePoolDefPtr def) {
if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
goto cleanup;
- virBufferAddLit(&buf," <target>\n");
+ /* RBD devices are no local block devs nor files, so it doesn't have a target */
+ if (def->type != VIR_STORAGE_POOL_RBD) {
+ virBufferAddLit(&buf," <target>\n");
- if (def->target.path)
- virBufferAsprintf(&buf," <path>%s</path>\n", def->target.path);
+ if (def->target.path)
+ virBufferAsprintf(&buf," <path>%s</path>\n", def->target.path);
- virBufferAddLit(&buf," <permissions>\n");
- virBufferAsprintf(&buf," <mode>0%o</mode>\n",
- def->target.perms.mode);
- virBufferAsprintf(&buf," <owner>%d</owner>\n",
- def->target.perms.uid);
- virBufferAsprintf(&buf," <group>%d</group>\n",
- def->target.perms.gid);
+ virBufferAddLit(&buf," <permissions>\n");
+ virBufferAsprintf(&buf," <mode>0%o</mode>\n",
+ def->target.perms.mode);
+ virBufferAsprintf(&buf," <owner>%d</owner>\n",
+ def->target.perms.uid);
+ virBufferAsprintf(&buf," <group>%d</group>\n",
+ def->target.perms.gid);
- if (def->target.perms.label)
- virBufferAsprintf(&buf," <label>%s</label>\n",
- def->target.perms.label);
+ if (def->target.perms.label)
+ virBufferAsprintf(&buf," <label>%s</label>\n",
+ def->target.perms.label);
- virBufferAddLit(&buf," </permissions>\n");
- virBufferAddLit(&buf," </target>\n");
+ virBufferAddLit(&buf," </permissions>\n");
+ virBufferAddLit(&buf," </target>\n");
+ }
virBufferAddLit(&buf,"</pool>\n");
if (virBufferError(&buf))
diff --git a/src/conf/storage_conf.h b/src/conf/storage_conf.h
index 1ef9295..6b91ca5 100644
--- a/src/conf/storage_conf.h
+++ b/src/conf/storage_conf.h
@@ -120,6 +120,7 @@ enum virStoragePoolType {
VIR_STORAGE_POOL_ISCSI, /* iSCSI targets */
VIR_STORAGE_POOL_SCSI, /* SCSI HBA */
VIR_STORAGE_POOL_MPATH, /* Multipath devices */
+ VIR_STORAGE_POOL_RBD, /* RADOS Block Device */
VIR_STORAGE_POOL_LAST,
};
@@ -137,6 +138,7 @@ enum virStoragePoolDeviceType {
enum virStoragePoolAuthType {
VIR_STORAGE_POOL_AUTH_NONE,
VIR_STORAGE_POOL_AUTH_CHAP,
+ VIR_STORAGE_POOL_AUTH_CEPHX,
};
typedef struct _virStoragePoolAuthChap virStoragePoolAuthChap;
@@ -146,6 +148,15 @@ struct _virStoragePoolAuthChap {
char *passwd;
};
+typedef struct _virStoragePoolAuthCephx virStoragePoolAuthCephx;
+typedef virStoragePoolAuthCephx *virStoragePoolAuthCephxPtr;
+struct _virStoragePoolAuthCephx {
+ char *username;
+ struct {
+ char *uuid;
+ char *usage;
+ } secret;
+};
/*
* For remote pools, info on how to reach the host
@@ -215,6 +226,10 @@ struct _virStoragePoolSource {
/* An optional host */
virStoragePoolSourceHost host;
+ /* Or multiple hosts */
+ int nhost;
+ virStoragePoolSourceHostPtr hosts;
+
/* And either one or more devices ... */
int ndevice;
virStoragePoolSourceDevicePtr devices;
@@ -234,6 +249,7 @@ struct _virStoragePoolSource {
int authType; /* virStoragePoolAuthType */
union {
virStoragePoolAuthChap chap;
+ virStoragePoolAuthCephx cephx;
} auth;
/* Vendor of the source */
diff --git a/src/storage/storage_backend.c b/src/storage/storage_backend.c
index caac2f8..e2e9b51 100644
--- a/src/storage/storage_backend.c
+++ b/src/storage/storage_backend.c
@@ -77,6 +77,9 @@
#if WITH_STORAGE_DIR
# include "storage_backend_fs.h"
#endif
+#if WITH_STORAGE_RBD
+# include "storage_backend_rbd.h"
+#endif
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -103,6 +106,9 @@ static virStorageBackendPtr backends[] = {
#if WITH_STORAGE_DISK
&virStorageBackendDisk,
#endif
+#if WITH_STORAGE_RBD
+ &virStorageBackendRBD,
+#endif
NULL
};
diff --git a/src/storage/storage_backend_rbd.c b/src/storage/storage_backend_rbd.c
new file mode 100644
index 0000000..056059a
--- /dev/null
+++ b/src/storage/storage_backend_rbd.c
@@ -0,0 +1,465 @@
+/*
+ * storage_backend_rbd.c: storage backend for RBD (RADOS Block Device) handling
+ *
+ * Copyright (C) 2012 Wido den Hollander
+ *
+ * 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
+ *
+ * Author: Wido den Hollander <wido(a)widodh.nl>
+ */
+
+#include <config.h>
+
+#include "virterror_internal.h"
+#include "storage_backend_rbd.h"
+#include "storage_conf.h"
+#include "util.h"
+#include "memory.h"
+#include "logging.h"
+#include "base64.h"
+#include "rados/librados.h"
+#include "rbd/librbd.h"
+
+#define VIR_FROM_THIS VIR_FROM_STORAGE
+
+struct _virStorageBackendRBDState {
+ rados_t cluster;
+ rados_ioctx_t ioctx;
+ time_t starttime;
+};
+
+typedef struct _virStorageBackendRBDState virStorageBackendRBDState;
+typedef virStorageBackendRBDState virStorageBackendRBDStatePtr;
+
+static int virStorageBackendRBDOpenRADOSConn(virStorageBackendRBDStatePtr *ptr,
+ virConnectPtr conn,
+ virStoragePoolObjPtr pool)
+{
+ int ret = -1;
+ unsigned char *secret_value;
+ size_t secret_value_size;
+ char *rados_key;
+ virBuffer mon_host = VIR_BUFFER_INITIALIZER;
+ virSecretPtr secret = NULL;
+
+ VIR_DEBUG("Found Cephx username: %s",
+ pool->def->source.auth.cephx.username);
+
+ if (pool->def->source.auth.cephx.username != NULL) {
+ VIR_DEBUG("Using cephx authorization");
+ if (rados_create(&ptr->cluster,
+ pool->def->source.auth.cephx.username) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to initialize RADOS"));
+ goto cleanup;
+ }
+
+ if (pool->def->source.auth.cephx.secret.uuid != NULL) {
+ VIR_DEBUG("Looking up secret by UUID: %s",
+ pool->def->source.auth.cephx.secret.uuid);
+ secret = virSecretLookupByUUIDString(conn,
+ pool->def->source.auth.cephx.secret.uuid);
+ }
+
+ if (pool->def->source.auth.cephx.secret.usage != NULL) {
+ VIR_DEBUG("Looking up secret by usage: %s",
+ pool->def->source.auth.cephx.secret.usage);
+ secret = virSecretLookupByUsage(conn, VIR_SECRET_USAGE_TYPE_CEPH,
+ pool->def->source.auth.cephx.secret.usage);
+ }
+
+ if (secret == NULL) {
+ virStorageReportError(VIR_ERR_NO_SECRET,
+ _("failed to find the secret"));
+ goto cleanup;
+ }
+
+ secret_value = virSecretGetValue(secret, &secret_value_size, 0);
+ base64_encode_alloc((char *)secret_value,
+ secret_value_size, &rados_key);
+ memset(secret_value, 0, secret_value_size);
+
+ if (rados_key == NULL) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to decode the RADOS key"));
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Found cephx key: %s", rados_key);
+ if (rados_conf_set(ptr->cluster, "key", rados_key) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "rados_key");
+ goto cleanup;
+ }
+
+ memset(rados_key, 0, strlen(rados_key));
+
+ if (rados_conf_set(ptr->cluster, "auth_supported", "cephx") < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "auth_supported");
+ goto cleanup;
+ }
+ } else {
+ VIR_DEBUG("Not using cephx authorization");
+ if (rados_conf_set(ptr->cluster, "auth_supported", "none") < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "auth_supported");
+ goto cleanup;
+ }
+ if (rados_create(&ptr->cluster, NULL) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RADOS cluster"));
+ goto cleanup;
+ }
+ }
+
+ VIR_DEBUG("Found %d RADOS cluster monitors in the pool configuration",
+ pool->def->source.nhost);
+
+ int i;
+ for (i = 0; i < pool->def->source.nhost; i++) {
+ if (pool->def->source.hosts[i].name != NULL &&
+ !pool->def->source.hosts[i].port) {
+ virBufferAsprintf(&mon_host, "%s:6789,",
+ pool->def->source.hosts[i].name);
+ } else if (pool->def->source.hosts[i].name != NULL &&
+ pool->def->source.hosts[i].port) {
+ virBufferAsprintf(&mon_host, "%s:%d,",
+ pool->def->source.hosts[i].name,
+ pool->def->source.hosts[i].port);
+ } else {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("received malformed monitor, check the XML definition"));
+ }
+ }
+
+ char *mon_buff = virBufferContentAndReset(&mon_host);
+ VIR_DEBUG("RADOS mon_host has been set to: %s", mon_buff);
+ if (rados_conf_set(ptr->cluster, "mon_host", mon_buff) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to set RADOS option: %s"),
+ "mon_host");
+ goto cleanup;
+ }
+
+ ptr->starttime = time(0);
+ if (rados_connect(ptr->cluster) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to connect to the RADOS monitor on: %s"),
+ virBufferContentAndReset(&mon_host));
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(secret_value);
+ VIR_FREE(rados_key);
+ virSecretFree(secret);
+ virBufferFreeAndReset(&mon_host);
+ return ret;
+}
+
+static int virStorageBackendRBDCloseRADOSConn(virStorageBackendRBDStatePtr ptr)
+{
+ int ret = 0;
+
+ if (ptr.ioctx != NULL) {
+ VIR_DEBUG("Closing RADOS IoCTX");
+ rados_ioctx_destroy(ptr.ioctx);
+ ret = -1;
+ }
+
+ if (ptr.cluster != NULL) {
+ VIR_DEBUG("Closing RADOS connection");
+ rados_shutdown(ptr.cluster);
+ ret = -2;
+ }
+
+ time_t runtime = time(0) - ptr.starttime;
+ VIR_DEBUG("RADOS connection existed for %ld seconds", runtime);
+
+ return ret;
+}
+
+static int volStorageBackendRBDRefreshVolInfo(virStorageVolDefPtr vol,
+ virStoragePoolObjPtr pool,
+ virStorageBackendRBDStatePtr ptr)
+{
+ int ret = -1;
+ rbd_image_t image;
+ if (rbd_open(ptr.ioctx, vol->name, &image, NULL) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to open the RBD image '%s'"),
+ vol->name);
+ goto cleanup;
+ }
+
+ rbd_image_info_t info;
+ if (rbd_stat(image, &info, sizeof(info)) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to stat the RBD image"));
+ goto cleanup;
+ }
+
+ VIR_DEBUG("Refreshed RBD image %s/%s (size: %llu obj_size: %llu num_objs: %llu)",
+ pool->def->source.name, vol->name, (unsigned long long)info.size,
+ (unsigned long long)info.obj_size,
+ (unsigned long long)info.num_objs);
+
+ vol->capacity = info.size;
+ vol->allocation = info.obj_size * info.num_objs;
+ vol->type = VIR_STORAGE_VOL_NETWORK;
+
+ VIR_FREE(vol->target.path);
+ if (virAsprintf(&vol->target.path, "rbd:%s/%s",
+ pool->def->source.name,
+ vol->name) == -1) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ VIR_FREE(vol->key);
+ if (virAsprintf(&vol->key, "%s/%s",
+ pool->def->source.name,
+ vol->name) == -1) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ rbd_close(image);
+ return ret;
+}
+
+static int virStorageBackendRBDRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
+ virStoragePoolObjPtr pool)
+{
+ size_t max_size = 1024;
+ int ret = -1;
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name, &ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ struct rados_cluster_stat_t stat;
+ if (rados_cluster_stat(ptr.cluster, &stat) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("failed to stat the RADOS cluster"));
+ goto cleanup;
+ }
+
+ struct rados_pool_stat_t poolstat;
+ if (rados_ioctx_pool_stat(ptr.ioctx, &poolstat) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to stat the RADOS pool '%s'"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ pool->def->capacity = stat.kb * 1024;
+ pool->def->available = stat.kb_avail * 1024;
+ pool->def->allocation = poolstat.num_bytes;
+
+ int num_images, i;
+ char *names, *name = NULL;
+
+ if (VIR_ALLOC_N(names, 1024) < 0)
+ goto cleanup;
+
+ int len = rbd_list(ptr.ioctx, names, &max_size);
+
+ for (i = 0, num_images = 0, name = names; name < names + len; i++) {
+
+ if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0) {
+ virStoragePoolObjClearVols(pool);
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ virStorageVolDefPtr vol;
+ if (VIR_ALLOC(vol) < 0)
+ goto cleanup;
+
+ vol->name = strdup(name);
+ if (vol->name == NULL)
+ goto cleanup;
+ name += strlen(name) + 1;
+
+ if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0)
+ goto cleanup;
+
+ pool->volumes.objs[pool->volumes.count++] = vol;
+ }
+
+ VIR_DEBUG("Refreshed RBD pool %s (kb: %llu kb_avail: %llu num_bytes: %llu num_images: %d)",
+ pool->def->source.name, (unsigned long long)stat.kb,
+ (unsigned long long)stat.kb_avail,
+ (unsigned long long)poolstat.num_bytes, pool->volumes.count);
+
+ ret = 0;
+
+cleanup:
+ VIR_FREE(names);
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+static int virStorageBackendRBDDeleteVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol,
+ unsigned int flags)
+{
+ int ret = -1;
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+
+ VIR_DEBUG("Removing RBD image %s/%s", pool->def->source.name, vol->name);
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name, &ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ if (rbd_remove(ptr.ioctx, vol->name) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to remove volume '%s/%s'"),
+ pool->def->source.name,
+ vol->name);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+static int virStorageBackendRBDCreateVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool,
+ virStorageVolDefPtr vol)
+{
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+ int order = 0;
+ int ret = -1;
+
+ VIR_DEBUG("Creating RBD image %s/%s with size %llu",
+ pool->def->source.name,
+ vol->name, vol->capacity);
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name,&ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ if (vol->target.encryption != NULL) {
+ virStorageReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("storage pool does not support encrypted volumes"));
+ goto cleanup;
+ }
+
+ if (rbd_create(ptr.ioctx, vol->name, vol->capacity, &order) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create volume '%s/%s'"),
+ pool->def->source.name,
+ vol->name);
+ goto cleanup;
+ }
+
+ if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0) {
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+static int virStorageBackendRBDRefreshVol(virConnectPtr conn,
+ virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
+ virStorageVolDefPtr vol)
+{
+ virStorageBackendRBDStatePtr ptr;
+ ptr.cluster = NULL;
+ ptr.ioctx = NULL;
+ int ret = -1;
+
+ if (virStorageBackendRBDOpenRADOSConn(&ptr, conn, pool) < 0) {
+ goto cleanup;
+ }
+
+ if (rados_ioctx_create(ptr.cluster,
+ pool->def->source.name, &ptr.ioctx) < 0) {
+ virStorageReportError(VIR_ERR_INTERNAL_ERROR,
+ _("failed to create the RBD IoCTX. Does the pool '%s' exist?"),
+ pool->def->source.name);
+ goto cleanup;
+ }
+
+ if (volStorageBackendRBDRefreshVolInfo(vol, pool, ptr) < 0) {
+ goto cleanup;
+ }
+
+ ret = 0;
+
+cleanup:
+ virStorageBackendRBDCloseRADOSConn(ptr);
+ return ret;
+}
+
+virStorageBackend virStorageBackendRBD = {
+ .type = VIR_STORAGE_POOL_RBD,
+
+ .refreshPool = virStorageBackendRBDRefreshPool,
+ .createVol = virStorageBackendRBDCreateVol,
+ .refreshVol = virStorageBackendRBDRefreshVol,
+ .deleteVol = virStorageBackendRBDDeleteVol,
+};
diff --git a/src/storage/storage_backend_rbd.h b/src/storage/storage_backend_rbd.h
new file mode 100644
index 0000000..2ae2513
--- /dev/null
+++ b/src/storage/storage_backend_rbd.h
@@ -0,0 +1,30 @@
+/*
+ * storage_backend_rbd.h: storage backend for RBD (RADOS Block Device) handling
+ *
+ * Copyright (C) 2012 Wido den Hollander
+ *
+ * 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
+ *
+ * Author: Wido den Hollander <wido(a)widodh.nl>
+ */
+
+#ifndef __VIR_STORAGE_BACKEND_RBD_H__
+# define __VIR_STORAGE_BACKEND_RBD_H__
+
+# include "storage_backend.h"
+
+extern virStorageBackend virStorageBackendRBD;
+
+#endif /* __VIR_STORAGE_BACKEND_RBD_H__ */
diff --git a/tests/storagepoolxml2xmlin/pool-rbd.xml b/tests/storagepoolxml2xmlin/pool-rbd.xml
new file mode 100644
index 0000000..c9d4790
--- /dev/null
+++ b/tests/storagepoolxml2xmlin/pool-rbd.xml
@@ -0,0 +1,11 @@
+<pool type='rbd'>
+ <name>ceph</name>
+ <source>
+ <name>rbd</name>
+ <host name='localhost' port='6789'/>
+ <host name='localhost' port='6790'/>
+ <auth username='admin' type='ceph'>
+ <secret uuid='2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' usage='admin'/>
+ </auth>
+ </source>
+</pool>
diff --git a/tests/storagepoolxml2xmlout/pool-rbd.xml b/tests/storagepoolxml2xmlout/pool-rbd.xml
new file mode 100644
index 0000000..fa7fb34
--- /dev/null
+++ b/tests/storagepoolxml2xmlout/pool-rbd.xml
@@ -0,0 +1,15 @@
+<pool type='rbd'>
+ <name>ceph</name>
+ <uuid>47c1faee-0207-e741-f5ae-d9b019b98fe2</uuid>
+ <capacity unit='bytes'>0</capacity>
+ <allocation unit='bytes'>0</allocation>
+ <available unit='bytes'>0</available>
+ <source>
+ <host name='localhost' port='6789'/>
+ <host name='localhost' port='6790'/>
+ <name>rbd</name>
+ <auth username='admin' type='ceph'>
+ <secret uuid='2ec115d7-3a88-3ceb-bc12-0ac909a6fd87' usage='admin'/>
+ </auth>
+ </source>
+</pool>
diff --git a/tools/virsh.c b/tools/virsh.c
index 8ee25c3..632c75e 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -11894,6 +11894,10 @@ cmdVolInfo(vshControl *ctl, const vshCmd *cmd)
vshPrint(ctl, "%-15s %s\n", _("Type:"), _("dir"));
break;
+ case VIR_STORAGE_VOL_NETWORK:
+ vshPrint(ctl, "%-15s %s\n", _("Type:"), _("network"));
+ break;
+
default:
vshPrint(ctl, "%-15s %s\n", _("Type:"), _("unknown"));
}
@@ -19852,6 +19856,9 @@ vshShowVersion(vshControl *ctl ATTRIBUTE_UNUSED)
#ifdef WITH_STORAGE_LVM
vshPrint(ctl, " LVM");
#endif
+#ifdef WITH_STORAGE_RBD
+ vshPrint(ctl, " RBD");
+#endif
vshPrint(ctl, "\n");
vshPrint(ctl, "%s", _(" Miscellaneous:"));
--
1.7.0.4
12 years, 10 months
[libvirt] [PATCH 0/6] support to set cpu bandwidth for hypervisor threads
by Wen Congyang
Currently, we only can set cpu bandwidth for vcpu. If the hypervisor threads
consume too much cpu time, it may affect the vcpu.
This patchset allows the user to control the cpu bandwidth for hypervisor
threads. It does not change the behavior if the cpu bandwidth for hypervisor
is unlimited.
Wen Congyang (6):
Introduce the function virCgroupForHypervisor
introduce the function virCgroupMoveTask()
create a new cgroup and move all hypervisor threads to the new cgroup
Update XML Schema for new entries
qemu: Implement hypervisor's period and quota tunable XML
configuration and parsing
qemu: Implement hypervisor_period and hypervisor_quota's modification
docs/schemas/domaincommon.rng | 10 ++
include/libvirt/libvirt.h.in | 16 +++
src/conf/domain_conf.c | 25 +++++-
src/conf/domain_conf.h | 2 +
src/libvirt_private.syms | 1 +
src/qemu/qemu_cgroup.c | 94 +++++++++++++++--
src/qemu/qemu_cgroup.h | 2 +
src/qemu/qemu_driver.c | 220 +++++++++++++++++++++++++++++++++++-----
src/qemu/qemu_process.c | 4 +
src/util/cgroup.c | 97 ++++++++++++++++++
src/util/cgroup.h | 6 +
11 files changed, 436 insertions(+), 41 deletions(-)
12 years, 11 months
[libvirt] [PATCH 0/2] qemu: Add support for -no-user-config
by Jiri Denemark
Eduardo submitted patches[1] for qemu implementing -no-user-config as a better
alternative to all-or-nothing -nodefconfig. With this new option, we are
finally able to use modern CPU models defined in qemu's configuration file
without allowing user-supplied qemu configuration to mess up with qemu
processes started by libvirt. The qemu patches are not committed upstream yet
(and this patchset won't be committed either until qemu support is finished)
but they are very close and are expected to make it into qemu-1.1.
[1] https://www.redhat.com/archives/libvir-list/2012-April/msg01293.html
Jiri Denemark (2):
qemu: Use common helper when probing qemu capabilities
qemu: Add support for -no-user-config
src/qemu/qemu_capabilities.c | 64 +++++++++++++++++++++++++++--------------
src/qemu/qemu_capabilities.h | 6 ++++
src/qemu/qemu_command.c | 11 ++++---
src/qemu/qemu_driver.c | 9 +++++-
4 files changed, 62 insertions(+), 28 deletions(-)
--
1.7.8.5
12 years, 11 months
[libvirt] [PATCH] openvz: read vmguarpages/privvmpages to set memory tunables [v2]
by Guido Günther
---
This is a reworked version of the patch already sent, now adding
handling for "unlimited" (represented by LONG_MAX in openvz) as well as
a schema testcase. I also switched all value to unsigned long long to
avoid overflows.
Note that privvmpages is the amount of memory available to the
application. The total memory usage of the container might be higher due
to used kernel memory. This does probably warrant an extra tunable
later. O.k. to apply?
Cheers,
-- Guido
src/openvz/openvz_conf.c | 113 ++++++++++++
src/openvz/openvz_driver.c | 208 +++++++++++++++++++++++
tests/domainschemadata/domain-openvz-simple.xml | 27 +++
3 files changed, 348 insertions(+)
create mode 100644 tests/domainschemadata/domain-openvz-simple.xml
diff --git a/src/openvz/openvz_conf.c b/src/openvz/openvz_conf.c
index 5848ec4..a169ae6 100644
--- a/src/openvz/openvz_conf.c
+++ b/src/openvz/openvz_conf.c
@@ -129,6 +129,46 @@ int openvzExtractVersion(struct openvz_driver *driver)
}
+/* Parse config values of the form barrier:limit into barrier and limit */
+static int
+openvzParseBarrierLimit(const char* value,
+ unsigned long long *barrier,
+ unsigned long long *limit)
+{
+ char *token;
+ char *saveptr = NULL;
+ char *str = strdup(value);
+
+ if (str == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ token = strtok_r(str, ":", &saveptr);
+ if (token == NULL) {
+ goto error;
+ } else {
+ if (barrier != NULL) {
+ if (virStrToLong_ull(token, NULL, 10, barrier))
+ goto error;
+ }
+ }
+ token = strtok_r(NULL, ":", &saveptr);
+ if (token == NULL) {
+ goto error;
+ } else {
+ if (limit != NULL) {
+ if (virStrToLong_ull(token, NULL, 10, limit))
+ goto error;
+ }
+ }
+ return 0;
+error:
+ VIR_FREE(str);
+ return -1;
+}
+
+
static int openvzDefaultConsoleType(const char *ostype ATTRIBUTE_UNUSED)
{
return VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_OPENVZ;
@@ -423,6 +463,78 @@ error:
}
+static int
+openvzReadMemConf(virDomainDefPtr def, int veid)
+{
+ int ret;
+ char *temp = NULL;
+ unsigned long long barrier, limit;
+ const char *param;
+ unsigned long kb_per_pages;
+
+ kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+ if (kb_per_pages == -1) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Can't determine page size"));
+ goto error;
+ }
+
+ /* Memory allocation guarantee */
+ param = "VMGUARPAGES";
+ ret = openvzReadVPSConfigParam(veid, param, &temp);
+ if (ret < 0) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not read '%s' from config for container %d"),
+ param, veid);
+ goto error;
+ } else if (ret > 0) {
+ ret = openvzParseBarrierLimit(temp, &barrier, NULL);
+ if (ret < 0) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not parse barrier of '%s' "
+ "from config for container %d"), param, veid);
+ goto error;
+ }
+ if (barrier == LONG_MAX)
+ def->mem.min_guarantee = 0ull;
+ else
+ def->mem.min_guarantee = barrier * kb_per_pages;
+ }
+
+ /* Memory hard and soft limits */
+ param = "PRIVVMPAGES";
+ ret = openvzReadVPSConfigParam(veid, param, &temp);
+ if (ret < 0) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not read '%s' from config for container %d"),
+ param, veid);
+ goto error;
+ } else if (ret > 0) {
+ ret = openvzParseBarrierLimit(temp, &barrier, &limit);
+ if (ret < 0) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Could not parse barrier and limit of '%s' "
+ "from config for container %d"), param, veid);
+ goto error;
+ }
+ if (barrier == LONG_MAX)
+ def->mem.soft_limit = 0ull;
+ else
+ def->mem.soft_limit = barrier * kb_per_pages;
+
+ if (limit == LONG_MAX)
+ def->mem.hard_limit = 0ull;
+ else
+ def->mem.hard_limit = limit * kb_per_pages;
+ }
+
+ ret = 0;
+error:
+ VIR_FREE(temp);
+ return ret;
+}
+
+
/* Free all memory associated with a openvz_driver structure */
void
openvzFreeDriver(struct openvz_driver *driver)
@@ -535,6 +647,7 @@ int openvzLoadDomains(struct openvz_driver *driver) {
openvzReadNetworkConf(dom->def, veid);
openvzReadFSConf(dom->def, veid);
+ openvzReadMemConf(dom->def, veid);
virUUIDFormat(dom->def->uuid, uuidstr);
if (virHashAddEntry(driver->domains.objs, uuidstr, dom) < 0)
diff --git a/src/openvz/openvz_driver.c b/src/openvz/openvz_driver.c
index e8b6915..555161e 100644
--- a/src/openvz/openvz_driver.c
+++ b/src/openvz/openvz_driver.c
@@ -54,6 +54,7 @@
#include "nodeinfo.h"
#include "memory.h"
#include "virfile.h"
+#include "virtypedparam.h"
#include "logging.h"
#include "command.h"
#include "viruri.h"
@@ -65,6 +66,8 @@
#define CMDBUF_LEN 1488
#define CMDOP_LEN 288
+#define OPENVZ_NB_MEM_PARAM 3
+
static int openvzGetProcessInfo(unsigned long long *cpuTime, int vpsid);
static int openvzGetMaxVCPUs(virConnectPtr conn, const char *type);
static int openvzDomainGetMaxVcpus(virDomainPtr dom);
@@ -1631,6 +1634,209 @@ cleanup:
return -1;
}
+
+static int
+openvzDomainGetBarrierLimit(virDomainPtr domain,
+ const char *param,
+ unsigned long long *barrier,
+ unsigned long long *limit)
+{
+ int status, ret = -1;
+ char *output = NULL;
+ virCommandPtr cmd = virCommandNewArgList(VZLIST, "--no-header", NULL);
+
+ virCommandSetOutputBuffer(cmd, &output);
+ virCommandAddArgFormat(cmd, "-o%s.b,%s.l", param, param);
+ virCommandAddArg(cmd, domain->name);
+ if (virCommandRun(cmd, &status)) {
+ openvzError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to get %s for %s: %d"), param, domain->name,
+ status);
+ goto cleanup;
+ }
+
+ if (sscanf(output, "%llu %llu", barrier, limit) != 2) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Can't parse "VZLIST" output, got %s"), output);
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ VIR_FREE(output);
+ virCommandFree(cmd);
+ return ret;
+}
+
+
+static int
+openvzDomainSetBarrierLimit(virDomainPtr domain,
+ const char *param,
+ unsigned long long barrier,
+ unsigned long long limit)
+{
+ int status, ret = -1;
+ virCommandPtr cmd = virCommandNewArgList(VZCTL, "--quiet", "set", NULL);
+
+ /* LONG_MAX indicates unlimited so reject larger values */
+ if (barrier > LONG_MAX || limit > LONG_MAX) {
+ openvzError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to set %s for %s: value too large"), param,
+ domain->name);
+ goto cleanup;
+ }
+
+ virCommandAddArg(cmd, domain->name);
+ virCommandAddArgFormat(cmd, "--%s", param);
+ virCommandAddArgFormat(cmd, "%llu:%llu", barrier, limit);
+ virCommandAddArg(cmd, "--save");
+ if (virCommandRun(cmd, &status)) {
+ openvzError(VIR_ERR_OPERATION_FAILED,
+ _("Failed to set %s for %s: %d"), param, domain->name,
+ status);
+ goto cleanup;
+ }
+
+ ret = 0;
+cleanup:
+ virCommandFree(cmd);
+ return ret;
+}
+
+
+static int
+openvzDomainGetMemoryParameters(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int *nparams,
+ unsigned int flags)
+{
+ int i, result = -1;
+ const char *name;
+ long kb_per_pages;
+ unsigned long long barrier, limit, val;
+
+ virCheckFlags(0, -1);
+
+ kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+ if (kb_per_pages == -1) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Can't determine page size"));
+ goto cleanup;
+ }
+
+ if (*nparams == 0) {
+ *nparams = OPENVZ_NB_MEM_PARAM;
+ return 0;
+ }
+
+ for (i = 0; i <= *nparams; i++) {
+ virMemoryParameterPtr param = ¶ms[i];
+
+ switch (i) {
+ case 0:
+ name = "privvmpages";
+ if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
+ goto cleanup;
+
+ val = (limit == LONG_MAX) ? 0ull : limit * kb_per_pages;
+ if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
+ VIR_TYPED_PARAM_ULLONG, val) < 0)
+ goto cleanup;
+ break;
+
+ case 1:
+ name = "privvmpages";
+ if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
+ goto cleanup;
+
+ val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
+ if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
+ VIR_TYPED_PARAM_ULLONG, val) < 0)
+ goto cleanup;
+ break;
+
+ case 2:
+ name = "vmguarpages";
+ if (openvzDomainGetBarrierLimit(domain, name, &barrier, &limit) < 0)
+ goto cleanup;
+
+ val = (barrier == LONG_MAX) ? 0ull : barrier * kb_per_pages;
+ if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
+ VIR_TYPED_PARAM_ULLONG, val) < 0)
+ goto cleanup;
+ break;
+ }
+ }
+
+ if (*nparams > OPENVZ_NB_MEM_PARAM)
+ *nparams = OPENVZ_NB_MEM_PARAM;
+ result = 0;
+
+cleanup:
+ return result;
+}
+
+
+static int
+openvzDomainSetMemoryParameters(virDomainPtr domain,
+ virTypedParameterPtr params,
+ int nparams,
+ unsigned int flags)
+{
+ int i, result = -1;
+ long kb_per_pages;
+
+ kb_per_pages = sysconf(_SC_PAGESIZE) / 1024;
+ if (kb_per_pages == -1) {
+ openvzError(VIR_ERR_INTERNAL_ERROR,
+ _("Can't determine page size"));
+ goto cleanup;
+ }
+
+ virCheckFlags(0, -1);
+ if (virTypedParameterArrayValidate(params, nparams,
+ VIR_DOMAIN_MEMORY_HARD_LIMIT,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_MEMORY_SOFT_LIMIT,
+ VIR_TYPED_PARAM_ULLONG,
+ VIR_DOMAIN_MEMORY_MIN_GUARANTEE,
+ VIR_TYPED_PARAM_ULLONG,
+ NULL) < 0)
+ return -1;
+
+ for (i = 0; i < nparams; i++) {
+ virTypedParameterPtr param = ¶ms[i];
+ unsigned long long barrier, limit;
+
+ if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
+ if (openvzDomainGetBarrierLimit(domain, "privvmpages",
+ &barrier, &limit) < 0)
+ goto cleanup;
+ limit = params[i].value.ul / kb_per_pages;
+ if (openvzDomainSetBarrierLimit(domain, "privvmpages",
+ barrier, limit) < 0)
+ goto cleanup;
+ } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
+ if (openvzDomainGetBarrierLimit(domain, "privvmpages",
+ &barrier, &limit) < 0)
+ goto cleanup;
+ barrier = params[i].value.ul / kb_per_pages;
+ if (openvzDomainSetBarrierLimit(domain, "privvmpages",
+ barrier, limit) < 0)
+ goto cleanup;
+ } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_MIN_GUARANTEE)) {
+ barrier = params[i].value.ul / kb_per_pages;
+ if (openvzDomainSetBarrierLimit(domain, "vmguarpages",
+ barrier, LONG_MAX) < 0)
+ goto cleanup;
+ }
+ }
+ result = 0;
+cleanup:
+ return result;
+}
+
+
static int
openvzGetVEStatus(virDomainObjPtr vm, int *status, int *reason)
{
@@ -1752,6 +1958,8 @@ static virDriver openvzDriver = {
.domainDestroy = openvzDomainShutdown, /* 0.3.1 */
.domainDestroyFlags = openvzDomainShutdownFlags, /* 0.9.4 */
.domainGetOSType = openvzGetOSType, /* 0.3.1 */
+ .domainGetMemoryParameters = openvzDomainGetMemoryParameters, /* 0.9.12 */
+ .domainSetMemoryParameters = openvzDomainSetMemoryParameters, /* 0.9.12 */
.domainGetInfo = openvzDomainGetInfo, /* 0.3.1 */
.domainGetState = openvzDomainGetState, /* 0.9.2 */
.domainSetVcpus = openvzDomainSetVcpus, /* 0.4.6 */
diff --git a/tests/domainschemadata/domain-openvz-simple.xml b/tests/domainschemadata/domain-openvz-simple.xml
new file mode 100644
index 0000000..aba64a4
--- /dev/null
+++ b/tests/domainschemadata/domain-openvz-simple.xml
@@ -0,0 +1,27 @@
+<domain type='openvz'>
+ <name>100</name>
+ <uuid>7109d234-f5a8-30a6-5dd2-39ca85ce3958</uuid>
+ <memory unit='KiB'>0</memory>
+ <currentMemory unit='KiB'>0</currentMemory>
+ <memtune>
+ <hard_limit unit='KiB'>278528</hard_limit>
+ <soft_limit unit='KiB'>262144</soft_limit>
+ <min_guarantee unit='KiB'>135168</min_guarantee>
+ </memtune>
+ <vcpu>1</vcpu>
+ <os>
+ <type>exe</type>
+ <init>/sbin/init</init>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>destroy</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <filesystem type='template' accessmode='passthrough'>
+ <source name='debian'/>
+ <target dir='/'/>
+ </filesystem>
+ </devices>
+</domain>
+
--
1.7.10
12 years, 11 months