2008-02-20 15:34:52 +00:00
|
|
|
/*
|
|
|
|
* storage_conf.c: config handling for storage driver
|
|
|
|
*
|
2012-02-23 00:48:38 +00:00
|
|
|
* Copyright (C) 2006-2012 Red Hat, Inc.
|
2008-02-20 15:34:52 +00:00
|
|
|
* Copyright (C) 2006-2008 Daniel P. Berrange
|
|
|
|
*
|
|
|
|
* 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
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-02-20 15:34:52 +00:00
|
|
|
*
|
|
|
|
* Author: Daniel P. Berrange <berrange@redhat.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2008-11-04 23:22:06 +00:00
|
|
|
#include "datatypes.h"
|
2008-02-20 15:34:52 +00:00
|
|
|
#include "storage_conf.h"
|
2012-12-13 15:25:48 +00:00
|
|
|
#include "virstoragefile.h"
|
2008-11-17 11:19:33 +00:00
|
|
|
|
2012-12-13 18:13:21 +00:00
|
|
|
#include "virxml.h"
|
2012-12-13 18:01:25 +00:00
|
|
|
#include "viruuid.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2013-05-22 12:05:22 +00:00
|
|
|
#include "virlog.h"
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
|
2012-07-11 14:40:48 +00:00
|
|
|
#define DEFAULT_POOL_PERM_MODE 0755
|
|
|
|
#define DEFAULT_VOL_PERM_MODE 0600
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePool,
|
|
|
|
VIR_STORAGE_POOL_LAST,
|
|
|
|
"dir", "fs", "netfs",
|
|
|
|
"logical", "disk", "iscsi",
|
2012-07-18 19:06:58 +00:00
|
|
|
"scsi", "mpath", "rbd", "sheepdog")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
|
|
|
|
VIR_STORAGE_POOL_FS_LAST,
|
|
|
|
"auto", "ext2", "ext3",
|
|
|
|
"ext4", "ufs", "iso9660", "udf",
|
2009-10-14 15:03:22 +00:00
|
|
|
"gfs", "gfs2", "vfat", "hfs+", "xfs", "ocfs2")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatFileSystemNet,
|
|
|
|
VIR_STORAGE_POOL_NETFS_LAST,
|
2010-05-17 23:24:32 +00:00
|
|
|
"auto", "nfs", "glusterfs", "cifs")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatDisk,
|
|
|
|
VIR_STORAGE_POOL_DISK_LAST,
|
|
|
|
"unknown", "dos", "dvh", "gpt",
|
2008-12-17 21:09:44 +00:00
|
|
|
"mac", "bsd", "pc98", "sun", "lvm2")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStoragePoolFormatLogical,
|
|
|
|
VIR_STORAGE_POOL_LOGICAL_LAST,
|
2008-12-17 21:09:44 +00:00
|
|
|
"unknown", "lvm2")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
VIR_ENUM_IMPL(virStorageVolFormatDisk,
|
|
|
|
VIR_STORAGE_VOL_DISK_LAST,
|
|
|
|
"none", "linux", "fat16",
|
|
|
|
"fat32", "linux-swap",
|
|
|
|
"linux-lvm", "linux-raid",
|
2008-12-17 21:09:44 +00:00
|
|
|
"extended")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
2009-06-26 16:18:59 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePartedFsType,
|
|
|
|
VIR_STORAGE_PARTED_FS_TYPE_LAST,
|
2009-07-10 13:02:30 +00:00
|
|
|
"ext2", "ext2", "fat16",
|
2009-06-26 16:18:59 +00:00
|
|
|
"fat32", "linux-swap",
|
|
|
|
"ext2", "ext2",
|
|
|
|
"extended")
|
2008-11-17 11:19:33 +00:00
|
|
|
|
2013-03-25 16:43:36 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePoolSourceAdapterType,
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_LAST,
|
|
|
|
"default", "scsi_host", "fc_host")
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
typedef const char *(*virStorageVolFormatToString)(int format);
|
|
|
|
typedef int (*virStorageVolFormatFromString)(const char *format);
|
|
|
|
|
|
|
|
typedef const char *(*virStoragePoolFormatToString)(int format);
|
|
|
|
typedef int (*virStoragePoolFormatFromString)(const char *format);
|
|
|
|
|
|
|
|
typedef struct _virStorageVolOptions virStorageVolOptions;
|
|
|
|
typedef virStorageVolOptions *virStorageVolOptionsPtr;
|
|
|
|
struct _virStorageVolOptions {
|
2008-12-04 15:22:04 +00:00
|
|
|
int defaultFormat;
|
2008-11-17 11:19:33 +00:00
|
|
|
virStorageVolFormatToString formatToString;
|
|
|
|
virStorageVolFormatFromString formatFromString;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Flags to indicate mandatory components in the pool source */
|
|
|
|
enum {
|
2013-05-16 03:10:28 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_HOST = (1 << 0),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE = (1 << 1),
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DIR = (1 << 2),
|
|
|
|
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),
|
2008-11-17 11:19:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virStoragePoolOptions virStoragePoolOptions;
|
|
|
|
typedef virStoragePoolOptions *virStoragePoolOptionsPtr;
|
|
|
|
struct _virStoragePoolOptions {
|
2011-07-07 23:29:42 +00:00
|
|
|
unsigned int flags;
|
2008-11-17 11:19:33 +00:00
|
|
|
int defaultFormat;
|
|
|
|
virStoragePoolFormatToString formatToString;
|
|
|
|
virStoragePoolFormatFromString formatFromString;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _virStoragePoolTypeInfo virStoragePoolTypeInfo;
|
|
|
|
typedef virStoragePoolTypeInfo *virStoragePoolTypeInfoPtr;
|
|
|
|
struct _virStoragePoolTypeInfo {
|
|
|
|
int poolType;
|
|
|
|
virStoragePoolOptions poolOptions;
|
|
|
|
virStorageVolOptions volOptions;
|
|
|
|
};
|
|
|
|
|
storage: list more file types
When an image has no backing file, using VIR_STORAGE_FILE_AUTO
for its type is a bit confusing. Additionally, a future patch
would like to reserve a default value for the case of no file
type specified in the XML, but different from the current use
of -1 to imply probing, since probing is not always safe.
Also, a couple of file types were missing compared to supported
code: libxl supports 'vhd', and qemu supports 'fat' for directories
passed through as a file system.
* src/util/storage_file.h (virStorageFileFormat): Add
VIR_STORAGE_FILE_NONE, VIR_STORAGE_FILE_FAT, VIR_STORAGE_FILE_VHD.
* src/util/storage_file.c (virStorageFileMatchesVersion): Match
documentation when version probing not supported.
(cowGetBackingStore, qcowXGetBackingStore, qcow1GetBackingStore)
(qcow2GetBackingStoreFormat, qedGetBackingStore)
(virStorageFileGetMetadataFromBuf)
(virStorageFileGetMetadataFromFD): Take NONE into account.
* src/conf/domain_conf.c (virDomainDiskDefForeachPath): Likewise.
* src/qemu/qemu_driver.c (qemuDomainGetBlockInfo): Likewise.
* src/conf/storage_conf.c (virStorageVolumeFormatFromString): New
function.
(poolTypeInfo): Use it.
2012-09-28 17:11:07 +00:00
|
|
|
static int
|
|
|
|
virStorageVolumeFormatFromString(const char *format)
|
|
|
|
{
|
|
|
|
int ret = virStorageFileFormatTypeFromString(format);
|
|
|
|
if (ret == VIR_STORAGE_FILE_NONE)
|
|
|
|
return -1;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
static virStoragePoolTypeInfo poolTypeInfo[] = {
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_LOGICAL,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_NAME |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_LOGICAL_LVM2,
|
|
|
|
.formatFromString = virStoragePoolFormatLogicalTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatLogicalTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_DIR,
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_FS,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_FS_AUTO,
|
|
|
|
.formatFromString = virStoragePoolFormatFileSystemTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatFileSystemTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
.volOptions = {
|
2013-05-16 12:40:51 +00:00
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_NETFS,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DIR),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_NETFS_AUTO,
|
|
|
|
.formatFromString = virStoragePoolFormatFileSystemNetTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatFileSystemNetTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
.volOptions = {
|
2013-05-16 12:40:51 +00:00
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_ISCSI,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN),
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
.volOptions = {
|
2013-05-16 12:40:51 +00:00
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{.poolType = VIR_STORAGE_POOL_SCSI,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_ADAPTER),
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
}
|
2008-11-17 11:19:33 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_RBD,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME),
|
|
|
|
},
|
2009-04-01 16:03:22 +00:00
|
|
|
.volOptions = {
|
2013-05-16 12:40:51 +00:00
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
}
|
2009-04-01 16:03:22 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_SHEEPDOG,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME),
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
}
|
2012-05-14 09:06:42 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_MPATH,
|
|
|
|
.volOptions = {
|
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
}
|
2012-07-18 19:06:58 +00:00
|
|
|
},
|
2013-05-16 12:40:51 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_DISK,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_DEVICE),
|
|
|
|
.defaultFormat = VIR_STORAGE_POOL_DISK_UNKNOWN,
|
|
|
|
.formatFromString = virStoragePoolFormatDiskTypeFromString,
|
|
|
|
.formatToString = virStoragePoolFormatDiskTypeToString,
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_VOL_DISK_NONE,
|
|
|
|
.formatFromString = virStorageVolFormatDiskTypeFromString,
|
|
|
|
.formatToString = virStorageVolFormatDiskTypeToString,
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static virStoragePoolTypeInfoPtr
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolTypeInfoLookup(int type)
|
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
unsigned int i;
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < ARRAY_CARDINALITY(poolTypeInfo); i++)
|
2008-11-17 11:19:33 +00:00
|
|
|
if (poolTypeInfo[i].poolType == type)
|
|
|
|
return &poolTypeInfo[i];
|
|
|
|
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("missing backend for pool type %d"), type);
|
2008-11-17 11:19:33 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virStoragePoolOptionsPtr
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolOptionsForPoolType(int type)
|
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
|
|
|
|
if (backend == NULL)
|
|
|
|
return NULL;
|
|
|
|
return &backend->poolOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virStorageVolOptionsPtr
|
2013-05-16 12:40:50 +00:00
|
|
|
virStorageVolOptionsForPoolType(int type)
|
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolTypeInfoPtr backend = virStoragePoolTypeInfoLookup(type);
|
|
|
|
if (backend == NULL)
|
|
|
|
return NULL;
|
|
|
|
return &backend->volOptions;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
2013-05-16 12:40:50 +00:00
|
|
|
virStorageVolDefFree(virStorageVolDefPtr def)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
int i;
|
2008-10-10 15:13:28 +00:00
|
|
|
|
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(def->name);
|
|
|
|
VIR_FREE(def->key);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < def->source.nextent; i++) {
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(def->source.extents[i].path);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(def->source.extents);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(def->target.path);
|
|
|
|
VIR_FREE(def->target.perms.label);
|
2012-07-25 07:43:37 +00:00
|
|
|
VIR_FREE(def->target.timestamps);
|
2009-07-20 22:28:11 +00:00
|
|
|
virStorageEncryptionFree(def->target.encryption);
|
2009-01-27 18:30:03 +00:00
|
|
|
VIR_FREE(def->backingStore.path);
|
|
|
|
VIR_FREE(def->backingStore.perms.label);
|
2012-07-25 07:43:37 +00:00
|
|
|
VIR_FREE(def->backingStore.timestamps);
|
2009-07-20 22:28:11 +00:00
|
|
|
virStorageEncryptionFree(def->backingStore.encryption);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2013-03-25 16:43:36 +00:00
|
|
|
static void
|
|
|
|
virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapter adapter)
|
|
|
|
{
|
|
|
|
if (adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
VIR_FREE(adapter.data.fchost.wwnn);
|
|
|
|
VIR_FREE(adapter.data.fchost.wwpn);
|
|
|
|
VIR_FREE(adapter.data.fchost.parent);
|
|
|
|
} else if (adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
|
|
|
VIR_FREE(adapter.data.name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
2011-10-21 22:44:52 +00:00
|
|
|
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
int i;
|
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
if (!source)
|
2008-10-10 15:13:28 +00:00
|
|
|
return;
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < source->nhost; i++) {
|
2012-04-25 10:43:09 +00:00
|
|
|
VIR_FREE(source->hosts[i].name);
|
|
|
|
}
|
|
|
|
VIR_FREE(source->hosts);
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < source->ndevice; i++) {
|
2008-10-23 11:39:53 +00:00
|
|
|
VIR_FREE(source->devices[i].freeExtents);
|
|
|
|
VIR_FREE(source->devices[i].path);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2008-10-23 11:39:53 +00:00
|
|
|
VIR_FREE(source->devices);
|
|
|
|
VIR_FREE(source->dir);
|
|
|
|
VIR_FREE(source->name);
|
2013-03-25 16:43:36 +00:00
|
|
|
virStoragePoolSourceAdapterClear(source->adapter);
|
2010-01-21 11:50:52 +00:00
|
|
|
VIR_FREE(source->initiator.iqn);
|
2010-08-17 17:44:27 +00:00
|
|
|
VIR_FREE(source->vendor);
|
|
|
|
VIR_FREE(source->product);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
|
|
|
|
VIR_FREE(source->auth.chap.login);
|
|
|
|
VIR_FREE(source->auth.chap.passwd);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2012-05-14 09:06:42 +00:00
|
|
|
|
|
|
|
if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
|
|
|
|
VIR_FREE(source->auth.cephx.username);
|
|
|
|
VIR_FREE(source->auth.cephx.secret.usage);
|
|
|
|
}
|
2008-10-23 11:39:53 +00:00
|
|
|
}
|
|
|
|
|
2011-10-21 22:44:52 +00:00
|
|
|
void
|
|
|
|
virStoragePoolSourceFree(virStoragePoolSourcePtr source)
|
|
|
|
{
|
|
|
|
virStoragePoolSourceClear(source);
|
|
|
|
VIR_FREE(source);
|
|
|
|
}
|
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
void
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefFree(virStoragePoolDefPtr def)
|
|
|
|
{
|
2008-10-23 11:39:53 +00:00
|
|
|
if (!def)
|
|
|
|
return;
|
|
|
|
|
|
|
|
VIR_FREE(def->name);
|
|
|
|
|
2011-10-21 22:44:52 +00:00
|
|
|
virStoragePoolSourceClear(&def->source);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(def->target.path);
|
|
|
|
VIR_FREE(def->target.perms.label);
|
|
|
|
VIR_FREE(def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolObjFree(virStoragePoolObjPtr obj)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
if (!obj)
|
|
|
|
return;
|
|
|
|
|
2009-01-30 16:48:52 +00:00
|
|
|
virStoragePoolObjClearVols(obj);
|
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolDefFree(obj->def);
|
|
|
|
virStoragePoolDefFree(obj->newDef);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(obj->configFile);
|
|
|
|
VIR_FREE(obj->autostartLink);
|
2009-01-15 19:56:05 +00:00
|
|
|
|
|
|
|
virMutexDestroy(&obj->lock);
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(obj);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
void
|
|
|
|
virStoragePoolObjListFree(virStoragePoolObjListPtr pools)
|
2008-10-10 15:13:28 +00:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < pools->count; i++)
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjFree(pools->objs[i]);
|
|
|
|
VIR_FREE(pools->objs);
|
|
|
|
pools->count = 0;
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjRemove(virStoragePoolObjListPtr pools,
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolObjPtr pool)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjUnlock(pool);
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < pools->count; i++) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjLock(pools->objs[i]);
|
2008-10-10 15:13:28 +00:00
|
|
|
if (pools->objs[i] == pool) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjUnlock(pools->objs[i]);
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjFree(pools->objs[i]);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
if (i < (pools->count - 1))
|
|
|
|
memmove(pools->objs + i, pools->objs + i + 1,
|
|
|
|
sizeof(*(pools->objs)) * (pools->count - (i + 1)));
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
if (VIR_REALLOC_N(pools->objs, pools->count - 1) < 0) {
|
|
|
|
; /* Failure to reduce memory allocation isn't fatal */
|
|
|
|
}
|
|
|
|
pools->count--;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjUnlock(pools->objs[i]);
|
2008-10-10 15:13:28 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseAuthChap(xmlXPathContextPtr ctxt,
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolAuthChapPtr auth)
|
|
|
|
{
|
2010-02-04 21:52:34 +00:00
|
|
|
auth->login = virXPathString("string(./auth/@login)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (auth->login == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing auth login attribute"));
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
auth->passwd = virXPathString("string(./auth/@passwd)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (auth->passwd == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing auth passwd attribute"));
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
static int
|
|
|
|
virStoragePoolDefParseAuthCephx(xmlXPathContextPtr ctxt,
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolAuthCephxPtr auth)
|
|
|
|
{
|
2012-05-14 09:06:42 +00:00
|
|
|
char *uuid = NULL;
|
2013-05-22 12:05:12 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
auth->username = virXPathString("string(./auth/@username)", ctxt);
|
|
|
|
if (auth->username == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing auth username attribute"));
|
2012-05-14 09:06:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
uuid = virXPathString("string(./auth/secret/@uuid)", ctxt);
|
|
|
|
auth->secret.usage = virXPathString("string(./auth/secret/@usage)", ctxt);
|
|
|
|
if (uuid == NULL && auth->secret.usage == NULL) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing auth secret uuid or usage attribute"));
|
2012-05-14 09:06:42 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-12-03 12:35:05 +00:00
|
|
|
if (uuid != NULL) {
|
|
|
|
if (auth->secret.usage != NULL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("either auth secret uuid or usage expected"));
|
2013-05-22 12:05:12 +00:00
|
|
|
goto cleanup;
|
2012-12-03 12:35:05 +00:00
|
|
|
}
|
|
|
|
if (virUUIDParse(uuid, auth->secret.uuid) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("invalid auth secret uuid"));
|
2013-05-22 12:05:12 +00:00
|
|
|
goto cleanup;
|
2012-12-03 12:35:05 +00:00
|
|
|
}
|
|
|
|
auth->secret.uuidUsable = true;
|
|
|
|
} else {
|
|
|
|
auth->secret.uuidUsable = false;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
|
|
|
|
2013-05-22 12:05:12 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(uuid);
|
|
|
|
return ret;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
|
|
|
|
2009-10-15 14:55:19 +00:00
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseSource(xmlXPathContextPtr ctxt,
|
2009-10-15 14:55:19 +00:00
|
|
|
virStoragePoolSourcePtr source,
|
|
|
|
int pool_type,
|
2013-05-16 12:40:50 +00:00
|
|
|
xmlNodePtr node)
|
|
|
|
{
|
2009-10-15 14:55:19 +00:00
|
|
|
int ret = -1;
|
|
|
|
xmlNodePtr relnode, *nodeset = NULL;
|
|
|
|
char *authType = NULL;
|
|
|
|
int nsource, i;
|
|
|
|
virStoragePoolOptionsPtr options;
|
2012-04-25 10:43:09 +00:00
|
|
|
char *name = NULL;
|
2011-03-16 08:28:07 +00:00
|
|
|
char *port = NULL;
|
2013-03-25 16:43:36 +00:00
|
|
|
char *adapter_type = NULL;
|
2012-11-28 13:34:50 +00:00
|
|
|
int n;
|
2009-10-15 14:55:19 +00:00
|
|
|
|
|
|
|
relnode = ctxt->node;
|
|
|
|
ctxt->node = node;
|
|
|
|
|
|
|
|
if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL) {
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
source->name = virXPathString("string(./name)", ctxt);
|
2012-05-14 09:06:42 +00:00
|
|
|
if (pool_type == VIR_STORAGE_POOL_RBD && source->name == NULL) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2013-05-22 12:05:21 +00:00
|
|
|
_("element 'name' is mandatory for RBD pool"));
|
2012-05-14 09:06:42 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2009-10-15 14:55:19 +00:00
|
|
|
|
|
|
|
if (options->formatFromString) {
|
2010-02-04 21:52:34 +00:00
|
|
|
char *format = virXPathString("string(./format/@type)", ctxt);
|
2009-10-15 14:55:19 +00:00
|
|
|
if (format == NULL)
|
|
|
|
source->format = options->defaultFormat;
|
|
|
|
else
|
|
|
|
source->format = options->formatFromString(format);
|
|
|
|
|
|
|
|
if (source->format < 0) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("unknown pool format type %s"), format);
|
2009-10-15 14:55:19 +00:00
|
|
|
VIR_FREE(format);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(format);
|
|
|
|
}
|
|
|
|
|
2012-11-28 13:34:50 +00:00
|
|
|
if ((n = virXPathNodeSet("./host", ctxt, &nodeset)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
source->nhost = n;
|
2012-04-25 10:43:09 +00:00
|
|
|
|
|
|
|
if (source->nhost) {
|
|
|
|
if (VIR_ALLOC_N(source->hosts, source->nhost) < 0) {
|
|
|
|
virReportOOMError();
|
2010-11-12 13:23:55 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < source->nhost; i++) {
|
2012-04-25 10:43:09 +00:00
|
|
|
name = virXMLPropString(nodeset[i], "name");
|
|
|
|
if (name == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool host name"));
|
2012-04-25 10:43:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
source->hosts[i].name = name;
|
|
|
|
|
|
|
|
port = virXMLPropString(nodeset[i], "port");
|
|
|
|
if (port) {
|
|
|
|
if (virStrToLong_i(port, NULL, 10, &source->hosts[i].port) < 0) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("Invalid port number: %s"),
|
|
|
|
port);
|
2012-04-25 10:43:09 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-11-12 13:23:55 +00:00
|
|
|
|
2012-05-09 10:48:46 +00:00
|
|
|
VIR_FREE(nodeset);
|
2010-02-04 21:52:34 +00:00
|
|
|
source->initiator.iqn = virXPathString("string(./initiator/iqn/@name)", ctxt);
|
2009-10-15 14:55:19 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
nsource = virXPathNodeSet("./device", ctxt, &nodeset);
|
2011-05-12 19:45:22 +00:00
|
|
|
if (nsource < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2009-10-15 14:55:19 +00:00
|
|
|
if (nsource > 0) {
|
|
|
|
if (VIR_ALLOC_N(source->devices, nsource) < 0) {
|
|
|
|
VIR_FREE(nodeset);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-10-15 14:55:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < nsource; i++) {
|
2010-11-24 20:08:55 +00:00
|
|
|
char *path = virXMLPropString(nodeset[i], "path");
|
2009-10-15 14:55:19 +00:00
|
|
|
if (path == NULL) {
|
|
|
|
VIR_FREE(nodeset);
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source device path"));
|
2009-10-15 14:55:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-11-24 20:08:55 +00:00
|
|
|
source->devices[i].path = path;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
source->ndevice = nsource;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
source->dir = virXPathString("string(./dir/@path)", ctxt);
|
2013-03-25 16:43:36 +00:00
|
|
|
|
|
|
|
if ((adapter_type = virXPathString("string(./adapter/@type)", ctxt))) {
|
|
|
|
if ((source->adapter.type =
|
|
|
|
virStoragePoolSourceAdapterTypeTypeFromString(adapter_type)) <= 0) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("Unknown pool adapter type '%s'"),
|
|
|
|
adapter_type);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source->adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
source->adapter.data.fchost.parent =
|
|
|
|
virXPathString("string(./adapter/@parent)", ctxt);
|
|
|
|
source->adapter.data.fchost.wwnn =
|
|
|
|
virXPathString("string(./adapter/@wwnn)", ctxt);
|
|
|
|
source->adapter.data.fchost.wwpn =
|
|
|
|
virXPathString("string(./adapter/@wwpn)", ctxt);
|
|
|
|
} else if (source->adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
|
|
|
source->adapter.data.name =
|
|
|
|
virXPathString("string(./adapter/@name)", ctxt);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
char *wwnn = NULL;
|
|
|
|
char *wwpn = NULL;
|
|
|
|
char *parent = NULL;
|
|
|
|
|
|
|
|
wwnn = virXPathString("string(./adapter/@wwnn)", ctxt);
|
|
|
|
wwpn = virXPathString("string(./adapter/@wwpn)", ctxt);
|
|
|
|
parent = virXPathString("string(./adapter/@parent)", ctxt);
|
|
|
|
|
|
|
|
if (wwnn || wwpn || parent) {
|
|
|
|
VIR_FREE(wwnn);
|
|
|
|
VIR_FREE(wwpn);
|
|
|
|
VIR_FREE(parent);
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("Use of 'wwnn', 'wwpn', and 'parent' attributes "
|
|
|
|
"requires the 'fc_host' adapter 'type'"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* To keep back-compat, 'type' is not required to specify
|
|
|
|
* for scsi_host adapter.
|
|
|
|
*/
|
|
|
|
if ((source->adapter.data.name =
|
|
|
|
virXPathString("string(./adapter/@name)", ctxt)))
|
|
|
|
source->adapter.type =
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST;
|
|
|
|
}
|
2009-10-15 14:55:19 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
authType = virXPathString("string(./auth/@type)", ctxt);
|
2009-10-15 14:55:19 +00:00
|
|
|
if (authType == NULL) {
|
|
|
|
source->authType = VIR_STORAGE_POOL_AUTH_NONE;
|
|
|
|
} else {
|
|
|
|
if (STREQ(authType, "chap")) {
|
|
|
|
source->authType = VIR_STORAGE_POOL_AUTH_CHAP;
|
2012-05-14 09:06:42 +00:00
|
|
|
} else if (STREQ(authType, "ceph")) {
|
|
|
|
source->authType = VIR_STORAGE_POOL_AUTH_CEPHX;
|
2009-10-15 14:55:19 +00:00
|
|
|
} else {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("unknown auth type '%s'"),
|
2013-05-22 12:05:13 +00:00
|
|
|
authType);
|
2009-10-15 14:55:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (source->authType == VIR_STORAGE_POOL_AUTH_CHAP) {
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStoragePoolDefParseAuthChap(ctxt, &source->auth.chap) < 0)
|
2009-10-15 14:55:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
if (source->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
|
|
|
|
if (virStoragePoolDefParseAuthCephx(ctxt, &source->auth.cephx) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-08-17 17:44:27 +00:00
|
|
|
source->vendor = virXPathString("string(./vendor/@name)", ctxt);
|
|
|
|
source->product = virXPathString("string(./product/@name)", ctxt);
|
|
|
|
|
2009-10-15 14:55:19 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
ctxt->node = relnode;
|
|
|
|
|
2010-11-12 13:23:55 +00:00
|
|
|
VIR_FREE(port);
|
2009-10-15 14:55:19 +00:00
|
|
|
VIR_FREE(authType);
|
|
|
|
VIR_FREE(nodeset);
|
2013-03-25 16:43:36 +00:00
|
|
|
VIR_FREE(adapter_type);
|
2009-10-15 14:55:19 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-10-15 15:58:35 +00:00
|
|
|
virStoragePoolSourcePtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseSourceString(const char *srcSpec,
|
2009-10-15 15:58:35 +00:00
|
|
|
int pool_type)
|
|
|
|
{
|
|
|
|
xmlDocPtr doc = NULL;
|
|
|
|
xmlNodePtr node = NULL;
|
|
|
|
xmlXPathContextPtr xpath_ctxt = NULL;
|
|
|
|
virStoragePoolSourcePtr def = NULL, ret = NULL;
|
|
|
|
|
2012-07-09 12:08:00 +00:00
|
|
|
if (!(doc = virXMLParseStringCtxt(srcSpec,
|
|
|
|
_("(storage_source_specification)"),
|
|
|
|
&xpath_ctxt)))
|
2009-10-15 15:58:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(def) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-10-15 15:58:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2012-07-09 12:08:00 +00:00
|
|
|
if (!(node = virXPathNode("/source", xpath_ctxt))) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("root element was not source"));
|
2009-10-15 15:58:35 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStoragePoolDefParseSource(xpath_ctxt, def, pool_type,
|
2009-10-15 15:58:35 +00:00
|
|
|
node) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
ret = def;
|
|
|
|
def = NULL;
|
|
|
|
cleanup:
|
2010-02-05 16:09:43 +00:00
|
|
|
virStoragePoolSourceFree(def);
|
2009-10-15 15:58:35 +00:00
|
|
|
xmlFreeDoc(doc);
|
|
|
|
xmlXPathFreeContext(xpath_ctxt);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageDefParsePerms(xmlXPathContextPtr ctxt,
|
2009-03-12 20:15:32 +00:00
|
|
|
virStoragePermsPtr perms,
|
|
|
|
const char *permxpath,
|
2013-05-16 12:40:50 +00:00
|
|
|
int defaultmode)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
char *mode;
|
2013-05-22 12:05:22 +00:00
|
|
|
long val;
|
2009-03-12 20:15:32 +00:00
|
|
|
int ret = -1;
|
|
|
|
xmlNodePtr relnode;
|
|
|
|
xmlNodePtr node;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
node = virXPathNode(permxpath, ctxt);
|
2009-03-12 20:15:32 +00:00
|
|
|
if (node == NULL) {
|
|
|
|
/* Set default values if there is not <permissions> element */
|
|
|
|
perms->mode = defaultmode;
|
2013-02-22 16:41:32 +00:00
|
|
|
perms->uid = (uid_t) -1;
|
|
|
|
perms->gid = (gid_t) -1;
|
2009-03-12 20:15:32 +00:00
|
|
|
perms->label = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
relnode = ctxt->node;
|
|
|
|
ctxt->node = node;
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
mode = virXPathString("string(./mode)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (!mode) {
|
2009-03-12 20:15:32 +00:00
|
|
|
perms->mode = defaultmode;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
2012-04-18 23:58:44 +00:00
|
|
|
int tmp;
|
|
|
|
|
|
|
|
if (virStrToLong_i(mode, NULL, 8, &tmp) < 0 || (tmp & ~0777)) {
|
2009-04-01 10:21:34 +00:00
|
|
|
VIR_FREE(mode);
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed octal mode"));
|
2009-03-12 20:15:32 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2012-04-18 23:58:44 +00:00
|
|
|
perms->mode = tmp;
|
2009-04-01 10:21:34 +00:00
|
|
|
VIR_FREE(mode);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
if (virXPathNode("./owner", ctxt) == NULL) {
|
2013-02-22 16:41:32 +00:00
|
|
|
perms->uid = (uid_t) -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
2013-05-22 12:05:22 +00:00
|
|
|
if (virXPathLong("number(./owner)", ctxt, &val) < 0 ||
|
|
|
|
((uid_t)val != val &&
|
|
|
|
val != -1)) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed owner element"));
|
2009-03-12 20:15:32 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2013-05-22 12:05:22 +00:00
|
|
|
|
|
|
|
perms->uid = val;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
if (virXPathNode("./group", ctxt) == NULL) {
|
2013-02-22 16:41:32 +00:00
|
|
|
perms->gid = (gid_t) -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
2013-05-22 12:05:22 +00:00
|
|
|
if (virXPathLong("number(./group)", ctxt, &val) < 0 ||
|
|
|
|
((gid_t) val != val &&
|
|
|
|
val != -1)) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed group element"));
|
2009-03-12 20:15:32 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2013-05-22 12:05:22 +00:00
|
|
|
perms->gid = val;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* NB, we're ignoring missing labels here - they'll simply inherit */
|
2010-02-04 21:52:34 +00:00
|
|
|
perms->label = virXPathString("string(./label)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-03-12 20:15:32 +00:00
|
|
|
ret = 0;
|
|
|
|
error:
|
|
|
|
ctxt->node = relnode;
|
|
|
|
return ret;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static virStoragePoolDefPtr
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolOptionsPtr options;
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefPtr ret;
|
2009-10-15 14:55:19 +00:00
|
|
|
xmlNodePtr source_node;
|
2009-06-22 16:41:34 +00:00
|
|
|
char *type = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
char *uuid = NULL;
|
2013-05-29 10:04:33 +00:00
|
|
|
char *target_path = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC(ret) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
2008-06-06 11:09:57 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
type = virXPathString("string(./@type)", ctxt);
|
2013-05-31 13:07:28 +00:00
|
|
|
if (type == NULL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("storage pool missing type attribute"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2013-05-22 12:05:13 +00:00
|
|
|
if ((ret->type = virStoragePoolTypeFromString(type)) < 0) {
|
2013-05-22 12:05:16 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2013-05-22 12:05:13 +00:00
|
|
|
_("unknown storage pool type %s"), type);
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-11-17 11:19:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if ((options = virStoragePoolOptionsForPoolType(ret->type)) == NULL) {
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
source_node = virXPathNode("./source", ctxt);
|
2009-10-15 14:55:19 +00:00
|
|
|
if (source_node) {
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStoragePoolDefParseSource(ctxt, &ret->source, ret->type,
|
2009-10-15 14:55:19 +00:00
|
|
|
source_node) < 0)
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
ret->name = virXPathString("string(./name)", ctxt);
|
2008-09-02 14:15:42 +00:00
|
|
|
if (ret->name == NULL &&
|
2008-11-17 11:19:33 +00:00
|
|
|
options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
|
2009-10-15 14:55:19 +00:00
|
|
|
ret->name = ret->source.name;
|
2008-09-02 14:15:42 +00:00
|
|
|
if (ret->name == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing pool source name element"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
uuid = virXPathString("string(./uuid)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (uuid == NULL) {
|
|
|
|
if (virUUIDGenerate(ret->uuid) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unable to generate uuid"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (virUUIDParse(uuid, ret->uuid) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed uuid element"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_HOST) {
|
2012-04-25 10:43:09 +00:00
|
|
|
if (!ret->source.nhost) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2012-07-18 10:50:44 +00:00
|
|
|
_("missing storage pool source host name"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR) {
|
2009-10-15 14:55:19 +00:00
|
|
|
if (!ret->source.dir) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source path"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
}
|
2008-11-17 11:19:33 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME) {
|
2008-09-02 14:15:42 +00:00
|
|
|
if (ret->source.name == NULL) {
|
|
|
|
/* source name defaults to pool name */
|
2013-05-03 12:40:46 +00:00
|
|
|
if (VIR_STRDUP(ret->source.name, ret->name) < 0)
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-09-02 14:15:42 +00:00
|
|
|
}
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-04-01 16:03:22 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER) {
|
2013-03-25 16:43:36 +00:00
|
|
|
if (!ret->source.adapter.type) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source adapter"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2009-04-01 16:03:22 +00:00
|
|
|
}
|
2013-03-25 16:43:36 +00:00
|
|
|
|
|
|
|
if (ret->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
if (!ret->source.adapter.data.fchost.wwnn ||
|
|
|
|
!ret->source.adapter.data.fchost.wwpn) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("'wwnn' and 'wwpn' must be specified for adapter "
|
|
|
|
"type 'fchost'"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2013-03-25 16:43:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!virValidateWWN(ret->source.adapter.data.fchost.wwnn) ||
|
|
|
|
!virValidateWWN(ret->source.adapter.data.fchost.wwpn))
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2013-03-25 16:43:36 +00:00
|
|
|
} else if (ret->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
|
|
|
if (!ret->source.adapter.data.name) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source adapter name"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2013-03-25 16:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
2009-04-01 16:03:22 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-03-03 18:47:12 +00:00
|
|
|
/* If DEVICE is the only source type, then its required */
|
|
|
|
if (options->flags == VIR_STORAGE_POOL_SOURCE_DEVICE) {
|
|
|
|
if (!ret->source.ndevice) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source device name"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2010-03-03 18:47:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
/* When we are working with a virtual disk we can skip the target
|
|
|
|
* path and permissions */
|
|
|
|
if (!(options->flags & VIR_STORAGE_POOL_SOURCE_NETWORK)) {
|
2013-05-29 10:04:33 +00:00
|
|
|
if (!(target_path = virXPathString("string(./target/path)", ctxt))) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool target path"));
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2013-05-29 10:04:33 +00:00
|
|
|
ret->target.path = virFileSanitizePath(target_path);
|
2012-05-14 09:06:42 +00:00
|
|
|
if (!ret->target.path)
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
if (virStorageDefParsePerms(ctxt, &ret->target.perms,
|
2012-07-11 14:40:48 +00:00
|
|
|
"./target/permissions",
|
|
|
|
DEFAULT_POOL_PERM_MODE) < 0)
|
2013-05-29 10:04:33 +00:00
|
|
|
goto error;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
cleanup:
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(uuid);
|
2013-05-29 10:04:33 +00:00
|
|
|
VIR_FREE(type);
|
|
|
|
VIR_FREE(target_path);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefFree(ret);
|
2013-05-29 10:04:33 +00:00
|
|
|
ret = NULL;
|
|
|
|
goto cleanup;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virStoragePoolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseNode(xmlDocPtr xml,
|
2013-05-16 12:40:50 +00:00
|
|
|
xmlNodePtr root)
|
|
|
|
{
|
2009-06-22 16:41:34 +00:00
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virStoragePoolDefPtr def = NULL;
|
|
|
|
|
2013-05-22 12:05:14 +00:00
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "pool")) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2013-05-22 12:05:14 +00:00
|
|
|
_("unexpected root element <%s>, "
|
|
|
|
"expecting <pool>"),
|
|
|
|
root->name);
|
2009-06-22 16:41:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-06-22 16:41:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2010-02-10 11:42:56 +00:00
|
|
|
def = virStoragePoolDefParseXML(ctxt);
|
2009-06-22 16:41:34 +00:00
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virStoragePoolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParse(const char *xmlStr,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *filename)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefPtr ret = NULL;
|
2010-02-24 20:53:16 +00:00
|
|
|
xmlDocPtr xml;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2011-09-14 14:17:57 +00:00
|
|
|
if ((xml = virXMLParse(filename, xmlStr, _("(storage_pool_definition)")))) {
|
2010-02-24 20:53:16 +00:00
|
|
|
ret = virStoragePoolDefParseNode(xml, xmlDocGetRootElement(xml));
|
|
|
|
xmlFreeDoc(xml);
|
2009-06-22 16:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-22 16:41:34 +00:00
|
|
|
virStoragePoolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseString(const char *xmlStr)
|
2009-06-22 16:41:34 +00:00
|
|
|
{
|
2010-02-10 11:42:56 +00:00
|
|
|
return virStoragePoolDefParse(xmlStr, NULL);
|
2009-06-22 16:41:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virStoragePoolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolDefParseFile(const char *filename)
|
2009-06-22 16:41:34 +00:00
|
|
|
{
|
2010-02-10 11:42:56 +00:00
|
|
|
return virStoragePoolDefParse(NULL, filename);
|
2009-06-22 16:41:34 +00:00
|
|
|
}
|
|
|
|
|
2008-11-04 21:54:21 +00:00
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolSourceFormat(virBufferPtr buf,
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolOptionsPtr options,
|
2008-11-04 21:54:21 +00:00
|
|
|
virStoragePoolSourcePtr src)
|
|
|
|
{
|
|
|
|
int i, j;
|
2012-05-14 09:06:42 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
2008-11-04 21:54:21 +00:00
|
|
|
|
|
|
|
virBufferAddLit(buf," <source>\n");
|
2012-04-25 10:43:09 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_HOST) && src->nhost) {
|
|
|
|
for (i = 0; i < src->nhost; i++) {
|
2012-04-30 16:36:44 +00:00
|
|
|
virBufferAsprintf(buf, " <host name='%s'", src->hosts[i].name);
|
2012-04-25 10:43:09 +00:00
|
|
|
if (src->hosts[i].port)
|
|
|
|
virBufferAsprintf(buf, " port='%d'", src->hosts[i].port);
|
|
|
|
virBufferAddLit(buf, "/>\n");
|
|
|
|
}
|
2010-11-12 13:23:55 +00:00
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DEVICE) &&
|
2008-11-04 21:54:21 +00:00
|
|
|
src->ndevice) {
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < src->ndevice; i++) {
|
2008-11-04 21:54:21 +00:00
|
|
|
if (src->devices[i].nfreeExtent) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <device path='%s'>\n",
|
2008-11-04 21:54:21 +00:00
|
|
|
src->devices[i].path);
|
2013-05-16 12:40:50 +00:00
|
|
|
for (j = 0; j < src->devices[i].nfreeExtent; j++) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " <freeExtent start='%llu' end='%llu'/>\n",
|
2008-11-04 21:54:21 +00:00
|
|
|
src->devices[i].freeExtents[j].start,
|
|
|
|
src->devices[i].freeExtents[j].end);
|
|
|
|
}
|
|
|
|
virBufferAddLit(buf," </device>\n");
|
2013-05-16 12:40:50 +00:00
|
|
|
} else {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " <device path='%s'/>\n",
|
2008-11-04 21:54:21 +00:00
|
|
|
src->devices[i].path);
|
2013-05-16 12:40:50 +00:00
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_DIR) &&
|
2008-11-04 21:54:21 +00:00
|
|
|
src->dir)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <dir path='%s'/>\n", src->dir);
|
2013-05-16 12:40:50 +00:00
|
|
|
|
2013-03-25 16:43:36 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_ADAPTER)) {
|
|
|
|
if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST ||
|
|
|
|
src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST)
|
|
|
|
virBufferAsprintf(buf, " <adapter type='%s'",
|
|
|
|
virStoragePoolSourceAdapterTypeTypeToString(src->adapter.type));
|
|
|
|
|
|
|
|
if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
virBufferEscapeString(buf, " parent='%s'",
|
|
|
|
src->adapter.data.fchost.parent);
|
|
|
|
virBufferAsprintf(buf," wwnn='%s' wwpn='%s'/>\n",
|
|
|
|
src->adapter.data.fchost.wwnn,
|
|
|
|
src->adapter.data.fchost.wwpn);
|
|
|
|
} else if (src->adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
|
|
|
virBufferAsprintf(buf," name='%s'/>\n", src->adapter.data.name);
|
|
|
|
}
|
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_NAME) &&
|
2008-11-04 21:54:21 +00:00
|
|
|
src->name)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <name>%s</name>\n", src->name);
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2010-06-07 19:06:20 +00:00
|
|
|
if ((options->flags & VIR_STORAGE_POOL_SOURCE_INITIATOR_IQN) &&
|
|
|
|
src->initiator.iqn) {
|
|
|
|
virBufferAddLit(buf," <initiator>\n");
|
|
|
|
virBufferEscapeString(buf," <iqn name='%s'/>\n", src->initiator.iqn);
|
|
|
|
virBufferAddLit(buf," </initiator>\n");
|
|
|
|
}
|
|
|
|
|
2008-11-04 21:54:21 +00:00
|
|
|
if (options->formatToString) {
|
|
|
|
const char *format = (options->formatToString)(src->format);
|
|
|
|
if (!format) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown pool format number %d"),
|
|
|
|
src->format);
|
2008-11-04 21:54:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <format type='%s'/>\n", format);
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (src->authType == VIR_STORAGE_POOL_AUTH_CHAP)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <auth type='chap' login='%s' passwd='%s'/>\n",
|
2008-11-04 21:54:21 +00:00
|
|
|
src->auth.chap.login,
|
|
|
|
src->auth.chap.passwd);
|
2010-08-17 17:44:27 +00:00
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
if (src->authType == VIR_STORAGE_POOL_AUTH_CEPHX) {
|
|
|
|
virBufferAsprintf(buf," <auth username='%s' type='ceph'>\n",
|
|
|
|
src->auth.cephx.username);
|
|
|
|
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(buf," <secret");
|
2012-12-03 12:35:05 +00:00
|
|
|
if (src->auth.cephx.secret.uuidUsable) {
|
2012-05-14 09:06:42 +00:00
|
|
|
virUUIDFormat(src->auth.cephx.secret.uuid, uuid);
|
|
|
|
virBufferAsprintf(buf," uuid='%s'", uuid);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src->auth.cephx.secret.usage != NULL) {
|
|
|
|
virBufferAsprintf(buf," usage='%s'", src->auth.cephx.secret.usage);
|
|
|
|
}
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(buf,"/>\n");
|
2012-05-14 09:06:42 +00:00
|
|
|
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddLit(buf," </auth>\n");
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
|
|
|
|
2010-08-17 17:44:27 +00:00
|
|
|
if (src->vendor != NULL) {
|
|
|
|
virBufferEscapeString(buf," <vendor name='%s'/>\n", src->vendor);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (src->product != NULL) {
|
|
|
|
virBufferEscapeString(buf," <product name='%s'/>\n", src->product);
|
|
|
|
}
|
|
|
|
|
2008-11-04 21:54:21 +00:00
|
|
|
virBufferAddLit(buf," </source>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
char *
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefFormat(virStoragePoolDefPtr def)
|
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolOptionsPtr options;
|
2008-04-28 15:14:59 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2008-02-20 15:34:52 +00:00
|
|
|
const char *type;
|
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStoragePoolOptionsForPoolType(def->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
type = virStoragePoolTypeToString(def->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (!type) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected pool type"));
|
2008-02-20 15:34:52 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, "<pool type='%s'>\n", type);
|
|
|
|
virBufferAsprintf(&buf," <name>%s</name>\n", def->name);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuid);
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf," <uuid>%s</uuid>\n", uuid);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-02-23 00:48:38 +00:00
|
|
|
virBufferAsprintf(&buf," <capacity unit='bytes'>%llu</capacity>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->capacity);
|
2012-02-23 00:48:38 +00:00
|
|
|
virBufferAsprintf(&buf," <allocation unit='bytes'>%llu</allocation>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->allocation);
|
2012-02-23 00:48:38 +00:00
|
|
|
virBufferAsprintf(&buf," <available unit='bytes'>%llu</available>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->available);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStoragePoolSourceFormat(&buf, options, &def->source) < 0)
|
2008-11-04 21:54:21 +00:00
|
|
|
goto cleanup;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
/* RBD and Sheepdog devices are not local block devs nor files, so it
|
|
|
|
* doesn't have a target */
|
|
|
|
if (def->type != VIR_STORAGE_POOL_RBD &&
|
|
|
|
def->type != VIR_STORAGE_POOL_SHEEPDOG) {
|
2012-05-14 09:06:42 +00:00
|
|
|
virBufferAddLit(&buf," <target>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
if (def->target.path)
|
|
|
|
virBufferAsprintf(&buf," <path>%s</path>\n", def->target.path);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
virBufferAddLit(&buf," <permissions>\n");
|
|
|
|
virBufferAsprintf(&buf," <mode>0%o</mode>\n",
|
|
|
|
def->target.perms.mode);
|
2012-08-02 11:23:16 +00:00
|
|
|
virBufferAsprintf(&buf," <owner>%d</owner>\n",
|
|
|
|
(int) def->target.perms.uid);
|
|
|
|
virBufferAsprintf(&buf," <group>%d</group>\n",
|
|
|
|
(int) def->target.perms.gid);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
if (def->target.perms.label)
|
|
|
|
virBufferAsprintf(&buf," <label>%s</label>\n",
|
|
|
|
def->target.perms.label);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-05-14 09:06:42 +00:00
|
|
|
virBufferAddLit(&buf," </permissions>\n");
|
|
|
|
virBufferAddLit(&buf," </target>\n");
|
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&buf,"</pool>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (virBufferError(&buf))
|
2008-02-20 15:34:52 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2013-05-16 12:40:50 +00:00
|
|
|
cleanup:
|
2009-12-09 23:00:50 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageSize(const char *unit,
|
2008-02-20 15:34:52 +00:00
|
|
|
const char *val,
|
2012-03-05 21:06:33 +00:00
|
|
|
unsigned long long *ret)
|
|
|
|
{
|
|
|
|
if (virStrToLong_ull(val, NULL, 10, ret) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("malformed capacity element"));
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2012-03-05 21:06:33 +00:00
|
|
|
/* off_t is signed, so you cannot create a file larger than 2**63
|
|
|
|
* bytes in the first place. */
|
|
|
|
if (virScaleInteger(ret, unit, 1, LLONG_MAX) < 0)
|
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virStorageVolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefParseXML(virStoragePoolDefPtr pool,
|
2013-05-16 12:40:50 +00:00
|
|
|
xmlXPathContextPtr ctxt)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
virStorageVolDefPtr ret;
|
2008-11-17 11:19:33 +00:00
|
|
|
virStorageVolOptionsPtr options;
|
2008-02-20 15:34:52 +00:00
|
|
|
char *allocation = NULL;
|
|
|
|
char *capacity = NULL;
|
|
|
|
char *unit = NULL;
|
2009-07-20 22:28:11 +00:00
|
|
|
xmlNodePtr node;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStorageVolOptionsForPoolType(pool->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC(ret) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
2008-06-06 11:09:57 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
ret->name = virXPathString("string(./name)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (ret->name == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing volume name element"));
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2008-02-27 10:37:19 +00:00
|
|
|
/* Auto-generated so deliberately ignore */
|
2013-05-16 12:40:50 +00:00
|
|
|
/* ret->key = virXPathString("string(./key)", ctxt); */
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
capacity = virXPathString("string(./capacity)", ctxt);
|
|
|
|
unit = virXPathString("string(./capacity/@unit)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (capacity == NULL) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing capacity element"));
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageSize(unit, capacity, &ret->capacity) < 0)
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(unit);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
allocation = virXPathString("string(./allocation)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (allocation) {
|
2010-02-04 21:52:34 +00:00
|
|
|
unit = virXPathString("string(./allocation/@unit)", ctxt);
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageSize(unit, allocation, &ret->allocation) < 0)
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
|
|
|
ret->allocation = ret->capacity;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
ret->target.path = virXPathString("string(./target/path)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options->formatFromString) {
|
2010-02-04 21:52:34 +00:00
|
|
|
char *format = virXPathString("string(./target/format/@type)", ctxt);
|
2008-12-04 15:22:04 +00:00
|
|
|
if (format == NULL)
|
|
|
|
ret->target.format = options->defaultFormat;
|
|
|
|
else
|
|
|
|
ret->target.format = (options->formatFromString)(format);
|
|
|
|
|
|
|
|
if (ret->target.format < 0) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("unknown volume format type %s"), format);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(format);
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(format);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageDefParsePerms(ctxt, &ret->target.perms,
|
2012-07-11 14:40:48 +00:00
|
|
|
"./target/permissions",
|
|
|
|
DEFAULT_VOL_PERM_MODE) < 0)
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
node = virXPathNode("./target/encryption", ctxt);
|
2009-07-20 22:28:11 +00:00
|
|
|
if (node != NULL) {
|
2010-02-10 11:42:56 +00:00
|
|
|
ret->target.encryption = virStorageEncryptionParseNode(ctxt->doc,
|
2009-07-20 22:28:11 +00:00
|
|
|
node);
|
|
|
|
if (ret->target.encryption == NULL)
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2009-07-20 22:28:11 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
ret->backingStore.path = virXPathString("string(./backingStore/path)", ctxt);
|
2009-01-27 18:30:03 +00:00
|
|
|
if (options->formatFromString) {
|
2010-02-04 21:52:34 +00:00
|
|
|
char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
|
2009-01-27 18:30:03 +00:00
|
|
|
if (format == NULL)
|
|
|
|
ret->backingStore.format = options->defaultFormat;
|
|
|
|
else
|
|
|
|
ret->backingStore.format = (options->formatFromString)(format);
|
|
|
|
|
|
|
|
if (ret->backingStore.format < 0) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("unknown volume format type %s"), format);
|
2009-01-27 18:30:03 +00:00
|
|
|
VIR_FREE(format);
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2009-01-27 18:30:03 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(format);
|
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageDefParsePerms(ctxt, &ret->backingStore.perms,
|
2012-07-11 14:40:48 +00:00
|
|
|
"./backingStore/permissions",
|
|
|
|
DEFAULT_VOL_PERM_MODE) < 0)
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
cleanup:
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(allocation);
|
|
|
|
VIR_FREE(capacity);
|
|
|
|
VIR_FREE(unit);
|
2013-05-22 12:05:18 +00:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
error:
|
2008-02-20 15:34:52 +00:00
|
|
|
virStorageVolDefFree(ret);
|
2013-05-22 12:05:18 +00:00
|
|
|
ret = NULL;
|
|
|
|
goto cleanup;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefParseNode(virStoragePoolDefPtr pool,
|
2009-06-22 16:41:34 +00:00
|
|
|
xmlDocPtr xml,
|
2013-05-16 12:40:50 +00:00
|
|
|
xmlNodePtr root)
|
|
|
|
{
|
2009-06-22 16:41:34 +00:00
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
virStorageVolDefPtr def = NULL;
|
|
|
|
|
2013-05-22 12:05:14 +00:00
|
|
|
if (!xmlStrEqual(root->name, BAD_CAST "volume")) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2013-05-22 12:05:14 +00:00
|
|
|
_("unexpected root element <%s>, "
|
|
|
|
"expecting <volume>"),
|
|
|
|
root->name);
|
2009-06-22 16:41:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt = xmlXPathNewContext(xml);
|
|
|
|
if (ctxt == NULL) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-06-22 16:41:34 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = root;
|
2010-02-10 11:42:56 +00:00
|
|
|
def = virStorageVolDefParseXML(pool, ctxt);
|
2009-06-22 16:41:34 +00:00
|
|
|
cleanup:
|
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return def;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virStorageVolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefParse(virStoragePoolDefPtr pool,
|
2008-02-20 15:34:52 +00:00
|
|
|
const char *xmlStr,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *filename)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
virStorageVolDefPtr ret = NULL;
|
2010-02-24 20:53:16 +00:00
|
|
|
xmlDocPtr xml;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2011-09-14 14:17:57 +00:00
|
|
|
if ((xml = virXMLParse(filename, xmlStr, _("(storage_volume_definition)")))) {
|
2010-02-24 20:53:16 +00:00
|
|
|
ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml));
|
|
|
|
xmlFreeDoc(xml);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2009-06-22 16:41:34 +00:00
|
|
|
virStorageVolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefParseString(virStoragePoolDefPtr pool,
|
2009-06-22 16:41:34 +00:00
|
|
|
const char *xmlStr)
|
|
|
|
{
|
2010-02-10 11:42:56 +00:00
|
|
|
return virStorageVolDefParse(pool, xmlStr, NULL);
|
2009-06-22 16:41:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
|
2009-06-22 16:41:34 +00:00
|
|
|
const char *filename)
|
|
|
|
{
|
2010-02-10 11:42:56 +00:00
|
|
|
return virStorageVolDefParse(pool, NULL, filename);
|
2009-06-22 16:41:34 +00:00
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-07-25 07:43:37 +00:00
|
|
|
static void
|
|
|
|
virStorageVolTimestampFormat(virBufferPtr buf, const char *name,
|
|
|
|
struct timespec *ts)
|
|
|
|
{
|
|
|
|
if (ts->tv_nsec < 0)
|
|
|
|
return;
|
|
|
|
virBufferAsprintf(buf, " <%s>%llu", name,
|
|
|
|
(unsigned long long) ts->tv_sec);
|
|
|
|
if (ts->tv_nsec)
|
|
|
|
virBufferAsprintf(buf, ".%09ld", ts->tv_nsec);
|
|
|
|
virBufferAsprintf(buf, "</%s>\n", name);
|
|
|
|
}
|
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
static int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolTargetDefFormat(virStorageVolOptionsPtr options,
|
2009-01-27 18:30:03 +00:00
|
|
|
virBufferPtr buf,
|
|
|
|
virStorageVolTargetPtr def,
|
|
|
|
const char *type) {
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " <%s>\n", type);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
|
|
|
if (def->path)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <path>%s</path>\n", def->path);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
|
|
|
if (options->formatToString) {
|
|
|
|
const char *format = (options->formatToString)(def->format);
|
|
|
|
if (!format) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("unknown volume format number %d"),
|
|
|
|
def->format);
|
2009-01-27 18:30:03 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <format type='%s'/>\n", format);
|
2009-01-27 18:30:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(buf," <permissions>\n");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <mode>0%o</mode>\n",
|
2009-01-27 18:30:03 +00:00
|
|
|
def->perms.mode);
|
2012-03-30 22:50:52 +00:00
|
|
|
virBufferAsprintf(buf," <owner>%u</owner>\n",
|
|
|
|
(unsigned int) def->perms.uid);
|
|
|
|
virBufferAsprintf(buf," <group>%u</group>\n",
|
|
|
|
(unsigned int) def->perms.gid);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (def->perms.label)
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf," <label>%s</label>\n",
|
2009-01-27 18:30:03 +00:00
|
|
|
def->perms.label);
|
|
|
|
|
|
|
|
virBufferAddLit(buf," </permissions>\n");
|
|
|
|
|
2012-07-25 07:43:37 +00:00
|
|
|
if (def->timestamps) {
|
|
|
|
virBufferAddLit(buf, " <timestamps>\n");
|
|
|
|
virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
|
|
|
|
virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
|
|
|
|
virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
|
|
|
|
virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
|
|
|
|
virBufferAddLit(buf, " </timestamps>\n");
|
|
|
|
}
|
|
|
|
|
2011-09-22 18:16:26 +00:00
|
|
|
if (def->encryption) {
|
|
|
|
virBufferAdjustIndent(buf, 4);
|
|
|
|
if (virStorageEncryptionFormat(buf, def->encryption) < 0)
|
|
|
|
return -1;
|
|
|
|
virBufferAdjustIndent(buf, -4);
|
|
|
|
}
|
2009-07-20 22:28:11 +00:00
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(buf, " </%s>\n", type);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
char *
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefFormat(virStoragePoolDefPtr pool,
|
2013-05-16 12:40:50 +00:00
|
|
|
virStorageVolDefPtr def)
|
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStorageVolOptionsPtr options;
|
2008-04-28 15:14:59 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStorageVolOptionsForPoolType(pool->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&buf, "<volume>\n");
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf," <name>%s</name>\n", def->name);
|
2013-05-22 12:05:19 +00:00
|
|
|
virBufferAsprintf(&buf," <key>%s</key>\n", NULLSTR(def->key));
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&buf, " <source>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
if (def->source.nextent) {
|
|
|
|
int i;
|
|
|
|
const char *thispath = NULL;
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < def->source.nextent; i++) {
|
2008-02-20 15:34:52 +00:00
|
|
|
if (thispath == NULL ||
|
|
|
|
STRNEQ(thispath, def->source.extents[i].path)) {
|
|
|
|
if (thispath != NULL)
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&buf, " </device>\n");
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf, " <device path='%s'>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->source.extents[i].path);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&buf,
|
2008-04-28 15:14:59 +00:00
|
|
|
" <extent start='%llu' end='%llu'/>\n",
|
|
|
|
def->source.extents[i].start,
|
|
|
|
def->source.extents[i].end);
|
2008-02-20 15:34:52 +00:00
|
|
|
thispath = def->source.extents[i].path;
|
|
|
|
}
|
|
|
|
if (thispath != NULL)
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&buf, " </device>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2008-04-28 15:14:59 +00:00
|
|
|
virBufferAddLit(&buf, " </source>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2012-02-23 00:48:38 +00:00
|
|
|
virBufferAsprintf(&buf," <capacity unit='bytes'>%llu</capacity>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->capacity);
|
2012-02-23 00:48:38 +00:00
|
|
|
virBufferAsprintf(&buf," <allocation unit='bytes'>%llu</allocation>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->allocation);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (virStorageVolTargetDefFormat(options, &buf,
|
2009-01-27 18:30:03 +00:00
|
|
|
&def->target, "target") < 0)
|
|
|
|
goto cleanup;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-01-27 18:30:03 +00:00
|
|
|
if (def->backingStore.path &&
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolTargetDefFormat(options, &buf,
|
2009-01-27 18:30:03 +00:00
|
|
|
&def->backingStore, "backingStore") < 0)
|
|
|
|
goto cleanup;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
|
|
|
virBufferAddLit(&buf,"</volume>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
if (virBufferError(&buf))
|
2008-02-20 15:34:52 +00:00
|
|
|
goto no_memory;
|
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2013-05-16 12:40:50 +00:00
|
|
|
cleanup:
|
2009-12-09 23:00:50 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virStoragePoolObjPtr
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjFindByUUID(virStoragePoolObjListPtr pools,
|
2013-05-16 12:40:50 +00:00
|
|
|
const unsigned char *uuid)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < pools->count; i++) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjLock(pools->objs[i]);
|
2008-10-10 15:13:28 +00:00
|
|
|
if (!memcmp(pools->objs[i]->def->uuid, uuid, VIR_UUID_BUFLEN))
|
|
|
|
return pools->objs[i];
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjUnlock(pools->objs[i]);
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virStoragePoolObjPtr
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjFindByName(virStoragePoolObjListPtr pools,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < pools->count; i++) {
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjLock(pools->objs[i]);
|
2008-10-10 15:13:28 +00:00
|
|
|
if (STREQ(pools->objs[i]->def->name, name))
|
|
|
|
return pools->objs[i];
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjUnlock(pools->objs[i]);
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-09-05 07:52:03 +00:00
|
|
|
virStoragePoolObjPtr
|
|
|
|
virStoragePoolSourceFindDuplicateDevices(virStoragePoolObjPtr pool,
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
2011-09-05 07:52:03 +00:00
|
|
|
unsigned int i, j;
|
|
|
|
|
|
|
|
for (i = 0; i < pool->def->source.ndevice; i++) {
|
|
|
|
for (j = 0; j < def->source.ndevice; j++) {
|
|
|
|
if (STREQ(pool->def->source.devices[i].path, def->source.devices[j].path))
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
|
|
|
virStoragePoolObjClearVols(virStoragePoolObjPtr pool)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < pool->volumes.count; i++)
|
2008-10-10 15:13:28 +00:00
|
|
|
virStorageVolDefFree(pool->volumes.objs[i]);
|
|
|
|
|
|
|
|
VIR_FREE(pool->volumes.objs);
|
|
|
|
pool->volumes.count = 0;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefPtr
|
|
|
|
virStorageVolDefFindByKey(virStoragePoolObjPtr pool,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *key)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < pool->volumes.count; i++)
|
2008-10-10 15:13:28 +00:00
|
|
|
if (STREQ(pool->volumes.objs[i]->key, key))
|
|
|
|
return pool->volumes.objs[i];
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefPtr
|
|
|
|
virStorageVolDefFindByPath(virStoragePoolObjPtr pool,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *path)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-21 07:21:17 +00:00
|
|
|
for (i = 0; i < pool->volumes.count; i++)
|
2008-10-10 15:13:28 +00:00
|
|
|
if (STREQ(pool->volumes.objs[i]->target.path, path))
|
|
|
|
return pool->volumes.objs[i];
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefPtr
|
|
|
|
virStorageVolDefFindByName(virStoragePoolObjPtr pool,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *name)
|
|
|
|
{
|
2008-10-10 15:13:28 +00:00
|
|
|
unsigned int i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
for (i = 0; i < pool->volumes.count; i++)
|
2008-10-10 15:13:28 +00:00
|
|
|
if (STREQ(pool->volumes.objs[i]->name, name))
|
|
|
|
return pool->volumes.objs[i];
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
virStoragePoolObjPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolObjAssignDef(virStoragePoolObjListPtr pools,
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolObjPtr pool;
|
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
if ((pool = virStoragePoolObjFindByName(pools, def->name))) {
|
2008-02-20 15:34:52 +00:00
|
|
|
if (!virStoragePoolObjIsActive(pool)) {
|
|
|
|
virStoragePoolDefFree(pool->def);
|
|
|
|
pool->def = def;
|
|
|
|
} else {
|
2010-05-17 20:38:59 +00:00
|
|
|
virStoragePoolDefFree(pool->newDef);
|
2008-02-20 15:34:52 +00:00
|
|
|
pool->newDef = def;
|
|
|
|
}
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
2008-06-06 11:09:57 +00:00
|
|
|
if (VIR_ALLOC(pool) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&pool->lock) < 0) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("cannot initialize mutex"));
|
2009-01-15 19:56:05 +00:00
|
|
|
VIR_FREE(pool);
|
|
|
|
return NULL;
|
|
|
|
}
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjLock(pool);
|
2008-02-20 15:34:52 +00:00
|
|
|
pool->active = 0;
|
|
|
|
pool->def = def;
|
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
if (VIR_REALLOC_N(pools->objs, pools->count+1) < 0) {
|
|
|
|
pool->def = NULL;
|
2009-01-15 19:56:05 +00:00
|
|
|
virStoragePoolObjUnlock(pool);
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjFree(pool);
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2008-10-10 15:13:28 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pools->objs[pools->count++] = pool;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
static virStoragePoolObjPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolObjLoad(virStoragePoolObjListPtr pools,
|
2008-02-20 15:34:52 +00:00
|
|
|
const char *file,
|
|
|
|
const char *path,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *autostartLink)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefPtr def;
|
|
|
|
virStoragePoolObjPtr pool;
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (!(def = virStoragePoolDefParseFile(path))) {
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!virFileMatchesNameSuffix(file, def->name, ".xml")) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
2013-05-22 12:05:21 +00:00
|
|
|
_("Storage pool config filename '%s' does "
|
|
|
|
"not match pool name '%s'"),
|
2012-07-18 10:50:44 +00:00
|
|
|
path, def->name);
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (!(pool = virStoragePoolObjAssignDef(pools, def))) {
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-01-28 21:38:06 +00:00
|
|
|
VIR_FREE(pool->configFile); /* for driver reload */
|
2013-05-03 12:40:46 +00:00
|
|
|
if (VIR_STRDUP(pool->configFile, path) < 0) {
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
2011-01-28 21:38:06 +00:00
|
|
|
VIR_FREE(pool->autostartLink); /* for driver reload */
|
2013-05-03 12:40:46 +00:00
|
|
|
if (VIR_STRDUP(pool->autostartLink, autostartLink) < 0) {
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolDefFree(def);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool->autostart = virFileLinkPointsTo(pool->autostartLink,
|
|
|
|
pool->configFile);
|
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolLoadAllConfigs(virStoragePoolObjListPtr pools,
|
2008-10-10 15:13:28 +00:00
|
|
|
const char *configDir,
|
2013-05-16 12:40:50 +00:00
|
|
|
const char *autostartDir)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
DIR *dir;
|
|
|
|
struct dirent *entry;
|
|
|
|
|
2008-10-10 15:13:28 +00:00
|
|
|
if (!(dir = opendir(configDir))) {
|
2008-02-20 15:34:52 +00:00
|
|
|
if (errno == ENOENT)
|
|
|
|
return 0;
|
2010-02-04 20:02:58 +00:00
|
|
|
virReportSystemError(errno, _("Failed to open dir '%s'"),
|
2009-05-20 13:37:30 +00:00
|
|
|
configDir);
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((entry = readdir(dir))) {
|
2011-04-03 09:21:14 +00:00
|
|
|
char *path;
|
|
|
|
char *autostartLink;
|
2008-12-04 22:00:14 +00:00
|
|
|
virStoragePoolObjPtr pool;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
if (entry->d_name[0] == '.')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!virFileHasSuffix(entry->d_name, ".xml"))
|
|
|
|
continue;
|
|
|
|
|
2011-04-24 09:48:00 +00:00
|
|
|
if (!(path = virFileBuildPath(configDir, entry->d_name, NULL)))
|
2008-02-20 15:34:52 +00:00
|
|
|
continue;
|
|
|
|
|
2011-04-03 09:21:14 +00:00
|
|
|
if (!(autostartLink = virFileBuildPath(autostartDir, entry->d_name,
|
|
|
|
NULL))) {
|
|
|
|
VIR_FREE(path);
|
2008-02-20 15:34:52 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
pool = virStoragePoolObjLoad(pools, entry->d_name, path,
|
2009-06-25 15:13:25 +00:00
|
|
|
autostartLink);
|
2008-12-04 22:00:14 +00:00
|
|
|
if (pool)
|
|
|
|
virStoragePoolObjUnlock(pool);
|
2011-04-03 09:21:14 +00:00
|
|
|
|
|
|
|
VIR_FREE(path);
|
|
|
|
VIR_FREE(autostartLink);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
closedir(dir);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
|
2008-02-20 15:34:52 +00:00
|
|
|
virStoragePoolObjPtr pool,
|
2011-10-27 16:55:47 +00:00
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
2012-10-29 12:15:55 +00:00
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
2008-02-20 15:34:52 +00:00
|
|
|
char *xml;
|
2011-10-27 16:55:47 +00:00
|
|
|
int ret = -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
if (!pool->configFile) {
|
2011-07-05 21:02:53 +00:00
|
|
|
if (virFileMakePath(driver->configDir) < 0) {
|
|
|
|
virReportSystemError(errno,
|
2009-10-27 16:20:22 +00:00
|
|
|
_("cannot create config directory %s"),
|
|
|
|
driver->configDir);
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-04-03 09:21:14 +00:00
|
|
|
if (!(pool->configFile = virFileBuildPath(driver->configDir,
|
|
|
|
def->name, ".xml"))) {
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2011-04-03 09:21:14 +00:00
|
|
|
if (!(pool->autostartLink = virFileBuildPath(driver->autostartDir,
|
|
|
|
def->name, ".xml"))) {
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(pool->configFile);
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-02-10 11:42:56 +00:00
|
|
|
if (!(xml = virStoragePoolDefFormat(def))) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to generate XML"));
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-10-29 12:15:55 +00:00
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
|
|
|
ret = virXMLSaveFile(pool->configFile,
|
|
|
|
virXMLPickShellSafeComment(def->name, uuidstr),
|
|
|
|
"pool-edit", xml);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(xml);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolObjDeleteDef(virStoragePoolObjPtr pool)
|
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
if (!pool->configFile) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("no config file for %s"), pool->def->name);
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unlink(pool->configFile) < 0) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("cannot remove config for %s"),
|
|
|
|
pool->def->name);
|
2008-02-20 15:34:52 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2009-10-15 15:41:53 +00:00
|
|
|
virStoragePoolSourcePtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolSourceListNewSource(virStoragePoolSourceListPtr list)
|
2009-10-15 15:41:53 +00:00
|
|
|
{
|
|
|
|
virStoragePoolSourcePtr source;
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0) {
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2009-10-15 15:41:53 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
source = &list->sources[list->nsources++];
|
|
|
|
memset(source, 0, sizeof(*source));
|
|
|
|
|
|
|
|
return source;
|
|
|
|
}
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
char *
|
|
|
|
virStoragePoolSourceListFormat(virStoragePoolSourceListPtr def)
|
2008-10-23 11:39:53 +00:00
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolOptionsPtr options;
|
2008-10-23 11:39:53 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2008-11-04 21:54:21 +00:00
|
|
|
const char *type;
|
|
|
|
int i;
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStoragePoolOptionsForPoolType(def->type);
|
2008-11-04 21:54:21 +00:00
|
|
|
if (options == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
type = virStoragePoolTypeToString(def->type);
|
2008-11-04 21:54:21 +00:00
|
|
|
if (!type) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("unexpected pool type"));
|
2008-11-04 21:54:21 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<sources>\n");
|
2008-10-23 11:39:53 +00:00
|
|
|
|
|
|
|
for (i = 0; i < def->nsources; i++) {
|
2010-02-10 11:42:56 +00:00
|
|
|
virStoragePoolSourceFormat(&buf, options, &def->sources[i]);
|
2008-10-23 11:39:53 +00:00
|
|
|
}
|
|
|
|
|
2008-11-04 21:54:21 +00:00
|
|
|
virBufferAddLit(&buf, "</sources>\n");
|
|
|
|
|
|
|
|
if (virBufferError(&buf))
|
|
|
|
goto no_memory;
|
2008-10-23 11:39:53 +00:00
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
no_memory:
|
2010-02-04 18:19:08 +00:00
|
|
|
virReportOOMError();
|
2013-05-16 12:40:50 +00:00
|
|
|
cleanup:
|
2009-12-09 23:00:50 +00:00
|
|
|
virBufferFreeAndReset(&buf);
|
2008-11-04 21:54:21 +00:00
|
|
|
return NULL;
|
2008-10-23 11:39:53 +00:00
|
|
|
}
|
2008-12-04 20:53:20 +00:00
|
|
|
|
|
|
|
|
2010-05-27 11:41:30 +00:00
|
|
|
/*
|
|
|
|
* virStoragePoolObjIsDuplicate:
|
|
|
|
* @doms : virStoragePoolObjListPtr to search
|
|
|
|
* @def : virStoragePoolDefPtr definition of pool to lookup
|
|
|
|
* @check_active: If true, ensure that pool is not active
|
|
|
|
*
|
|
|
|
* Returns: -1 on error
|
|
|
|
* 0 if pool is new
|
|
|
|
* 1 if pool is a duplicate
|
|
|
|
*/
|
2013-05-16 12:40:50 +00:00
|
|
|
int
|
|
|
|
virStoragePoolObjIsDuplicate(virStoragePoolObjListPtr pools,
|
|
|
|
virStoragePoolDefPtr def,
|
|
|
|
unsigned int check_active)
|
2010-05-27 11:41:30 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
virStoragePoolObjPtr pool = NULL;
|
|
|
|
|
|
|
|
/* See if a Pool with matching UUID already exists */
|
|
|
|
pool = virStoragePoolObjFindByUUID(pools, def->uuid);
|
|
|
|
if (pool) {
|
|
|
|
/* UUID matches, but if names don't match, refuse it */
|
|
|
|
if (STRNEQ(pool->def->name, def->name)) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(pool->def->uuid, uuidstr);
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("pool '%s' is already defined with uuid %s"),
|
|
|
|
pool->def->name, uuidstr);
|
2010-05-27 11:41:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (check_active) {
|
|
|
|
/* UUID & name match, but if Pool is already active, refuse it */
|
|
|
|
if (virStoragePoolObjIsActive(pool)) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_INVALID,
|
|
|
|
_("pool is already active as '%s'"),
|
|
|
|
pool->def->name);
|
2010-05-27 11:41:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-24 10:29:28 +00:00
|
|
|
ret = 1;
|
2010-05-27 11:41:30 +00:00
|
|
|
} else {
|
|
|
|
/* UUID does not match, but if a name matches, refuse it */
|
|
|
|
pool = virStoragePoolObjFindByName(pools, def->name);
|
|
|
|
if (pool) {
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
virUUIDFormat(pool->def->uuid, uuidstr);
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("pool '%s' already exists with uuid %s"),
|
|
|
|
def->name, uuidstr);
|
2010-05-27 11:41:30 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-05-24 10:29:28 +00:00
|
|
|
ret = 0;
|
2010-05-27 11:41:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (pool)
|
|
|
|
virStoragePoolObjUnlock(pool);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
int
|
|
|
|
virStoragePoolSourceFindDuplicate(virStoragePoolObjListPtr pools,
|
|
|
|
virStoragePoolDefPtr def)
|
2011-09-05 07:52:03 +00:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int ret = 1;
|
|
|
|
virStoragePoolObjPtr pool = NULL;
|
|
|
|
virStoragePoolObjPtr matchpool = NULL;
|
|
|
|
|
|
|
|
/* Check the pool list for duplicate underlying storage */
|
|
|
|
for (i = 0; i < pools->count; i++) {
|
|
|
|
pool = pools->objs[i];
|
|
|
|
if (def->type != pool->def->type)
|
|
|
|
continue;
|
|
|
|
|
2011-10-07 16:38:09 +00:00
|
|
|
/* Don't mach against ourself if re-defining existing pool ! */
|
|
|
|
if (STREQ(pool->def->name, def->name))
|
|
|
|
continue;
|
|
|
|
|
2011-09-05 07:52:03 +00:00
|
|
|
virStoragePoolObjLock(pool);
|
|
|
|
|
|
|
|
switch (pool->def->type) {
|
|
|
|
case VIR_STORAGE_POOL_DIR:
|
|
|
|
if (STREQ(pool->def->target.path, def->target.path))
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_NETFS:
|
|
|
|
if ((STREQ(pool->def->source.dir, def->source.dir)) \
|
2012-04-25 10:43:09 +00:00
|
|
|
&& (pool->def->source.nhost == 1 && def->source.nhost == 1) \
|
|
|
|
&& (STREQ(pool->def->source.hosts[0].name, def->source.hosts[0].name)))
|
2011-09-05 07:52:03 +00:00
|
|
|
matchpool = pool;
|
|
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_SCSI:
|
2013-03-25 16:43:36 +00:00
|
|
|
if (pool->def->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
if (STREQ(pool->def->source.adapter.data.fchost.wwnn,
|
|
|
|
def->source.adapter.data.fchost.wwnn) &&
|
|
|
|
STREQ(pool->def->source.adapter.data.fchost.wwpn,
|
|
|
|
def->source.adapter.data.fchost.wwpn))
|
|
|
|
matchpool = pool;
|
|
|
|
} else if (pool->def->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST){
|
|
|
|
if (STREQ(pool->def->source.adapter.data.name,
|
|
|
|
def->source.adapter.data.name))
|
|
|
|
matchpool = pool;
|
|
|
|
}
|
2011-09-05 07:52:03 +00:00
|
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_ISCSI:
|
|
|
|
matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
|
|
|
|
if (matchpool) {
|
2012-04-25 10:43:09 +00:00
|
|
|
if (matchpool->def->source.nhost == 1 && def->source.nhost == 1) {
|
|
|
|
if (STREQ(matchpool->def->source.hosts[0].name, def->source.hosts[0].name)) {
|
|
|
|
if ((matchpool->def->source.initiator.iqn) && (def->source.initiator.iqn)) {
|
|
|
|
if (STREQ(matchpool->def->source.initiator.iqn, def->source.initiator.iqn))
|
|
|
|
break;
|
|
|
|
matchpool = NULL;
|
|
|
|
}
|
|
|
|
break;
|
2011-09-05 07:52:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
matchpool = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_FS:
|
|
|
|
case VIR_STORAGE_POOL_LOGICAL:
|
|
|
|
case VIR_STORAGE_POOL_DISK:
|
|
|
|
matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
virStoragePoolObjUnlock(pool);
|
2012-04-28 08:18:44 +00:00
|
|
|
|
|
|
|
if (matchpool)
|
|
|
|
break;
|
2011-09-05 07:52:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (matchpool) {
|
2012-07-18 10:50:44 +00:00
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
_("Storage source conflict with pool: '%s'"),
|
|
|
|
matchpool->def->name);
|
2011-09-05 07:52:03 +00:00
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
2010-05-27 11:41:30 +00:00
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
void
|
|
|
|
virStoragePoolObjLock(virStoragePoolObjPtr obj)
|
2008-12-04 22:00:14 +00:00
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&obj->lock);
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
void
|
|
|
|
virStoragePoolObjUnlock(virStoragePoolObjPtr obj)
|
2008-12-04 22:00:14 +00:00
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&obj->lock);
|
2008-12-04 22:00:14 +00:00
|
|
|
}
|
2012-09-04 15:16:25 +00:00
|
|
|
|
|
|
|
#define MATCH(FLAG) (flags & (FLAG))
|
|
|
|
static bool
|
|
|
|
virStoragePoolMatch(virStoragePoolObjPtr poolobj,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
/* filter by active state */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ACTIVE) &&
|
|
|
|
virStoragePoolObjIsActive(poolobj)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_INACTIVE) &&
|
|
|
|
!virStoragePoolObjIsActive(poolobj))))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by persistence */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_PERSISTENT) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_PERSISTENT) &&
|
|
|
|
poolobj->configFile) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_TRANSIENT) &&
|
|
|
|
!poolobj->configFile)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by autostart option */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_AUTOSTART) &&
|
|
|
|
!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_AUTOSTART) &&
|
|
|
|
poolobj->autostart) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NO_AUTOSTART) &&
|
|
|
|
!poolobj->autostart)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* filter by pool type */
|
|
|
|
if (MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_POOL_TYPE)) {
|
|
|
|
if (!((MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DIR) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_DIR)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_FS) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_FS)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_NETFS) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_NETFS)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_LOGICAL) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_LOGICAL)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_DISK) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_DISK)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ISCSI) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_ISCSI)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SCSI) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_SCSI)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_MPATH) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_MPATH)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_RBD) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_RBD)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG) &&
|
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_SHEEPDOG))))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#undef MATCH
|
|
|
|
|
|
|
|
int
|
|
|
|
virStoragePoolList(virConnectPtr conn,
|
|
|
|
virStoragePoolObjList poolobjs,
|
|
|
|
virStoragePoolPtr **pools,
|
|
|
|
unsigned int flags)
|
|
|
|
{
|
|
|
|
virStoragePoolPtr *tmp_pools = NULL;
|
|
|
|
virStoragePoolPtr pool = NULL;
|
|
|
|
int npools = 0;
|
|
|
|
int ret = -1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (pools) {
|
|
|
|
if (VIR_ALLOC_N(tmp_pools, poolobjs.count + 1) < 0) {
|
|
|
|
virReportOOMError();
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < poolobjs.count; i++) {
|
|
|
|
virStoragePoolObjPtr poolobj = poolobjs.objs[i];
|
|
|
|
virStoragePoolObjLock(poolobj);
|
|
|
|
if (virStoragePoolMatch(poolobj, flags)) {
|
|
|
|
if (pools) {
|
|
|
|
if (!(pool = virGetStoragePool(conn,
|
|
|
|
poolobj->def->name,
|
2012-11-10 07:18:07 +00:00
|
|
|
poolobj->def->uuid,
|
|
|
|
NULL, NULL))) {
|
2012-09-04 15:16:25 +00:00
|
|
|
virStoragePoolObjUnlock(poolobj);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
tmp_pools[npools] = pool;
|
|
|
|
}
|
|
|
|
npools++;
|
|
|
|
}
|
|
|
|
virStoragePoolObjUnlock(poolobj);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp_pools) {
|
|
|
|
/* trim the array to the final size */
|
|
|
|
ignore_value(VIR_REALLOC_N(tmp_pools, npools + 1));
|
|
|
|
*pools = tmp_pools;
|
|
|
|
tmp_pools = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = npools;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (tmp_pools) {
|
|
|
|
for (i = 0; i < npools; i++) {
|
|
|
|
if (tmp_pools[i])
|
|
|
|
virStoragePoolFree(tmp_pools[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(tmp_pools);
|
|
|
|
return ret;
|
|
|
|
}
|