mirror of
https://github.com/libvirt/libvirt.git
synced 2025-02-25 18:55:26 -06:00
storage: ZFS support
Implement ZFS storage backend driver. Currently supported only on FreeBSD because of ZFS limitations on Linux. Features supported: - pool-start, pool-stop - pool-info - vol-list - vol-create / vol-delete Pool definition looks like that: <pool type='zfs'> <name>myzfspool</name> <source> <name>actualpoolname</name> </source> </pool> The 'actualpoolname' value is a name of the pool on the system, such as shown by 'zpool list' command. Target makes no sense here because volumes path is always /dev/zvol/$poolname/$volname. User has to create a pool on his own, this driver doesn't support pool creation currently. A volume could be used with Qemu by adding an entry like this: <disk type='volume' device='disk'> <driver name='qemu' type='raw'/> <source pool='myzfspool' volume='vol5'/> <target dev='hdc' bus='ide'/> </disk>
This commit is contained in:
parent
1b7c2c549e
commit
0257d06ba4
43
configure.ac
43
configure.ac
@ -1734,6 +1734,10 @@ AC_ARG_WITH([storage-gluster],
|
|||||||
[AS_HELP_STRING([--with-storage-gluster],
|
[AS_HELP_STRING([--with-storage-gluster],
|
||||||
[with Gluster backend for the storage driver @<:@default=check@:>@])],
|
[with Gluster backend for the storage driver @<:@default=check@:>@])],
|
||||||
[],[with_storage_gluster=check])
|
[],[with_storage_gluster=check])
|
||||||
|
AC_ARG_WITH([storage-zfs],
|
||||||
|
[AS_HELP_STRING([--with-storage-zfs],
|
||||||
|
[with ZFS backend for the storage driver @<:@default=check@:>@])],
|
||||||
|
[],[with_storage_zfs=check])
|
||||||
|
|
||||||
if test "$with_libvirtd" = "no"; then
|
if test "$with_libvirtd" = "no"; then
|
||||||
with_storage_dir=no
|
with_storage_dir=no
|
||||||
@ -1746,6 +1750,7 @@ if test "$with_libvirtd" = "no"; then
|
|||||||
with_storage_rbd=no
|
with_storage_rbd=no
|
||||||
with_storage_sheepdog=no
|
with_storage_sheepdog=no
|
||||||
with_storage_gluster=no
|
with_storage_gluster=no
|
||||||
|
with_storage_zfs=no
|
||||||
fi
|
fi
|
||||||
if test "$with_storage_dir" = "yes" ; then
|
if test "$with_storage_dir" = "yes" ; then
|
||||||
AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled])
|
AC_DEFINE_UNQUOTED([WITH_STORAGE_DIR], 1, [whether directory backend for storage driver is enabled])
|
||||||
@ -1963,6 +1968,43 @@ if test "$with_storage_gluster" = "yes"; then
|
|||||||
fi
|
fi
|
||||||
AM_CONDITIONAL([WITH_STORAGE_GLUSTER], [test "$with_storage_gluster" = "yes"])
|
AM_CONDITIONAL([WITH_STORAGE_GLUSTER], [test "$with_storage_gluster" = "yes"])
|
||||||
|
|
||||||
|
if test "$with_storage_zfs" = "check"; then
|
||||||
|
with_storage_zfs=$with_freebsd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$with_storage_zfs" = "yes" && test "$with_freebsd" = "no"; then
|
||||||
|
AC_MSG_ERROR([The ZFS storage driver can be enabled on FreeBSD only.])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$with_storage_zfs" = "yes" ||
|
||||||
|
test "$with_storage_zfs" = "check"; then
|
||||||
|
AC_PATH_PROG([ZFS], [zfs], [], [$PATH:/sbin:/usr/sbin])
|
||||||
|
AC_PATH_PROG([ZPOOL], [zpool], [], [$PATH:/sbin:/usr/sbin])
|
||||||
|
|
||||||
|
if test "$with_storage_zfs" = "yes"; then
|
||||||
|
if test -z "$ZFS" || test -z "$ZPOOL"; then
|
||||||
|
AC_MSG_ERROR([We need zfs and zpool for ZFS storage driver])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test -z "$ZFS" || test -z "$ZPOOL"; then
|
||||||
|
with_storage_zfs=no
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$with_storage_zfs" = "check"; then
|
||||||
|
with_storage_zfs=yes
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "$with_storage_zfs" = "yes"; then
|
||||||
|
AC_DEFINE_UNQUOTED([WITH_STORAGE_ZFS], 1,
|
||||||
|
[whether ZFS backend for storage driver is enabled])
|
||||||
|
AC_DEFINE_UNQUOTED([ZFS], ["$ZFS"], [Location of zfs program])
|
||||||
|
AC_DEFINE_UNQUOTED([ZPOOL], ["$ZPOOL"], [Location of zpool program])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL([WITH_STORAGE_ZFS],
|
||||||
|
[test "$with_storage_zfs" = "yes"])
|
||||||
|
|
||||||
if test "$with_storage_fs" = "yes" ||
|
if test "$with_storage_fs" = "yes" ||
|
||||||
test "$with_storage_gluster" = "yes"; then
|
test "$with_storage_gluster" = "yes"; then
|
||||||
AC_PATH_PROG([GLUSTER_CLI], [gluster], [], [$PATH:/sbin:/usr/sbin])
|
AC_PATH_PROG([GLUSTER_CLI], [gluster], [], [$PATH:/sbin:/usr/sbin])
|
||||||
@ -2806,6 +2848,7 @@ AC_MSG_NOTICE([ Disk: $with_storage_disk])
|
|||||||
AC_MSG_NOTICE([ RBD: $with_storage_rbd])
|
AC_MSG_NOTICE([ RBD: $with_storage_rbd])
|
||||||
AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog])
|
AC_MSG_NOTICE([Sheepdog: $with_storage_sheepdog])
|
||||||
AC_MSG_NOTICE([ Gluster: $with_storage_gluster])
|
AC_MSG_NOTICE([ Gluster: $with_storage_gluster])
|
||||||
|
AC_MSG_NOTICE([ ZFS: $with_storage_zfs])
|
||||||
AC_MSG_NOTICE([])
|
AC_MSG_NOTICE([])
|
||||||
AC_MSG_NOTICE([Security Drivers])
|
AC_MSG_NOTICE([Security Drivers])
|
||||||
AC_MSG_NOTICE([])
|
AC_MSG_NOTICE([])
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
<ref name='poolrbd'/>
|
<ref name='poolrbd'/>
|
||||||
<ref name='poolsheepdog'/>
|
<ref name='poolsheepdog'/>
|
||||||
<ref name='poolgluster'/>
|
<ref name='poolgluster'/>
|
||||||
|
<ref name='poolzfs'/>
|
||||||
</choice>
|
</choice>
|
||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
@ -157,6 +158,17 @@
|
|||||||
</interleave>
|
</interleave>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name='poolzfs'>
|
||||||
|
<attribute name='type'>
|
||||||
|
<value>zfs</value>
|
||||||
|
</attribute>
|
||||||
|
<interleave>
|
||||||
|
<ref name='commonmetadata'/>
|
||||||
|
<ref name='sizing'/>
|
||||||
|
<ref name='sourcezfs'/>
|
||||||
|
</interleave>
|
||||||
|
</define>
|
||||||
|
|
||||||
<define name='sourceinfovendor'>
|
<define name='sourceinfovendor'>
|
||||||
<interleave>
|
<interleave>
|
||||||
<optional>
|
<optional>
|
||||||
@ -370,6 +382,14 @@
|
|||||||
</element>
|
</element>
|
||||||
</define>
|
</define>
|
||||||
|
|
||||||
|
<define name='sourcezfs'>
|
||||||
|
<element name='source'>
|
||||||
|
<interleave>
|
||||||
|
<ref name='sourceinfoname'/>
|
||||||
|
</interleave>
|
||||||
|
</element>
|
||||||
|
</define>
|
||||||
|
|
||||||
<define name='sourcefmtfs'>
|
<define name='sourcefmtfs'>
|
||||||
<optional>
|
<optional>
|
||||||
<element name='format'>
|
<element name='format'>
|
||||||
|
@ -117,6 +117,9 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="#StorageBackendGluster">Gluster backend</a>
|
<a href="#StorageBackendGluster">Gluster backend</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#StorageBackendZFS">ZFS backend</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2><a name="StorageBackendDir">Directory pool</a></h2>
|
<h2><a name="StorageBackendDir">Directory pool</a></h2>
|
||||||
@ -743,5 +746,36 @@
|
|||||||
pool type.
|
pool type.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h2><a name="StorageBackendZFS">ZFS pools</a></h2>
|
||||||
|
<p>
|
||||||
|
This provides a pool based on the ZFS filesystem. It is currently
|
||||||
|
supported on FreeBSD only.
|
||||||
|
|
||||||
|
A pool has to be created before libvirt could start using it. That
|
||||||
|
could be done using <code>zpool create</code> command. Please refer to
|
||||||
|
the ZFS documentation for details on a pool creation.
|
||||||
|
|
||||||
|
<span class="since">Since 1.2.8</span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Example pool input</h3>
|
||||||
|
<pre>
|
||||||
|
<pool type="zfs">
|
||||||
|
<name>myzfspool</name>
|
||||||
|
<source>
|
||||||
|
<name>zpoolname</name>
|
||||||
|
</source>
|
||||||
|
</pool></pre>
|
||||||
|
|
||||||
|
<h3>Valid pool format types</h3>
|
||||||
|
<p>
|
||||||
|
The ZFS volume pool does not use the pool format type element.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Valid pool format types</h3>
|
||||||
|
<p>
|
||||||
|
The ZFS volume pool does not use the volume format type element.
|
||||||
|
</p>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -3170,6 +3170,7 @@ typedef enum {
|
|||||||
VIR_CONNECT_LIST_STORAGE_POOLS_RBD = 1 << 14,
|
VIR_CONNECT_LIST_STORAGE_POOLS_RBD = 1 << 14,
|
||||||
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15,
|
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG = 1 << 15,
|
||||||
VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER = 1 << 16,
|
VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER = 1 << 16,
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_ZFS = 1 << 17,
|
||||||
} virConnectListAllStoragePoolsFlags;
|
} virConnectListAllStoragePoolsFlags;
|
||||||
|
|
||||||
int virConnectListAllStoragePools(virConnectPtr conn,
|
int virConnectListAllStoragePools(virConnectPtr conn,
|
||||||
|
@ -148,6 +148,7 @@ src/storage/storage_backend_mpath.c
|
|||||||
src/storage/storage_backend_rbd.c
|
src/storage/storage_backend_rbd.c
|
||||||
src/storage/storage_backend_scsi.c
|
src/storage/storage_backend_scsi.c
|
||||||
src/storage/storage_backend_sheepdog.c
|
src/storage/storage_backend_sheepdog.c
|
||||||
|
src/storage/storage_backend_zfs.c
|
||||||
src/storage/storage_driver.c
|
src/storage/storage_driver.c
|
||||||
src/test/test_driver.c
|
src/test/test_driver.c
|
||||||
src/uml/uml_conf.c
|
src/uml/uml_conf.c
|
||||||
|
@ -862,6 +862,9 @@ STORAGE_DRIVER_SHEEPDOG_SOURCES = \
|
|||||||
STORAGE_DRIVER_GLUSTER_SOURCES = \
|
STORAGE_DRIVER_GLUSTER_SOURCES = \
|
||||||
storage/storage_backend_gluster.h storage/storage_backend_gluster.c
|
storage/storage_backend_gluster.h storage/storage_backend_gluster.c
|
||||||
|
|
||||||
|
STORAGE_DRIVER_ZFS_SOURCES = \
|
||||||
|
storage/storage_backend_zfs.h storage/storage_backend_zfs.c
|
||||||
|
|
||||||
STORAGE_HELPER_DISK_SOURCES = \
|
STORAGE_HELPER_DISK_SOURCES = \
|
||||||
storage/parthelper.c
|
storage/parthelper.c
|
||||||
|
|
||||||
@ -1514,6 +1517,10 @@ libvirt_driver_storage_impl_la_CFLAGS += $(GLUSTERFS_CFLAGS)
|
|||||||
libvirt_driver_storage_impl_la_LIBADD += $(GLUSTERFS_LIBS)
|
libvirt_driver_storage_impl_la_LIBADD += $(GLUSTERFS_LIBS)
|
||||||
endif WITH_STORAGE_GLUSTER
|
endif WITH_STORAGE_GLUSTER
|
||||||
|
|
||||||
|
if WITH_STORAGE_ZFS
|
||||||
|
libvirt_driver_storage_impl_la_SOURCES += $(STORAGE_DRIVER_ZFS_SOURCES)
|
||||||
|
endif WITH_STORAGE_ZFS
|
||||||
|
|
||||||
if WITH_NODE_DEVICES
|
if WITH_NODE_DEVICES
|
||||||
# Needed to keep automake quiet about conditionals
|
# Needed to keep automake quiet about conditionals
|
||||||
if WITH_DRIVER_MODULES
|
if WITH_DRIVER_MODULES
|
||||||
@ -1723,6 +1730,7 @@ EXTRA_DIST += \
|
|||||||
$(STORAGE_DRIVER_RBD_SOURCES) \
|
$(STORAGE_DRIVER_RBD_SOURCES) \
|
||||||
$(STORAGE_DRIVER_SHEEPDOG_SOURCES) \
|
$(STORAGE_DRIVER_SHEEPDOG_SOURCES) \
|
||||||
$(STORAGE_DRIVER_GLUSTER_SOURCES) \
|
$(STORAGE_DRIVER_GLUSTER_SOURCES) \
|
||||||
|
$(STORAGE_DRIVER_ZFS_SOURCES) \
|
||||||
$(NODE_DEVICE_DRIVER_SOURCES) \
|
$(NODE_DEVICE_DRIVER_SOURCES) \
|
||||||
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
|
$(NODE_DEVICE_DRIVER_HAL_SOURCES) \
|
||||||
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
|
$(NODE_DEVICE_DRIVER_UDEV_SOURCES) \
|
||||||
|
@ -61,7 +61,8 @@ VIR_ENUM_IMPL(virStoragePool,
|
|||||||
VIR_STORAGE_POOL_LAST,
|
VIR_STORAGE_POOL_LAST,
|
||||||
"dir", "fs", "netfs",
|
"dir", "fs", "netfs",
|
||||||
"logical", "disk", "iscsi",
|
"logical", "disk", "iscsi",
|
||||||
"scsi", "mpath", "rbd", "sheepdog", "gluster")
|
"scsi", "mpath", "rbd",
|
||||||
|
"sheepdog", "gluster", "zfs")
|
||||||
|
|
||||||
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
|
VIR_ENUM_IMPL(virStoragePoolFormatFileSystem,
|
||||||
VIR_STORAGE_POOL_FS_LAST,
|
VIR_STORAGE_POOL_FS_LAST,
|
||||||
@ -278,7 +279,13 @@ static virStoragePoolTypeInfo poolTypeInfo[] = {
|
|||||||
.formatFromString = virStorageVolFormatDiskTypeFromString,
|
.formatFromString = virStorageVolFormatDiskTypeFromString,
|
||||||
.formatToString = virStorageVolFormatDiskTypeToString,
|
.formatToString = virStorageVolFormatDiskTypeToString,
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
|
{.poolType = VIR_STORAGE_POOL_ZFS,
|
||||||
|
.poolOptions = {
|
||||||
|
.flags = (VIR_STORAGE_POOL_SOURCE_NAME),
|
||||||
|
.defaultFormat = VIR_STORAGE_FILE_RAW,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -924,6 +931,10 @@ virStoragePoolDefParseXML(xmlXPathContextPtr ctxt)
|
|||||||
if (virAsprintf(&target_path, "/dev/%s", ret->source.name) < 0) {
|
if (virAsprintf(&target_path, "/dev/%s", ret->source.name) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
} else if (ret->type == VIR_STORAGE_POOL_ZFS) {
|
||||||
|
if (virAsprintf(&target_path, "/dev/zvol/%s", ret->source.name) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
target_path = virXPathString("string(./target/path)", ctxt);
|
target_path = virXPathString("string(./target/path)", ctxt);
|
||||||
if (!target_path) {
|
if (!target_path) {
|
||||||
|
@ -92,6 +92,7 @@ typedef enum {
|
|||||||
VIR_STORAGE_POOL_RBD, /* RADOS Block Device */
|
VIR_STORAGE_POOL_RBD, /* RADOS Block Device */
|
||||||
VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */
|
VIR_STORAGE_POOL_SHEEPDOG, /* Sheepdog device */
|
||||||
VIR_STORAGE_POOL_GLUSTER, /* Gluster device */
|
VIR_STORAGE_POOL_GLUSTER, /* Gluster device */
|
||||||
|
VIR_STORAGE_POOL_ZFS, /* ZFS */
|
||||||
|
|
||||||
VIR_STORAGE_POOL_LAST,
|
VIR_STORAGE_POOL_LAST,
|
||||||
} virStoragePoolType;
|
} virStoragePoolType;
|
||||||
@ -509,7 +510,8 @@ VIR_ENUM_DECL(virStoragePartedFs)
|
|||||||
VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \
|
VIR_CONNECT_LIST_STORAGE_POOLS_MPATH | \
|
||||||
VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \
|
VIR_CONNECT_LIST_STORAGE_POOLS_RBD | \
|
||||||
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG | \
|
VIR_CONNECT_LIST_STORAGE_POOLS_SHEEPDOG | \
|
||||||
VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER)
|
VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER | \
|
||||||
|
VIR_CONNECT_LIST_STORAGE_POOLS_ZFS)
|
||||||
|
|
||||||
# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL \
|
# define VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ALL \
|
||||||
(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE | \
|
(VIR_CONNECT_LIST_STORAGE_POOLS_FILTERS_ACTIVE | \
|
||||||
|
@ -1369,6 +1369,7 @@ qemuTranslateDiskSourcePool(virConnectPtr conn,
|
|||||||
case VIR_STORAGE_POOL_LOGICAL:
|
case VIR_STORAGE_POOL_LOGICAL:
|
||||||
case VIR_STORAGE_POOL_DISK:
|
case VIR_STORAGE_POOL_DISK:
|
||||||
case VIR_STORAGE_POOL_SCSI:
|
case VIR_STORAGE_POOL_SCSI:
|
||||||
|
case VIR_STORAGE_POOL_ZFS:
|
||||||
if (!(def->src->path = virStorageVolGetPath(vol)))
|
if (!(def->src->path = virStorageVolGetPath(vol)))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
@ -88,6 +88,9 @@
|
|||||||
#if WITH_STORAGE_GLUSTER
|
#if WITH_STORAGE_GLUSTER
|
||||||
# include "storage_backend_gluster.h"
|
# include "storage_backend_gluster.h"
|
||||||
#endif
|
#endif
|
||||||
|
#if WITH_STORAGE_ZFS
|
||||||
|
# include "storage_backend_zfs.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
||||||
|
|
||||||
@ -124,6 +127,9 @@ static virStorageBackendPtr backends[] = {
|
|||||||
#endif
|
#endif
|
||||||
#if WITH_STORAGE_GLUSTER
|
#if WITH_STORAGE_GLUSTER
|
||||||
&virStorageBackendGluster,
|
&virStorageBackendGluster,
|
||||||
|
#endif
|
||||||
|
#if WITH_STORAGE_ZFS
|
||||||
|
&virStorageBackendZFS,
|
||||||
#endif
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
329
src/storage/storage_backend_zfs.c
Normal file
329
src/storage/storage_backend_zfs.c
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/*
|
||||||
|
* storage_backend_zfs.c: storage backend for ZFS handling
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Roman Bogorodskiy
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include "viralloc.h"
|
||||||
|
#include "virerror.h"
|
||||||
|
#include "virfile.h"
|
||||||
|
#include "storage_backend_zfs.h"
|
||||||
|
#include "virlog.h"
|
||||||
|
#include "virstring.h"
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_STORAGE
|
||||||
|
|
||||||
|
VIR_LOG_INIT("storage.storage_backend_zfs");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some common flags of zfs and zpool commands we use:
|
||||||
|
* -H -- don't print headers and separate fields by tab
|
||||||
|
* -p -- show exact numbers instead of human-readable, i.e.
|
||||||
|
* for size, show just a number instead of 2G etc
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendZFSCheckPool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED,
|
||||||
|
bool *isActive)
|
||||||
|
{
|
||||||
|
char *devpath;
|
||||||
|
|
||||||
|
if (virAsprintf(&devpath, "/dev/zvol/%s",
|
||||||
|
pool->def->source.name) == -1)
|
||||||
|
return -1;
|
||||||
|
*isActive = virFileIsDir(devpath);
|
||||||
|
VIR_FREE(devpath);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendZFSParseVol(virStoragePoolObjPtr pool,
|
||||||
|
const char *volume)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
char **tokens;
|
||||||
|
size_t count;
|
||||||
|
char **name_tokens = NULL;
|
||||||
|
char *vol_name;
|
||||||
|
bool is_new_vol = false;
|
||||||
|
virStorageVolDefPtr vol = NULL;
|
||||||
|
|
||||||
|
if (!(tokens = virStringSplitCount(volume, "\t", 0, &count)))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (count != 2)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(name_tokens = virStringSplit(tokens[0], "/", 2)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
vol_name = name_tokens[1];
|
||||||
|
|
||||||
|
vol = virStorageVolDefFindByName(pool, vol_name);
|
||||||
|
|
||||||
|
if (vol == NULL) {
|
||||||
|
if (VIR_ALLOC(vol) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
is_new_vol = true;
|
||||||
|
vol->type = VIR_STORAGE_VOL_BLOCK;
|
||||||
|
|
||||||
|
if (VIR_STRDUP(vol->name, vol_name) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vol->key && VIR_STRDUP(vol->key, tokens[0]) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (vol->target.path == NULL) {
|
||||||
|
if (virAsprintf(&vol->target.path, "%s/%s",
|
||||||
|
pool->def->target.path, vol->name) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virStrToLong_ull(tokens[1], NULL, 10, &vol->target.capacity) < 0) {
|
||||||
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("malformed volsize reported"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_new_vol &&
|
||||||
|
VIR_APPEND_ELEMENT(pool->volumes.objs, pool->volumes.count, vol) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
virStringFreeList(tokens);
|
||||||
|
virStringFreeList(name_tokens);
|
||||||
|
if (is_new_vol && (ret == -1))
|
||||||
|
virStorageVolDefFree(vol);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendZFSFindVols(virStoragePoolObjPtr pool)
|
||||||
|
{
|
||||||
|
virCommandPtr cmd = NULL;
|
||||||
|
char *volumes_list = NULL;
|
||||||
|
char **lines = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $ zfs list -Hp -t volume -o name,volsize -r test
|
||||||
|
* test/vol1 5368709120
|
||||||
|
* test/vol3 1073741824
|
||||||
|
* test/vol4 1572864000
|
||||||
|
* $
|
||||||
|
*
|
||||||
|
* Arguments description:
|
||||||
|
* -t volume -- we want to see only volumes
|
||||||
|
* -o name,volsize -- limit output to name and volume size
|
||||||
|
* -r -- we want to see all the childer of our pool
|
||||||
|
*/
|
||||||
|
cmd = virCommandNewArgList(ZFS,
|
||||||
|
"list", "-Hp",
|
||||||
|
"-t", "volume", "-r",
|
||||||
|
"-o", "name,volsize",
|
||||||
|
pool->def->source.name,
|
||||||
|
NULL);
|
||||||
|
virCommandSetOutputBuffer(cmd, &volumes_list);
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(lines = virStringSplit(volumes_list, "\n", 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (i = 0; lines[i]; i++) {
|
||||||
|
if (STREQ(lines[i], ""))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (virStorageBackendZFSParseVol(pool, lines[i]) < 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virCommandFree(cmd);
|
||||||
|
virStringFreeList(lines);
|
||||||
|
VIR_FREE(volumes_list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendZFSRefreshPool(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool ATTRIBUTE_UNUSED)
|
||||||
|
{
|
||||||
|
virCommandPtr cmd = NULL;
|
||||||
|
char *zpool_props = NULL;
|
||||||
|
char **lines = NULL;
|
||||||
|
char **tokens = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $ zpool get -Hp health,size,free,allocated test
|
||||||
|
* test health ONLINE -
|
||||||
|
* test size 199715979264 -
|
||||||
|
* test free 198899976704 -
|
||||||
|
* test allocated 816002560 -
|
||||||
|
* $
|
||||||
|
*
|
||||||
|
* Here we just provide a list of properties we want to see
|
||||||
|
*/
|
||||||
|
cmd = virCommandNewArgList(ZPOOL,
|
||||||
|
"get", "-Hp",
|
||||||
|
"health,size,free,allocated",
|
||||||
|
pool->def->source.name,
|
||||||
|
NULL);
|
||||||
|
virCommandSetOutputBuffer(cmd, &zpool_props);
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (!(lines = virStringSplit(zpool_props, "\n", 0)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
for (i = 0; lines[i]; i++) {
|
||||||
|
size_t count;
|
||||||
|
char *prop_name;
|
||||||
|
|
||||||
|
if (STREQ(lines[i], ""))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
virStringFreeList(tokens);
|
||||||
|
if (!(tokens = virStringSplitCount(lines[i], "\t", 0, &count)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (count != 4)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
prop_name = tokens[1];
|
||||||
|
|
||||||
|
if (STREQ(prop_name, "free") || STREQ(prop_name, "size") ||
|
||||||
|
STREQ(prop_name, "allocated")) {
|
||||||
|
unsigned long long value;
|
||||||
|
if (virStrToLong_ull(tokens[2], NULL, 10, &value) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (STREQ(prop_name, "free"))
|
||||||
|
pool->def->available = value;
|
||||||
|
else if (STREQ(prop_name, "size"))
|
||||||
|
pool->def->capacity = value;
|
||||||
|
else if (STREQ(prop_name, "allocated"))
|
||||||
|
pool->def->allocation = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Obtain a list of volumes */
|
||||||
|
if (virStorageBackendZFSFindVols(pool) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
virCommandFree(cmd);
|
||||||
|
virStringFreeList(lines);
|
||||||
|
virStringFreeList(tokens);
|
||||||
|
VIR_FREE(zpool_props);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendZFSCreateVol(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool,
|
||||||
|
virStorageVolDefPtr vol)
|
||||||
|
{
|
||||||
|
virCommandPtr cmd = NULL;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
vol->type = VIR_STORAGE_VOL_BLOCK;
|
||||||
|
|
||||||
|
if (vol->target.path != NULL) {
|
||||||
|
/* A target path passed to CreateVol has no meaning */
|
||||||
|
VIR_FREE(vol->target.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virAsprintf(&vol->target.path, "%s/%s",
|
||||||
|
pool->def->target.path, vol->name) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (VIR_STRDUP(vol->key, vol->target.path) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* $ zfs create -o volmode=dev -V 10240K test/volname
|
||||||
|
*
|
||||||
|
* -o volmode=dev -- we want to get volumes exposed as cdev
|
||||||
|
* devices. If we don't specify that zfs
|
||||||
|
* will lookup vfs.zfs.vol.mode sysctl value
|
||||||
|
* -V -- tells to create a volume with the specified size
|
||||||
|
*/
|
||||||
|
cmd = virCommandNewArgList(ZFS, "create", "-o", "volmode=dev",
|
||||||
|
"-V", NULL);
|
||||||
|
virCommandAddArgFormat(cmd, "%lluK",
|
||||||
|
VIR_DIV_UP(vol->target.capacity, 1024));
|
||||||
|
virCommandAddArgFormat(cmd, "%s/%s",
|
||||||
|
pool->def->source.name, vol->name);
|
||||||
|
|
||||||
|
if (virCommandRun(cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (virStorageBackendZFSFindVols(pool) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
virCommandFree(cmd);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
virStorageBackendZFSDeleteVol(virConnectPtr conn ATTRIBUTE_UNUSED,
|
||||||
|
virStoragePoolObjPtr pool,
|
||||||
|
virStorageVolDefPtr vol,
|
||||||
|
unsigned int flags)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
virCommandPtr destroy_cmd = virCommandNewArgList(ZFS, "destroy", NULL);
|
||||||
|
|
||||||
|
virCheckFlags(0, -1);
|
||||||
|
|
||||||
|
virCommandAddArgFormat(destroy_cmd, "%s/%s",
|
||||||
|
pool->def->source.name, vol->name);
|
||||||
|
|
||||||
|
if (virCommandRun(destroy_cmd, NULL) < 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
cleanup:
|
||||||
|
virCommandFree(destroy_cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
virStorageBackend virStorageBackendZFS = {
|
||||||
|
.type = VIR_STORAGE_POOL_ZFS,
|
||||||
|
|
||||||
|
.checkPool = virStorageBackendZFSCheckPool,
|
||||||
|
.refreshPool = virStorageBackendZFSRefreshPool,
|
||||||
|
.createVol = virStorageBackendZFSCreateVol,
|
||||||
|
.deleteVol = virStorageBackendZFSDeleteVol,
|
||||||
|
};
|
29
src/storage/storage_backend_zfs.h
Normal file
29
src/storage/storage_backend_zfs.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* storage_backend_zfs.h: storage backend for ZFS handling
|
||||||
|
*
|
||||||
|
* Copyright (C) 2014 Roman Bogorodskiy
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __VIR_STORAGE_BACKEND_ZFS_H__
|
||||||
|
# define __VIR_STORAGE_BACKEND_ZFS_H__
|
||||||
|
|
||||||
|
# include "storage_backend.h"
|
||||||
|
|
||||||
|
extern virStorageBackend virStorageBackendZFS;
|
||||||
|
|
||||||
|
#endif /* __VIR_STORAGE_BACKEND_ZFS_H__ */
|
@ -1437,6 +1437,7 @@ storageVolLookupByPath(virConnectPtr conn,
|
|||||||
case VIR_STORAGE_POOL_GLUSTER:
|
case VIR_STORAGE_POOL_GLUSTER:
|
||||||
case VIR_STORAGE_POOL_RBD:
|
case VIR_STORAGE_POOL_RBD:
|
||||||
case VIR_STORAGE_POOL_SHEEPDOG:
|
case VIR_STORAGE_POOL_SHEEPDOG:
|
||||||
|
case VIR_STORAGE_POOL_ZFS:
|
||||||
case VIR_STORAGE_POOL_LAST:
|
case VIR_STORAGE_POOL_LAST:
|
||||||
if (VIR_STRDUP(stable_path, path) < 0) {
|
if (VIR_STRDUP(stable_path, path) < 0) {
|
||||||
virStoragePoolObjUnlock(pool);
|
virStoragePoolObjUnlock(pool);
|
||||||
|
@ -1063,6 +1063,9 @@ cmdPoolList(vshControl *ctl, const vshCmd *cmd ATTRIBUTE_UNUSED)
|
|||||||
case VIR_STORAGE_POOL_GLUSTER:
|
case VIR_STORAGE_POOL_GLUSTER:
|
||||||
flags |= VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER;
|
flags |= VIR_CONNECT_LIST_STORAGE_POOLS_GLUSTER;
|
||||||
break;
|
break;
|
||||||
|
case VIR_STORAGE_POOL_ZFS:
|
||||||
|
flags |= VIR_CONNECT_LIST_STORAGE_POOLS_ZFS;
|
||||||
|
break;
|
||||||
case VIR_STORAGE_POOL_LAST:
|
case VIR_STORAGE_POOL_LAST:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user