[Libguestfs] [PATCH v3 5/6] lib: qemu: Add accessor to test if qemu does mandatory locking.

Richard W.M. Jones rjones at redhat.com
Tue Sep 12 17:04:23 UTC 2017


QEMU >= 2.10 started to do mandatory locking.  This checks the QMP
schema to see if we are using that version of qemu.  (Note it is
sometimes disabled in downstream builds, and it was also enabled in
upstream prereleases with version 2.9.9x, so we cannot just check the
version number).
---
 lib/guestfs-internal.h |  1 +
 lib/qemu.c             | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/lib/guestfs-internal.h b/lib/guestfs-internal.h
index 2ca258cb3..ab839de4d 100644
--- a/lib/guestfs-internal.h
+++ b/lib/guestfs-internal.h
@@ -983,6 +983,7 @@ extern struct qemu_data *guestfs_int_test_qemu (guestfs_h *g);
 extern struct version guestfs_int_qemu_version (guestfs_h *g, struct qemu_data *);
 extern int guestfs_int_qemu_supports (guestfs_h *g, const struct qemu_data *, const char *option);
 extern int guestfs_int_qemu_supports_device (guestfs_h *g, const struct qemu_data *, const char *device_name);
+extern int guestfs_int_qemu_mandatory_locking (guestfs_h *g, const struct qemu_data *data);
 extern char *guestfs_int_drive_source_qemu_param (guestfs_h *g, const struct drive_source *src);
 extern bool guestfs_int_discard_possible (guestfs_h *g, struct drive *drv, const struct version *qemu_version);
 extern char *guestfs_int_qemu_escape_param (guestfs_h *g, const char *param);
diff --git a/lib/qemu.c b/lib/qemu.c
index 1549bb33a..9ab4efec8 100644
--- a/lib/qemu.c
+++ b/lib/qemu.c
@@ -580,6 +580,71 @@ guestfs_int_qemu_supports_device (guestfs_h *g,
   return strstr (data->qemu_devices, device_name) != NULL;
 }
 
+/* GCC can't work out that the YAJL_IS_<foo> test is sufficient to
+ * ensure that YAJL_GET_<foo> later doesn't return NULL.
+ */
+#pragma GCC diagnostic push
+#if defined(__GNUC__) && __GNUC__ >= 6 /* gcc >= 6 */
+#pragma GCC diagnostic ignored "-Wnull-dereference"
+#endif
+
+/**
+ * Test if the qemu binary uses mandatory file locking, added in
+ * QEMU >= 2.10 (but sometimes disabled).
+ */
+int
+guestfs_int_qemu_mandatory_locking (guestfs_h *g,
+                                    const struct qemu_data *data)
+{
+  const char *return_path[] = { "return", NULL };
+  const char *meta_type_path[] = { "meta-type", NULL };
+  const char *members_path[] = { "members", NULL };
+  const char *name_path[] = { "name", NULL };
+  yajl_val schema, v, meta_type, members, m, name;
+  size_t i, j;
+
+  /* If there's no QMP schema, fall back to checking the version. */
+  if (!data->qmp_schema_tree) {
+  fallback:
+    return guestfs_int_version_ge (&data->qemu_version, 2, 10, 0);
+  }
+
+  /* Top element of qmp_schema_tree is the { "return": ... } wrapper.
+   * Extract the schema from the wrapper.  Note the returned ‘schema’
+   * will be an array.
+   */
+  schema = yajl_tree_get (data->qmp_schema_tree, return_path, yajl_t_array);
+  if (schema == NULL)
+    goto fallback;
+  assert (YAJL_IS_ARRAY(schema));
+
+  /* Now look for any member of the array which has:
+   * { "meta-type": "object",
+   *   "members": [ ... { "name": "locking", ... } ... ] ... }
+   */
+  for (i = 0; i < YAJL_GET_ARRAY(schema)->len; ++i) {
+    v = YAJL_GET_ARRAY(schema)->values[i];
+    meta_type = yajl_tree_get (v, meta_type_path, yajl_t_string);
+    if (meta_type && YAJL_IS_STRING (meta_type) &&
+        STREQ (YAJL_GET_STRING (meta_type), "object")) {
+      members = yajl_tree_get (v, members_path, yajl_t_array);
+      if (members) {
+        for (j = 0; j < YAJL_GET_ARRAY(members)->len; ++j) {
+          m = YAJL_GET_ARRAY(members)->values[j];
+          name = yajl_tree_get (m, name_path, yajl_t_string);
+          if (name && YAJL_IS_STRING (name) &&
+              STREQ (YAJL_GET_STRING (name), "locking"))
+            return 1;
+        }
+      }
+    }
+  }
+
+  return 0;
+}
+
+#pragma GCC diagnostic pop
+
 /**
  * Escape a qemu parameter.
  *
-- 
2.13.2




More information about the Libguestfs mailing list