diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index e9a1e32c9b..38b2763013 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -1670,8 +1670,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 c270b54b4a..0aae6229d1 100644 --- a/include/libvirt/virterror.h +++ b/include/libvirt/virterror.h @@ -235,6 +235,8 @@ typedef enum { VIR_ERR_INVALID_STREAM = 73, /* stream pointer not valid */ VIR_ERR_ARGUMENT_UNSUPPORTED = 74, /* valid API use but unsupported by the given driver */ + VIR_ERR_STORAGE_PROBE_FAILED = 75, /* storage pool proble failed */ + VIR_ERR_STORAGE_POOL_BUILT = 76, /* storage pool already built */ } virErrorNumber; /** diff --git a/src/Makefile.am b/src/Makefile.am index 322c900a3c..14f09e4c8c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -954,6 +954,10 @@ endif if WITH_SECDRIVER_APPARMOR libvirt_driver_storage_la_LIBADD += $(APPARMOR_LIBS) endif +if HAVE_LIBBLKID +libvirt_driver_storage_la_CFLAGS += $(BLKID_CFLAGS) +libvirt_driver_storage_la_LIBADD += $(BLKID_LIBS) +endif if WITH_STORAGE_DIR if WITH_DRIVER_MODULES mod_LTLIBRARIES += libvirt_driver_storage.la diff --git a/src/libvirt.c b/src/libvirt.c index eca919ad0e..13425ff852 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -10466,6 +10466,10 @@ error: * virStoragePoolBuild: * @pool: pointer to storage pool * @flags: future flags, use 0 for now + * @flags: flags to control pool build behaviour + * + * Currently only filesystem pool accepts flags VIR_STORAGE_POOL_BUILD_OVERWRITE + * and VIR_STORAGE_POOL_BUILD_NO_OVERWRITE. * * Build the underlying storage pool * diff --git a/src/storage/storage_backend_fs.c b/src/storage/storage_backend_fs.c index 61d86d207b..02c4c175a3 100644 --- a/src/storage/storage_backend_fs.c +++ b/src/storage/storage_backend_fs.c @@ -37,6 +37,10 @@ #include <libxml/tree.h> #include <libxml/xpath.h> +#if HAVE_LIBBLKID +# include <blkid/blkid.h> +#endif + #include "virterror_internal.h" #include "storage_backend_fs.h" #include "storage_conf.h" @@ -45,6 +49,7 @@ #include "memory.h" #include "xml.h" #include "virfile.h" +#include "logging.h" #define VIR_FROM_THIS VIR_FROM_STORAGE @@ -534,13 +539,172 @@ 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_POOL_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; + virCommandPtr cmd = NULL; + + cmd = virCommandNewArgList(MKFS, + "-t", + format, + device, + NULL); + + if (virCommandRun(cmd, 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 + * @flags controls the pool formating behaviour * * Build a directory or FS based storage pool. * + * If no flag is set, it only makes the directory; If + * VIR_STORAGE_POOL_BUILD_NO_OVERWRITE set, it probes to determine if + * filesystem already exists on the target device, renurning an error + * if exists, or using mkfs to format the target device if not; If + * VIR_STORAGE_POOL_BUILD_OVERWRITE is set, mkfs is always executed, + * any existed data on the target device is overwritten unconditionally. + * * - If it is a FS based pool, mounts the unlying source device on the pool * * Returns 0 on success, -1 on error @@ -551,10 +715,20 @@ virStorageBackendFileSystemBuild(virConnectPtr conn ATTRIBUTE_UNUSED, unsigned int flags) { int err, ret = -1; - char *parent; - char *p; + char *parent = NULL; + char *p = NULL; - virCheckFlags(0, -1); + 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(); @@ -604,7 +778,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 7def53ef3d..54c6739c6a 100644 --- a/src/storage/storage_backend_fs.h +++ b/src/storage/storage_backend_fs.h @@ -29,6 +29,11 @@ # if WITH_STORAGE_FS extern virStorageBackend virStorageBackendFileSystem; extern virStorageBackend virStorageBackendNetFileSystem; +typedef enum { + FILESYSTEM_PROBE_FOUND, + FILESYSTEM_PROBE_NOT_FOUND, + FILESYSTEM_PROBE_ERROR, +} virStoragePoolProbeResult; # endif extern virStorageBackend virStorageBackendDirectory; diff --git a/src/util/virterror.c b/src/util/virterror.c index b50fbfd109..26c4981b06 100644 --- a/src/util/virterror.c +++ b/src/util/virterror.c @@ -1030,6 +1030,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_POOL_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");