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.
This commit is contained in:
Richard W.M. Jones 2008-06-10 10:43:28 +00:00
parent 0d0c96722c
commit 6bcf25017b
21 changed files with 402 additions and 5 deletions

View File

@ -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

View 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

View 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>

View 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
*/

View 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
*/

View 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

View 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
}

View 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,

View 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;

View 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;

View 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);

View 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)
{

View 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 ();

View 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. */

View 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

View 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;
};

View 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;
}
/************************************************************************
* *

View File

@ -74,6 +74,7 @@
virDomainBlockStats;
virDomainInterfaceStats;
virDomainBlockPeek;
virDomainMemoryPeek;
virDomainAttachDevice;
virDomainDetachDevice;

View 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 */

View 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,
};

View File

@ -2061,6 +2061,7 @@ static virDriver testDriver = {
NULL, /* domainBlockStats */
NULL, /* domainInterfaceStats */
NULL, /* domainBlockPeek */
NULL, /* domainMemoryPeek */
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
};