+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
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
<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>
<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>
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
*/
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
*/
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
%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
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
if [ $RETVAL -eq 0 ]; then
rm -f @localstatedir@/lock/subsys/$SERVICE
rm -f @localstatedir@/run/$SERVICE.pid
+ rm -rf @localstatedir@/cache/libvirt/*
fi
}
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,
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;
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;
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);
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)
{
#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];
};
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;
};
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;
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*);
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 ();
/* 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];
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;
};
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. */
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
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,
virDrvDomainBlockStats domainBlockStats;
virDrvDomainInterfaceStats domainInterfaceStats;
virDrvDomainBlockPeek domainBlockPeek;
+ virDrvDomainMemoryPeek domainMemoryPeek;
virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
virDrvNodeGetFreeMemory getFreeMemory;
};
*
* '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
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;
+}
+
/************************************************************************
* *
virDomainBlockStats;
virDomainInterfaceStats;
virDomainBlockPeek;
+ virDomainMemoryPeek;
virDomainAttachDevice;
virDomainDetachDevice;
#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. */
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;
qemudDomainBlockStats, /* domainBlockStats */
qemudDomainInterfaceStats, /* domainInterfaceStats */
qemudDomainBlockPeek, /* domainBlockPeek */
+ qemudDomainMemoryPeek, /* domainMemoryPeek */
#if HAVE_NUMACTL
qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
qemudNodeGetFreeMemory, /* getFreeMemory */
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
.domainBlockStats = remoteDomainBlockStats,
.domainInterfaceStats = remoteDomainInterfaceStats,
.domainBlockPeek = remoteDomainBlockPeek,
+ .domainMemoryPeek = remoteDomainMemoryPeek,
.nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
.getFreeMemory = remoteNodeGetFreeMemory,
};
NULL, /* domainBlockStats */
NULL, /* domainInterfaceStats */
NULL, /* domainBlockPeek */
+ NULL, /* domainMemoryPeek */
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
NULL, /* getFreeMemory */
};