mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 13:45:38 +00:00
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:
parent
0d0c96722c
commit
6bcf25017b
17
ChangeLog
17
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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 ();
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* *
|
||||
|
@ -74,6 +74,7 @@
|
||||
virDomainBlockStats;
|
||||
virDomainInterfaceStats;
|
||||
virDomainBlockPeek;
|
||||
virDomainMemoryPeek;
|
||||
virDomainAttachDevice;
|
||||
virDomainDetachDevice;
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -2061,6 +2061,7 @@ static virDriver testDriver = {
|
||||
NULL, /* domainBlockStats */
|
||||
NULL, /* domainInterfaceStats */
|
||||
NULL, /* domainBlockPeek */
|
||||
NULL, /* domainMemoryPeek */
|
||||
testNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
|
||||
NULL, /* getFreeMemory */
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user