2008-02-20 15:34:52 +00:00
|
|
|
/*
|
|
|
|
* storage_conf.c: config handling for storage driver
|
|
|
|
*
|
2016-01-07 11:57:28 +00:00
|
|
|
* Copyright (C) 2006-2016 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"
|
2017-02-18 13:26:21 +00:00
|
|
|
#include "node_device_conf.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"
|
2017-01-23 19:48:12 +00:00
|
|
|
#include "virscsihost.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2014-06-26 12:18:09 +00:00
|
|
|
#include "virlog.h"
|
2017-01-23 17:54:42 +00:00
|
|
|
#include "virvhba.h"
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2009-01-20 17:13:33 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
|
|
|
|
2014-06-26 12:18:09 +00:00
|
|
|
VIR_LOG_INIT("conf.storage_conf");
|
|
|
|
|
2013-11-19 20:14:54 +00:00
|
|
|
VIR_ENUM_IMPL(virStorageVol,
|
|
|
|
VIR_STORAGE_VOL_LAST,
|
2016-04-11 16:16:19 +00:00
|
|
|
"file", "block", "dir", "network",
|
|
|
|
"netdir", "ploop")
|
2013-11-19 20:14:54 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePool,
|
|
|
|
VIR_STORAGE_POOL_LAST,
|
|
|
|
"dir", "fs", "netfs",
|
|
|
|
"logical", "disk", "iscsi",
|
2014-07-21 14:38:42 +00:00
|
|
|
"scsi", "mpath", "rbd",
|
2017-01-17 14:10:55 +00:00
|
|
|
"sheepdog", "gluster", "zfs",
|
|
|
|
"vstorage")
|
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
|
|
|
|
2014-05-14 19:48:15 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePartedFs,
|
2009-06-26 16:18:59 +00:00
|
|
|
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
|
|
|
|
2014-05-14 19:48:15 +00:00
|
|
|
VIR_ENUM_IMPL(virStoragePoolSourceAdapter,
|
2013-03-25 16:43:36 +00:00
|
|
|
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,
|
2015-12-24 12:34:58 +00:00
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
2013-05-16 12:40:51 +00:00
|
|
|
}
|
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-11-19 23:26:05 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_GLUSTER,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_HOST |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NETWORK |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_NAME |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DIR),
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
}
|
|
|
|
},
|
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,
|
|
|
|
},
|
2014-07-21 14:38:42 +00:00
|
|
|
},
|
|
|
|
{.poolType = VIR_STORAGE_POOL_ZFS,
|
|
|
|
.poolOptions = {
|
2014-09-07 14:01:34 +00:00
|
|
|
.flags = (VIR_STORAGE_POOL_SOURCE_NAME |
|
|
|
|
VIR_STORAGE_POOL_SOURCE_DEVICE),
|
2014-07-21 14:38:42 +00:00
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
},
|
|
|
|
},
|
2017-01-17 14:10:55 +00:00
|
|
|
{.poolType = VIR_STORAGE_POOL_VSTORAGE,
|
|
|
|
.poolOptions = {
|
|
|
|
.flags = VIR_STORAGE_POOL_SOURCE_NAME,
|
|
|
|
},
|
|
|
|
.volOptions = {
|
|
|
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
|
|
|
.formatFromString = virStorageVolumeFormatFromString,
|
|
|
|
.formatToString = virStorageFileFormatTypeToString,
|
|
|
|
},
|
|
|
|
},
|
2008-11-17 11:19:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static virStoragePoolTypeInfoPtr
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolTypeInfoLookup(int type)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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
|
|
|
|
2014-11-13 14:23:27 +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);
|
|
|
|
VIR_FREE(def->source.extents);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-04-01 21:11:30 +00:00
|
|
|
virStorageSourceClear(&def->target);
|
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
|
2014-11-10 16:34:57 +00:00
|
|
|
virStoragePoolSourceAdapterClear(virStoragePoolSourceAdapterPtr adapter)
|
2013-03-25 16:43:36 +00:00
|
|
|
{
|
2014-11-10 16:34:57 +00:00
|
|
|
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);
|
2016-11-17 22:48:35 +00:00
|
|
|
VIR_FREE(adapter->data.fchost.parent_wwnn);
|
|
|
|
VIR_FREE(adapter->data.fchost.parent_wwpn);
|
|
|
|
VIR_FREE(adapter->data.fchost.parent_fabric_wwn);
|
2014-11-10 16:34:57 +00:00
|
|
|
} else if (adapter->type ==
|
2013-03-25 16:43:36 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
2014-11-10 16:34:57 +00:00
|
|
|
VIR_FREE(adapter->data.scsi_host.name);
|
2013-03-25 16:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-11 07:44:22 +00:00
|
|
|
void
|
|
|
|
virStoragePoolSourceDeviceClear(virStoragePoolSourceDevicePtr dev)
|
|
|
|
{
|
|
|
|
VIR_FREE(dev->freeExtents);
|
|
|
|
VIR_FREE(dev->path);
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
void
|
2011-10-21 22:44:52 +00:00
|
|
|
virStoragePoolSourceClear(virStoragePoolSourcePtr source)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-10-23 11:39:53 +00:00
|
|
|
if (!source)
|
2008-10-10 15:13:28 +00:00
|
|
|
return;
|
|
|
|
|
2014-11-13 14:23:27 +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);
|
|
|
|
|
2014-03-11 07:44:22 +00:00
|
|
|
for (i = 0; i < source->ndevice; i++)
|
|
|
|
virStoragePoolSourceDeviceClear(&source->devices[i]);
|
2008-10-23 11:39:53 +00:00
|
|
|
VIR_FREE(source->devices);
|
|
|
|
VIR_FREE(source->dir);
|
|
|
|
VIR_FREE(source->name);
|
2014-11-10 16:34:57 +00:00
|
|
|
virStoragePoolSourceAdapterClear(&source->adapter);
|
2010-01-21 11:50:52 +00:00
|
|
|
VIR_FREE(source->initiator.iqn);
|
2014-06-26 12:18:09 +00:00
|
|
|
virStorageAuthDefFree(source->auth);
|
2010-08-17 17:44:27 +00:00
|
|
|
VIR_FREE(source->vendor);
|
|
|
|
VIR_FREE(source->product);
|
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
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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
|
|
|
|
2014-03-07 08:33:31 +00:00
|
|
|
VIR_DELETE_ELEMENT(pools->objs, i, pools->count);
|
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
|
|
|
}
|
|
|
|
|
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;
|
2014-06-26 12:18:09 +00:00
|
|
|
xmlNodePtr relnode, authnode, *nodeset = NULL;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
int nsource;
|
|
|
|
size_t i;
|
2009-10-15 14:55:19 +00:00
|
|
|
virStoragePoolOptionsPtr options;
|
2014-06-26 12:18:09 +00:00
|
|
|
virStorageAuthDefPtr authdef = NULL;
|
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;
|
storage: Introduce 'managed' for the fchost parent
https://bugzilla.redhat.com/show_bug.cgi?id=1160926
Introduce a 'managed' attribute to allow libvirt to decide whether to
delete a vHBA vport created via external means such as nodedev-create.
The code currently decides whether to delete the vHBA based solely on
whether the parent was provided at creation time. However, that may not
be the desired action, so rather than delete and force someone to create
another vHBA via an additional nodedev-create allow the configuration of
the storage pool to decide the desired action.
During createVport when libvirt does the VPORT_CREATE, set the managed
value to YES if not already set to indicate to the deleteVport code that
it should delete the vHBA when the pool is destroyed.
If libvirtd is restarted all the memory only state was lost, so for a
persistent storage pool, use the virStoragePoolSaveConfig in order to
write out the managed value.
Because we're now saving the current configuration, we need to be sure
to not save the parent in the output XML if it was undefined at start.
Saving the name would cause future starts to always use the same parent
which is not the expected result when not providing a parent. By not
providing a parent, libvirt is expected to find the best available
vHBA port for each subsequent (re)start.
At deleteVport, use the new managed value to decide whether to execute
the VPORT_DELETE. Since we no longer save the parent in memory or in
XML when provided, if it was not provided, then we have to look it up.
2014-11-10 16:19:51 +00:00
|
|
|
char *managed = 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;
|
|
|
|
|
2014-11-13 14:23:27 +00:00
|
|
|
if ((options = virStoragePoolOptionsForPoolType(pool_type)) == NULL)
|
2009-10-15 14:55:19 +00:00
|
|
|
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) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-07-18 10:50:44 +00:00
|
|
|
_("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;
|
2012-04-25 10:43:09 +00:00
|
|
|
|
2013-09-25 09:22:42 +00:00
|
|
|
if (n) {
|
|
|
|
if (VIR_ALLOC_N(source->hosts, n) < 0)
|
2010-11-12 13:23:55 +00:00
|
|
|
goto cleanup;
|
2013-09-25 09:22:42 +00:00
|
|
|
source->nhost = n;
|
2010-11-12 13:23:55 +00:00
|
|
|
|
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;
|
|
|
|
|
2014-03-11 08:13:15 +00:00
|
|
|
for (i = 0; i < nsource; i++) {
|
2016-01-07 11:57:28 +00:00
|
|
|
char *partsep;
|
2014-03-11 08:13:15 +00:00
|
|
|
virStoragePoolSourceDevice dev = { .path = NULL };
|
|
|
|
dev.path = virXMLPropString(nodeset[i], "path");
|
|
|
|
|
|
|
|
if (dev.path == NULL) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool source device path"));
|
2009-10-15 14:55:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2016-01-07 11:57:28 +00:00
|
|
|
partsep = virXMLPropString(nodeset[i], "part_separator");
|
|
|
|
if (partsep) {
|
|
|
|
dev.part_separator = virTristateBoolTypeFromString(partsep);
|
|
|
|
if (dev.part_separator <= 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("invalid part_separator setting '%s'"),
|
|
|
|
partsep);
|
|
|
|
virStoragePoolSourceDeviceClear(&dev);
|
|
|
|
VIR_FREE(partsep);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(partsep);
|
|
|
|
}
|
|
|
|
|
2014-03-11 08:13:15 +00:00
|
|
|
if (VIR_APPEND_ELEMENT(source->devices, source->ndevice, dev) < 0) {
|
|
|
|
virStoragePoolSourceDeviceClear(&dev);
|
|
|
|
goto cleanup;
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
2016-01-07 11:57:28 +00:00
|
|
|
|
2009-10-15 14:55:19 +00:00
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
source->dir = virXPathString("string(./dir/@path)", ctxt);
|
2013-11-19 23:26:05 +00:00
|
|
|
/* In gluster, a missing dir defaults to "/" */
|
|
|
|
if (!source->dir && pool_type == VIR_STORAGE_POOL_GLUSTER &&
|
|
|
|
VIR_STRDUP(source->dir, "/") < 0)
|
|
|
|
goto cleanup;
|
2013-03-25 16:43:36 +00:00
|
|
|
|
|
|
|
if ((adapter_type = virXPathString("string(./adapter/@type)", ctxt))) {
|
|
|
|
if ((source->adapter.type =
|
2014-05-14 19:48:15 +00:00
|
|
|
virStoragePoolSourceAdapterTypeFromString(adapter_type)) <= 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2013-03-25 16:43:36 +00:00
|
|
|
_("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);
|
storage: Introduce 'managed' for the fchost parent
https://bugzilla.redhat.com/show_bug.cgi?id=1160926
Introduce a 'managed' attribute to allow libvirt to decide whether to
delete a vHBA vport created via external means such as nodedev-create.
The code currently decides whether to delete the vHBA based solely on
whether the parent was provided at creation time. However, that may not
be the desired action, so rather than delete and force someone to create
another vHBA via an additional nodedev-create allow the configuration of
the storage pool to decide the desired action.
During createVport when libvirt does the VPORT_CREATE, set the managed
value to YES if not already set to indicate to the deleteVport code that
it should delete the vHBA when the pool is destroyed.
If libvirtd is restarted all the memory only state was lost, so for a
persistent storage pool, use the virStoragePoolSaveConfig in order to
write out the managed value.
Because we're now saving the current configuration, we need to be sure
to not save the parent in the output XML if it was undefined at start.
Saving the name would cause future starts to always use the same parent
which is not the expected result when not providing a parent. By not
providing a parent, libvirt is expected to find the best available
vHBA port for each subsequent (re)start.
At deleteVport, use the new managed value to decide whether to execute
the VPORT_DELETE. Since we no longer save the parent in memory or in
XML when provided, if it was not provided, then we have to look it up.
2014-11-10 16:19:51 +00:00
|
|
|
managed = virXPathString("string(./adapter/@managed)", ctxt);
|
|
|
|
if (managed) {
|
|
|
|
source->adapter.data.fchost.managed =
|
|
|
|
virTristateBoolTypeFromString(managed);
|
|
|
|
if (source->adapter.data.fchost.managed < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unknown fc_host managed setting '%s'"),
|
|
|
|
managed);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-17 22:48:35 +00:00
|
|
|
source->adapter.data.fchost.parent_wwnn =
|
|
|
|
virXPathString("string(./adapter/@parent_wwnn)", ctxt);
|
|
|
|
source->adapter.data.fchost.parent_wwpn =
|
|
|
|
virXPathString("string(./adapter/@parent_wwpn)", ctxt);
|
|
|
|
source->adapter.data.fchost.parent_fabric_wwn =
|
|
|
|
virXPathString("string(./adapter/@parent_fabric_wwn)", ctxt);
|
|
|
|
|
2013-03-25 16:43:36 +00:00
|
|
|
source->adapter.data.fchost.wwpn =
|
|
|
|
virXPathString("string(./adapter/@wwpn)", ctxt);
|
2016-11-17 22:48:35 +00:00
|
|
|
source->adapter.data.fchost.wwnn =
|
|
|
|
virXPathString("string(./adapter/@wwnn)", ctxt);
|
2013-03-25 16:43:36 +00:00
|
|
|
} else if (source->adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
2014-03-04 03:15:13 +00:00
|
|
|
|
2014-03-03 20:04:17 +00:00
|
|
|
source->adapter.data.scsi_host.name =
|
2013-03-25 16:43:36 +00:00
|
|
|
virXPathString("string(./adapter/@name)", ctxt);
|
2014-03-04 03:15:13 +00:00
|
|
|
if (virXPathNode("./adapter/parentaddr", ctxt)) {
|
|
|
|
xmlNodePtr addrnode = virXPathNode("./adapter/parentaddr/address",
|
|
|
|
ctxt);
|
2016-04-03 18:16:51 +00:00
|
|
|
virPCIDeviceAddressPtr addr =
|
2014-03-04 03:15:13 +00:00
|
|
|
&source->adapter.data.scsi_host.parentaddr;
|
|
|
|
|
|
|
|
if (!addrnode) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("Missing scsi_host PCI address element"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
source->adapter.data.scsi_host.has_parent = true;
|
2016-04-03 18:16:51 +00:00
|
|
|
if (virPCIDeviceAddressParseXML(addrnode, addr) < 0)
|
2014-03-04 03:15:13 +00:00
|
|
|
goto cleanup;
|
|
|
|
if ((virXPathInt("string(./adapter/parentaddr/@unique_id)",
|
|
|
|
ctxt,
|
|
|
|
&source->adapter.data.scsi_host.unique_id) < 0) ||
|
|
|
|
(source->adapter.data.scsi_host.unique_id < 0)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("Missing or invalid scsi adapter "
|
|
|
|
"'unique_id' value"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
2013-03-25 16:43:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
char *wwnn = NULL;
|
|
|
|
char *wwpn = NULL;
|
|
|
|
char *parent = NULL;
|
|
|
|
|
2014-03-04 03:15:13 +00:00
|
|
|
/* "type" was not specified in the XML, so we must verify that
|
|
|
|
* "wwnn", "wwpn", "parent", or "parentaddr" are also not in the
|
|
|
|
* XML. If any are found, then we cannot just use "name" alone".
|
|
|
|
*/
|
2013-03-25 16:43:36 +00:00
|
|
|
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 "
|
2014-03-04 03:15:13 +00:00
|
|
|
"requires use of the adapter 'type'"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virXPathNode("./adapter/parentaddr", ctxt)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("Use of 'parent' element requires use "
|
|
|
|
"of the adapter 'type'"));
|
2013-03-25 16:43:36 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* To keep back-compat, 'type' is not required to specify
|
|
|
|
* for scsi_host adapter.
|
|
|
|
*/
|
2014-03-03 20:04:17 +00:00
|
|
|
if ((source->adapter.data.scsi_host.name =
|
2013-03-25 16:43:36 +00:00
|
|
|
virXPathString("string(./adapter/@name)", ctxt)))
|
|
|
|
source->adapter.type =
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST;
|
|
|
|
}
|
2009-10-15 14:55:19 +00:00
|
|
|
|
2014-06-26 12:18:09 +00:00
|
|
|
if ((authnode = virXPathNode("./auth", ctxt))) {
|
|
|
|
if (!(authdef = virStorageAuthDefParse(node->doc, authnode)))
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (authdef->authType == VIR_STORAGE_AUTH_TYPE_NONE) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
|
|
|
|
_("storage pool missing auth type"));
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
source->auth = authdef;
|
2014-08-27 19:40:57 +00:00
|
|
|
authdef = NULL;
|
2014-06-26 12:18:09 +00:00
|
|
|
}
|
2012-05-14 09:06:42 +00:00
|
|
|
|
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;
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2009-10-15 14:55:19 +00:00
|
|
|
ctxt->node = relnode;
|
|
|
|
|
2010-11-12 13:23:55 +00:00
|
|
|
VIR_FREE(port);
|
2009-10-15 14:55:19 +00:00
|
|
|
VIR_FREE(nodeset);
|
2013-03-25 16:43:36 +00:00
|
|
|
VIR_FREE(adapter_type);
|
storage: Introduce 'managed' for the fchost parent
https://bugzilla.redhat.com/show_bug.cgi?id=1160926
Introduce a 'managed' attribute to allow libvirt to decide whether to
delete a vHBA vport created via external means such as nodedev-create.
The code currently decides whether to delete the vHBA based solely on
whether the parent was provided at creation time. However, that may not
be the desired action, so rather than delete and force someone to create
another vHBA via an additional nodedev-create allow the configuration of
the storage pool to decide the desired action.
During createVport when libvirt does the VPORT_CREATE, set the managed
value to YES if not already set to indicate to the deleteVport code that
it should delete the vHBA when the pool is destroyed.
If libvirtd is restarted all the memory only state was lost, so for a
persistent storage pool, use the virStoragePoolSaveConfig in order to
write out the managed value.
Because we're now saving the current configuration, we need to be sure
to not save the parent in the output XML if it was undefined at start.
Saving the name would cause future starts to always use the same parent
which is not the expected result when not providing a parent. By not
providing a parent, libvirt is expected to find the best available
vHBA port for each subsequent (re)start.
At deleteVport, use the new managed value to decide whether to execute
the VPORT_DELETE. Since we no longer save the parent in memory or in
XML when provided, if it was not provided, then we have to look it up.
2014-11-10 16:19:51 +00:00
|
|
|
VIR_FREE(managed);
|
2014-08-27 19:40:57 +00:00
|
|
|
virStorageAuthDefFree(authdef);
|
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;
|
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (VIR_ALLOC(def) < 0)
|
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;
|
2014-03-25 06:48:31 +00:00
|
|
|
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,
|
2015-04-27 20:48:05 +00:00
|
|
|
const char *permxpath)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
char *mode;
|
2014-12-16 16:38:59 +00:00
|
|
|
long 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 */
|
2015-04-27 20:48:05 +00:00
|
|
|
perms->mode = (mode_t) -1;
|
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;
|
|
|
|
|
2015-04-27 20:48:05 +00:00
|
|
|
if ((mode = virXPathString("string(./mode)", ctxt))) {
|
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);
|
2015-04-27 20:48:05 +00:00
|
|
|
} else {
|
|
|
|
perms->mode = (mode_t) -1;
|
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 {
|
2015-05-05 15:58:12 +00:00
|
|
|
/* We previously could output -1, so continue to parse it */
|
2014-12-16 16:38:59 +00:00
|
|
|
if (virXPathLongLong("number(./owner)", ctxt, &val) < 0 ||
|
2013-05-22 12:05:22 +00:00
|
|
|
((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 {
|
2015-05-05 15:58:12 +00:00
|
|
|
/* We previously could output -1, so continue to parse it */
|
2014-12-16 16:38:59 +00:00
|
|
|
if (virXPathLongLong("number(./group)", ctxt, &val) < 0 ||
|
2013-05-22 12:05:22 +00:00
|
|
|
((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;
|
2014-03-25 06:48:31 +00:00
|
|
|
error:
|
2009-03-12 20:15:32 +00:00
|
|
|
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
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (VIR_ALLOC(ret) < 0)
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
|
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) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
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
|
|
|
}
|
|
|
|
|
2014-11-13 14:23:27 +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
|
|
|
}
|
|
|
|
|
2016-04-26 18:51:33 +00:00
|
|
|
if (strchr(ret->name, '/')) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("name %s cannot contain '/'"), ret->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
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;
|
2017-03-10 15:29:32 +00:00
|
|
|
|
|
|
|
if ((ret->source.adapter.data.fchost.parent_wwnn &&
|
|
|
|
!ret->source.adapter.data.fchost.parent_wwpn)) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("when providing parent_wwnn='%s', the "
|
|
|
|
"parent_wwpn must also be provided"),
|
|
|
|
ret->source.adapter.data.fchost.parent_wwnn);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ret->source.adapter.data.fchost.parent_wwnn &&
|
|
|
|
ret->source.adapter.data.fchost.parent_wwpn) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR,
|
|
|
|
_("when providing parent_wwpn='%s', the "
|
|
|
|
"parent_wwnn must also be provided"),
|
|
|
|
ret->source.adapter.data.fchost.parent_wwpn);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2017-03-10 15:04:20 +00:00
|
|
|
if (ret->source.adapter.data.fchost.parent_wwnn &&
|
|
|
|
!virValidateWWN(ret->source.adapter.data.fchost.parent_wwnn))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (ret->source.adapter.data.fchost.parent_wwpn &&
|
|
|
|
!virValidateWWN(ret->source.adapter.data.fchost.parent_wwpn))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (ret->source.adapter.data.fchost.parent_fabric_wwn &&
|
|
|
|
!virValidateWWN(ret->source.adapter.data.fchost.parent_fabric_wwn))
|
|
|
|
goto error;
|
|
|
|
|
2013-03-25 16:43:36 +00:00
|
|
|
} else if (ret->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
2014-03-04 03:15:13 +00:00
|
|
|
if (!ret->source.adapter.data.scsi_host.name &&
|
|
|
|
!ret->source.adapter.data.scsi_host.has_parent) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("Either 'name' or 'parent' must be specified "
|
|
|
|
"for the 'scsi_host' adapter"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret->source.adapter.data.scsi_host.name &&
|
|
|
|
ret->source.adapter.data.scsi_host.has_parent) {
|
2013-05-22 12:05:15 +00:00
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
2014-03-04 03:15:13 +00:00
|
|
|
_("Both 'name' and 'parent' cannot be specified "
|
|
|
|
"for the 'scsi_host' adapter"));
|
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-04-30 11:48:46 +00:00
|
|
|
if (ret->type == VIR_STORAGE_POOL_LOGICAL) {
|
2014-11-13 14:23:27 +00:00
|
|
|
if (virAsprintf(&target_path, "/dev/%s", ret->source.name) < 0)
|
2013-04-30 11:48:46 +00:00
|
|
|
goto error;
|
2014-07-21 14:38:42 +00:00
|
|
|
} else if (ret->type == VIR_STORAGE_POOL_ZFS) {
|
2014-11-13 14:23:27 +00:00
|
|
|
if (virAsprintf(&target_path, "/dev/zvol/%s", ret->source.name) < 0)
|
2014-07-21 14:38:42 +00:00
|
|
|
goto error;
|
2013-04-30 11:48:46 +00:00
|
|
|
} else {
|
|
|
|
target_path = virXPathString("string(./target/path)", ctxt);
|
|
|
|
if (!target_path) {
|
|
|
|
virReportError(VIR_ERR_XML_ERROR, "%s",
|
|
|
|
_("missing storage pool target path"));
|
|
|
|
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,
|
2015-04-27 20:48:05 +00:00
|
|
|
"./target/permissions") < 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
|
|
|
|
2014-03-25 06:48:31 +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;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
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);
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2009-06-22 16:41:34 +00:00
|
|
|
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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(buf, "<source>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
|
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++) {
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<host name='%s'",
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
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++) {
|
2016-03-17 11:29:23 +00:00
|
|
|
virBufferEscapeString(buf, "<device path='%s'",
|
|
|
|
src->devices[i].path);
|
|
|
|
if (src->devices[i].part_separator !=
|
|
|
|
VIR_TRISTATE_SWITCH_ABSENT) {
|
|
|
|
virBufferAsprintf(buf, " part_separator='%s'",
|
|
|
|
virTristateBoolTypeToString(src->devices[i].part_separator));
|
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
if (src->devices[i].nfreeExtent) {
|
2016-03-17 11:29:23 +00:00
|
|
|
virBufferAddLit(buf, ">\n");
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, 2);
|
2013-05-16 12:40:50 +00:00
|
|
|
for (j = 0; j < src->devices[i].nfreeExtent; j++) {
|
2014-03-06 14:57:47 +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);
|
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</device>\n");
|
2013-05-16 12:40:50 +00:00
|
|
|
} else {
|
2016-01-07 11:57:28 +00:00
|
|
|
virBufferAddLit(buf, "/>\n");
|
2013-05-16 12:40:50 +00:00
|
|
|
}
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_DIR)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(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)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<adapter type='%s'",
|
2014-05-14 19:48:15 +00:00
|
|
|
virStoragePoolSourceAdapterTypeToString(src->adapter.type));
|
2013-03-25 16:43:36 +00:00
|
|
|
|
|
|
|
if (src->adapter.type == VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
virBufferEscapeString(buf, " parent='%s'",
|
|
|
|
src->adapter.data.fchost.parent);
|
storage: Introduce 'managed' for the fchost parent
https://bugzilla.redhat.com/show_bug.cgi?id=1160926
Introduce a 'managed' attribute to allow libvirt to decide whether to
delete a vHBA vport created via external means such as nodedev-create.
The code currently decides whether to delete the vHBA based solely on
whether the parent was provided at creation time. However, that may not
be the desired action, so rather than delete and force someone to create
another vHBA via an additional nodedev-create allow the configuration of
the storage pool to decide the desired action.
During createVport when libvirt does the VPORT_CREATE, set the managed
value to YES if not already set to indicate to the deleteVport code that
it should delete the vHBA when the pool is destroyed.
If libvirtd is restarted all the memory only state was lost, so for a
persistent storage pool, use the virStoragePoolSaveConfig in order to
write out the managed value.
Because we're now saving the current configuration, we need to be sure
to not save the parent in the output XML if it was undefined at start.
Saving the name would cause future starts to always use the same parent
which is not the expected result when not providing a parent. By not
providing a parent, libvirt is expected to find the best available
vHBA port for each subsequent (re)start.
At deleteVport, use the new managed value to decide whether to execute
the VPORT_DELETE. Since we no longer save the parent in memory or in
XML when provided, if it was not provided, then we have to look it up.
2014-11-10 16:19:51 +00:00
|
|
|
if (src->adapter.data.fchost.managed)
|
|
|
|
virBufferAsprintf(buf, " managed='%s'",
|
|
|
|
virTristateBoolTypeToString(src->adapter.data.fchost.managed));
|
2016-11-17 22:48:35 +00:00
|
|
|
virBufferEscapeString(buf, " parent_wwnn='%s'",
|
|
|
|
src->adapter.data.fchost.parent_wwnn);
|
|
|
|
virBufferEscapeString(buf, " parent_wwpn='%s'",
|
|
|
|
src->adapter.data.fchost.parent_wwpn);
|
|
|
|
virBufferEscapeString(buf, " parent_fabric_wwn='%s'",
|
|
|
|
src->adapter.data.fchost.parent_fabric_wwn);
|
|
|
|
|
2013-11-19 22:21:40 +00:00
|
|
|
virBufferAsprintf(buf, " wwnn='%s' wwpn='%s'/>\n",
|
2013-03-25 16:43:36 +00:00
|
|
|
src->adapter.data.fchost.wwnn,
|
|
|
|
src->adapter.data.fchost.wwpn);
|
|
|
|
} else if (src->adapter.type ==
|
2014-03-04 03:15:13 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
|
|
|
if (src->adapter.data.scsi_host.name) {
|
|
|
|
virBufferAsprintf(buf, " name='%s'/>\n",
|
|
|
|
src->adapter.data.scsi_host.name);
|
|
|
|
} else {
|
2016-04-03 18:16:51 +00:00
|
|
|
virPCIDeviceAddress addr;
|
2014-03-04 03:15:13 +00:00
|
|
|
virBufferAddLit(buf, ">\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferAsprintf(buf, "<parentaddr unique_id='%d'>\n",
|
|
|
|
src->adapter.data.scsi_host.unique_id);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
addr = src->adapter.data.scsi_host.parentaddr;
|
2016-04-03 18:16:51 +00:00
|
|
|
ignore_value(virPCIDeviceAddressFormat(buf, addr, false));
|
2014-03-04 03:15:13 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</parentaddr>\n");
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</adapter>\n");
|
|
|
|
}
|
2013-03-25 16:43:36 +00:00
|
|
|
}
|
|
|
|
}
|
2013-05-16 12:40:50 +00:00
|
|
|
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
if (options->flags & VIR_STORAGE_POOL_SOURCE_NAME)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(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) {
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(buf, "<initiator>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferEscapeString(buf, "<iqn name='%s'/>\n",
|
2013-11-19 22:21:40 +00:00
|
|
|
src->initiator.iqn);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</initiator>\n");
|
2010-06-07 19:06:20 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<format type='%s'/>\n", format);
|
2008-11-04 21:54:21 +00:00
|
|
|
}
|
|
|
|
|
2014-06-26 12:18:09 +00:00
|
|
|
if (src->auth) {
|
|
|
|
if (virStorageAuthDefFormat(buf, src->auth) < 0)
|
|
|
|
return -1;
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<vendor name='%s'/>\n", src->vendor);
|
|
|
|
virBufferEscapeString(buf, "<product name='%s'/>\n", src->product);
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</source>\n");
|
2008-11-04 21:54:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
static int
|
|
|
|
virStoragePoolDefFormatBuf(virBufferPtr buf,
|
|
|
|
virStoragePoolDefPtr def)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2008-11-17 11:19:33 +00:00
|
|
|
virStoragePoolOptionsPtr options;
|
2008-02-20 15:34:52 +00:00
|
|
|
char uuid[VIR_UUID_STRING_BUFLEN];
|
2015-03-26 15:44:38 +00:00
|
|
|
const char *type;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-11-17 11:19:33 +00:00
|
|
|
options = virStoragePoolOptionsForPoolType(def->type);
|
2008-02-20 15:34:52 +00:00
|
|
|
if (options == NULL)
|
2015-03-26 15:44:38 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
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"));
|
2015-03-26 15:44:38 +00:00
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<pool type='%s'>\n", type);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
virBufferEscapeString(buf, "<name>%s</name>\n", def->name);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuid);
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<uuid>%s</uuid>\n", uuid);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<capacity unit='bytes'>%llu</capacity>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->capacity);
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAsprintf(buf, "<allocation unit='bytes'>%llu</allocation>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->allocation);
|
2015-03-26 15:44: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
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
if (virStoragePoolSourceFormat(buf, options, &def->source) < 0)
|
|
|
|
return -1;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-11-19 23:26:05 +00:00
|
|
|
/* RBD, Sheepdog, and Gluster devices are not local block devs nor
|
|
|
|
* files, so they don't have a target */
|
2013-05-16 12:40:50 +00:00
|
|
|
if (def->type != VIR_STORAGE_POOL_RBD &&
|
2013-11-19 23:26:05 +00:00
|
|
|
def->type != VIR_STORAGE_POOL_SHEEPDOG &&
|
|
|
|
def->type != VIR_STORAGE_POOL_GLUSTER) {
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAddLit(buf, "<target>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferEscapeString(buf, "<path>%s</path>\n", def->target.path);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-05-21 19:15:24 +00:00
|
|
|
if (def->target.perms.mode != (mode_t) -1 ||
|
|
|
|
def->target.perms.uid != (uid_t) -1 ||
|
|
|
|
def->target.perms.gid != (gid_t) -1 ||
|
|
|
|
def->target.perms.label) {
|
|
|
|
virBufferAddLit(buf, "<permissions>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
if (def->target.perms.mode != (mode_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<mode>0%o</mode>\n",
|
|
|
|
def->target.perms.mode);
|
|
|
|
if (def->target.perms.uid != (uid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<owner>%d</owner>\n",
|
|
|
|
(int) def->target.perms.uid);
|
|
|
|
if (def->target.perms.gid != (gid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<group>%d</group>\n",
|
|
|
|
(int) def->target.perms.gid);
|
|
|
|
virBufferEscapeString(buf, "<label>%s</label>\n",
|
|
|
|
def->target.perms.label);
|
|
|
|
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</permissions>\n");
|
|
|
|
}
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</target>\n");
|
2012-05-14 09:06:42 +00:00
|
|
|
}
|
2015-03-26 15:44:38 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</pool>\n");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
virStoragePoolDefFormat(virStoragePoolDefPtr def)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
if (virStoragePoolDefFormatBuf(&buf, def) < 0)
|
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
2015-03-26 15:44:38 +00:00
|
|
|
goto error;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-03-26 15:44:38 +00:00
|
|
|
error:
|
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,
|
2015-02-05 15:20:17 +00:00
|
|
|
xmlXPathContextPtr ctxt,
|
|
|
|
unsigned int flags)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
2008-02-20 15:34:52 +00:00
|
|
|
virStorageVolDefPtr ret;
|
2008-11-17 11:19:33 +00:00
|
|
|
virStorageVolOptionsPtr options;
|
2013-11-19 20:14:54 +00:00
|
|
|
char *type = NULL;
|
2008-02-20 15:34:52 +00:00
|
|
|
char *allocation = NULL;
|
|
|
|
char *capacity = NULL;
|
|
|
|
char *unit = NULL;
|
2014-07-14 13:19:49 +00:00
|
|
|
char *backingStore = NULL;
|
2009-07-20 22:28:11 +00:00
|
|
|
xmlNodePtr node;
|
2013-05-16 10:38:26 +00:00
|
|
|
xmlNodePtr *nodes = NULL;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
int n;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2015-02-17 15:55:59 +00:00
|
|
|
virCheckFlags(VIR_VOL_XML_PARSE_NO_CAPACITY |
|
|
|
|
VIR_VOL_XML_PARSE_OPT_CAPACITY, NULL);
|
2015-02-05 15:20:17 +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;
|
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (VIR_ALLOC(ret) < 0)
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
/* Normally generated by pool refresh, but useful for unit tests */
|
|
|
|
ret->key = virXPathString("string(./key)", ctxt);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2013-11-19 20:14:54 +00:00
|
|
|
/* Technically overridden by pool refresh, but useful for unit tests */
|
|
|
|
type = virXPathString("string(./@type)", ctxt);
|
|
|
|
if (type) {
|
|
|
|
if ((ret->type = virStorageVolTypeFromString(type)) < 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2013-11-19 20:14:54 +00:00
|
|
|
_("unknown volume type '%s'"), type);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-10 14:10:05 +00:00
|
|
|
if ((backingStore = virXPathString("string(./backingStore/path)", ctxt))) {
|
|
|
|
if (VIR_ALLOC(ret->target.backingStore) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ret->target.backingStore->path = backingStore;
|
|
|
|
backingStore = NULL;
|
|
|
|
|
|
|
|
if (options->formatFromString) {
|
|
|
|
char *format = virXPathString("string(./backingStore/format/@type)", ctxt);
|
|
|
|
if (format == NULL)
|
|
|
|
ret->target.backingStore->format = options->defaultFormat;
|
|
|
|
else
|
|
|
|
ret->target.backingStore->format = (options->formatFromString)(format);
|
|
|
|
|
|
|
|
if (ret->target.backingStore->format < 0) {
|
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
|
|
|
_("unknown volume format type %s"), format);
|
|
|
|
VIR_FREE(format);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
VIR_FREE(format);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VIR_ALLOC(ret->target.backingStore->perms) < 0)
|
|
|
|
goto error;
|
|
|
|
if (virStorageDefParsePerms(ctxt, ret->target.backingStore->perms,
|
2015-04-27 20:48:05 +00:00
|
|
|
"./backingStore/permissions") < 0)
|
2015-02-10 14:10:05 +00:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
2010-02-04 21:52:34 +00:00
|
|
|
capacity = virXPathString("string(./capacity)", ctxt);
|
|
|
|
unit = virXPathString("string(./capacity/@unit)", ctxt);
|
2015-02-17 15:47:04 +00:00
|
|
|
if (capacity) {
|
|
|
|
if (virStorageSize(unit, capacity, &ret->target.capacity) < 0)
|
|
|
|
goto error;
|
2015-02-17 15:55:59 +00:00
|
|
|
} else if (!(flags & VIR_VOL_XML_PARSE_NO_CAPACITY) &&
|
|
|
|
!((flags & VIR_VOL_XML_PARSE_OPT_CAPACITY) && ret->target.backingStore)) {
|
2015-02-17 15:47:04 +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
|
|
|
}
|
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);
|
conf: track sizes directly in source struct
One of the features of qcow2 is that a wrapper file can have
more capacity than its backing file from the guest's perspective;
what's more, sparse files make tracking allocation of both
the active and backing file worthwhile. As such, it makes
more sense to show allocation numbers for each file in a chain,
and not just the top-level file. This sets up the fields for
the tracking, although it does not modify XML to display any
new information.
* src/util/virstoragefile.h (_virStorageSource): Add fields.
* src/conf/storage_conf.h (_virStorageVolDef): Drop redundant
fields.
* src/storage/storage_backend.c (virStorageBackendCreateBlockFrom)
(createRawFile, virStorageBackendCreateQemuImgCmd)
(virStorageBackendCreateQcowCreate): Update clients.
* src/storage/storage_driver.c (storageVolDelete)
(storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize)
(storageVolWipeInternal, storageVolGetInfo): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolResize)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol)
(virStorageBackendLogicalCreateVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_rbd.c
(volStorageBackendRBDRefreshVolInfo)
(virStorageBackendRBDCreateImage): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol): Likewise.
* src/storage/storage_backend_sheepdog.c
(virStorageBackendSheepdogBuildVol)
(virStorageBackendSheepdogParseVdiList): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/conf/storage_conf.c (virStorageVolDefFormat)
(virStorageVolDefParseXML): Likewise.
* src/test/test_driver.c (testOpenVolumesForPool)
(testStorageVolCreateXML, testStorageVolCreateXMLFrom)
(testStorageVolDelete, testStorageVolGetInfo): Likewise.
* src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc):
Likewise.
* src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc)
(esxStorageVolCreateXML): Likewise.
* src/parallels/parallels_driver.c (parallelsAddHddByVolume):
Likewise.
* src/parallels/parallels_storage.c (parallelsDiskDescParseNode)
(parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom)
(parallelsStorageVolDefRemove, parallelsStorageVolGetInfo):
Likewise.
* src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML)
(vboxStorageVolGetXMLDesc): Likewise.
* tests/storagebackendsheepdogtest.c (test_vdi_list_parser):
Likewise.
* src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
|
|
|
if (virStorageSize(unit, allocation, &ret->target.allocation) < 0)
|
2013-05-22 12:05:18 +00:00
|
|
|
goto error;
|
2016-04-29 11:43:57 +00:00
|
|
|
ret->target.has_allocation = true;
|
2008-02-20 15:34:52 +00:00
|
|
|
} else {
|
conf: track sizes directly in source struct
One of the features of qcow2 is that a wrapper file can have
more capacity than its backing file from the guest's perspective;
what's more, sparse files make tracking allocation of both
the active and backing file worthwhile. As such, it makes
more sense to show allocation numbers for each file in a chain,
and not just the top-level file. This sets up the fields for
the tracking, although it does not modify XML to display any
new information.
* src/util/virstoragefile.h (_virStorageSource): Add fields.
* src/conf/storage_conf.h (_virStorageVolDef): Drop redundant
fields.
* src/storage/storage_backend.c (virStorageBackendCreateBlockFrom)
(createRawFile, virStorageBackendCreateQemuImgCmd)
(virStorageBackendCreateQcowCreate): Update clients.
* src/storage/storage_driver.c (storageVolDelete)
(storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize)
(storageVolWipeInternal, storageVolGetInfo): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolResize)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol)
(virStorageBackendLogicalCreateVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_rbd.c
(volStorageBackendRBDRefreshVolInfo)
(virStorageBackendRBDCreateImage): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol): Likewise.
* src/storage/storage_backend_sheepdog.c
(virStorageBackendSheepdogBuildVol)
(virStorageBackendSheepdogParseVdiList): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/conf/storage_conf.c (virStorageVolDefFormat)
(virStorageVolDefParseXML): Likewise.
* src/test/test_driver.c (testOpenVolumesForPool)
(testStorageVolCreateXML, testStorageVolCreateXMLFrom)
(testStorageVolDelete, testStorageVolGetInfo): Likewise.
* src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc):
Likewise.
* src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc)
(esxStorageVolCreateXML): Likewise.
* src/parallels/parallels_driver.c (parallelsAddHddByVolume):
Likewise.
* src/parallels/parallels_storage.c (parallelsDiskDescParseNode)
(parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom)
(parallelsStorageVolDefRemove, parallelsStorageVolGetInfo):
Likewise.
* src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML)
(vboxStorageVolGetXMLDesc): Likewise.
* tests/storagebackendsheepdogtest.c (test_vdi_list_parser):
Likewise.
* src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
|
|
|
ret->target.allocation = ret->target.capacity;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
|
2012-07-18 10:50:44 +00:00
|
|
|
_("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
|
|
|
}
|
|
|
|
|
2014-03-30 02:27:44 +00:00
|
|
|
if (VIR_ALLOC(ret->target.perms) < 0)
|
|
|
|
goto error;
|
|
|
|
if (virStorageDefParsePerms(ctxt, ret->target.perms,
|
2015-04-27 20:48:05 +00:00
|
|
|
"./target/permissions") < 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
|
|
|
}
|
|
|
|
|
2013-05-16 10:38:26 +00:00
|
|
|
ret->target.compat = virXPathString("string(./target/compat)", ctxt);
|
2015-04-09 08:48:49 +00:00
|
|
|
if (virStorageFileCheckCompat(ret->target.compat) < 0)
|
|
|
|
goto error;
|
2013-05-16 10:38:26 +00:00
|
|
|
|
2014-07-15 08:49:46 +00:00
|
|
|
if (virXPathNode("./target/nocow", ctxt))
|
|
|
|
ret->target.nocow = true;
|
|
|
|
|
2015-04-09 12:02:53 +00:00
|
|
|
if (virXPathNode("./target/features", ctxt)) {
|
2013-05-16 10:38:26 +00:00
|
|
|
if ((n = virXPathNodeSet("./target/features/*", ctxt, &nodes)) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!ret->target.compat && VIR_STRDUP(ret->target.compat, "1.1") < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(ret->target.features = virBitmapNew(VIR_STORAGE_FILE_FEATURE_LAST)))
|
2013-07-04 10:02:00 +00:00
|
|
|
goto error;
|
2013-05-16 10:38:26 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
2015-04-09 12:02:53 +00:00
|
|
|
int f = virStorageFileFeatureTypeFromString((const char*)nodes[i]->name);
|
2013-05-16 10:38:26 +00:00
|
|
|
|
|
|
|
if (f < 0) {
|
2014-01-10 16:41:33 +00:00
|
|
|
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, _("unsupported feature %s"),
|
2013-05-16 10:38:26 +00:00
|
|
|
(const char*)nodes[i]->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
ignore_value(virBitmapSetBit(ret->target.features, f));
|
|
|
|
}
|
|
|
|
VIR_FREE(nodes);
|
|
|
|
}
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2013-05-16 10:38:26 +00:00
|
|
|
VIR_FREE(nodes);
|
2008-06-06 11:09:57 +00:00
|
|
|
VIR_FREE(allocation);
|
|
|
|
VIR_FREE(capacity);
|
|
|
|
VIR_FREE(unit);
|
2013-11-19 20:14:54 +00:00
|
|
|
VIR_FREE(type);
|
2014-07-14 13:19:49 +00:00
|
|
|
VIR_FREE(backingStore);
|
2013-05-22 12:05:18 +00:00
|
|
|
return ret;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
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,
|
2015-02-05 15:20:17 +00:00
|
|
|
xmlNodePtr root,
|
|
|
|
unsigned int flags)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
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;
|
2015-02-05 15:20:17 +00:00
|
|
|
def = virStorageVolDefParseXML(pool, ctxt, flags);
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2009-06-22 16:41:34 +00:00
|
|
|
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,
|
2015-02-05 15:20:17 +00:00
|
|
|
const char *filename,
|
|
|
|
unsigned int flags)
|
2013-05-16 12:40:50 +00:00
|
|
|
{
|
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)")))) {
|
2015-02-05 15:20:17 +00:00
|
|
|
ret = virStorageVolDefParseNode(pool, xml, xmlDocGetRootElement(xml), flags);
|
2010-02-24 20:53:16 +00:00
|
|
|
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,
|
2015-02-05 15:20:17 +00:00
|
|
|
const char *xmlStr,
|
|
|
|
unsigned int flags)
|
2009-06-22 16:41:34 +00:00
|
|
|
{
|
2015-02-05 15:20:17 +00:00
|
|
|
return virStorageVolDefParse(pool, xmlStr, NULL, flags);
|
2009-06-22 16:41:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virStorageVolDefPtr
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolDefParseFile(virStoragePoolDefPtr pool,
|
2015-02-05 15:20:17 +00:00
|
|
|
const char *filename,
|
|
|
|
unsigned int flags)
|
2009-06-22 16:41:34 +00:00
|
|
|
{
|
2015-02-05 15:20:17 +00:00
|
|
|
return virStorageVolDefParse(pool, NULL, filename, flags);
|
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;
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<%s>%llu", name,
|
2012-07-25 07:43:37 +00:00
|
|
|
(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,
|
2014-04-01 21:11:30 +00:00
|
|
|
virStorageSourcePtr def,
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
const char *type)
|
|
|
|
{
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<%s>\n", type);
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(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;
|
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<format type='%s'/>\n", format);
|
2009-01-27 18:30:03 +00:00
|
|
|
}
|
|
|
|
|
2015-05-21 19:15:24 +00:00
|
|
|
if (def->perms &&
|
|
|
|
(def->perms->mode != (mode_t) -1 ||
|
|
|
|
def->perms->uid != (uid_t) -1 ||
|
|
|
|
def->perms->gid != (gid_t) -1 ||
|
|
|
|
def->perms->label)) {
|
2014-07-11 16:13:34 +00:00
|
|
|
virBufferAddLit(buf, "<permissions>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2014-03-06 14:57:47 +00:00
|
|
|
|
2015-04-27 20:48:05 +00:00
|
|
|
if (def->perms->mode != (mode_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<mode>0%o</mode>\n",
|
|
|
|
def->perms->mode);
|
2015-05-05 15:58:12 +00:00
|
|
|
if (def->perms->uid != (uid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<owner>%d</owner>\n",
|
|
|
|
(int) def->perms->uid);
|
|
|
|
if (def->perms->gid != (gid_t) -1)
|
|
|
|
virBufferAsprintf(buf, "<group>%d</group>\n",
|
|
|
|
(int) def->perms->gid);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2014-07-11 16:13:34 +00:00
|
|
|
virBufferEscapeString(buf, "<label>%s</label>\n",
|
|
|
|
def->perms->label);
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2014-07-11 16:13:34 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</permissions>\n");
|
|
|
|
}
|
2009-01-27 18:30:03 +00:00
|
|
|
|
2012-07-25 07:43:37 +00:00
|
|
|
if (def->timestamps) {
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(buf, "<timestamps>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
2012-07-25 07:43:37 +00:00
|
|
|
virStorageVolTimestampFormat(buf, "atime", &def->timestamps->atime);
|
|
|
|
virStorageVolTimestampFormat(buf, "mtime", &def->timestamps->mtime);
|
|
|
|
virStorageVolTimestampFormat(buf, "ctime", &def->timestamps->ctime);
|
|
|
|
virStorageVolTimestampFormat(buf, "btime", &def->timestamps->btime);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</timestamps>\n");
|
2012-07-25 07:43:37 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
if (def->encryption &&
|
|
|
|
virStorageEncryptionFormat(buf, def->encryption) < 0)
|
2011-09-22 18:16:26 +00:00
|
|
|
return -1;
|
2009-07-20 22:28:11 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(buf, "<compat>%s</compat>\n", def->compat);
|
2013-05-16 10:38:26 +00:00
|
|
|
|
2015-04-09 12:02:53 +00:00
|
|
|
if (def->features) {
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2013-05-16 10:38:26 +00:00
|
|
|
bool empty = virBitmapIsAllClear(def->features);
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
if (empty) {
|
|
|
|
virBufferAddLit(buf, "<features/>\n");
|
|
|
|
} else {
|
|
|
|
virBufferAddLit(buf, "<features>\n");
|
|
|
|
virBufferAdjustIndent(buf, 2);
|
|
|
|
}
|
2013-05-16 10:38:26 +00:00
|
|
|
|
|
|
|
for (i = 0; i < VIR_STORAGE_FILE_FEATURE_LAST; i++) {
|
2015-03-11 15:41:57 +00:00
|
|
|
if (virBitmapIsBitSet(def->features, i))
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(buf, "<%s/>\n",
|
2015-04-09 12:02:53 +00:00
|
|
|
virStorageFileFeatureTypeToString(i));
|
2013-05-16 10:38:26 +00:00
|
|
|
}
|
2014-03-06 14:57:47 +00:00
|
|
|
if (!empty) {
|
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
virBufferAddLit(buf, "</features>\n");
|
|
|
|
}
|
2013-05-16 10:38:26 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(buf, -2);
|
|
|
|
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;
|
|
|
|
|
2013-11-19 20:14:54 +00:00
|
|
|
virBufferAsprintf(&buf, "<volume type='%s'>\n",
|
|
|
|
virStorageVolTypeToString(def->type));
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
|
|
|
|
virBufferEscapeString(&buf, "<name>%s</name>\n", def->name);
|
|
|
|
virBufferEscapeString(&buf, "<key>%s</key>\n", def->key);
|
|
|
|
virBufferAddLit(&buf, "<source>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
|
|
|
if (def->source.nextent) {
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-02-20 15:34:52 +00:00
|
|
|
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)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(&buf, "</device>\n");
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferEscapeString(&buf, "<device path='%s'>\n",
|
storage: use valid XML for awkward volume names
$ touch /var/lib/libvirt/images/'a<b>c'
$ virsh pool-refresh default
$ virsh vol-dumpxml 'a<b>c' default | head -n2
<volume>
<name>a<b>c</name>
Oops. That's not valid XML. And when we fix the XML
generation, it fails RelaxNG validation.
I'm also tired of seeing <key>(null)</key> in the example
output for volume xml; while we used NULLSTR() to avoid
a NULL deref rather than relying on glibc's printf
extension behavior, it's even better if we avoid the issue
in the first place. But this requires being careful that
we don't invalidate any storage backends that were relying
on key being unassigned during virStoragVolCreateXML[From].
I would have split this into two patches (one for escaping,
one for avoiding <key>(null)</key>), but since they both
end up touching a lot of the same test files, I ended up
merging it into one.
Note that this patch allows pretty much any volume name
that can appear in a directory (excluding . and .. because
those are special), but does nothing to change the current
(unenforced) RelaxNG claim that pool names will consist
only of letters, numbers, _, -, and +. Tightening the C
code to match RelaxNG patterns and/or relaxing the grammar
to match the C code for pool names is a task for another
day (but remember, we DID recently tighten C code for
domain names to exclude a leading '.').
* src/conf/storage_conf.c (virStoragePoolSourceFormat)
(virStoragePoolDefFormat, virStorageVolTargetDefFormat)
(virStorageVolDefFormat): Escape user-controlled strings.
(virStorageVolDefParseXML): Parse key, for use in unit tests.
* src/storage/storage_driver.c (storageVolCreateXML)
(storageVolCreateXMLFrom): Ensure parsed key doesn't confuse
volume creation.
* docs/schemas/basictypes.rng (volName): Relax definition.
* tests/storagepoolxml2xmltest.c (mymain): Test it.
* tests/storagevolxml2xmltest.c (mymain): Likewise.
* tests/storagepoolxml2xmlin/pool-dir-naming.xml: New file.
* tests/storagepoolxml2xmlout/pool-dir-naming.xml: Likewise.
* tests/storagevolxml2xmlin/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-file-naming.xml: Likewise.
* tests/storagevolxml2xmlout/vol-*.xml: Fix fallout.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-11-21 00:04:05 +00:00
|
|
|
def->source.extents[i].path);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
virBufferAsprintf(&buf, "<extent start='%llu' end='%llu'/>\n",
|
2008-04-28 15:14:59 +00:00
|
|
|
def->source.extents[i].start,
|
|
|
|
def->source.extents[i].end);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
2008-02-20 15:34:52 +00:00
|
|
|
thispath = def->source.extents[i].path;
|
|
|
|
}
|
|
|
|
if (thispath != NULL)
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAddLit(&buf, "</device>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</source>\n");
|
|
|
|
|
|
|
|
virBufferAsprintf(&buf, "<capacity unit='bytes'>%llu</capacity>\n",
|
conf: track sizes directly in source struct
One of the features of qcow2 is that a wrapper file can have
more capacity than its backing file from the guest's perspective;
what's more, sparse files make tracking allocation of both
the active and backing file worthwhile. As such, it makes
more sense to show allocation numbers for each file in a chain,
and not just the top-level file. This sets up the fields for
the tracking, although it does not modify XML to display any
new information.
* src/util/virstoragefile.h (_virStorageSource): Add fields.
* src/conf/storage_conf.h (_virStorageVolDef): Drop redundant
fields.
* src/storage/storage_backend.c (virStorageBackendCreateBlockFrom)
(createRawFile, virStorageBackendCreateQemuImgCmd)
(virStorageBackendCreateQcowCreate): Update clients.
* src/storage/storage_driver.c (storageVolDelete)
(storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize)
(storageVolWipeInternal, storageVolGetInfo): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolResize)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol)
(virStorageBackendLogicalCreateVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_rbd.c
(volStorageBackendRBDRefreshVolInfo)
(virStorageBackendRBDCreateImage): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol): Likewise.
* src/storage/storage_backend_sheepdog.c
(virStorageBackendSheepdogBuildVol)
(virStorageBackendSheepdogParseVdiList): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/conf/storage_conf.c (virStorageVolDefFormat)
(virStorageVolDefParseXML): Likewise.
* src/test/test_driver.c (testOpenVolumesForPool)
(testStorageVolCreateXML, testStorageVolCreateXMLFrom)
(testStorageVolDelete, testStorageVolGetInfo): Likewise.
* src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc):
Likewise.
* src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc)
(esxStorageVolCreateXML): Likewise.
* src/parallels/parallels_driver.c (parallelsAddHddByVolume):
Likewise.
* src/parallels/parallels_storage.c (parallelsDiskDescParseNode)
(parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom)
(parallelsStorageVolDefRemove, parallelsStorageVolGetInfo):
Likewise.
* src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML)
(vboxStorageVolGetXMLDesc): Likewise.
* tests/storagebackendsheepdogtest.c (test_vdi_list_parser):
Likewise.
* src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
|
|
|
def->target.capacity);
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAsprintf(&buf, "<allocation unit='bytes'>%llu</allocation>\n",
|
conf: track sizes directly in source struct
One of the features of qcow2 is that a wrapper file can have
more capacity than its backing file from the guest's perspective;
what's more, sparse files make tracking allocation of both
the active and backing file worthwhile. As such, it makes
more sense to show allocation numbers for each file in a chain,
and not just the top-level file. This sets up the fields for
the tracking, although it does not modify XML to display any
new information.
* src/util/virstoragefile.h (_virStorageSource): Add fields.
* src/conf/storage_conf.h (_virStorageVolDef): Drop redundant
fields.
* src/storage/storage_backend.c (virStorageBackendCreateBlockFrom)
(createRawFile, virStorageBackendCreateQemuImgCmd)
(virStorageBackendCreateQcowCreate): Update clients.
* src/storage/storage_driver.c (storageVolDelete)
(storageVolCreateXML, storageVolCreateXMLFrom, storageVolResize)
(storageVolWipeInternal, storageVolGetInfo): Likewise.
* src/storage/storage_backend_fs.c (virStorageBackendProbeTarget)
(virStorageBackendFileSystemRefresh)
(virStorageBackendFileSystemVolResize)
(virStorageBackendFileSystemVolRefresh): Likewise.
* src/storage/storage_backend_logical.c
(virStorageBackendLogicalMakeVol)
(virStorageBackendLogicalCreateVol): Likewise.
* src/storage/storage_backend_scsi.c
(virStorageBackendSCSINewLun): Likewise.
* src/storage/storage_backend_mpath.c
(virStorageBackendMpathNewVol): Likewise.
* src/storage/storage_backend_rbd.c
(volStorageBackendRBDRefreshVolInfo)
(virStorageBackendRBDCreateImage): Likewise.
* src/storage/storage_backend_disk.c
(virStorageBackendDiskMakeDataVol)
(virStorageBackendDiskCreateVol): Likewise.
* src/storage/storage_backend_sheepdog.c
(virStorageBackendSheepdogBuildVol)
(virStorageBackendSheepdogParseVdiList): Likewise.
* src/storage/storage_backend_gluster.c
(virStorageBackendGlusterRefreshVol): Likewise.
* src/conf/storage_conf.c (virStorageVolDefFormat)
(virStorageVolDefParseXML): Likewise.
* src/test/test_driver.c (testOpenVolumesForPool)
(testStorageVolCreateXML, testStorageVolCreateXMLFrom)
(testStorageVolDelete, testStorageVolGetInfo): Likewise.
* src/esx/esx_storage_backend_iscsi.c (esxStorageVolGetXMLDesc):
Likewise.
* src/esx/esx_storage_backend_vmfs.c (esxStorageVolGetXMLDesc)
(esxStorageVolCreateXML): Likewise.
* src/parallels/parallels_driver.c (parallelsAddHddByVolume):
Likewise.
* src/parallels/parallels_storage.c (parallelsDiskDescParseNode)
(parallelsStorageVolDefineXML, parallelsStorageVolCreateXMLFrom)
(parallelsStorageVolDefRemove, parallelsStorageVolGetInfo):
Likewise.
* src/vbox/vbox_tmpl.c (vboxStorageVolCreateXML)
(vboxStorageVolGetXMLDesc): Likewise.
* tests/storagebackendsheepdogtest.c (test_vdi_list_parser):
Likewise.
* src/phyp/phyp_driver.c (phypStorageVolCreateXML): Likewise.
2014-04-01 23:43:36 +00:00
|
|
|
def->target.allocation);
|
2016-12-13 15:56:21 +00:00
|
|
|
/* NB: Display only - since virStorageVolInfo is limited to just
|
|
|
|
* 'capacity' and 'allocation' on output. Since we don't read this
|
|
|
|
* in, be sure it was filled in before printing */
|
|
|
|
if (def->target.physical)
|
|
|
|
virBufferAsprintf(&buf, "<physical unit='bytes'>%llu</physical>\n",
|
|
|
|
def->target.physical);
|
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
|
|
|
|
2014-07-14 13:19:49 +00:00
|
|
|
if (def->target.backingStore &&
|
2010-02-10 11:42:56 +00:00
|
|
|
virStorageVolTargetDefFormat(options, &buf,
|
2014-07-14 13:19:49 +00:00
|
|
|
def->target.backingStore,
|
|
|
|
"backingStore") < 0)
|
2009-01-27 18:30:03 +00:00
|
|
|
goto cleanup;
|
2008-04-28 15:14:59 +00:00
|
|
|
|
2014-03-06 14:57:47 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
2013-11-19 22:21:40 +00:00
|
|
|
virBufferAddLit(&buf, "</volume>\n");
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto cleanup;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2008-04-28 15:14:59 +00:00
|
|
|
return virBufferContentAndReset(&buf);
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-03-25 06:48:31 +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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2011-09-05 07:52:03 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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;
|
|
|
|
}
|
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (VIR_ALLOC(pool) < 0)
|
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;
|
|
|
|
|
2014-03-07 08:33:31 +00:00
|
|
|
if (VIR_APPEND_ELEMENT_COPY(pools->objs, pools->count, pool) < 0) {
|
2009-01-15 19:56:05 +00:00
|
|
|
virStoragePoolObjUnlock(pool);
|
2008-10-10 15:13:28 +00:00
|
|
|
virStoragePoolObjFree(pool);
|
|
|
|
return NULL;
|
|
|
|
}
|
2014-03-07 08:33:31 +00:00
|
|
|
pool->def = def;
|
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;
|
|
|
|
|
2014-11-13 14:23:27 +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) {
|
2016-02-25 20:24:27 +00:00
|
|
|
virStoragePoolObjRemove(pools, pool);
|
2008-02-20 15:34:52 +00:00
|
|
|
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) {
|
2016-02-25 20:24:27 +00:00
|
|
|
virStoragePoolObjRemove(pools, pool);
|
2008-02-20 15:34:52 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool->autostart = virFileLinkPointsTo(pool->autostartLink,
|
|
|
|
pool->configFile);
|
|
|
|
|
|
|
|
return pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-10 12:59:51 +00:00
|
|
|
virStoragePoolObjPtr
|
|
|
|
virStoragePoolLoadState(virStoragePoolObjListPtr pools,
|
|
|
|
const char *stateDir,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
char *stateFile = NULL;
|
|
|
|
virStoragePoolDefPtr def = NULL;
|
|
|
|
virStoragePoolObjPtr pool = NULL;
|
|
|
|
xmlDocPtr xml = NULL;
|
|
|
|
xmlXPathContextPtr ctxt = NULL;
|
|
|
|
xmlNodePtr node = NULL;
|
|
|
|
|
|
|
|
if (!(stateFile = virFileBuildPath(stateDir, name, ".xml")))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(xml = virXMLParseCtxt(stateFile, NULL, _("(pool state)"), &ctxt)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(node = virXPathNode("//pool", ctxt))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Could not find any 'pool' element in state file"));
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
ctxt->node = node;
|
|
|
|
if (!(def = virStoragePoolDefParseXML(ctxt)))
|
|
|
|
goto error;
|
|
|
|
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(name, def->name)) {
|
2015-03-10 12:59:51 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Storage pool state file '%s' does not match "
|
|
|
|
"pool name '%s'"),
|
|
|
|
stateFile, def->name);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the object */
|
|
|
|
if (!(pool = virStoragePoolObjAssignDef(pools, def)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
/* XXX: future handling of some additional useful status data,
|
|
|
|
* for now, if a status file for a pool exists, the pool will be marked
|
|
|
|
* as active
|
|
|
|
*/
|
|
|
|
|
|
|
|
pool->active = 1;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(stateFile);
|
2015-05-29 13:06:14 +00:00
|
|
|
xmlFreeDoc(xml);
|
2015-03-10 12:59:51 +00:00
|
|
|
xmlXPathFreeContext(ctxt);
|
|
|
|
return pool;
|
|
|
|
|
|
|
|
error:
|
|
|
|
virStoragePoolDefFree(def);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virStoragePoolLoadAllState(virStoragePoolObjListPtr pools,
|
|
|
|
const char *stateDir)
|
|
|
|
{
|
|
|
|
DIR *dir;
|
|
|
|
struct dirent *entry;
|
|
|
|
int ret = -1;
|
2016-06-21 14:47:24 +00:00
|
|
|
int rc;
|
2015-03-10 12:59:51 +00:00
|
|
|
|
2016-06-21 14:47:24 +00:00
|
|
|
if ((rc = virDirOpenIfExists(&dir, stateDir)) <= 0)
|
|
|
|
return rc;
|
2015-03-10 12:59:51 +00:00
|
|
|
|
|
|
|
while ((ret = virDirRead(dir, &entry, stateDir)) > 0) {
|
|
|
|
virStoragePoolObjPtr pool;
|
|
|
|
|
|
|
|
if (!virFileStripSuffix(entry->d_name, ".xml"))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!(pool = virStoragePoolLoadState(pools, stateDir, entry->d_name)))
|
|
|
|
continue;
|
|
|
|
virStoragePoolObjUnlock(pool);
|
|
|
|
}
|
|
|
|
|
2016-06-21 10:40:29 +00:00
|
|
|
VIR_DIR_CLOSE(dir);
|
2015-03-10 12:59:51 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
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;
|
2014-04-24 04:27:44 +00:00
|
|
|
int ret;
|
2016-06-21 14:47:24 +00:00
|
|
|
int rc;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2016-06-21 14:47:24 +00:00
|
|
|
if ((rc = virDirOpenIfExists(&dir, configDir)) <= 0)
|
|
|
|
return rc;
|
2008-02-20 15:34:52 +00:00
|
|
|
|
2014-04-24 04:27:44 +00:00
|
|
|
while ((ret = virDirRead(dir, &entry, configDir)) > 0) {
|
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 (!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
|
|
|
}
|
|
|
|
|
2016-06-21 10:40:29 +00:00
|
|
|
VIR_DIR_CLOSE(dir);
|
2014-04-24 04:27:44 +00:00
|
|
|
return ret;
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
2015-03-26 15:49:20 +00:00
|
|
|
|
|
|
|
static int virStoragePoolSaveXML(const char *path,
|
|
|
|
virStoragePoolDefPtr def,
|
|
|
|
const char *xml)
|
|
|
|
{
|
|
|
|
char uuidstr[VIR_UUID_STRING_BUFLEN];
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virUUIDFormat(def->uuid, uuidstr);
|
|
|
|
ret = virXMLSaveFile(path,
|
|
|
|
virXMLPickShellSafeComment(def->name, uuidstr),
|
|
|
|
"pool-edit", xml);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2015-04-02 14:41:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
virStoragePoolSaveState(const char *stateFile,
|
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
int ret = -1;
|
|
|
|
char *xml;
|
|
|
|
|
|
|
|
virBufferAddLit(&buf, "<poolstate>\n");
|
|
|
|
virBufferAdjustIndent(&buf, 2);
|
|
|
|
|
|
|
|
if (virStoragePoolDefFormatBuf(&buf, def) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virBufferAdjustIndent(&buf, -2);
|
|
|
|
virBufferAddLit(&buf, "</poolstate>\n");
|
|
|
|
|
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (!(xml = virBufferContentAndReset(&buf)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (virStoragePoolSaveXML(stateFile, def, xml))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(xml);
|
|
|
|
return ret;
|
|
|
|
}
|
2015-03-26 15:49:20 +00:00
|
|
|
|
|
|
|
|
2008-02-20 15:34:52 +00:00
|
|
|
int
|
2014-11-10 17:23:46 +00:00
|
|
|
virStoragePoolSaveConfig(const char *configFile,
|
2011-10-27 16:55:47 +00:00
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
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
|
|
|
|
2014-11-10 17:23:46 +00:00
|
|
|
if (!(xml = virStoragePoolDefFormat(def))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("failed to generate XML"));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-03-26 15:49:20 +00:00
|
|
|
if (virStoragePoolSaveXML(configFile, def, xml))
|
|
|
|
goto cleanup;
|
2014-11-10 17:23:46 +00:00
|
|
|
|
2015-03-26 15:49:20 +00:00
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(xml);
|
2014-11-10 17:23:46 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
virStoragePoolObjSaveDef(virStorageDriverStatePtr driver,
|
|
|
|
virStoragePoolObjPtr pool,
|
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-10 17:23:46 +00:00
|
|
|
return virStoragePoolSaveConfig(pool->configFile, def);
|
2008-02-20 15:34:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-07-04 10:02:00 +00:00
|
|
|
if (VIR_REALLOC_N(list->sources, list->nsources + 1) < 0)
|
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;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t 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");
|
2014-03-26 18:16:48 +00:00
|
|
|
virBufferAdjustIndent(&buf, 2);
|
2008-10-23 11:39:53 +00:00
|
|
|
|
2014-11-13 14:23:27 +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
|
|
|
|
2014-03-26 18:16:48 +00:00
|
|
|
virBufferAdjustIndent(&buf, -2);
|
2008-11-04 21:54:21 +00:00
|
|
|
virBufferAddLit(&buf, "</sources>\n");
|
|
|
|
|
2014-06-27 08:40:15 +00:00
|
|
|
if (virBufferCheckError(&buf) < 0)
|
|
|
|
goto cleanup;
|
2008-10-23 11:39:53 +00:00
|
|
|
|
|
|
|
return virBufferContentAndReset(&buf);
|
2008-11-04 21:54:21 +00:00
|
|
|
|
2014-03-25 06:48:31 +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
|
|
|
}
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2010-05-27 11:41:30 +00:00
|
|
|
if (pool)
|
|
|
|
virStoragePoolObjUnlock(pool);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-11-17 13:40:59 +00:00
|
|
|
|
2014-09-30 19:28:20 +00:00
|
|
|
static int
|
|
|
|
getSCSIHostNumber(virStoragePoolSourceAdapter adapter,
|
|
|
|
unsigned int *hostnum)
|
2014-03-04 03:15:13 +00:00
|
|
|
{
|
2014-09-30 19:28:20 +00:00
|
|
|
int ret = -1;
|
|
|
|
unsigned int num;
|
|
|
|
char *name = NULL;
|
|
|
|
|
|
|
|
if (adapter.data.scsi_host.has_parent) {
|
2016-04-03 18:16:51 +00:00
|
|
|
virPCIDeviceAddress addr = adapter.data.scsi_host.parentaddr;
|
2014-09-30 19:28:20 +00:00
|
|
|
unsigned int unique_id = adapter.data.scsi_host.unique_id;
|
|
|
|
|
2017-01-23 19:48:12 +00:00
|
|
|
if (!(name = virSCSIHostGetNameByParentaddr(addr.domain,
|
2014-09-30 19:28:20 +00:00
|
|
|
addr.bus,
|
|
|
|
addr.slot,
|
|
|
|
addr.function,
|
|
|
|
unique_id)))
|
|
|
|
goto cleanup;
|
2017-01-23 19:48:12 +00:00
|
|
|
if (virSCSIHostGetNumber(name, &num) < 0)
|
2014-09-30 19:28:20 +00:00
|
|
|
goto cleanup;
|
|
|
|
} else {
|
2017-01-23 19:48:12 +00:00
|
|
|
if (virSCSIHostGetNumber(adapter.data.scsi_host.name, &num) < 0)
|
2014-09-30 19:28:20 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
*hostnum = num;
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(name);
|
|
|
|
return ret;
|
2014-03-04 03:15:13 +00:00
|
|
|
}
|
2014-11-14 14:50:59 +00:00
|
|
|
|
2017-01-23 19:48:12 +00:00
|
|
|
|
|
|
|
static bool
|
|
|
|
virStorageIsSameHostnum(const char *name,
|
|
|
|
unsigned int scsi_hostnum)
|
|
|
|
{
|
|
|
|
unsigned int fc_hostnum;
|
|
|
|
|
|
|
|
if (virSCSIHostGetNumber(name, &fc_hostnum) == 0 &&
|
|
|
|
scsi_hostnum == fc_hostnum)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-11-14 14:50:59 +00:00
|
|
|
/*
|
|
|
|
* matchFCHostToSCSIHost:
|
|
|
|
*
|
|
|
|
* @conn: Connection pointer
|
|
|
|
* @fc_adapter: fc_host adapter (either def or pool->def)
|
|
|
|
* @scsi_hostnum: Already determined "scsi_pool" hostnum
|
|
|
|
*
|
|
|
|
* Returns true/false whether there is a match between the incoming
|
|
|
|
* fc_adapter host# and the scsi_host host#
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
matchFCHostToSCSIHost(virConnectPtr conn,
|
|
|
|
virStoragePoolSourceAdapter fc_adapter,
|
|
|
|
unsigned int scsi_hostnum)
|
|
|
|
{
|
2017-02-20 18:59:36 +00:00
|
|
|
bool ret = false;
|
2014-11-14 14:50:59 +00:00
|
|
|
char *name = NULL;
|
2017-02-18 13:26:21 +00:00
|
|
|
char *scsi_host_name = NULL;
|
2014-11-14 14:50:59 +00:00
|
|
|
char *parent_name = NULL;
|
|
|
|
|
2015-06-03 10:10:36 +00:00
|
|
|
/* If we have a parent defined, get its hostnum, and compare to the
|
2014-11-14 14:50:59 +00:00
|
|
|
* scsi_hostnum. If they are the same, then we have a match
|
|
|
|
*/
|
|
|
|
if (fc_adapter.data.fchost.parent &&
|
2017-01-23 19:48:12 +00:00
|
|
|
virStorageIsSameHostnum(fc_adapter.data.fchost.parent, scsi_hostnum))
|
2014-11-14 14:50:59 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
/* If we find an fc_adapter name, then either libvirt created a vHBA
|
|
|
|
* for this fc_host or a 'virsh nodedev-create' generated a vHBA.
|
|
|
|
*/
|
2017-01-23 17:54:42 +00:00
|
|
|
if ((name = virVHBAGetHostByWWN(NULL, fc_adapter.data.fchost.wwnn,
|
|
|
|
fc_adapter.data.fchost.wwpn))) {
|
2014-11-14 14:50:59 +00:00
|
|
|
|
|
|
|
/* Get the scsi_hostN for the vHBA in order to see if it
|
|
|
|
* matches our scsi_hostnum
|
|
|
|
*/
|
2017-01-23 19:48:12 +00:00
|
|
|
if (virStorageIsSameHostnum(name, scsi_hostnum)) {
|
2017-02-20 18:59:36 +00:00
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
2014-11-14 14:50:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We weren't provided a parent, so we have to query the node
|
|
|
|
* device driver in order to ascertain the parent of the vHBA.
|
|
|
|
* If the parent fc_hostnum is the same as the scsi_hostnum, we
|
|
|
|
* have a match.
|
|
|
|
*/
|
|
|
|
if (conn && !fc_adapter.data.fchost.parent) {
|
2017-02-20 18:59:36 +00:00
|
|
|
if (virAsprintf(&scsi_host_name, "scsi_%s", name) < 0)
|
|
|
|
goto cleanup;
|
2017-02-18 13:26:21 +00:00
|
|
|
if ((parent_name = virNodeDeviceGetParentName(conn,
|
|
|
|
scsi_host_name))) {
|
2017-01-23 19:48:12 +00:00
|
|
|
if (virStorageIsSameHostnum(parent_name, scsi_hostnum)) {
|
2017-02-20 18:59:36 +00:00
|
|
|
ret = true;
|
|
|
|
goto cleanup;
|
2014-11-14 14:50:59 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Throw away the error and fall through */
|
|
|
|
virResetLastError();
|
|
|
|
VIR_DEBUG("Could not determine parent vHBA");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NB: Lack of a name means that this vHBA hasn't yet been created,
|
|
|
|
* which means our scsi_host cannot be using the vHBA. Furthermore,
|
|
|
|
* lack of a provided parent means libvirt is going to choose the
|
|
|
|
* "best" fc_host capable adapter based on availabilty. That could
|
|
|
|
* conflict with an existing scsi_host definition, but there's no
|
|
|
|
* way to know that now.
|
|
|
|
*/
|
2017-02-20 18:59:36 +00:00
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(name);
|
|
|
|
VIR_FREE(parent_name);
|
|
|
|
VIR_FREE(scsi_host_name);
|
|
|
|
return ret;
|
2014-11-14 14:50:59 +00:00
|
|
|
}
|
|
|
|
|
2014-11-01 11:10:17 +00:00
|
|
|
static bool
|
|
|
|
matchSCSIAdapterParent(virStoragePoolObjPtr pool,
|
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
2016-04-03 18:16:51 +00:00
|
|
|
virPCIDeviceAddressPtr pooladdr =
|
2014-11-01 11:10:17 +00:00
|
|
|
&pool->def->source.adapter.data.scsi_host.parentaddr;
|
2016-04-03 18:16:51 +00:00
|
|
|
virPCIDeviceAddressPtr defaddr =
|
2014-11-01 11:10:17 +00:00
|
|
|
&def->source.adapter.data.scsi_host.parentaddr;
|
|
|
|
int pool_unique_id =
|
|
|
|
pool->def->source.adapter.data.scsi_host.unique_id;
|
|
|
|
int def_unique_id =
|
|
|
|
def->source.adapter.data.scsi_host.unique_id;
|
|
|
|
if (pooladdr->domain == defaddr->domain &&
|
|
|
|
pooladdr->bus == defaddr->bus &&
|
|
|
|
pooladdr->slot == defaddr->slot &&
|
|
|
|
pooladdr->function == defaddr->function &&
|
|
|
|
pool_unique_id == def_unique_id) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-01 18:05:54 +00:00
|
|
|
static bool
|
|
|
|
virStoragePoolSourceMatchSingleHost(virStoragePoolSourcePtr poolsrc,
|
|
|
|
virStoragePoolSourcePtr defsrc)
|
|
|
|
{
|
|
|
|
if (poolsrc->nhost != 1 && defsrc->nhost != 1)
|
|
|
|
return false;
|
|
|
|
|
2015-05-11 14:19:39 +00:00
|
|
|
if (defsrc->hosts[0].port &&
|
|
|
|
poolsrc->hosts[0].port != defsrc->hosts[0].port)
|
2015-04-13 21:11:53 +00:00
|
|
|
return false;
|
|
|
|
|
2015-04-01 18:05:54 +00:00
|
|
|
return STREQ(poolsrc->hosts[0].name, defsrc->hosts[0].name);
|
|
|
|
}
|
|
|
|
|
2014-03-04 03:15:13 +00:00
|
|
|
|
2015-03-30 23:59:26 +00:00
|
|
|
static bool
|
|
|
|
virStoragePoolSourceISCSIMatch(virStoragePoolObjPtr matchpool,
|
|
|
|
virStoragePoolDefPtr def)
|
|
|
|
{
|
|
|
|
virStoragePoolSourcePtr poolsrc = &matchpool->def->source;
|
|
|
|
virStoragePoolSourcePtr defsrc = &def->source;
|
|
|
|
|
2015-05-11 17:51:04 +00:00
|
|
|
/* NB: Do not check the source host name */
|
2015-03-30 23:59:26 +00:00
|
|
|
if (STRNEQ_NULLABLE(poolsrc->initiator.iqn, defsrc->initiator.iqn))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-05-16 12:40:50 +00:00
|
|
|
int
|
2014-11-14 14:50:59 +00:00
|
|
|
virStoragePoolSourceFindDuplicate(virConnectPtr conn,
|
|
|
|
virStoragePoolObjListPtr pools,
|
2013-05-16 12:40:50 +00:00
|
|
|
virStoragePoolDefPtr def)
|
2011-09-05 07:52:03 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-09-05 07:52:03 +00:00
|
|
|
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;
|
|
|
|
|
2016-09-22 10:33:24 +00:00
|
|
|
/* Don't match against ourself if re-defining existing pool ! */
|
2011-10-07 16:38:09 +00:00
|
|
|
if (STREQ(pool->def->name, def->name))
|
|
|
|
continue;
|
|
|
|
|
2011-09-05 07:52:03 +00:00
|
|
|
virStoragePoolObjLock(pool);
|
|
|
|
|
2015-04-02 16:39:27 +00:00
|
|
|
switch ((virStoragePoolType)pool->def->type) {
|
2011-09-05 07:52:03 +00:00
|
|
|
case VIR_STORAGE_POOL_DIR:
|
|
|
|
if (STREQ(pool->def->target.path, def->target.path))
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
2015-06-30 08:14:17 +00:00
|
|
|
|
2015-04-02 16:48:04 +00:00
|
|
|
case VIR_STORAGE_POOL_GLUSTER:
|
2015-06-30 08:14:17 +00:00
|
|
|
if (STREQ(pool->def->source.name, def->source.name) &&
|
|
|
|
STREQ_NULLABLE(pool->def->source.dir, def->source.dir) &&
|
|
|
|
virStoragePoolSourceMatchSingleHost(&pool->def->source,
|
|
|
|
&def->source))
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_STORAGE_POOL_NETFS:
|
2015-04-01 18:09:05 +00:00
|
|
|
if (STREQ(pool->def->source.dir, def->source.dir) &&
|
|
|
|
virStoragePoolSourceMatchSingleHost(&pool->def->source,
|
|
|
|
&def->source))
|
2011-09-05 07:52:03 +00:00
|
|
|
matchpool = pool;
|
|
|
|
break;
|
2015-06-30 08:14:17 +00:00
|
|
|
|
2011-09-05 07:52:03 +00:00
|
|
|
case VIR_STORAGE_POOL_SCSI:
|
2013-03-25 16:43:36 +00:00
|
|
|
if (pool->def->source.adapter.type ==
|
2014-09-05 05:47:49 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST &&
|
|
|
|
def->source.adapter.type ==
|
2013-03-25 16:43:36 +00:00
|
|
|
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 ==
|
2014-09-05 05:47:49 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST &&
|
|
|
|
def->source.adapter.type ==
|
2014-08-20 11:00:30 +00:00
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
2014-09-30 19:28:20 +00:00
|
|
|
unsigned int pool_hostnum, def_hostnum;
|
|
|
|
|
2014-11-01 11:10:17 +00:00
|
|
|
if (pool->def->source.adapter.data.scsi_host.has_parent &&
|
|
|
|
def->source.adapter.data.scsi_host.has_parent &&
|
|
|
|
matchSCSIAdapterParent(pool, def)) {
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2014-09-30 19:28:20 +00:00
|
|
|
if (getSCSIHostNumber(pool->def->source.adapter,
|
|
|
|
&pool_hostnum) < 0 ||
|
|
|
|
getSCSIHostNumber(def->source.adapter, &def_hostnum) < 0)
|
2014-11-01 11:11:38 +00:00
|
|
|
break;
|
2014-09-30 19:28:20 +00:00
|
|
|
if (pool_hostnum == def_hostnum)
|
|
|
|
matchpool = pool;
|
2014-11-14 14:50:59 +00:00
|
|
|
} else if (pool->def->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST &&
|
|
|
|
def->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST) {
|
|
|
|
unsigned int scsi_hostnum;
|
|
|
|
|
|
|
|
/* Get the scsi_hostN for the scsi_host source adapter def */
|
|
|
|
if (getSCSIHostNumber(def->source.adapter,
|
|
|
|
&scsi_hostnum) < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (matchFCHostToSCSIHost(conn, pool->def->source.adapter,
|
|
|
|
scsi_hostnum)) {
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (pool->def->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_SCSI_HOST &&
|
|
|
|
def->source.adapter.type ==
|
|
|
|
VIR_STORAGE_POOL_SOURCE_ADAPTER_TYPE_FC_HOST) {
|
|
|
|
unsigned int scsi_hostnum;
|
|
|
|
|
|
|
|
if (getSCSIHostNumber(pool->def->source.adapter,
|
|
|
|
&scsi_hostnum) < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (matchFCHostToSCSIHost(conn, def->source.adapter,
|
|
|
|
scsi_hostnum)) {
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
|
|
|
}
|
2013-03-25 16:43:36 +00:00
|
|
|
}
|
2011-09-05 07:52:03 +00:00
|
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_ISCSI:
|
|
|
|
matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
|
|
|
|
if (matchpool) {
|
2015-03-30 23:59:26 +00:00
|
|
|
if (!virStoragePoolSourceISCSIMatch(matchpool, def))
|
|
|
|
matchpool = NULL;
|
2011-09-05 07:52:03 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case VIR_STORAGE_POOL_FS:
|
|
|
|
case VIR_STORAGE_POOL_LOGICAL:
|
|
|
|
case VIR_STORAGE_POOL_DISK:
|
2015-04-02 16:50:07 +00:00
|
|
|
case VIR_STORAGE_POOL_ZFS:
|
2011-09-05 07:52:03 +00:00
|
|
|
matchpool = virStoragePoolSourceFindDuplicateDevices(pool, def);
|
|
|
|
break;
|
2015-04-02 16:46:00 +00:00
|
|
|
case VIR_STORAGE_POOL_SHEEPDOG:
|
|
|
|
if (virStoragePoolSourceMatchSingleHost(&pool->def->source,
|
|
|
|
&def->source))
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
2015-04-02 16:39:27 +00:00
|
|
|
case VIR_STORAGE_POOL_MPATH:
|
2015-06-24 12:45:24 +00:00
|
|
|
/* Only one mpath pool is valid per host */
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
2017-01-17 14:10:55 +00:00
|
|
|
case VIR_STORAGE_POOL_VSTORAGE:
|
|
|
|
if (STREQ(pool->def->source.name, def->source.name))
|
|
|
|
matchpool = pool;
|
|
|
|
break;
|
2015-04-02 16:39:27 +00:00
|
|
|
case VIR_STORAGE_POOL_RBD:
|
|
|
|
case VIR_STORAGE_POOL_LAST:
|
2011-09-05 07:52:03 +00:00
|
|
|
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) &&
|
2013-12-13 09:31:50 +00:00
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_SHEEPDOG)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER) &&
|
2017-03-13 08:20:35 +00:00
|
|
|
(poolobj->def->type == VIR_STORAGE_POOL_GLUSTER)) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_ZFS) &&
|
|
|
|
poolobj->def->type == VIR_STORAGE_POOL_ZFS) ||
|
|
|
|
(MATCH(VIR_CONNECT_LIST_STORAGE_POOLS_VSTORAGE) &&
|
|
|
|
poolobj->def->type == VIR_STORAGE_POOL_VSTORAGE)))
|
2012-09-04 15:16:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#undef MATCH
|
|
|
|
|
|
|
|
int
|
2013-06-26 17:47:48 +00:00
|
|
|
virStoragePoolObjListExport(virConnectPtr conn,
|
|
|
|
virStoragePoolObjList poolobjs,
|
|
|
|
virStoragePoolPtr **pools,
|
|
|
|
virStoragePoolObjListFilter filter,
|
|
|
|
unsigned int flags)
|
2012-09-04 15:16:25 +00:00
|
|
|
{
|
|
|
|
virStoragePoolPtr *tmp_pools = NULL;
|
|
|
|
virStoragePoolPtr pool = NULL;
|
|
|
|
int npools = 0;
|
|
|
|
int ret = -1;
|
Convert 'int i' to 'size_t i' in src/conf/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2012-09-04 15:16:25 +00:00
|
|
|
|
2013-07-04 10:02:00 +00:00
|
|
|
if (pools && VIR_ALLOC_N(tmp_pools, poolobjs.count + 1) < 0)
|
|
|
|
goto cleanup;
|
2012-09-04 15:16:25 +00:00
|
|
|
|
|
|
|
for (i = 0; i < poolobjs.count; i++) {
|
|
|
|
virStoragePoolObjPtr poolobj = poolobjs.objs[i];
|
|
|
|
virStoragePoolObjLock(poolobj);
|
2013-06-26 17:47:48 +00:00
|
|
|
if ((!filter || filter(conn, poolobj->def)) &&
|
|
|
|
virStoragePoolMatch(poolobj, flags)) {
|
2012-09-04 15:16:25 +00:00
|
|
|
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;
|
|
|
|
|
2014-03-25 06:48:31 +00:00
|
|
|
cleanup:
|
2012-09-04 15:16:25 +00:00
|
|
|
if (tmp_pools) {
|
2014-11-30 14:35:12 +00:00
|
|
|
for (i = 0; i < npools; i++)
|
|
|
|
virObjectUnref(tmp_pools[i]);
|
2012-09-04 15:16:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VIR_FREE(tmp_pools);
|
|
|
|
return ret;
|
|
|
|
}
|