PVS has one serious discrepancy with libvirt: libvirt stores
domain configuration files always in one place, and storage files
in other places (with API of storage pools and storage volumes).
PVS store all domain data in a single directory, for example, you
may have domain with name fedora-15, which will be located in
'/var/parallels/fedora-15.pvm', and it's hard disk image will be
in '/var/parallels/fedora-15.pvm/harddisk1.hdd'.
I've decided to create storage driver, which produces pseudo-volumes
(xml files with volume description), and they will be 'converted' to
real disk images after attaching to a VM.
So if someone creates VM with one hard disk using virt-manager,
at first virt-manager creates a new volume, and then defines a
domain. We can lookup a volume by path in XML domain definition
and find out location of new domain and size of its hard disk.
This code mostly duplicates code in libvirt's default storage
driver, but I haven't found, how functions from that driver can
be reused. So if it possible I'll be very grateful for the advice,
how to do it.
Signed-off-by: Dmitry Guryanov <dguryanov(a)parallels.com>
---
src/Makefile.am | 3 +-
src/pvs/pvs_driver.c | 6 +-
src/pvs/pvs_driver.h | 5 +
src/pvs/pvs_storage.c | 1464 +++++++++++++++++++++++++++++++++++++++++++++++++
src/pvs/pvs_utils.c | 20 +
5 files changed, 1495 insertions(+), 3 deletions(-)
create mode 100644 src/pvs/pvs_storage.c
diff --git a/src/Makefile.am b/src/Makefile.am
index bc9efcf..0765aaf 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -468,7 +468,8 @@ HYPERV_DRIVER_EXTRA_DIST = \
PVS_DRIVER_SOURCES = \
pvs/pvs_driver.h \
pvs/pvs_driver.c \
- pvs/pvs_utils.c
+ pvs/pvs_utils.c \
+ pvs/pvs_storage.c
NETWORK_DRIVER_SOURCES = \
network/bridge_driver.h network/bridge_driver.c
diff --git a/src/pvs/pvs_driver.c b/src/pvs/pvs_driver.c
index ceca50d..5e9b691 100644
--- a/src/pvs/pvs_driver.c
+++ b/src/pvs/pvs_driver.c
@@ -66,13 +66,13 @@ int pvsStart(virDomainObjPtr privdom);
int pvsKill(virDomainObjPtr privdom);
int pvsStop(virDomainObjPtr privdom);
-static void
+void
pvsDriverLock(pvsConnPtr driver)
{
virMutexLock(&driver->lock);
}
-static void
+void
pvsDriverUnlock(pvsConnPtr driver)
{
virMutexUnlock(&driver->lock);
@@ -1177,6 +1177,8 @@ pvsRegister(void)
{
if (virRegisterDriver(&pvsDriver) < 0)
return -1;
+ if (pvsStorageRegister())
+ return -1;
return 0;
}
diff --git a/src/pvs/pvs_driver.h b/src/pvs/pvs_driver.h
index d3cbca2..7384eb1 100644
--- a/src/pvs/pvs_driver.h
+++ b/src/pvs/pvs_driver.h
@@ -27,6 +27,7 @@
#include "domain_conf.h"
#include "storage_conf.h"
+#include "driver.h"
#include "domain_event.h"
#define PRLCTL "prlctl"
@@ -60,8 +61,12 @@ typedef struct _pvsConn pvsConn;
typedef struct _pvsConn *pvsConnPtr;
int pvsRegister(void);
+int pvsStorageRegister(void);
virJSONValuePtr pvsParseOutput(const char *binary, ...);
int pvsCmdRun(const char *binary, ...);
+char * pvsAddFileExt(const char *path, const char *ext);
+void pvsDriverLock(pvsConnPtr driver);
+void pvsDriverUnlock(pvsConnPtr driver);
#endif
diff --git a/src/pvs/pvs_storage.c b/src/pvs/pvs_storage.c
new file mode 100644
index 0000000..95f1fde
--- /dev/null
+++ b/src/pvs/pvs_storage.c
@@ -0,0 +1,1464 @@
+/*
+ * pvs_storage.c: core driver functions for managing
+ * Parallels Virtuozzo Server hosts
+ *
+ * Copyright (C) 2012 Parallels, 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
+ *
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <dirent.h>
+#include <sys/statvfs.h>
+
+#include "datatypes.h"
+#include "memory.h"
+#include "configmake.h"
+#include "storage_file.h"
+#include "virterror_internal.h"
+
+#include "pvs_driver.h"
+
+#define VIR_FROM_THIS VIR_FROM_PVS
+
+static int pvsStorageClose(virConnectPtr conn);
+static virStorageVolDefPtr pvsStorageVolumeDefine(virStoragePoolObjPtr pool,
+ const char *xmldesc,
+ const char *xmlfile,
+ bool is_new);
+static virStorageVolPtr pvsStorageVolumeLookupByPathLocked(virConnectPtr
+ conn,
+ const char
+ *path);
+static virStorageVolPtr pvsStorageVolumeLookupByPath(virConnectPtr conn,
+ const char *path);
+static int pvsStoragePoolGetAlloc(virStoragePoolDefPtr def);
+
+static void
+pvsStorageLock(virStorageDriverStatePtr driver)
+{
+ virMutexLock(&driver->lock);
+}
+
+static void
+pvsStorageUnlock(virStorageDriverStatePtr driver)
+{
+ virMutexUnlock(&driver->lock);
+}
+
+static int
+pvsFindVolumes(virStoragePoolObjPtr pool)
+{
+ int ret;
+ DIR *dir;
+ struct dirent *ent;
+ char *path;
+
+ if (!(dir = opendir(pool->def->target.path))) {
+ virReportSystemError(errno,
+ _("cannot open path '%s'"),
+ pool->def->target.path);
+ goto cleanup;
+ }
+
+ while ((ent = readdir(dir)) != NULL) {
+ if (!virFileHasSuffix(ent->d_name, ".xml"))
+ continue;
+
+ if (!(path = virFileBuildPath(pool->def->target.path,
+ ent->d_name, NULL)))
+ goto no_memory;
+ if (!pvsStorageVolumeDefine(pool, NULL, path, false))
+ goto cleanup;
+ VIR_FREE(path);
+ }
+
+ return ret;
+ no_memory:
+ virReportOOMError();
+ cleanup:
+ return ret;
+
+}
+
+static virDrvOpenStatus
+pvsStorageOpen(virConnectPtr conn,
+ virConnectAuthPtr auth ATTRIBUTE_UNUSED, unsigned int flags)
+{
+ char *base = NULL;
+ virStorageDriverStatePtr storageState;
+ int privileged = (geteuid() == 0);
+ pvsConnPtr privconn = conn->privateData;
+ virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
+
+ if (STRNEQ(conn->driver->name, "PVS"))
+ return VIR_DRV_OPEN_DECLINED;
+
+ if (VIR_ALLOC(storageState) < 0)
+ return VIR_DRV_OPEN_ERROR;
+
+ if (virMutexInit(&storageState->lock) < 0) {
+ VIR_FREE(storageState);
+ return VIR_DRV_OPEN_ERROR;
+ }
+ pvsStorageLock(storageState);
+
+ if (privileged) {
+ if ((base = strdup(SYSCONFDIR "/libvirt")) == NULL)
+ goto out_of_memory;
+ } else {
+ uid_t uid = geteuid();
+
+ char *userdir = virGetUserDirectory(uid);
+
+ if (!userdir)
+ goto error;
+
+ if (virAsprintf(&base, "%s/.libvirt", userdir) == -1) {
+ VIR_FREE(userdir);
+ goto out_of_memory;
+ }
+ VIR_FREE(userdir);
+ }
+
+ /* Configuration paths are either ~/.libvirt/storage/... (session) or
+ * /etc/libvirt/storage/... (system).
+ */
+ if (virAsprintf(&storageState->configDir,
+ "%s/pvs-storage", base) == -1)
+ goto out_of_memory;
+
+ if (virAsprintf(&storageState->autostartDir,
+ "%s/pvs-storage/autostart", base) == -1)
+ goto out_of_memory;
+
+ VIR_FREE(base);
+
+ if (virStoragePoolLoadAllConfigs(&privconn->pools,
+ storageState->configDir,
+ storageState->autostartDir) < 0) {
+ pvsError(VIR_ERR_INTERNAL_ERROR, _("Failed to load pool configs"));
+ goto error;
+ }
+
+ for (int i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ virStoragePoolObjPtr pool;
+
+ pool = privconn->pools.objs[i];
+ if (pool->autostart)
+ pool->active = 1;
+ pool->active = 1;
+
+ if (pvsStoragePoolGetAlloc(pool->def))
+ goto error;
+
+ if (pvsFindVolumes(pool))
+ goto error;
+
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+
+ pvsStorageUnlock(storageState);
+
+ conn->storagePrivateData = storageState;
+
+ return VIR_DRV_OPEN_SUCCESS;
+
+ out_of_memory:
+ virReportOOMError();
+ error:
+ VIR_FREE(base);
+ pvsStorageUnlock(storageState);
+ pvsStorageClose(conn);
+ return -1;
+}
+
+static int
+pvsStorageClose(virConnectPtr conn)
+{
+ pvsConnPtr privconn = conn->privateData;
+ virStorageDriverStatePtr storageState = conn->storagePrivateData;
+ conn->storagePrivateData = NULL;
+
+ pvsStorageLock(storageState);
+ virStoragePoolObjListFree(&privconn->pools);
+ VIR_FREE(storageState->configDir);
+ VIR_FREE(storageState->autostartDir);
+ pvsStorageUnlock(storageState);
+ virMutexDestroy(&storageState->lock);
+ VIR_FREE(storageState);
+
+ return 0;
+}
+
+static int
+pvsStorageNumPools(virConnectPtr conn)
+{
+ pvsConnPtr privconn = conn->privateData;
+ int numActive = 0, i;
+
+ pvsDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++)
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i]))
+ numActive++;
+ pvsDriverUnlock(privconn);
+
+ return numActive;
+}
+
+static int
+pvsStorageListPools(virConnectPtr conn, char **const names, int nnames)
+{
+ pvsConnPtr privconn = conn->privateData;
+ int n = 0, i;
+
+ pvsDriverLock(privconn);
+ memset(names, 0, sizeof(*names) * nnames);
+ for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+ !(names[n++] = strdup(privconn->pools.objs[i]->def->name))) {
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ goto no_memory;
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ pvsDriverUnlock(privconn);
+
+ return n;
+
+ no_memory:
+ virReportOOMError();
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ pvsDriverUnlock(privconn);
+ return -1;
+}
+
+static int
+pvsStorageNumDefinedPools(virConnectPtr conn)
+{
+ pvsConnPtr privconn = conn->privateData;
+ int numInactive = 0, i;
+
+ pvsDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (!virStoragePoolObjIsActive(privconn->pools.objs[i]))
+ numInactive++;
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ pvsDriverUnlock(privconn);
+
+ return numInactive;
+}
+
+static int
+pvsStorageListDefinedPools(virConnectPtr conn,
+ char **const names, int nnames)
+{
+ pvsConnPtr privconn = conn->privateData;
+ int n = 0, i;
+
+ pvsDriverLock(privconn);
+ memset(names, 0, sizeof(*names) * nnames);
+ for (i = 0; i < privconn->pools.count && n < nnames; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (!virStoragePoolObjIsActive(privconn->pools.objs[i]) &&
+ !(names[n++] = strdup(privconn->pools.objs[i]->def->name))) {
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ goto no_memory;
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ pvsDriverUnlock(privconn);
+
+ return n;
+
+ no_memory:
+ virReportOOMError();
+ for (n = 0; n < nnames; n++)
+ VIR_FREE(names[n]);
+ pvsDriverUnlock(privconn);
+ return -1;
+}
+
+
+static int
+pvsStoragePoolIsActive(virStoragePoolPtr pool)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr obj;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ obj = virStoragePoolObjFindByUUID(&privconn->pools, pool->uuid);
+ pvsDriverUnlock(privconn);
+ if (!obj) {
+ pvsError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+ ret = virStoragePoolObjIsActive(obj);
+
+ cleanup:
+ if (obj)
+ virStoragePoolObjUnlock(obj);
+ return ret;
+}
+
+static int
+pvsStoragePoolIsPersistent(virStoragePoolPtr pool ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+static char *
+pvsStorageFindPoolSources(virConnectPtr conn ATTRIBUTE_UNUSED,
+ const char *type ATTRIBUTE_UNUSED,
+ const char *srcSpec ATTRIBUTE_UNUSED,
+ unsigned int flags ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+static virStoragePoolPtr
+pvsStoragePoolLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
+{
+ pvsConnPtr privconn = conn->privateData;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret = NULL;
+
+ pvsDriverLock(privconn);
+ pool = virStoragePoolObjFindByUUID(&privconn->pools, uuid);
+ pvsDriverUnlock(privconn);
+
+ if (pool == NULL) {
+ pvsError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+
+ cleanup:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
+
+static virStoragePoolPtr
+pvsStoragePoolLookupByName(virConnectPtr conn, const char *name)
+{
+ pvsConnPtr privconn = conn->privateData;
+ virStoragePoolObjPtr pool;
+ virStoragePoolPtr ret = NULL;
+
+ pvsDriverLock(privconn);
+ pool = virStoragePoolObjFindByName(&privconn->pools, name);
+ pvsDriverUnlock(privconn);
+
+ if (pool == NULL) {
+ pvsError(VIR_ERR_NO_STORAGE_POOL, NULL);
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+
+ cleanup:
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ return ret;
+}
+
+static virStoragePoolPtr
+pvsStoragePoolLookupByVolume(virStorageVolPtr vol)
+{
+ return pvsStoragePoolLookupByName(vol->conn, vol->pool);
+}
+
+/*
+ * Fill capacity, available and allocation
+ * fields in pool definition.
+ */
+static int
+pvsStoragePoolGetAlloc(virStoragePoolDefPtr def)
+{
+ struct statvfs sb;
+
+ if (statvfs(def->target.path, &sb) < 0) {
+ virReportSystemError(errno,
+ _("cannot statvfs path '%s'"),
+ def->target.path);
+ return -1;
+ }
+
+ def->capacity = ((unsigned long long)sb.f_frsize *
+ (unsigned long long)sb.f_blocks);
+ def->available = ((unsigned long long)sb.f_bfree *
+ (unsigned long long)sb.f_bsize);
+ def->allocation = def->capacity - def->available;
+
+ return 0;
+}
+
+static virStoragePoolPtr
+pvsStoragePoolDefine(virConnectPtr conn,
+ const char *xml, unsigned int flags)
+{
+ pvsConnPtr privconn = conn->privateData;
+ virStoragePoolDefPtr def;
+ virStoragePoolObjPtr pool = NULL;
+ virStoragePoolPtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pvsDriverLock(privconn);
+ if (!(def = virStoragePoolDefParseString(xml)))
+ goto cleanup;
+
+ if (def->type != VIR_STORAGE_POOL_DIR) {
+ pvsError(VIR_ERR_NO_SUPPORT, "%s",
+ _("Only local directories are supported"));
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsDuplicate(&privconn->pools, def, 0) < 0)
+ goto cleanup;
+
+ if (virStoragePoolSourceFindDuplicate(&privconn->pools, def) < 0)
+ goto cleanup;
+
+ if (pvsStoragePoolGetAlloc(def))
+ goto cleanup;
+
+ if (!(pool = virStoragePoolObjAssignDef(&privconn->pools, def)))
+ goto cleanup;
+
+ if (virStoragePoolObjSaveDef(conn->storagePrivateData, pool, def) < 0) {
+ virStoragePoolObjRemove(&privconn->pools, pool);
+ def = NULL;
+ goto cleanup;
+ }
+ def = NULL;
+
+ pool->configFile = strdup("\0");
+ if (!pool->configFile) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ ret = virGetStoragePool(conn, pool->def->name, pool->def->uuid);
+
+ cleanup:
+ virStoragePoolDefFree(def);
+ if (pool)
+ virStoragePoolObjUnlock(pool);
+ pvsDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+pvsStoragePoolUndefine(virStoragePoolPtr pool)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is still active"),
pool->name);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjDeleteDef(privpool) < 0)
+ goto cleanup;
+
+ VIR_FREE(privpool->configFile);
+
+ virStoragePoolObjRemove(&privconn->pools, privpool);
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ pvsDriverUnlock(privconn);
+ return ret;
+}
+
+static int
+pvsStoragePoolBuild(virStoragePoolPtr pool, unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"),
pool->name);
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStoragePoolStart(virStoragePoolPtr pool, unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"),
pool->name);
+ goto cleanup;
+ }
+
+ privpool->active = 1;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStoragePoolDestroy(virStoragePoolPtr pool)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privpool->active = 0;
+
+ if (privpool->configFile == NULL) {
+ virStoragePoolObjRemove(&privconn->pools, privpool);
+ privpool = NULL;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ pvsDriverUnlock(privconn);
+ return ret;
+}
+
+
+static int
+pvsStoragePoolDelete(virStoragePoolPtr pool, unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is already active"),
pool->name);
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+
+static int
+pvsStoragePoolRefresh(virStoragePoolPtr pool, unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ virCheckFlags(0, -1);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+
+static int
+pvsStoragePoolGetInfo(virStoragePoolPtr pool, virStoragePoolInfoPtr info)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ memset(info, 0, sizeof(virStoragePoolInfo));
+ info->state = VIR_STORAGE_POOL_RUNNING;
+ info->capacity = privpool->def->capacity;
+ info->allocation = privpool->def->allocation;
+ info->available = privpool->def->available;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+pvsStoragePoolGetXMLDesc(virStoragePoolPtr pool, unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ ret = virStoragePoolDefFormat(privpool->def);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStoragePoolGetAutostart(virStoragePoolPtr pool, int *autostart)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!privpool->configFile) {
+ *autostart = 0;
+ } else {
+ *autostart = privpool->autostart;
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStoragePoolSetAutostart(virStoragePoolPtr pool, int autostart)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!privpool->configFile) {
+ pvsError(VIR_ERR_INVALID_ARG, "%s", _("pool has no config
file"));
+ goto cleanup;
+ }
+
+ autostart = (autostart != 0);
+ privpool->autostart = autostart;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStoragePoolNumVolumes(virStoragePoolPtr pool)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ ret = privpool->volumes.count;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStoragePoolListVolumes(virStoragePoolPtr pool,
+ char **const names, int maxnames)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ int i = 0, n = 0;
+
+ memset(names, 0, maxnames * sizeof(*names));
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ for (i = 0; i < privpool->volumes.count && n < maxnames; i++) {
+ if ((names[n++] = strdup(privpool->volumes.objs[i]->name)) == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+ }
+
+ virStoragePoolObjUnlock(privpool);
+ return n;
+
+ cleanup:
+ for (n = 0; n < maxnames; n++)
+ VIR_FREE(names[i]);
+
+ memset(names, 0, maxnames * sizeof(*names));
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return -1;
+}
+
+static virStorageVolPtr
+pvsStorageVolumeLookupByName(virStoragePoolPtr pool,
+ const char *name ATTRIBUTE_UNUSED)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ virStorageVolPtr ret = NULL;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, name);
+
+ if (!privvol) {
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"), name);
+ goto cleanup;
+ }
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+
+static virStorageVolPtr
+pvsStorageVolumeLookupByKey(virConnectPtr conn, const char *key)
+{
+ pvsConnPtr privconn = conn->privateData;
+ unsigned int i;
+ virStorageVolPtr ret = NULL;
+
+ pvsDriverLock(privconn);
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+ virStorageVolDefPtr privvol =
+ virStorageVolDefFindByKey(privconn->pools.objs[i], key);
+
+ if (privvol) {
+ ret = virGetStorageVol(conn,
+ privconn->pools.objs[i]->def->name,
+ privvol->name, privvol->key);
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ break;
+ }
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+ pvsDriverUnlock(privconn);
+
+ if (!ret)
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching key '%s'"), key);
+
+ return ret;
+}
+
+static virStorageVolPtr
+pvsStorageVolumeLookupByPathLocked(virConnectPtr conn, const char *path)
+{
+ pvsConnPtr privconn = conn->privateData;
+ unsigned int i;
+ virStorageVolPtr ret = NULL;
+
+ for (i = 0; i < privconn->pools.count; i++) {
+ virStoragePoolObjLock(privconn->pools.objs[i]);
+ if (virStoragePoolObjIsActive(privconn->pools.objs[i])) {
+ virStorageVolDefPtr privvol =
+ virStorageVolDefFindByPath(privconn->pools.objs[i], path);
+
+ if (privvol) {
+ ret = virGetStorageVol(conn,
+ privconn->pools.objs[i]->def->name,
+ privvol->name, privvol->key);
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ break;
+ }
+ }
+ virStoragePoolObjUnlock(privconn->pools.objs[i]);
+ }
+
+ if (!ret)
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching path '%s'"), path);
+
+ return ret;
+}
+
+static virStorageVolPtr
+pvsStorageVolumeLookupByPath(virConnectPtr conn, const char *path)
+{
+ pvsConnPtr privconn = conn->privateData;
+ virStorageVolPtr ret = NULL;
+
+ pvsDriverLock(privconn);
+ ret = pvsStorageVolumeLookupByPathLocked(conn, path);
+ pvsDriverUnlock(privconn);
+
+ return ret;
+}
+
+static virStorageVolDefPtr
+pvsStorageVolumeDefine(virStoragePoolObjPtr pool,
+ const char *xmldesc,
+ const char *xmlfile, bool is_new)
+{
+ virStorageVolDefPtr privvol = NULL;
+ virStorageVolDefPtr ret = NULL;
+ char *xml_path = NULL;
+
+ if (xmlfile)
+ privvol = virStorageVolDefParseFile(pool->def, xmlfile);
+ else
+ privvol = virStorageVolDefParseString(pool->def, xmldesc);
+ if (privvol == NULL)
+ goto cleanup;
+
+ if (virStorageVolDefFindByName(pool, privvol->name)) {
+ pvsError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("storage vol already exists"));
+ goto cleanup;
+ }
+
+ if (is_new) {
+ /* Make sure enough space */
+ if ((pool->def->allocation + privvol->allocation) >
+ pool->def->capacity) {
+ pvsError(VIR_ERR_INTERNAL_ERROR,
+ _("Not enough free space in pool for volume
'%s'"),
+ privvol->name);
+ goto cleanup;
+ }
+ }
+
+ if (VIR_REALLOC_N(pool->volumes.objs, pool->volumes.count + 1) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&privvol->target.path, "%s/%s",
+ pool->def->target.path, privvol->name) == -1) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ privvol->key = strdup(privvol->target.path);
+ if (privvol->key == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (is_new) {
+ xml_path = pvsAddFileExt(privvol->target.path, ".xml");
+ if (!xml_path) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virXMLSaveFile
+ (xml_path, privvol->name, "volume-create", xmldesc)) {
+ pvsError(VIR_ERR_OPERATION_FAILED,
+ "Can't create file with volume description");
+ goto cleanup;
+ }
+
+ pool->def->allocation += privvol->allocation;
+ pool->def->available = (pool->def->capacity -
+ pool->def->allocation);
+ }
+
+ pool->volumes.objs[pool->volumes.count++] = privvol;
+
+ ret = privvol;
+ privvol = NULL;
+
+ cleanup:
+ virStorageVolDefFree(privvol);
+ VIR_FREE(xml_path);
+ return ret;
+}
+
+static virStorageVolPtr
+pvsStorageVolumeCreateXML(virStoragePoolPtr pool,
+ const char *xmldesc, unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolPtr ret = NULL;
+ virStorageVolDefPtr privvol = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = pvsStorageVolumeDefine(privpool, xmldesc, NULL, true);
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key);
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static virStorageVolPtr
+pvsStorageVolumeCreateXMLFrom(virStoragePoolPtr pool,
+ const char *xmldesc,
+ virStorageVolPtr clonevol,
+ unsigned int flags)
+{
+ pvsConnPtr privconn = pool->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol = NULL, origvol = NULL;
+ virStorageVolPtr ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, pool->name);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), pool->name);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefParseString(privpool->def, xmldesc);
+ if (privvol == NULL)
+ goto cleanup;
+
+ if (virStorageVolDefFindByName(privpool, privvol->name)) {
+ pvsError(VIR_ERR_OPERATION_FAILED,
+ "%s", _("storage vol already exists"));
+ goto cleanup;
+ }
+
+ origvol = virStorageVolDefFindByName(privpool, clonevol->name);
+ if (!origvol) {
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
+ clonevol->name);
+ goto cleanup;
+ }
+
+ /* Make sure enough space */
+ if ((privpool->def->allocation + privvol->allocation) >
+ privpool->def->capacity) {
+ pvsError(VIR_ERR_INTERNAL_ERROR,
+ _("Not enough free space in pool for volume '%s'"),
+ privvol->name);
+ goto cleanup;
+ }
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ if (VIR_REALLOC_N(privpool->volumes.objs,
+ privpool->volumes.count + 1) < 0) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (virAsprintf(&privvol->target.path, "%s/%s",
+ privpool->def->target.path, privvol->name) == -1) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ privvol->key = strdup(privvol->target.path);
+ if (privvol->key == NULL) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ privpool->def->allocation += privvol->allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ privpool->volumes.objs[privpool->volumes.count++] = privvol;
+
+ ret = virGetStorageVol(pool->conn, privpool->def->name,
+ privvol->name, privvol->key);
+ privvol = NULL;
+
+ cleanup:
+ virStorageVolDefFree(privvol);
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static int
+pvsStorageVolumeDelete(virStorageVolPtr vol, unsigned int flags)
+{
+ pvsConnPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ int i;
+ int ret = -1;
+ char *xml_path = NULL;
+
+ virCheckFlags(0, -1);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+
+ privpool->def->allocation -= privvol->allocation;
+ privpool->def->available = (privpool->def->capacity -
+ privpool->def->allocation);
+
+ for (i = 0; i < privpool->volumes.count; i++) {
+ if (privpool->volumes.objs[i] == privvol) {
+ xml_path = pvsAddFileExt(privvol->target.path, ".xml");
+ if (!xml_path) {
+ virReportOOMError();
+ goto cleanup;
+ }
+
+ if (unlink(xml_path)) {
+ pvsError(VIR_ERR_OPERATION_FAILED,
+ _("Can't remove file '%s'"), xml_path);
+ goto cleanup;
+ }
+
+ virStorageVolDefFree(privvol);
+
+ if (i < (privpool->volumes.count - 1))
+ memmove(privpool->volumes.objs + i,
+ privpool->volumes.objs + i + 1,
+ sizeof(*(privpool->volumes.objs)) *
+ (privpool->volumes.count - (i + 1)));
+
+ if (VIR_REALLOC_N(privpool->volumes.objs,
+ privpool->volumes.count - 1) < 0) {
+ ; /* Failure to reduce memory allocation isn't fatal
*/
+ }
+ privpool->volumes.count--;
+
+ break;
+ }
+ }
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ VIR_FREE(xml_path);
+ return ret;
+}
+
+
+static int
+pvsStorageVolumeTypeForPool(int pooltype)
+{
+
+ switch (pooltype) {
+ case VIR_STORAGE_POOL_DIR:
+ case VIR_STORAGE_POOL_FS:
+ case VIR_STORAGE_POOL_NETFS:
+ return VIR_STORAGE_VOL_FILE;
+ default:
+ return VIR_STORAGE_VOL_BLOCK;
+ }
+}
+
+static int
+pvsStorageVolumeGetInfo(virStorageVolPtr vol, virStorageVolInfoPtr info)
+{
+ pvsConnPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ int ret = -1;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ memset(info, 0, sizeof(*info));
+ info->type = pvsStorageVolumeTypeForPool(privpool->def->type);
+ info->capacity = privvol->capacity;
+ info->allocation = privvol->allocation;
+ ret = 0;
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+pvsStorageVolumeGetXMLDesc(virStorageVolPtr vol, unsigned int flags)
+{
+ pvsConnPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ char *ret = NULL;
+
+ virCheckFlags(0, NULL);
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ ret = virStorageVolDefFormat(privpool->def, privvol);
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static char *
+pvsStorageVolumeGetPath(virStorageVolPtr vol)
+{
+ pvsConnPtr privconn = vol->conn->privateData;
+ virStoragePoolObjPtr privpool;
+ virStorageVolDefPtr privvol;
+ char *ret = NULL;
+
+ pvsDriverLock(privconn);
+ privpool = virStoragePoolObjFindByName(&privconn->pools, vol->pool);
+ pvsDriverUnlock(privconn);
+
+ if (privpool == NULL) {
+ pvsError(VIR_ERR_INVALID_ARG, __FUNCTION__);
+ goto cleanup;
+ }
+
+ privvol = virStorageVolDefFindByName(privpool, vol->name);
+
+ if (privvol == NULL) {
+ pvsError(VIR_ERR_NO_STORAGE_VOL,
+ _("no storage vol with matching name '%s'"),
vol->name);
+ goto cleanup;
+ }
+
+ if (!virStoragePoolObjIsActive(privpool)) {
+ pvsError(VIR_ERR_OPERATION_INVALID,
+ _("storage pool '%s' is not active"), vol->pool);
+ goto cleanup;
+ }
+
+ ret = strdup(privvol->target.path);
+ if (ret == NULL)
+ virReportOOMError();
+
+ cleanup:
+ if (privpool)
+ virStoragePoolObjUnlock(privpool);
+ return ret;
+}
+
+static virStorageDriver pvsStorageDriver = {
+ .name = "PVS",
+ .open = pvsStorageOpen, /* 0.9.11 */
+ .close = pvsStorageClose, /* 0.9.11 */
+
+ .numOfPools = pvsStorageNumPools, /* 0.9.11 */
+ .listPools = pvsStorageListPools, /* 0.9.11 */
+ .numOfDefinedPools = pvsStorageNumDefinedPools, /* 0.9.11 */
+ .listDefinedPools = pvsStorageListDefinedPools, /* 0.9.11 */
+ .findPoolSources = pvsStorageFindPoolSources, /* 0.9.11 */
+ .poolLookupByName = pvsStoragePoolLookupByName, /* 0.9.11 */
+ .poolLookupByUUID = pvsStoragePoolLookupByUUID, /* 0.9.11 */
+ .poolLookupByVolume = pvsStoragePoolLookupByVolume, /* 0.9.11 */
+ .poolDefineXML = pvsStoragePoolDefine, /* 0.9.11 */
+ .poolBuild = pvsStoragePoolBuild, /* 0.9.11 */
+ .poolUndefine = pvsStoragePoolUndefine, /* 0.9.11 */
+ .poolCreate = pvsStoragePoolStart, /* 0.9.11 */
+ .poolDestroy = pvsStoragePoolDestroy, /* 0.9.11 */
+ .poolDelete = pvsStoragePoolDelete, /* 0.9.11 */
+ .poolRefresh = pvsStoragePoolRefresh, /* 0.9.11 */
+ .poolGetInfo = pvsStoragePoolGetInfo, /* 0.9.11 */
+ .poolGetXMLDesc = pvsStoragePoolGetXMLDesc, /* 0.9.11 */
+ .poolGetAutostart = pvsStoragePoolGetAutostart, /* 0.9.11 */
+ .poolSetAutostart = pvsStoragePoolSetAutostart, /* 0.9.11 */
+ .poolNumOfVolumes = pvsStoragePoolNumVolumes, /* 0.9.11 */
+ .poolListVolumes = pvsStoragePoolListVolumes, /* 0.9.11 */
+
+ .volLookupByName = pvsStorageVolumeLookupByName, /* 0.9.11 */
+ .volLookupByKey = pvsStorageVolumeLookupByKey, /* 0.9.11 */
+ .volLookupByPath = pvsStorageVolumeLookupByPath, /* 0.9.11 */
+ .volCreateXML = pvsStorageVolumeCreateXML, /* 0.9.11 */
+ .volCreateXMLFrom = pvsStorageVolumeCreateXMLFrom, /* 0.9.11 */
+ .volDelete = pvsStorageVolumeDelete, /* 0.9.11 */
+ .volGetInfo = pvsStorageVolumeGetInfo, /* 0.9.11 */
+ .volGetXMLDesc = pvsStorageVolumeGetXMLDesc, /* 0.9.11 */
+ .volGetPath = pvsStorageVolumeGetPath, /* 0.9.11 */
+ .poolIsActive = pvsStoragePoolIsActive, /* 0.9.11 */
+ .poolIsPersistent = pvsStoragePoolIsPersistent, /* 0.9.11 */
+};
+
+int
+pvsStorageRegister(void)
+{
+ if (virRegisterStorageDriver(&pvsStorageDriver) < 0)
+ return -1;
+
+ return 0;
+}
diff --git a/src/pvs/pvs_utils.c b/src/pvs/pvs_utils.c
index 3a548bd..e5241ee 100644
--- a/src/pvs/pvs_utils.c
+++ b/src/pvs/pvs_utils.c
@@ -117,3 +117,23 @@ pvsCmdRun(const char *binary, ...)
return ret;
}
+
+/*
+ * Return new file path in malloced string created by
+ * concatenating first and second function arguments.
+ */
+char *
+pvsAddFileExt(const char *path, const char *ext)
+{
+ char *new_path = NULL;
+ size_t len = strlen(path) + strlen(ext) + 1;
+
+ if (VIR_ALLOC_N(new_path, len) < 0)
+ return NULL;
+
+ if (!virStrcpy(new_path, path, len))
+ return NULL;
+ strcat(new_path, ext);
+
+ return new_path;
+}
--
1.7.1