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 2008-06-05.
virDomainBlockPeek |
0.4.3 |
- x |
- x |
- x |
+ 0.4.3 |
+ 0.4.3 |
+ 0.4.3 |
x |
@@ -487,6 +487,14 @@ updated on 2008-06-05.
not a HV function |
+ virDomainMemoryPeek |
+ 0.4.3 |
+ x |
+ 0.4.3 |
+ 0.4.3 |
+ x |
+
+
virNodeGetInfo |
0.1.0 |
≥ 0.1.0 |
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;
};
+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;
+};
+
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 */
};