]> xenbits.xensource.com Git - libvirt.git/commitdiff
virDomainMemoryPeek API
authorRichard W.M. Jones <rjones@redhat.com>
Tue, 10 Jun 2008 10:43:28 +0000 (10:43 +0000)
committerRichard W.M. Jones <rjones@redhat.com>
Tue, 10 Jun 2008 10:43:28 +0000 (10:43 +0000)
        * include/libvirt/libvirt.h.in, src/libvirt.c, src/driver.h,
          src/libvirt_sym.version: New virDomainMemoryPeek API.
        * qemud/remote.c, qemud/remote_protocol.x, src/remote_internal.c:
          Support for remote.
        * src/qemu_driver.c: QEMU driver implementation of API.
        * src/test.c: Test driver (null) implementation of API.
        * docs/hvsupport.html.in: Document API.
        * libvirt.spec.in: New path /var/cache/libvirt for temporary
          storage of memory images.
        * qemud/libvirtd.init.in: Remove any old temp files in
          /var/cache/libvirt on restarts.
        * src/Makefile.am: make install creates /var/cache/libvirt.
        * configure.in: Detect mkdir -p.

21 files changed:
ChangeLog
configure.in
docs/hvsupport.html.in
include/libvirt/libvirt.h
include/libvirt/libvirt.h.in
libvirt.spec.in
qemud/libvirtd.init.in
qemud/remote.c
qemud/remote_dispatch_localvars.h
qemud/remote_dispatch_proc_switch.h
qemud/remote_dispatch_prototypes.h
qemud/remote_protocol.c
qemud/remote_protocol.h
qemud/remote_protocol.x
src/Makefile.am
src/driver.h
src/libvirt.c
src/libvirt_sym.version
src/qemu_driver.c
src/remote_internal.c
src/test.c

index 1aead245c6e66b2c356b811687b1b0d86f596ac0..7f4b795978cf1523e4cc361c435d82add7ffb83d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Tue Jun 10 11:34:00 BST 2008 Richard W.M. Jones <rjones@redhat.com>
+
+       virDomainMemoryPeek API
+       * include/libvirt/libvirt.h.in, src/libvirt.c, src/driver.h,
+         src/libvirt_sym.version: New virDomainMemoryPeek API.
+       * qemud/remote.c, qemud/remote_protocol.x, src/remote_internal.c:
+         Support for remote.
+       * src/qemu_driver.c: QEMU driver implementation of API.
+       * src/test.c: Test driver (null) implementation of API.
+       * docs/hvsupport.html.in: Document API.
+       * libvirt.spec.in: New path /var/cache/libvirt for temporary
+         storage of memory images.
+       * qemud/libvirtd.init.in: Remove any old temp files in
+         /var/cache/libvirt on restarts.
+       * src/Makefile.am: make install creates /var/cache/libvirt.
+       * configure.in: Detect mkdir -p.
+
 Mon Jun  9 15:42:34 PST 2008 David L. Leskovec <dlesko@linux.vnet.ibm.com>
 
        * src/lxc_driver.c: Console element is output only.  Always open new
index 47633b0d8ad495200abd8df20c0bf0fadc43ba52..d4758fa6667a864b6369840d1d609418de26f4c4 100644 (file)
@@ -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 545d5442c6991803223ee33d800914e7144ec8cf..42a1d703d0f28827702bccc19daef7e63d68210c 100644 (file)
@@ -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>
@@ -486,6 +486,14 @@ updated on <i>2008-06-05</i>.
         <td> 0.1.0 </td>
         <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>
index 1170b7606152ebd0b9c5d0116eed86bf1525e4e9..22dbc3f71d2122e86b14191fccf7a896add5d3c5 100644 (file)
@@ -537,6 +537,17 @@ int                     virDomainBlockPeek (virDomainPtr dom,
                                             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 a711edd304f43cbb9d42b0bc9034de97d571ea91..bd5195c10dc5f9cd685a7c1b17c6c7d3acd5c34b 100644 (file)
@@ -537,6 +537,17 @@ int                     virDomainBlockPeek (virDomainPtr dom,
                                             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 aff7ef2567c9766449ab1c17482a54847d5bfe79..0adbc207ccc2e9b604deafa2a353ba9239e9050e 100644 (file)
@@ -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 234c5509aaf7d9cb499271168b6f5f3ab1d08bf3..0eed4909c27abd62f5ded36b3c9519cbb7ad504d 100644 (file)
@@ -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 de462b930f78aa7eb5ba07cdd3da3bb47a79b6a1..b5a6ec9e621bd3098a18bedf76e61df4e8805df5 100644 (file)
@@ -938,6 +938,53 @@ remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED,
     return 0;
 }
 
+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,
index 56963ab053b6dbf2737a048e67442ddd7edd03f7..d889c8aba4f85eb0f507ecba9325353ee4d3f7cf 100644 (file)
@@ -91,6 +91,8 @@ remote_domain_get_scheduler_parameters_ret lv_remote_domain_get_scheduler_parame
 remote_node_get_info_ret lv_remote_node_get_info_ret;
 remote_network_lookup_by_name_args lv_remote_network_lookup_by_name_args;
 remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret;
+remote_domain_memory_peek_args lv_remote_domain_memory_peek_args;
+remote_domain_memory_peek_ret lv_remote_domain_memory_peek_ret;
 remote_num_of_defined_domains_ret lv_remote_num_of_defined_domains_ret;
 remote_domain_block_stats_args lv_remote_domain_block_stats_args;
 remote_domain_block_stats_ret lv_remote_domain_block_stats_ret;
index 00c98fe94a9ad6e5dae0e6886c55501c9a06ba45..ebb24334ca958b496a05b279529d7ec87b4fea24 100644 (file)
@@ -224,6 +224,15 @@ case REMOTE_PROC_DOMAIN_LOOKUP_BY_UUID:
         ret = (char *) &lv_remote_domain_lookup_by_uuid_ret;
         memset (&lv_remote_domain_lookup_by_uuid_ret, 0, sizeof lv_remote_domain_lookup_by_uuid_ret);
         break;
+case REMOTE_PROC_DOMAIN_MEMORY_PEEK:
+        fn = (dispatch_fn) remoteDispatchDomainMemoryPeek;
+        args_filter = (xdrproc_t) xdr_remote_domain_memory_peek_args;
+        args = (char *) &lv_remote_domain_memory_peek_args;
+        memset (&lv_remote_domain_memory_peek_args, 0, sizeof lv_remote_domain_memory_peek_args);
+        ret_filter = (xdrproc_t) xdr_remote_domain_memory_peek_ret;
+        ret = (char *) &lv_remote_domain_memory_peek_ret;
+        memset (&lv_remote_domain_memory_peek_ret, 0, sizeof lv_remote_domain_memory_peek_ret);
+        break;
 case REMOTE_PROC_DOMAIN_MIGRATE_FINISH:
         fn = (dispatch_fn) remoteDispatchDomainMigrateFinish;
         args_filter = (xdrproc_t) xdr_remote_domain_migrate_finish_args;
index 6d68b8cb4cffa35aacb4f57b0c5db0d9cda9c512..1d9d79494e82fe0c5a40bf11952ea919ab22d460 100644 (file)
@@ -30,6 +30,7 @@ static int remoteDispatchDomainInterfaceStats (struct qemud_server *server, stru
 static int remoteDispatchDomainLookupById (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_id_args *args, remote_domain_lookup_by_id_ret *ret);
 static int remoteDispatchDomainLookupByName (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_name_args *args, remote_domain_lookup_by_name_ret *ret);
 static int remoteDispatchDomainLookupByUuid (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_lookup_by_uuid_args *args, remote_domain_lookup_by_uuid_ret *ret);
+static int remoteDispatchDomainMemoryPeek (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_memory_peek_args *args, remote_domain_memory_peek_ret *ret);
 static int remoteDispatchDomainMigrateFinish (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_migrate_finish_args *args, remote_domain_migrate_finish_ret *ret);
 static int remoteDispatchDomainMigratePerform (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_migrate_perform_args *args, void *ret);
 static int remoteDispatchDomainMigratePrepare (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_migrate_prepare_args *args, remote_domain_migrate_prepare_ret *ret);
index 69045626e94edb8974820f1af3b1166f5664ba15..1a8e68d60ae12eab508bec6291b722fcd689b592 100644 (file)
@@ -561,6 +561,31 @@ xdr_remote_domain_block_peek_ret (XDR *xdrs, remote_domain_block_peek_ret *objp)
         return TRUE;
 }
 
+bool_t
+xdr_remote_domain_memory_peek_args (XDR *xdrs, remote_domain_memory_peek_args *objp)
+{
+
+         if (!xdr_remote_nonnull_domain (xdrs, &objp->dom))
+                 return FALSE;
+         if (!xdr_u_quad_t (xdrs, &objp->offset))
+                 return FALSE;
+         if (!xdr_u_int (xdrs, &objp->size))
+                 return FALSE;
+         if (!xdr_u_int (xdrs, &objp->flags))
+                 return FALSE;
+        return TRUE;
+}
+
+bool_t
+xdr_remote_domain_memory_peek_ret (XDR *xdrs, remote_domain_memory_peek_ret *objp)
+{
+        char **objp_cpp0 = (char **) (void *) &objp->buffer.buffer_val;
+
+         if (!xdr_bytes (xdrs, objp_cpp0, (u_int *) &objp->buffer.buffer_len, REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX))
+                 return FALSE;
+        return TRUE;
+}
+
 bool_t
 xdr_remote_list_domains_args (XDR *xdrs, remote_list_domains_args *objp)
 {
index 8eeaba2f4019f291deb48fb8a8941fbe1082b516..1ad0c547d87e84b9542c20701e2c290f30e4007e 100644 (file)
@@ -34,6 +34,7 @@ typedef remote_nonnull_string *remote_string;
 #define REMOTE_AUTH_SASL_DATA_MAX 65536
 #define REMOTE_AUTH_TYPE_LIST_MAX 20
 #define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536
+#define REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX 65536
 
 typedef char remote_uuid[VIR_UUID_BUFLEN];
 
@@ -281,6 +282,22 @@ struct remote_domain_block_peek_ret {
 };
 typedef struct remote_domain_block_peek_ret remote_domain_block_peek_ret;
 
+struct remote_domain_memory_peek_args {
+        remote_nonnull_domain dom;
+        u_quad_t offset;
+        u_int size;
+        u_int flags;
+};
+typedef struct remote_domain_memory_peek_args remote_domain_memory_peek_args;
+
+struct remote_domain_memory_peek_ret {
+        struct {
+                u_int buffer_len;
+                char *buffer_val;
+        } buffer;
+};
+typedef struct remote_domain_memory_peek_ret remote_domain_memory_peek_ret;
+
 struct remote_list_domains_args {
         int maxids;
 };
@@ -1157,6 +1174,7 @@ 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_MEMORY_PEEK = 104,
 };
 typedef enum remote_procedure remote_procedure;
 
@@ -1227,6 +1245,8 @@ extern  bool_t xdr_remote_domain_interface_stats_args (XDR *, remote_domain_inte
 extern  bool_t xdr_remote_domain_interface_stats_ret (XDR *, remote_domain_interface_stats_ret*);
 extern  bool_t xdr_remote_domain_block_peek_args (XDR *, remote_domain_block_peek_args*);
 extern  bool_t xdr_remote_domain_block_peek_ret (XDR *, remote_domain_block_peek_ret*);
+extern  bool_t xdr_remote_domain_memory_peek_args (XDR *, remote_domain_memory_peek_args*);
+extern  bool_t xdr_remote_domain_memory_peek_ret (XDR *, remote_domain_memory_peek_ret*);
 extern  bool_t xdr_remote_list_domains_args (XDR *, remote_list_domains_args*);
 extern  bool_t xdr_remote_list_domains_ret (XDR *, remote_list_domains_ret*);
 extern  bool_t xdr_remote_num_of_domains_ret (XDR *, remote_num_of_domains_ret*);
@@ -1404,6 +1424,8 @@ extern bool_t xdr_remote_domain_interface_stats_args ();
 extern bool_t xdr_remote_domain_interface_stats_ret ();
 extern bool_t xdr_remote_domain_block_peek_args ();
 extern bool_t xdr_remote_domain_block_peek_ret ();
+extern bool_t xdr_remote_domain_memory_peek_args ();
+extern bool_t xdr_remote_domain_memory_peek_ret ();
 extern bool_t xdr_remote_list_domains_args ();
 extern bool_t xdr_remote_list_domains_ret ();
 extern bool_t xdr_remote_num_of_domains_ret ();
index 048fcb68254d1db7c608a5f93679b5f5fabbde56..340203cbaea00ae164dd8bc2d3cf807239076a93 100644 (file)
@@ -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_MEMORY_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 0549bfda97ffa6e03f3ee9d1d31e049d51118611..51821b041f08cbeb855b082e32e40e65eac0a2e5 100644 (file)
@@ -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 ed6d2e513d4540a92c81636a714e6fb602f3092a..1404eb946016815ba409ebdf302f2b0d7f5e66a4 100644 (file)
@@ -233,6 +233,13 @@ typedef int
                      void *buffer,
                      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,
@@ -346,6 +353,7 @@ struct _virDriver {
     virDrvDomainBlockStats      domainBlockStats;
     virDrvDomainInterfaceStats  domainInterfaceStats;
     virDrvDomainBlockPeek      domainBlockPeek;
+    virDrvDomainMemoryPeek      domainMemoryPeek;
     virDrvNodeGetCellsFreeMemory       nodeGetCellsFreeMemory;
     virDrvNodeGetFreeMemory            getFreeMemory;
 };
index 53a93e30257feb40dc4373e53bca8967ead81875..48df71dbdedffe2322a5b99e539a84d23ddf998a 100644 (file)
@@ -2619,6 +2619,10 @@ virDomainInterfaceStats (virDomainPtr dom, const char *path,
  *
  * '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 2da720c65046e47234cc6858aabc5a63f58573c9..6561bc9671f8b6f74f17841afb4f6eba2f30f479 100644 (file)
@@ -74,6 +74,7 @@
        virDomainBlockStats;
        virDomainInterfaceStats;
        virDomainBlockPeek;
+       virDomainMemoryPeek;
        virDomainAttachDevice;
        virDomainDetachDevice;
 
index 969c253eda146544daa1e3776e417adecb5ada48..97c6483903242f350a27173bbeacd23ac4b2e8a8 100644 (file)
@@ -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 cc34ae6e353636ecad3a3f54693c79de3ff76d3c..713317d8f0423899293137c1337caab5efc98f5a 100644 (file)
@@ -2416,6 +2416,50 @@ remoteDomainBlockPeek (virDomainPtr domain,
     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 32e88bde12adc5ff01035a49cbbd2b285df4f44c..1d22720805cc2a542da2155863483e18a48082a4 100644 (file)
@@ -2061,6 +2061,7 @@ static virDriver testDriver = {
     NULL, /* domainBlockStats */
     NULL, /* domainInterfaceStats */
     NULL, /* domainBlockPeek */
+    NULL, /* domainMemoryPeek */
     testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
     NULL, /* getFreeMemory */
 };