* This patch adds the ability to make the filesystem for a filesystem
pool during a pool build.
The patch adds two new flags, no overwrite and overwrite, to control
when mkfs gets executed. By default, the patch preserves the
current behavior, i.e., if no flags are specified, pool build on a
filesystem pool only makes the directory on which the filesystem
will be mounted.
If the no overwrite flag is specified, the target device is checked
to determine if a filesystem of the type specified in the pool is
present. If a filesystem of that type is already present, mkfs is
not executed and the build call returns an error. Otherwise, mkfs
is executed and any data present on the device is overwritten.
If the overwrite flag is specified, mkfs is always executed, and any
existing data on the target device is overwritten unconditionally.
Changes per feedback from eblake:
* Made probe & overwrite flags exclusive
* Changed LDFLAGS to LIBADD in Makefile.am
* Added missing virCheckFlags()
* Fixed copyright dates
* Removed cast of char * passed to libblkid and replaced it with a strdup'd copy
* Changed flags to an unsigned int in virsh.c
Changes per feedback from Dan B.
* Changed probe flag to no-overwrite
* Moved libblkid probe code into storage_backend_fs.c
---
include/libvirt/libvirt.h.in | 6 +-
include/libvirt/virterror.h | 2 +
src/Makefile.am | 4 +
src/libvirt_private.syms | 4 +
src/storage/storage_backend_fs.c | 180 +++++++++++++++++++++++++++++++++++++-
src/storage/storage_backend_fs.h | 9 ++-
src/util/virterror.c | 12 +++
tools/virsh.c | 14 +++-
8 files changed, 224 insertions(+), 7 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
index 19d5205..075beee 100644
--- a/include/libvirt/libvirt.h.in
+++ b/include/libvirt/libvirt.h.in
@@ -1126,8 +1126,10 @@ typedef enum {
typedef enum {
VIR_STORAGE_POOL_BUILD_NEW = 0, /* Regular build from scratch */
- VIR_STORAGE_POOL_BUILD_REPAIR = 1, /* Repair / reinitialize */
- VIR_STORAGE_POOL_BUILD_RESIZE = 2 /* Extend existing pool */
+ VIR_STORAGE_POOL_BUILD_REPAIR = (1 << 0), /* Repair / reinitialize */
+ VIR_STORAGE_POOL_BUILD_RESIZE = (1 << 1), /* Extend existing pool */
+ VIR_STORAGE_POOL_BUILD_NO_OVERWRITE = (1 << 2), /* Do not overwrite existing
pool */
+ VIR_STORAGE_POOL_BUILD_OVERWRITE = (1 << 3) /* Overwrite data */
} virStoragePoolBuildFlags;
typedef enum {
diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 3bbb293..8d15671 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -163,6 +163,8 @@ typedef enum {
VIR_WAR_NO_STORAGE, /* failed to start storage */
VIR_ERR_NO_STORAGE_POOL, /* storage pool not found */
VIR_ERR_NO_STORAGE_VOL, /* storage pool not found */
+ VIR_ERR_STORAGE_PROBE_FAILED, /* storage pool probe failed */
+ VIR_ERR_STORAGE_PROBE_BUILT, /* storage pool already built */
VIR_WAR_NO_NODE, /* failed to start node driver */
VIR_ERR_INVALID_NODE_DEVICE,/* invalid node device object */
VIR_ERR_NO_NODE_DEVICE,/* node device not found */
diff --git a/src/Makefile.am b/src/Makefile.am
index 6bdf73c..bc4db48 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -773,6 +773,10 @@ libvirt_driver_storage_la_LDFLAGS += -module -avoid-version
endif
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_SOURCES)
libvirt_driver_storage_la_SOURCES += $(STORAGE_DRIVER_FS_SOURCES)
+if HAVE_LIBBLKID
+libvirt_driver_storage_la_CFLAGS += $(BLKID_CFLAGS)
+libvirt_driver_storage_la_LIBADD += $(BLKID_LIBS)
+endif
endif
if WITH_STORAGE_LVM
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 6cb3d66..abe9a2a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -624,6 +624,10 @@ virStorageFileGetMetadata;
virStorageFileGetMetadataFromFD;
virStorageFileIsSharedFS;
+# storage_backend_fs.h
+virStorageBackendFileSystemProbeLibblkid;
+virStorageBackendFileSystemProbeDummy;
+
# threads.h
virMutexInit;
virMutexDestroy;
diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c
index f0cd770..eb083cd 100644
--- a/src/storage/storage_backend_fs.c
+++ b/src/storage/storage_backend_fs.c
@@ -34,6 +34,10 @@
#include <unistd.h>
#include <string.h>
+#if HAVE_LIBBLKID
+# include <blkid/blkid.h>
+#endif
+
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
@@ -45,6 +49,7 @@
#include "util.h"
#include "memory.h"
#include "xml.h"
+#include "logging.h"
#define VIR_FROM_THIS VIR_FROM_STORAGE
@@ -483,6 +488,157 @@ virStorageBackendFileSystemStart(virConnectPtr conn
ATTRIBUTE_UNUSED,
#endif /* WITH_STORAGE_FS */
+#if HAVE_LIBBLKID
+static virStoragePoolProbeResult
+virStorageBackendFileSystemProbe(const char *device,
+ const char *format) {
+
+ virStoragePoolProbeResult ret = FILESYSTEM_PROBE_ERROR;
+ blkid_probe probe = NULL;
+ const char *fstype = NULL;
+ char *names[2], *libblkid_format = NULL;
+
+ VIR_DEBUG("Probing for existing filesystem of type %s on device %s",
+ format, device);
+
+ if (blkid_known_fstype(format) == 0) {
+ virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
+ _("Not capable of probing for "
+ "filesystem of type %s"),
+ format);
+ goto error;
+ }
+
+ probe = blkid_new_probe_from_filename(device);
+ if (probe == NULL) {
+ virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
+ _("Failed to create filesystem probe "
+ "for device %s"),
+ device);
+ goto error;
+ }
+
+ if ((libblkid_format = strdup(format)) == NULL) {
+ virReportOOMError();
+ goto error;
+ }
+
+ names[0] = libblkid_format;
+ names[1] = NULL;
+
+ blkid_probe_filter_superblocks_type(probe,
+ BLKID_FLTR_ONLYIN,
+ names);
+
+ if (blkid_do_probe(probe) != 0) {
+ VIR_INFO("No filesystem of type '%s' found on device
'%s'",
+ format, device);
+ ret = FILESYSTEM_PROBE_NOT_FOUND;
+ } else if (blkid_probe_lookup_value(probe, "TYPE", &fstype, NULL) == 0)
{
+ virStorageReportError(VIR_ERR_STORAGE_PROBE_BUILT,
+ _("Existing filesystem of type '%s' found on
"
+ "device '%s'"),
+ fstype, device);
+ ret = FILESYSTEM_PROBE_FOUND;
+ }
+
+ if (blkid_do_probe(probe) != 1) {
+ virStorageReportError(VIR_ERR_STORAGE_PROBE_FAILED,
+ _("Found additional probes to run, "
+ "filesystem probing may be incorrect"));
+ ret = FILESYSTEM_PROBE_ERROR;
+ }
+
+error:
+ VIR_FREE(libblkid_format);
+
+ if (probe != NULL) {
+ blkid_free_probe(probe);
+ }
+
+ return ret;
+}
+
+#else /* #if HAVE_LIBBLKID */
+
+static virStoragePoolProbeResult
+virStorageBackendFileSystemProbe(const char *device ATTRIBUTE_UNUSED,
+ const char *format ATTRIBUTE_UNUSED)
+{
+ virStorageReportError(VIR_ERR_OPERATION_INVALID,
+ _("probing for filesystems is unsupported "
+ "by this build"));
+
+ return FILESYSTEM_PROBE_ERROR;
+}
+
+#endif /* #if HAVE_LIBBLKID */
+
+static int
+virStorageBackendExecuteMKFS(const char *device,
+ const char *format)
+{
+ int ret = 0;
+ const char *mkfsargv[5] = { MKFS,
+ "-t",
+ format,
+ device,
+ NULL };
+
+ if (virRun(mkfsargv, NULL) < 0) {
+ virReportSystemError(errno,
+ _("Failed to make filesystem of "
+ "type '%s' on device '%s'"),
+ format, device);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int
+virStorageBackendMakeFileSystem(virStoragePoolObjPtr pool,
+ unsigned int flags)
+{
+ const char *device = NULL, *format = NULL;
+ bool ok_to_mkfs = false;
+ int ret = -1;
+
+ if (pool->def->source.devices == NULL) {
+ virStorageReportError(VIR_ERR_OPERATION_INVALID,
+ _("No source device specified when formatting pool
'%s'"),
+ pool->def->name);
+ goto error;
+ }
+
+ device = pool->def->source.devices[0].path;
+ format = virStoragePoolFormatFileSystemTypeToString(pool->def->source.format);
+ VIR_DEBUG("source device: '%s' format: '%s'", device,
format);
+
+ if (!virFileExists(device)) {
+ virStorageReportError(VIR_ERR_OPERATION_INVALID,
+ _("Source device does not exist when formatting pool
'%s'"),
+ pool->def->name);
+ goto error;
+ }
+
+ if (flags & VIR_STORAGE_POOL_BUILD_OVERWRITE) {
+ ok_to_mkfs = true;
+ } else if (flags & VIR_STORAGE_POOL_BUILD_NO_OVERWRITE &&
+ virStorageBackendFileSystemProbe(device, format) ==
+ FILESYSTEM_PROBE_NOT_FOUND) {
+ ok_to_mkfs = true;
+ }
+
+ if (ok_to_mkfs) {
+ ret = virStorageBackendExecuteMKFS(device, format);
+ }
+
+error:
+ return ret;
+}
+
/**
* @conn connection to report errors against
* @pool storage pool to build
@@ -496,12 +652,24 @@ virStorageBackendFileSystemStart(virConnectPtr conn
ATTRIBUTE_UNUSED,
static int
virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED,
virStoragePoolObjPtr pool,
- unsigned int flags ATTRIBUTE_UNUSED)
+ unsigned int flags)
{
int err, ret = -1;
- char *parent;
+ char *parent = NULL;
char *p;
+ virCheckFlags(VIR_STORAGE_POOL_BUILD_OVERWRITE |
+ VIR_STORAGE_POOL_BUILD_NO_OVERWRITE, ret);
+
+ if (flags == (VIR_STORAGE_POOL_BUILD_OVERWRITE |
+ VIR_STORAGE_POOL_BUILD_NO_OVERWRITE)) {
+
+ virStorageReportError(VIR_ERR_OPERATION_INVALID,
+ _("Overwrite and no overwrite flags"
+ " are mutually exclusive"));
+ goto error;
+ }
+
if ((parent = strdup(pool->def->target.path)) == NULL) {
virReportOOMError();
goto error;
@@ -550,7 +718,13 @@ virStorageBackendFileSystemBuild(virConnectPtr conn
ATTRIBUTE_UNUSED,
goto error;
}
}
- ret = 0;
+
+ if (flags != 0) {
+ ret = virStorageBackendMakeFileSystem(pool, flags);
+ } else {
+ ret = 0;
+ }
+
error:
VIR_FREE(parent);
return ret;
diff --git a/src/storage/storage_backend_fs.h b/src/storage/storage_backend_fs.h
index 7def53e..f4ae4e3 100644
--- a/src/storage/storage_backend_fs.h
+++ b/src/storage/storage_backend_fs.h
@@ -29,7 +29,14 @@
# if WITH_STORAGE_FS
extern virStorageBackend virStorageBackendFileSystem;
extern virStorageBackend virStorageBackendNetFileSystem;
-# endif
+
+typedef enum {
+ FILESYSTEM_PROBE_FOUND,
+ FILESYSTEM_PROBE_NOT_FOUND,
+ FILESYSTEM_PROBE_ERROR,
+} virStoragePoolProbeResult;
+
extern virStorageBackend virStorageBackendDirectory;
+# endif
#endif /* __VIR_STORAGE_BACKEND_FS_H__ */
diff --git a/src/util/virterror.c b/src/util/virterror.c
index 96dd1e7..bd845fb 100644
--- a/src/util/virterror.c
+++ b/src/util/virterror.c
@@ -1019,6 +1019,18 @@ virErrorMsg(virErrorNumber error, const char *info)
else
errmsg = _("Storage volume not found: %s");
break;
+ case VIR_ERR_STORAGE_PROBE_FAILED:
+ if (info == NULL)
+ errmsg = _("Storage pool probe failed");
+ else
+ errmsg = _("Storage pool probe failed: %s");
+ break;
+ case VIR_ERR_STORAGE_PROBE_BUILT:
+ if (info == NULL)
+ errmsg = _("Storage pool already built");
+ else
+ errmsg = _("Storage pool already built: %s");
+ break;
case VIR_ERR_INVALID_STORAGE_POOL:
if (info == NULL)
errmsg = _("invalid storage pool pointer in");
diff --git a/tools/virsh.c b/tools/virsh.c
index 1279f41..e4bc100 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -4672,6 +4672,9 @@ static const vshCmdInfo info_pool_build[] = {
static const vshCmdOptDef opts_pool_build[] = {
{"pool", VSH_OT_DATA, VSH_OFLAG_REQ, N_("pool name or uuid")},
+ {"no-overwrite", VSH_OT_BOOL, 0, N_("do not overwrite an existing
"
+ "pool of this type")},
+ {"overwrite", VSH_OT_BOOL, 0, N_("overwrite any existing
data")},
{NULL, 0, 0, NULL}
};
@@ -4680,6 +4683,7 @@ cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
{
virStoragePoolPtr pool;
int ret = TRUE;
+ unsigned int flags = 0;
char *name;
if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
@@ -4688,7 +4692,15 @@ cmdPoolBuild(vshControl *ctl, const vshCmd *cmd)
if (!(pool = vshCommandOptPool(ctl, cmd, "pool", &name)))
return FALSE;
- if (virStoragePoolBuild(pool, 0) == 0) {
+ if (vshCommandOptBool (cmd, "no-overwrite")) {
+ flags |= VIR_STORAGE_POOL_BUILD_NO_OVERWRITE;
+ }
+
+ if (vshCommandOptBool (cmd, "overwrite")) {
+ flags |= VIR_STORAGE_POOL_BUILD_OVERWRITE;
+ }
+
+ if (virStoragePoolBuild(pool, flags) == 0) {
vshPrint(ctl, _("Pool %s built\n"), name);
} else {
vshError(ctl, _("Failed to build pool %s"), name);
--
1.7.0.1