[libvirt] [PATCH] QEMU & remote support for virDomainBlockPeek

Richard W.M. Jones rjones at redhat.com
Thu Jun 5 18:42:10 UTC 2008


This patch adds support for virDomainBlockPeek over remote.

Also adds a QEMU driver implementation.

Also there is a minor fix in the Xen driver impl.

Rich.

-- 
Richard Jones, Emerging Technologies, Red Hat  http://et.redhat.com/~rjones
virt-top is 'top' for virtual machines.  Tiny program with many
powerful monitoring features, net stats, disk stats, logging, etc.
http://et.redhat.com/~rjones/virt-top
-------------- next part --------------
? scripts/Makefile
? scripts/Makefile.in
Index: qemud/remote.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote.c,v
retrieving revision 1.35
diff -u -r1.35 remote.c
--- qemud/remote.c	23 May 2008 08:24:44 -0000	1.35
+++ qemud/remote.c	5 Jun 2008 18:43:10 -0000
@@ -890,6 +890,54 @@
 }
 
 static int
+remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED,
+                               struct qemud_client *client,
+                               remote_message_header *req,
+                               remote_domain_block_peek_args *args,
+                               remote_domain_block_peek_ret *ret)
+{
+    virDomainPtr dom;
+    char *path;
+    unsigned long long offset;
+    size_t size;
+    unsigned int flags;
+    CHECK_CONN (client);
+
+    dom = get_nonnull_domain (client->conn, args->dom);
+    if (dom == NULL) {
+        remoteDispatchError (client, req, "%s", _("domain not found"));
+        return -2;
+    }
+    path = args->path;
+    offset = args->offset;
+    size = args->size;
+    flags = args->flags;
+
+    if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
+        remoteDispatchError (client, req,
+                             "%s", _("size > maximum buffer size"));
+        return -2;
+    }
+
+    ret->buffer.buffer_len = size;
+    ret->buffer.buffer_val = malloc (size);
+    if (!ret->buffer.buffer_val) {
+        remoteDispatchError (client, req, "%s", strerror (errno));
+        return -2;
+    }
+
+    if (virDomainBlockPeek (dom, path, offset, size,
+                            ret->buffer.buffer_val, flags) == -1) {
+        /* free (ret->buffer.buffer_val); - caller frees */
+        virDomainFree (dom);
+        return -1;
+    }
+    virDomainFree (dom);
+
+    return 0;
+}
+
+static int
 remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED,
                                   struct qemud_client *client,
                                   remote_message_header *req,
Index: qemud/remote_protocol.x
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote_protocol.x,v
retrieving revision 1.13
diff -u -r1.13 remote_protocol.x
--- qemud/remote_protocol.x	23 May 2008 08:24:44 -0000	1.13
+++ qemud/remote_protocol.x	5 Jun 2008 18:43:11 -0000
@@ -96,6 +96,12 @@
 /* Maximum number of auth types */
 const REMOTE_AUTH_TYPE_LIST_MAX = 20;
 
+/* Maximum length of a block or memory peek buffer message.
+ * Note applications need to be aware of this limit and issue multiple
+ * requests for large amounts of data.
+ */
+const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 65536;
+
 /* UUID.  VIR_UUID_BUFLEN definition comes from libvirt.h */
 typedef opaque remote_uuid[VIR_UUID_BUFLEN];
 
@@ -322,6 +328,18 @@
     hyper tx_drop;
 };
 
+struct remote_domain_block_peek_args {
+    remote_nonnull_domain dom;
+    remote_nonnull_string path;
+    unsigned hyper offset;
+    unsigned size;
+    unsigned flags;
+};
+
+struct remote_domain_block_peek_ret {
+    opaque buffer<REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX>;
+};
+
 struct remote_list_domains_args {
     int maxids;
 };
@@ -1036,7 +1054,9 @@
     REMOTE_PROC_STORAGE_VOL_GET_PATH = 100,
 
     REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
-    REMOTE_PROC_NODE_GET_FREE_MEMORY = 102
+    REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
+
+    REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103
 };
 
 /* Custom RPC structure. */
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.48
diff -u -r1.48 driver.h
--- src/driver.h	5 Jun 2008 13:17:45 -0000	1.48
+++ src/driver.h	5 Jun 2008 18:43:11 -0000
@@ -230,7 +230,8 @@
                     (virDomainPtr domain,
                      const char *path,
                      unsigned long long offset, size_t size,
-                     void *buffer);
+                     void *buffer,
+                     unsigned int flags);
 
 typedef int
     (*virDrvDomainMigratePrepare)
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.144
diff -u -r1.144 libvirt.c
--- src/libvirt.c	5 Jun 2008 13:17:45 -0000	1.144
+++ src/libvirt.c	5 Jun 2008 18:43:14 -0000
@@ -2659,7 +2659,8 @@
     }
 
     if (conn->driver->domainBlockPeek)
-        return conn->driver->domainBlockPeek (dom, path, offset, size, buffer);
+        return conn->driver->domainBlockPeek (dom, path, offset, size,
+                                              buffer, flags);
 
     virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
     return -1;
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.83
diff -u -r1.83 qemu_driver.c
--- src/qemu_driver.c	5 Jun 2008 13:17:45 -0000	1.83
+++ src/qemu_driver.c	5 Jun 2008 18:43:17 -0000
@@ -3163,6 +3163,64 @@
 #endif
 }
 
+static int
+qemudDomainBlockPeek (virDomainPtr dom,
+                      const char *path,
+                      unsigned long long offset, size_t size,
+                      void *buffer,
+                      unsigned int flags ATTRIBUTE_UNUSED)
+{
+    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+    struct qemud_vm *vm = qemudFindVMByUUID (driver, dom->uuid);
+    int i;
+    int fd, ret = -1;
+
+    if (!vm) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+                          _("no domain with matching uuid"));
+        return -1;
+    }
+
+    if (!path || path[0] == '\0') {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
+                         _("NULL or empty path"));
+        return -1;
+    }
+
+    /* Check the path belongs to this domain. */
+    for (i = 0; i < vm->def->ndisks; ++i) {
+        if (STREQ (vm->def->disks[i].src, path)) goto found;
+    }
+    qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
+                      _("invalid path"));
+    return -1;
+
+found:
+    /* The path is correct, now try to open it and get its size. */
+    fd = open (path, O_RDONLY);
+    if (fd == -1) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR,
+                          "%s", strerror (errno));
+        goto done;
+    }
+
+    /* Seek and read. */
+    /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
+     * be 64 bits on all platforms.
+     */
+    if (lseek (fd, offset, SEEK_SET) == (off_t) -1 ||
+        saferead (fd, buffer, size) == (ssize_t) -1) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR,
+                          "%s", strerror (errno));
+        goto done;
+    }
+
+    ret = 0;
+ done:
+    if (fd >= 0) close (fd);
+    return ret;
+}
+
 static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED,
                                      const unsigned char *uuid) {
     struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
@@ -3521,7 +3579,7 @@
     NULL, /* domainMigrateFinish */
     qemudDomainBlockStats, /* domainBlockStats */
     qemudDomainInterfaceStats, /* domainInterfaceStats */
-    NULL, /* domainBlockPeek */
+    qemudDomainBlockPeek, /* domainBlockPeek */
 #if HAVE_NUMACTL
     qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
     qemudNodeGetFreeMemory,  /* getFreeMemory */
Index: src/remote_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/remote_internal.c,v
retrieving revision 1.76
diff -u -r1.76 remote_internal.c
--- src/remote_internal.c	22 May 2008 15:20:25 -0000	1.76
+++ src/remote_internal.c	5 Jun 2008 18:43:20 -0000
@@ -2374,6 +2374,52 @@
     return 0;
 }
 
+static int
+remoteDomainBlockPeek (virDomainPtr domain,
+                       const char *path,
+                       unsigned long long offset,
+                       size_t size,
+                       void *buffer,
+                       unsigned int flags)
+{
+    remote_domain_block_peek_args args;
+    remote_domain_block_peek_ret ret;
+    GET_PRIVATE (domain->conn, -1);
+
+    if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) {
+        errorf (domain->conn, VIR_ERR_RPC,
+                _("block peek request too large for remote protocol, %zi > %d"),
+                size, REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX);
+        return -1;
+    }
+
+    make_nonnull_domain (&args.dom, domain);
+    args.path = (char *) path;
+    args.offset = offset;
+    args.size = size;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_BLOCK_PEEK,
+              (xdrproc_t) xdr_remote_domain_block_peek_args,
+                (char *) &args,
+              (xdrproc_t) xdr_remote_domain_block_peek_ret,
+                (char *) &ret) == -1)
+        return -1;
+
+    if (ret.buffer.buffer_len != size) {
+            errorf (domain->conn, VIR_ERR_RPC,
+                    _("returned buffer is not same size as requested"));
+            free (ret.buffer.buffer_val);
+            return -1;
+    }
+
+    memcpy (buffer, ret.buffer.buffer_val, size);
+    free (ret.buffer.buffer_val);
+
+    return 0;
+}
+
 /*----------------------------------------------------------------------*/
 
 static int
@@ -4784,6 +4830,7 @@
     .domainMigrateFinish = remoteDomainMigrateFinish,
     .domainBlockStats = remoteDomainBlockStats,
     .domainInterfaceStats = remoteDomainInterfaceStats,
+    .domainBlockPeek = remoteDomainBlockPeek,
     .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
     .getFreeMemory = remoteNodeGetFreeMemory,
 };
Index: src/xen_unified.c
===================================================================
RCS file: /data/cvs/libvirt/src/xen_unified.c,v
retrieving revision 1.45
diff -u -r1.45 xen_unified.c
--- src/xen_unified.c	5 Jun 2008 13:17:45 -0000	1.45
+++ src/xen_unified.c	5 Jun 2008 18:43:21 -0000
@@ -1237,7 +1237,7 @@
 static int
 xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path,
                            unsigned long long offset, size_t size,
-                           void *buffer)
+                           void *buffer, unsigned int flags ATTRIBUTE_UNUSED)
 {
     int r;
     GET_PRIVATE (dom->conn);
Index: src/xend_internal.c
===================================================================
RCS file: /data/cvs/libvirt/src/xend_internal.c,v
retrieving revision 1.195
diff -u -r1.195 xend_internal.c
--- src/xend_internal.c	5 Jun 2008 13:17:45 -0000	1.195
+++ src/xend_internal.c	5 Jun 2008 18:43:24 -0000
@@ -4541,7 +4541,6 @@
     struct sexpr *root;
     struct check_path_data data;
     int fd, ret = -1;
-    struct stat statbuf;
 
     priv = (xenUnifiedPrivatePtr) domain->conn->privateData;
 
@@ -4583,7 +4582,7 @@
 
     /* The path is correct, now try to open it and get its size. */
     fd = open (path, O_RDONLY);
-    if (fd == -1 || fstat (fd, &statbuf) == -1) {
+    if (fd == -1) {
         virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
         goto done;
     }


More information about the libvir-list mailing list