[libvirt] [PATCH] virDomainMemoryPeek - peek into guest memory

Richard W.M. Jones rjones at redhat.com
Mon Jun 9 12:47:09 UTC 2008


Here's a patch which should address all concerns raised, although I
left the VIR_MEMORY_VIRTUAL flag because I still think it's important
to have it.

Please note to whomever is maintaining libvirt in Fedora that there is
a change to the specfile.

Rich.

-- 
Richard Jones, Emerging Technologies, Red Hat  http://et.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines.  Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
-------------- next part --------------
Index: configure.in
===================================================================
RCS file: /data/cvs/libvirt/configure.in,v
retrieving revision 1.152
diff -u -p -r1.152 configure.in
--- configure.in	5 Jun 2008 13:17:45 -0000	1.152
+++ configure.in	9 Jun 2008 12:48:07 -0000
@@ -99,6 +99,8 @@ AC_PATH_PROG([TAR], [tar], [/bin/tar])
 AC_PATH_PROG([XMLLINT], [xmllint], [/usr/bin/xmllint])
 AC_PATH_PROG([XSLTPROC], [xsltproc], [/usr/bin/xsltproc])
 
+AC_PROG_MKDIR_P
+
 dnl External programs that we can use if they are available.
 dnl We will hard-code paths to these programs unless we cannot
 dnl detect them, in which case we'll search for the program
Index: libvirt.spec.in
===================================================================
RCS file: /data/cvs/libvirt/libvirt.spec.in,v
retrieving revision 1.84
diff -u -p -r1.84 libvirt.spec.in
--- libvirt.spec.in	22 May 2008 15:29:50 -0000	1.84
+++ libvirt.spec.in	9 Jun 2008 12:48:08 -0000
@@ -139,6 +139,7 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/*.a
 rm -f $RPM_BUILD_ROOT%{_libdir}/python*/site-packages/*.la
 rm -f $RPM_BUILD_ROOT%{_libdir}/python*/site-packages/*.a
 install -d -m 0755 $RPM_BUILD_ROOT%{_localstatedir}/run/libvirt/
+install -d -m 0755 $RPM_BUILD_ROOT%{_localstatedir}/cache/libvirt/
 
 # We don't want to install /etc/libvirt/qemu/networks in the main %files list
 # because if the admin wants to delete the default network completely, we don't
@@ -202,6 +203,7 @@ fi
 %dir %{_datadir}/libvirt/networks/
 %{_datadir}/libvirt/networks/default.xml
 %dir %{_localstatedir}/run/libvirt/
+%dir %{_localstatedir}/cache/libvirt/
 %dir %{_localstatedir}/lib/libvirt/
 %if %{with_polkit}
 %{_datadir}/PolicyKit/policy/libvirtd.policy
Index: docs/hvsupport.html.in
===================================================================
RCS file: /data/cvs/libvirt/docs/hvsupport.html.in,v
retrieving revision 1.2
diff -u -p -r1.2 hvsupport.html.in
--- docs/hvsupport.html.in	5 Jun 2008 13:17:45 -0000	1.2
+++ docs/hvsupport.html.in	9 Jun 2008 12:48:08 -0000
@@ -145,9 +145,9 @@ updated on <i>2008-06-05</i>.
       <tr>
         <td> virDomainBlockPeek </td>
         <td> 0.4.3 </td>
-        <td> x </td>
-        <td> x </td>
-        <td> x </td>
+        <td> 0.4.3 </td>
+        <td> 0.4.3 </td>
+        <td> 0.4.3 </td>
         <td> x </td>
       </tr>
       <tr>
@@ -487,6 +487,14 @@ updated on <i>2008-06-05</i>.
         <td colspan="4"> not a HV function </td>
       </tr>
       <tr>
+        <td> virDomainMemoryPeek </td>
+        <td> 0.4.3 </td>
+        <td> x </td>
+        <td> 0.4.3 </td>
+        <td> 0.4.3 </td>
+        <td> x </td>
+      </tr>
+      <tr>
         <td> virNodeGetInfo </td>
         <td> 0.1.0 </td>
         <td> &#x2265; 0.1.0 </td>
Index: include/libvirt/libvirt.h
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h,v
retrieving revision 1.75
diff -u -p -r1.75 libvirt.h
--- include/libvirt/libvirt.h	5 Jun 2008 13:17:45 -0000	1.75
+++ include/libvirt/libvirt.h	9 Jun 2008 12:48:09 -0000
@@ -537,6 +537,17 @@ int                     virDomainBlockPe
                                             void *buffer,
                                             unsigned int flags);
 
+/* Memory peeking flags. */
+typedef enum {
+  VIR_MEMORY_VIRTUAL              = 1, /* addresses are virtual addresses */
+} virDomainMemoryFlags;
+
+int                     virDomainMemoryPeek (virDomainPtr dom,
+                                             unsigned long long start,
+                                             size_t size,
+                                             void *buffer,
+                                             unsigned int flags);
+
 /*
  * defined but not running domains
  */
Index: include/libvirt/libvirt.h.in
===================================================================
RCS file: /data/cvs/libvirt/include/libvirt/libvirt.h.in,v
retrieving revision 1.50
diff -u -p -r1.50 libvirt.h.in
--- include/libvirt/libvirt.h.in	5 Jun 2008 13:17:45 -0000	1.50
+++ include/libvirt/libvirt.h.in	9 Jun 2008 12:48:10 -0000
@@ -537,6 +537,17 @@ int                     virDomainBlockPe
                                             void *buffer,
                                             unsigned int flags);
 
+/* Memory peeking flags. */
+typedef enum {
+  VIR_MEMORY_VIRTUAL              = 1, /* addresses are virtual addresses */
+} virDomainMemoryFlags;
+
+int                     virDomainMemoryPeek (virDomainPtr dom,
+                                             unsigned long long start,
+                                             size_t size,
+                                             void *buffer,
+                                             unsigned int flags);
+
 /*
  * defined but not running domains
  */
Index: qemud/libvirtd.init.in
===================================================================
RCS file: /data/cvs/libvirt/qemud/libvirtd.init.in,v
retrieving revision 1.6
diff -u -p -r1.6 libvirtd.init.in
--- qemud/libvirtd.init.in	15 May 2008 06:12:32 -0000	1.6
+++ qemud/libvirtd.init.in	9 Jun 2008 12:48:10 -0000
@@ -51,6 +51,8 @@ RETVAL=0
 
 start() {
     echo -n $"Starting $SERVICE daemon: "
+    mkdir -p @localstatedir@/cache/libvirt
+    rm -rf @localstatedir@/cache/libvirt/*
     KRB5_KTNAME=$KRB5_KTNAME daemon --check $SERVICE $PROCESS --daemon $LIBVIRTD_CONFIG_ARGS $LIBVIRTD_ARGS
     RETVAL=$?
     echo
@@ -66,6 +68,7 @@ stop() {
     if [ $RETVAL -eq 0 ]; then
         rm -f @localstatedir@/lock/subsys/$SERVICE
         rm -f @localstatedir@/run/$SERVICE.pid
+	rm -rf @localstatedir@/cache/libvirt/*
     fi
 }
 
Index: qemud/remote.c
===================================================================
RCS file: /data/cvs/libvirt/qemud/remote.c,v
retrieving revision 1.37
diff -u -p -r1.37 remote.c
--- qemud/remote.c	6 Jun 2008 10:52:01 -0000	1.37
+++ qemud/remote.c	9 Jun 2008 12:48:13 -0000
@@ -49,6 +49,7 @@
 #endif
 
 #include "internal.h"
+#include "memory.h"
 #include "qemud.h"
 #include "memory.h"
 
@@ -939,6 +940,53 @@ remoteDispatchDomainBlockPeek (struct qe
 }
 
 static int
+remoteDispatchDomainMemoryPeek (struct qemud_server *server ATTRIBUTE_UNUSED,
+                                struct qemud_client *client,
+                                remote_message_header *req,
+                                remote_domain_memory_peek_args *args,
+                                remote_domain_memory_peek_ret *ret)
+{
+    virDomainPtr dom;
+    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;
+    }
+    offset = args->offset;
+    size = args->size;
+    flags = args->flags;
+
+    if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
+        remoteDispatchError (client, req,
+                             "%s", _("size > maximum buffer size"));
+        virDomainFree (dom);
+        return -2;
+    }
+
+    ret->buffer.buffer_len = size;
+    if (VIR_ALLOC_N (ret->buffer.buffer_val, size) < 0) {
+        remoteDispatchError (client, req, "%s", strerror (errno));
+        virDomainFree (dom);
+        return -2;
+    }
+
+    if (virDomainMemoryPeek (dom, 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.14
diff -u -p -r1.14 remote_protocol.x
--- qemud/remote_protocol.x	5 Jun 2008 21:12:27 -0000	1.14
+++ qemud/remote_protocol.x	9 Jun 2008 12:48:13 -0000
@@ -96,12 +96,18 @@ const REMOTE_AUTH_SASL_DATA_MAX = 65536;
 /* Maximum number of auth types */
 const REMOTE_AUTH_TYPE_LIST_MAX = 20;
 
-/* Maximum length of a block or memory peek buffer message.
+/* Maximum length of a block 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;
 
+/* Maximum length of a 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_MEMORY_PEEK_BUFFER_MAX = 65536;
+
 /* UUID.  VIR_UUID_BUFLEN definition comes from libvirt.h */
 typedef opaque remote_uuid[VIR_UUID_BUFLEN];
 
@@ -340,6 +346,17 @@ struct remote_domain_block_peek_ret {
     opaque buffer<REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX>;
 };
 
+struct remote_domain_memory_peek_args {
+    remote_nonnull_domain dom;
+    unsigned hyper offset;
+    unsigned size;
+    unsigned flags;
+};
+
+struct remote_domain_memory_peek_ret {
+    opaque buffer<REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX>;
+};
+
 struct remote_list_domains_args {
     int maxids;
 };
@@ -1056,7 +1073,8 @@ enum remote_procedure {
     REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
     REMOTE_PROC_NODE_GET_FREE_MEMORY = 102,
 
-    REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103
+    REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103,
+    REMOTE_PROC_DOMAIN_MEMORY_PEEK = 104
 };
 
 /* Custom RPC structure. */
Index: src/Makefile.am
===================================================================
RCS file: /data/cvs/libvirt/src/Makefile.am,v
retrieving revision 1.81
diff -u -p -r1.81 Makefile.am
--- src/Makefile.am	29 May 2008 19:27:04 -0000	1.81
+++ src/Makefile.am	9 Jun 2008 12:48:13 -0000
@@ -149,4 +149,8 @@ else
 EXTRA_DIST += parthelper.c
 endif
 
+# Create the /var/cache/libvirt directory when installing.
+install-exec-local:
+	$(MKDIR_P) $(DESTDIR)@localstatedir@/cache/libvirt
+
 CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda
Index: src/driver.h
===================================================================
RCS file: /data/cvs/libvirt/src/driver.h,v
retrieving revision 1.49
diff -u -p -r1.49 driver.h
--- src/driver.h	5 Jun 2008 21:12:27 -0000	1.49
+++ src/driver.h	9 Jun 2008 12:48:14 -0000
@@ -234,6 +234,13 @@ typedef int
                      unsigned int flags);
 
 typedef int
+    (*virDrvDomainMemoryPeek)
+                    (virDomainPtr domain,
+                     unsigned long long start, size_t size,
+                     void *buffer,
+                     unsigned int flags);
+
+typedef int
     (*virDrvDomainMigratePrepare)
                     (virConnectPtr dconn,
                      char **cookie,
@@ -346,6 +353,7 @@ struct _virDriver {
     virDrvDomainBlockStats      domainBlockStats;
     virDrvDomainInterfaceStats  domainInterfaceStats;
     virDrvDomainBlockPeek	domainBlockPeek;
+    virDrvDomainMemoryPeek      domainMemoryPeek;
     virDrvNodeGetCellsFreeMemory	nodeGetCellsFreeMemory;
     virDrvNodeGetFreeMemory		getFreeMemory;
 };
Index: src/libvirt.c
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt.c,v
retrieving revision 1.145
diff -u -p -r1.145 libvirt.c
--- src/libvirt.c	5 Jun 2008 21:12:27 -0000	1.145
+++ src/libvirt.c	9 Jun 2008 12:48:17 -0000
@@ -2619,6 +2619,10 @@ virDomainInterfaceStats (virDomainPtr do
  *
  * 'buffer' is the return buffer and must be at least 'size' bytes.
  *
+ * NB. The remote driver imposes a 64K byte limit on 'size'.
+ * For your program to be able to work reliably over a remote
+ * connection you should split large requests to <= 65536 bytes.
+ *
  * Returns: 0 in case of success or -1 in case of failure.
  */
 int
@@ -2666,6 +2670,96 @@ virDomainBlockPeek (virDomainPtr dom,
     return -1;
 }
 
+/**
+ * virDomainMemoryPeek:
+ * @dom: pointer to the domain object
+ * @start: start of memory to peek
+ * @size: size of memory to peek
+ * @buffer: return buffer (must be at least size bytes)
+ * @flags: flags, see below
+ *
+ * This function allows you to read the contents of a domain's
+ * memory.
+ *
+ * The memory which is read is controlled by the 'start', 'size'
+ * and 'flags' parameters.
+ *
+ * If 'flags' is VIR_MEMORY_VIRTUAL then the 'start' and 'size'
+ * parameters are interpreted as virtual memory addresses for
+ * whichever task happens to be running on the domain at the
+ * moment.  Although this sounds haphazard it is in fact what
+ * you want in order to read Linux kernel state, because it
+ * ensures that pointers in the kernel image can be interpreted
+ * coherently.
+ *
+ * 'buffer' is the return buffer and must be at least 'size' bytes.
+ * 'size' may be 0 to test if the call would succeed.
+ *
+ * NB. The remote driver imposes a 64K byte limit on 'size'.
+ * For your program to be able to work reliably over a remote
+ * connection you should split large requests to <= 65536 bytes.
+ *
+ * Returns: 0 in case of success or -1 in case of failure.
+ */
+int
+virDomainMemoryPeek (virDomainPtr dom,
+                     unsigned long long start /* really 64 bits */,
+                     size_t size,
+                     void *buffer,
+                     unsigned int flags)
+{
+    virConnectPtr conn;
+    DEBUG ("domain=%p, start=%lld, size=%zi, buffer=%p, flags=%d",
+           dom, start, size, buffer, flags);
+
+    if (!VIR_IS_CONNECTED_DOMAIN (dom)) {
+        virLibDomainError (NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__);
+        return -1;
+    }
+    conn = dom->conn;
+
+    /* Flags must be VIR_MEMORY_VIRTUAL at the moment.
+     *
+     * Note on access to physical memory: A VIR_MEMORY_PHYSICAL flag is
+     * a possibility.  However it isn't really useful unless the caller
+     * can also access registers, particularly CR3 on x86 in order to
+     * get the Page Table Directory.  Since registers are different on
+     * every architecture, that would imply another call to get the
+     * machine registers.
+     *
+     * The QEMU driver handles only VIR_MEMORY_VIRTUAL, mapping it
+     * to the qemu 'memsave' command which does the virtual to physical
+     * mapping inside qemu.
+     *
+     * At time of writing there is no Xen driver.  However the Xen
+     * hypervisor only lets you map physical pages from other domains,
+     * and so the Xen driver would have to do the virtual to physical
+     * mapping by chasing 2, 3 or 4-level page tables from the PTD.
+     * There is example code in libxc (xc_translate_foreign_address)
+     * which does this, although we cannot copy this code directly
+     * because of incompatible licensing.
+     */
+    if (flags != VIR_MEMORY_VIRTUAL) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG,
+                           _("flags parameter must be VIR_MEMORY_VIRTUAL"));
+        return -1;
+    }
+
+    /* Allow size == 0 as an access test. */
+    if (size > 0 && !buffer) {
+        virLibDomainError (dom, VIR_ERR_INVALID_ARG,
+                           _("buffer is NULL but size is non-zero"));
+        return -1;
+    }
+
+    if (conn->driver->domainMemoryPeek)
+        return conn->driver->domainMemoryPeek (dom, start, size,
+                                               buffer, flags);
+
+    virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__);
+    return -1;
+}
+
 
 /************************************************************************
  *									*
Index: src/libvirt_sym.version
===================================================================
RCS file: /data/cvs/libvirt/src/libvirt_sym.version,v
retrieving revision 1.42
diff -u -p -r1.42 libvirt_sym.version
--- src/libvirt_sym.version	6 Jun 2008 10:52:01 -0000	1.42
+++ src/libvirt_sym.version	9 Jun 2008 12:48:17 -0000
@@ -74,6 +74,7 @@
 	virDomainBlockStats;
 	virDomainInterfaceStats;
 	virDomainBlockPeek;
+	virDomainMemoryPeek;
 	virDomainAttachDevice;
 	virDomainDetachDevice;
 
Index: src/qemu_driver.c
===================================================================
RCS file: /data/cvs/libvirt/src/qemu_driver.c,v
retrieving revision 1.84
diff -u -p -r1.84 qemu_driver.c
--- src/qemu_driver.c	5 Jun 2008 21:12:27 -0000	1.84
+++ src/qemu_driver.c	9 Jun 2008 12:48:19 -0000
@@ -66,6 +66,9 @@
 #include "capabilities.h"
 #include "memory.h"
 
+/* For storing short-lived temporary files. */
+#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
+
 static int qemudShutdown(void);
 
 /* qemudDebug statements should be changed to use this macro instead. */
@@ -3221,6 +3224,68 @@ found:
     return ret;
 }
 
+static int
+qemudDomainMemoryPeek (virDomainPtr dom,
+                       unsigned long long offset, size_t size,
+                       void *buffer,
+                       unsigned int flags)
+{
+    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
+    struct qemud_vm *vm = qemudFindVMByID (driver, dom->id);
+    char cmd[256], *info;
+    char tmp[] = TEMPDIR "/qemu.mem.XXXXXX";
+    int fd = -1, ret = -1;
+
+    if (flags != VIR_MEMORY_VIRTUAL) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG,
+                          _("QEMU driver only supports virtual memory addrs"));
+        return -1;
+    }
+
+    if (!vm) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN,
+                          _("no domain with matching id %d"), dom->id);
+        return -1;
+    }
+
+    if (!qemudIsActiveVM(vm)) {
+        qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                         "%s", _("domain is not running"));
+        return -1;
+    }
+
+    /* Create a temporary filename. */
+    if ((fd = mkstemp (tmp)) == -1) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR,
+                          "%s", strerror (errno));
+        return -1;
+    }
+
+    /* Issue the memsave command. */
+    snprintf (cmd, sizeof cmd, "memsave %llu %zi \"%s\"", offset, size, tmp);
+    if (qemudMonitorCommand (driver, vm, cmd, &info) < 0) {
+        qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
+                          "%s", _("'info blockstats' command failed"));
+        goto done;
+    }
+
+    DEBUG ("memsave reply: %s", info);
+    free (info);
+
+    /* Read the memory file into buffer. */
+    if (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);
+    unlink (tmp);
+    return ret;
+}
+
 static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED,
                                      const unsigned char *uuid) {
     struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
@@ -3580,6 +3645,7 @@ static virDriver qemuDriver = {
     qemudDomainBlockStats, /* domainBlockStats */
     qemudDomainInterfaceStats, /* domainInterfaceStats */
     qemudDomainBlockPeek, /* domainBlockPeek */
+    qemudDomainMemoryPeek, /* domainMemoryPeek */
 #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.78
diff -u -p -r1.78 remote_internal.c
--- src/remote_internal.c	6 Jun 2008 11:09:57 -0000	1.78
+++ src/remote_internal.c	9 Jun 2008 12:48:23 -0000
@@ -2416,6 +2416,50 @@ remoteDomainBlockPeek (virDomainPtr doma
     return 0;
 }
 
+static int
+remoteDomainMemoryPeek (virDomainPtr domain,
+                        unsigned long long offset,
+                        size_t size,
+                        void *buffer,
+                        unsigned int flags)
+{
+    remote_domain_memory_peek_args args;
+    remote_domain_memory_peek_ret ret;
+    GET_PRIVATE (domain->conn, -1);
+
+    if (size > REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX) {
+        errorf (domain->conn, VIR_ERR_RPC,
+                _("memory peek request too large for remote protocol, %zi > %d"),
+                size, REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX);
+        return -1;
+    }
+
+    make_nonnull_domain (&args.dom, domain);
+    args.offset = offset;
+    args.size = size;
+    args.flags = flags;
+
+    memset (&ret, 0, sizeof ret);
+    if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MEMORY_PEEK,
+              (xdrproc_t) xdr_remote_domain_memory_peek_args,
+                (char *) &args,
+              (xdrproc_t) xdr_remote_domain_memory_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
@@ -4824,6 +4868,7 @@ static virDriver driver = {
     .domainBlockStats = remoteDomainBlockStats,
     .domainInterfaceStats = remoteDomainInterfaceStats,
     .domainBlockPeek = remoteDomainBlockPeek,
+    .domainMemoryPeek = remoteDomainMemoryPeek,
     .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
     .getFreeMemory = remoteNodeGetFreeMemory,
 };
Index: src/test.c
===================================================================
RCS file: /data/cvs/libvirt/src/test.c,v
retrieving revision 1.76
diff -u -p -r1.76 test.c
--- src/test.c	5 Jun 2008 13:17:45 -0000	1.76
+++ src/test.c	9 Jun 2008 12:48:24 -0000
@@ -2061,6 +2061,7 @@ static virDriver testDriver = {
     NULL, /* domainBlockStats */
     NULL, /* domainInterfaceStats */
     NULL, /* domainBlockPeek */
+    NULL, /* domainMemoryPeek */
     testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
     NULL, /* getFreeMemory */
 };


More information about the libvir-list mailing list