]> xenbits.xensource.com Git - libvirt.git/commitdiff
storage: Move virStorageFileGetMetadata to the storage driver
authorPeter Krempa <pkrempa@redhat.com>
Thu, 24 Apr 2014 10:14:01 +0000 (12:14 +0200)
committerPeter Krempa <pkrempa@redhat.com>
Tue, 3 Jun 2014 07:27:23 +0000 (09:27 +0200)
My future work will modify the metadata crawler function to use the
storage driver file APIs to access the files instead of accessing them
directly so that we will be able to request the metadata for remote
files too. To avoid linking the storage driver to every helper file
using the utils code, the backing chain traversal function needs to be
moved to the storage driver source.

Additionally the virt-aa-helper and virstoragetest programs need to be
linked with the storage driver as a result of this change.

cfg.mk
src/Makefile.am
src/libvirt_private.syms
src/qemu/qemu_domain.c
src/security/virt-aa-helper.c
src/storage/storage_driver.c
src/storage/storage_driver.h
src/util/virstoragefile.c
src/util/virstoragefile.h
tests/Makefile.am
tests/virstoragetest.c

diff --git a/cfg.mk b/cfg.mk
index 5ff2721f2c6449aefa36bd773c3bcac92b809817..9e8fceced8244163c1b771139264970830bb31eb 100644 (file)
--- a/cfg.mk
+++ b/cfg.mk
@@ -774,7 +774,7 @@ sc_prohibit_cross_inclusion:
            access/ | conf/) safe="($$dir|conf|util)";;                 \
            locking/) safe="($$dir|util|conf|rpc)";;                    \
            cpu/| network/| node_device/| rpc/| security/| storage/)    \
-             safe="($$dir|util|conf)";;                                \
+             safe="($$dir|util|conf|storage)";;                        \
            xenapi/ | xenxs/ ) safe="($$dir|util|conf|xen)";;           \
            *) safe="($$dir|$(mid_dirs)|util)";;                        \
          esac;                                                         \
index 2397b293de516f9179a2aceba1f7968283ae11d4..d82ca265a644f7bd2a22e9d2f2403b090414a7c7 100644 (file)
@@ -2587,8 +2587,10 @@ virt_aa_helper_LDFLAGS = \
                $(PIE_LDFLAGS) \
                $(NULL)
 virt_aa_helper_LDADD =                                         \
+               libvirt.la                                      \
                libvirt_conf.la                                 \
                libvirt_util.la                                 \
+               libvirt_driver_storage_impl.la                  \
                ../gnulib/lib/libgnu.la
 if WITH_DTRACE_PROBES
 virt_aa_helper_LDADD += libvirt_probes.lo
index cb635cd5e0bb67a75079c15b0a92664d5c255d6a..91f13a4ef1583f20e3c73b0837aa47418d80d5e4 100644 (file)
@@ -1863,9 +1863,9 @@ virStorageFileFeatureTypeToString;
 virStorageFileFormatTypeFromString;
 virStorageFileFormatTypeToString;
 virStorageFileGetLVMKey;
-virStorageFileGetMetadata;
 virStorageFileGetMetadataFromBuf;
 virStorageFileGetMetadataFromFD;
+virStorageFileGetMetadataFromFDInternal;
 virStorageFileGetSCSIKey;
 virStorageFileIsClusterFS;
 virStorageFileParseChainIndex;
index 29177212f0d5aee7aef313851bad8452c8a11b08..be056909a5e6916789a9e19116e5e583aec86ccf 100644 (file)
@@ -40,6 +40,8 @@
 #include "virstoragefile.h"
 #include "virstring.h"
 
+#include "storage/storage_driver.h"
+
 #include <sys/time.h>
 #include <fcntl.h>
 
index 32fc04a4a298e5f913888d39dfefd3fca5bc3a81..bf540b44a35906b426c8b68ea13165b6f8c246c9 100644 (file)
@@ -55,6 +55,8 @@
 #include "virrandom.h"
 #include "virstring.h"
 
+#include "storage/storage_driver.h"
+
 #define VIR_FROM_THIS VIR_FROM_SECURITY
 
 static char *progname;
index f66c25946bf2032f0585881ada6bd936441a16a0..59f6fa809f8a646788d7cc5e99b117c4539778ee 100644 (file)
@@ -49,6 +49,7 @@
 #include "configmake.h"
 #include "virstring.h"
 #include "viraccessapicheck.h"
+#include "dirname.h"
 
 #define VIR_FROM_THIS VIR_FROM_STORAGE
 
@@ -3041,3 +3042,235 @@ virStorageFileAccess(virStorageSourcePtr src,
 
     return src->drv->backend->storageFileAccess(src, mode);
 }
+
+
+/**
+ * Given a starting point START (a directory containing the original
+ * file, if the original file was opened via a relative path; ignored
+ * if NAME is absolute), determine the location of the backing file
+ * NAME (possibly relative), and compute the relative DIRECTORY
+ * (optional) and CANONICAL (mandatory) location of the backing file.
+ * Return 0 on success, negative on error.
+ */
+static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4)
+virFindBackingFile(const char *start, const char *path,
+                   char **directory, char **canonical)
+{
+    /* FIXME - when we eventually allow non-raw network devices, we
+     * must ensure that we handle backing files the same way as qemu.
+     * For a qcow2 top file of gluster://server/vol/img, qemu treats
+     * the relative backing file 'rel' as meaning
+     * 'gluster://server/vol/rel', while the backing file '/abs' is
+     * used as a local file.  But we cannot canonicalize network
+     * devices via canonicalize_file_name(), because they are not part
+     * of the local file system.  */
+    char *combined = NULL;
+    int ret = -1;
+
+    if (*path == '/') {
+        /* Safe to cast away const */
+        combined = (char *)path;
+    } else if (virAsprintf(&combined, "%s/%s", start, path) < 0) {
+        goto cleanup;
+    }
+
+    if (directory && !(*directory = mdir_name(combined))) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virFileAccessibleAs(combined, F_OK, geteuid(), getegid()) < 0) {
+        virReportSystemError(errno,
+                             _("Cannot access backing file '%s'"),
+                             combined);
+        goto cleanup;
+    }
+
+    if (!(*canonical = canonicalize_file_name(combined))) {
+        virReportSystemError(errno,
+                             _("Can't canonicalize path '%s'"), path);
+        goto cleanup;
+    }
+
+    ret = 0;
+
+ cleanup:
+    if (combined != path)
+        VIR_FREE(combined);
+    return ret;
+}
+
+
+/* Recursive workhorse for virStorageFileGetMetadata.  */
+static int
+virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
+                                 const char *canonPath,
+                                 uid_t uid, gid_t gid,
+                                 bool allow_probe,
+                                 virHashTablePtr cycle)
+{
+    int fd;
+    int ret = -1;
+    virStorageSourcePtr backingStore = NULL;
+    int backingFormat;
+
+    VIR_DEBUG("path=%s canonPath=%s dir=%s format=%d uid=%d gid=%d probe=%d",
+              src->path, canonPath, NULLSTR(src->relDir), src->format,
+              (int)uid, (int)gid, allow_probe);
+
+    if (virHashLookup(cycle, canonPath)) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("backing store for %s is self-referential"),
+                       src->path);
+        return -1;
+    }
+
+    if (virHashAddEntry(cycle, canonPath, (void *)1) < 0)
+        return -1;
+
+    if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
+        if ((fd = virFileOpenAs(src->path, O_RDONLY, 0, uid, gid, 0)) < 0) {
+            virReportSystemError(-fd, _("Failed to open file '%s'"),
+                                 src->path);
+            return -1;
+        }
+
+        if (virStorageFileGetMetadataFromFDInternal(src, fd,
+                                                    &backingFormat) < 0) {
+            VIR_FORCE_CLOSE(fd);
+            return -1;
+        }
+
+        if (VIR_CLOSE(fd) < 0)
+            VIR_WARN("could not close file %s", src->path);
+    } else {
+        /* TODO: currently we call this only for local storage */
+        return 0;
+    }
+
+    /* check whether we need to go deeper */
+    if (!src->backingStoreRaw)
+        return 0;
+
+    if (VIR_ALLOC(backingStore) < 0)
+        return -1;
+
+    if (VIR_STRDUP(backingStore->relPath, src->backingStoreRaw) < 0)
+        goto cleanup;
+
+    if (virStorageIsFile(src->backingStoreRaw)) {
+        backingStore->type = VIR_STORAGE_TYPE_FILE;
+
+        if (virFindBackingFile(src->relDir,
+                               src->backingStoreRaw,
+                               &backingStore->relDir,
+                               &backingStore->path) < 0) {
+            /* the backing file is (currently) unavailable, treat this
+             * file as standalone:
+             * backingStoreRaw is kept to mark broken image chains */
+            VIR_WARN("Backing file '%s' of image '%s' is missing.",
+                     src->backingStoreRaw, src->path);
+            ret = 0;
+            goto cleanup;
+        }
+    } else {
+        /* TODO: To satisfy the test case, copy the network URI as path. This
+         * will be removed later. */
+        backingStore->type = VIR_STORAGE_TYPE_NETWORK;
+
+        if (VIR_STRDUP(backingStore->path, src->backingStoreRaw) < 0)
+            goto cleanup;
+    }
+
+    if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
+        backingStore->format = VIR_STORAGE_FILE_RAW;
+    else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
+        backingStore->format = VIR_STORAGE_FILE_AUTO;
+    else
+        backingStore->format = backingFormat;
+
+    if (virStorageFileGetMetadataRecurse(backingStore,
+                                         backingStore->path,
+                                         uid, gid, allow_probe,
+                                         cycle) < 0) {
+        /* if we fail somewhere midway, just accept and return a
+         * broken chain */
+        ret = 0;
+        goto cleanup;
+    }
+
+    src->backingStore = backingStore;
+    backingStore = NULL;
+    ret = 0;
+
+ cleanup:
+    virStorageSourceFree(backingStore);
+    return ret;
+}
+
+
+/**
+ * virStorageFileGetMetadata:
+ *
+ * Extract metadata about the storage volume with the specified
+ * image format. If image format is VIR_STORAGE_FILE_AUTO, it
+ * will probe to automatically identify the format.  Recurses through
+ * the entire chain.
+ *
+ * Open files using UID and GID (or pass -1 for the current user/group).
+ * Treat any backing files without explicit type as raw, unless ALLOW_PROBE.
+ *
+ * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
+ * format, since a malicious guest can turn a raw file into any
+ * other non-raw format at will.
+ *
+ * Caller MUST free result after use via virStorageSourceFree.
+ */
+int
+virStorageFileGetMetadata(virStorageSourcePtr src,
+                          uid_t uid, gid_t gid,
+                          bool allow_probe)
+{
+    VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d",
+              src->path, src->format, (int)uid, (int)gid, allow_probe);
+
+    virHashTablePtr cycle = NULL;
+    char *canonPath = NULL;
+    int ret = -1;
+
+    if (!(cycle = virHashCreate(5, NULL)))
+        return -1;
+
+    if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
+        if (!(canonPath = canonicalize_file_name(src->path))) {
+            virReportSystemError(errno, _("unable to resolve '%s'"),
+                                 src->path);
+            goto cleanup;
+        }
+
+        if (!src->relPath &&
+            VIR_STRDUP(src->relPath, src->path) < 0)
+            goto cleanup;
+
+        if (!src->relDir &&
+            !(src->relDir = mdir_name(src->path))) {
+            virReportOOMError();
+            goto cleanup;
+        }
+    } else {
+        /* TODO: currently unimplemented for non-local storage */
+        ret = 0;
+        goto cleanup;
+    }
+
+    if (src->format <= VIR_STORAGE_FILE_NONE)
+        src->format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW;
+
+    ret = virStorageFileGetMetadataRecurse(src, canonPath, uid, gid,
+                                           allow_probe, cycle);
+
+ cleanup:
+    VIR_FREE(canonPath);
+    virHashFree(cycle);
+    return ret;
+}
index 5452df21a4cf190c7a0d39d0841a5905a5b0cb0e..bd9e9edff6a4a8473ba9e8bc217137fbf62ec432 100644 (file)
@@ -44,6 +44,11 @@ ssize_t virStorageFileReadHeader(virStorageSourcePtr src,
 const char *virStorageFileGetUniqueIdentifier(virStorageSourcePtr src);
 int virStorageFileAccess(virStorageSourcePtr src, int mode);
 
+int virStorageFileGetMetadata(virStorageSourcePtr src,
+                              uid_t uid, gid_t gid,
+                              bool allow_probe)
+    ATTRIBUTE_NONNULL(1);
+
 int storageRegister(void);
 
 #endif /* __VIR_STORAGE_DRIVER_H__ */
index c9b6187fc724e5e5222d0750a0033ea6187def64..4956808c695e656960a9b73c703777f7eb2368c3 100644 (file)
@@ -28,7 +28,6 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <stdlib.h>
-#include "dirname.h"
 #include "viralloc.h"
 #include "virerror.h"
 #include "virlog.h"
@@ -565,62 +564,6 @@ qedGetBackingStore(char **res,
     return BACKING_STORE_OK;
 }
 
-/**
- * Given a starting point START (a directory containing the original
- * file, if the original file was opened via a relative path; ignored
- * if NAME is absolute), determine the location of the backing file
- * NAME (possibly relative), and compute the relative DIRECTORY
- * (optional) and CANONICAL (mandatory) location of the backing file.
- * Return 0 on success, negative on error.
- */
-static int ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4)
-virFindBackingFile(const char *start, const char *path,
-                   char **directory, char **canonical)
-{
-    /* FIXME - when we eventually allow non-raw network devices, we
-     * must ensure that we handle backing files the same way as qemu.
-     * For a qcow2 top file of gluster://server/vol/img, qemu treats
-     * the relative backing file 'rel' as meaning
-     * 'gluster://server/vol/rel', while the backing file '/abs' is
-     * used as a local file.  But we cannot canonicalize network
-     * devices via canonicalize_file_name(), because they are not part
-     * of the local file system.  */
-    char *combined = NULL;
-    int ret = -1;
-
-    if (*path == '/') {
-        /* Safe to cast away const */
-        combined = (char *)path;
-    } else if (virAsprintf(&combined, "%s/%s", start, path) < 0) {
-        goto cleanup;
-    }
-
-    if (directory && !(*directory = mdir_name(combined))) {
-        virReportOOMError();
-        goto cleanup;
-    }
-
-    if (virFileAccessibleAs(combined, F_OK, geteuid(), getegid()) < 0) {
-        virReportSystemError(errno,
-                             _("Cannot access backing file '%s'"),
-                             combined);
-        goto cleanup;
-    }
-
-    if (!(*canonical = canonicalize_file_name(combined))) {
-        virReportSystemError(errno,
-                             _("Can't canonicalize path '%s'"), path);
-        goto cleanup;
-    }
-
-    ret = 0;
-
- cleanup:
-    if (combined != path)
-        VIR_FREE(combined);
-    return ret;
-}
-
 
 static bool
 virStorageFileMatchesMagic(int format,
@@ -1012,7 +955,7 @@ virStorageFileGetMetadataFromBuf(const char *path,
 
 
 /* Internal version that also supports a containing directory name.  */
-static int
+int
 virStorageFileGetMetadataFromFDInternal(virStorageSourcePtr meta,
                                         int fd,
                                         int *backingFormat)
@@ -1111,180 +1054,6 @@ virStorageFileGetMetadataFromFD(const char *path,
 }
 
 
-/* Recursive workhorse for virStorageFileGetMetadata.  */
-static int
-virStorageFileGetMetadataRecurse(virStorageSourcePtr src,
-                                 const char *canonPath,
-                                 uid_t uid, gid_t gid,
-                                 bool allow_probe,
-                                 virHashTablePtr cycle)
-{
-    int fd;
-    int ret = -1;
-    virStorageSourcePtr backingStore = NULL;
-    int backingFormat;
-
-    VIR_DEBUG("path=%s canonPath=%s dir=%s format=%d uid=%d gid=%d probe=%d",
-              src->path, canonPath, NULLSTR(src->relDir), src->format,
-              (int)uid, (int)gid, allow_probe);
-
-    if (virHashLookup(cycle, canonPath)) {
-        virReportError(VIR_ERR_INTERNAL_ERROR,
-                       _("backing store for %s is self-referential"),
-                       src->path);
-        return -1;
-    }
-
-    if (virHashAddEntry(cycle, canonPath, (void *)1) < 0)
-        return -1;
-
-    if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
-        if ((fd = virFileOpenAs(src->path, O_RDONLY, 0, uid, gid, 0)) < 0) {
-            virReportSystemError(-fd, _("Failed to open file '%s'"),
-                                 src->path);
-            return -1;
-        }
-
-        if (virStorageFileGetMetadataFromFDInternal(src, fd,
-                                                    &backingFormat) < 0) {
-            VIR_FORCE_CLOSE(fd);
-            return -1;
-        }
-
-        if (VIR_CLOSE(fd) < 0)
-            VIR_WARN("could not close file %s", src->path);
-    } else {
-        /* TODO: currently we call this only for local storage */
-        return 0;
-    }
-
-    /* check whether we need to go deeper */
-    if (!src->backingStoreRaw)
-        return 0;
-
-    if (VIR_ALLOC(backingStore) < 0)
-        return -1;
-
-    if (VIR_STRDUP(backingStore->relPath, src->backingStoreRaw) < 0)
-        goto cleanup;
-
-    if (virStorageIsFile(src->backingStoreRaw)) {
-        backingStore->type = VIR_STORAGE_TYPE_FILE;
-
-        if (virFindBackingFile(src->relDir,
-                               src->backingStoreRaw,
-                               &backingStore->relDir,
-                               &backingStore->path) < 0) {
-            /* the backing file is (currently) unavailable, treat this
-             * file as standalone:
-             * backingStoreRaw is kept to mark broken image chains */
-            VIR_WARN("Backing file '%s' of image '%s' is missing.",
-                     src->backingStoreRaw, src->path);
-            ret = 0;
-            goto cleanup;
-        }
-    } else {
-        /* TODO: To satisfy the test case, copy the network URI as path. This
-         * will be removed later. */
-        backingStore->type = VIR_STORAGE_TYPE_NETWORK;
-
-        if (VIR_STRDUP(backingStore->path, src->backingStoreRaw) < 0)
-            goto cleanup;
-    }
-
-    if (backingFormat == VIR_STORAGE_FILE_AUTO && !allow_probe)
-        backingStore->format = VIR_STORAGE_FILE_RAW;
-    else if (backingFormat == VIR_STORAGE_FILE_AUTO_SAFE)
-        backingStore->format = VIR_STORAGE_FILE_AUTO;
-    else
-        backingStore->format = backingFormat;
-
-    if (virStorageFileGetMetadataRecurse(backingStore,
-                                         backingStore->path,
-                                         uid, gid, allow_probe,
-                                         cycle) < 0) {
-        /* if we fail somewhere midway, just accept and return a
-         * broken chain */
-        ret = 0;
-        goto cleanup;
-    }
-
-    src->backingStore = backingStore;
-    backingStore = NULL;
-    ret = 0;
-
- cleanup:
-    virStorageSourceFree(backingStore);
-    return ret;
-}
-
-
-/**
- * virStorageFileGetMetadata:
- *
- * Extract metadata about the storage volume with the specified
- * image format. If image format is VIR_STORAGE_FILE_AUTO, it
- * will probe to automatically identify the format.  Recurses through
- * the entire chain.
- *
- * Open files using UID and GID (or pass -1 for the current user/group).
- * Treat any backing files without explicit type as raw, unless ALLOW_PROBE.
- *
- * Callers are advised never to use VIR_STORAGE_FILE_AUTO as a
- * format, since a malicious guest can turn a raw file into any
- * other non-raw format at will.
- *
- * Caller MUST free result after use via virStorageSourceFree.
- */
-int
-virStorageFileGetMetadata(virStorageSourcePtr src,
-                          uid_t uid, gid_t gid,
-                          bool allow_probe)
-{
-    VIR_DEBUG("path=%s format=%d uid=%d gid=%d probe=%d",
-              src->path, src->format, (int)uid, (int)gid, allow_probe);
-
-    virHashTablePtr cycle = NULL;
-    char *canonPath = NULL;
-    int ret = -1;
-
-    if (!(cycle = virHashCreate(5, NULL)))
-        return -1;
-
-    if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK) {
-        if (!(canonPath = canonicalize_file_name(src->path))) {
-            virReportSystemError(errno, _("unable to resolve '%s'"),
-                                 src->path);
-            goto cleanup;
-        }
-
-        if (!src->relPath &&
-            VIR_STRDUP(src->relPath, src->path) < 0)
-            goto cleanup;
-
-        if (!src->relDir &&
-            !(src->relDir = mdir_name(src->path))) {
-            virReportOOMError();
-            goto cleanup;
-        }
-    } else {
-        /* TODO: currently unimplemented for non-local storage */
-        ret = 0;
-        goto cleanup;
-    }
-
-    if (src->format <= VIR_STORAGE_FILE_NONE)
-        src->format = allow_probe ? VIR_STORAGE_FILE_AUTO : VIR_STORAGE_FILE_RAW;
-
-    ret = virStorageFileGetMetadataRecurse(src, canonPath, uid, gid,
-                                           allow_probe, cycle);
-
- cleanup:
-    VIR_FREE(canonPath);
-    virHashFree(cycle);
-    return ret;
-}
-
 /**
  * virStorageFileChainCheckBroken
  *
index 158806b5813f2d9198ad3ccff919c20adbcc0651..99472039f48d6bbf34a12f2737b3bbdce940ed13 100644 (file)
@@ -265,10 +265,9 @@ struct _virStorageSource {
 
 int virStorageFileProbeFormat(const char *path, uid_t uid, gid_t gid);
 
-int virStorageFileGetMetadata(virStorageSourcePtr src,
-                              uid_t uid, gid_t gid,
-                              bool allow_probe)
-    ATTRIBUTE_NONNULL(1);
+int virStorageFileGetMetadataFromFDInternal(virStorageSourcePtr meta,
+                                            int fd,
+                                            int *backingFormat);
 virStorageSourcePtr virStorageFileGetMetadataFromFD(const char *path,
                                                     int fd,
                                                     int format,
index 5ef89408bfbe94db303b94a83663b78b93d38bbf..f9f2b84a611a1adee6628f243581e5d459d0c41e 100644 (file)
@@ -869,7 +869,13 @@ virstringtest_LDADD = $(LDADDS)
 
 virstoragetest_SOURCES = \
        virstoragetest.c testutils.h testutils.c
-virstoragetest_LDADD = $(LDADDS)
+virstoragetest_LDADD = $(LDADDS) \
+       ../src/libvirt.la \
+       ../src/libvirt_conf.la \
+       ../src/libvirt_util.la \
+       ../src/libvirt_driver_storage_impl.la \
+       ../gnulib/lib/libgnu.la \
+       $(NULL)
 
 viridentitytest_SOURCES = \
        viridentitytest.c testutils.h testutils.c
index d49098e836c5a81974533ff887dbff860a908411..fb96c71d07644f49a3035006e0aad3aeb24aa58d 100644 (file)
@@ -31,6 +31,8 @@
 #include "virstring.h"
 #include "dirname.h"
 
+#include "storage/storage_driver.h"
+
 #define VIR_FROM_THIS VIR_FROM_NONE
 
 VIR_LOG_INIT("tests.storagetest");