]> xenbits.xensource.com Git - libvirt.git/commitdiff
storage: Add fs pool formatting
authorOsier Yang <jyang@redhat.com>
Wed, 31 Aug 2011 13:54:07 +0000 (21:54 +0800)
committerOsier Yang <jyang@redhat.com>
Fri, 2 Sep 2011 13:16:58 +0000 (21:16 +0800)
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.

include/libvirt/libvirt.h.in
include/libvirt/virterror.h
src/Makefile.am
src/libvirt.c
src/storage/storage_backend_fs.c
src/storage/storage_backend_fs.h
src/util/virterror.c

index e9a1e32c9be3e646de274051dbdd4aceab5e5319..38b2763013bbbf1c5f8990a11906f407987df333 100644 (file)
@@ -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 {
index c270b54b4a798c4c3446a45ee95877965d316346..0aae6229d1d9c9b3d8fad7c85881e9ddf4edc4a7 100644 (file)
@@ -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;
 
 /**
index 322c900a3ceac92c5d8a0e34ad82b44c82c63fbb..14f09e4c8c4471497527a3d5ca490d7becfbd977 100644 (file)
@@ -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
index eca919ad0ea8c6fca9aa67b864f096d56b644ce1..13425ff8524e3d0af21cf3175bf991b1a91f12e9 100644 (file)
@@ -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
  *
index 61d86d207bf6754e916166d46c08a399de220e91..02c4c175a3e33b59d93930f4262d842d6997ca5a 100644 (file)
 #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;
index 7def53ef3d3f0e8e8bfc6226fa6d9ef26186a218..54c6739c6ad3fcd96cad1e23f297daed696a03d1 100644 (file)
 # 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;
 
index b50fbfd109276acce809637e90e0d4347e2311da..26c4981b067c9681c77821ffff7a6c4e0731f242 100644 (file)
@@ -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");