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> 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 * 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([XMLLINT], [xmllint], [/usr/bin/xmllint])
AC_PATH_PROG([XSLTPROC], [xsltproc], [/usr/bin/xsltproc]) AC_PATH_PROG([XSLTPROC], [xsltproc], [/usr/bin/xsltproc])
AC_PROG_MKDIR_P
dnl External programs that we can use if they are available. dnl External programs that we can use if they are available.
dnl We will hard-code paths to these programs unless we cannot dnl We will hard-code paths to these programs unless we cannot
dnl detect them, in which case we'll search for the program 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> <tr>
<td> virDomainBlockPeek </td> <td> virDomainBlockPeek </td>
<td> 0.4.3 </td> <td> 0.4.3 </td>
<td> x </td> <td> 0.4.3 </td>
<td> x </td> <td> 0.4.3 </td>
<td> x </td> <td> 0.4.3 </td>
<td> x </td> <td> x </td>
</tr> </tr>
<tr> <tr>
@ -486,6 +486,14 @@ updated on <i>2008-06-05</i>.
<td> 0.1.0 </td> <td> 0.1.0 </td>
<td colspan="4"> not a HV function </td> <td colspan="4"> not a HV function </td>
</tr> </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> <tr>
<td> virNodeGetInfo </td> <td> virNodeGetInfo </td>
<td> 0.1.0 </td> <td> 0.1.0 </td>

View File

@ -537,6 +537,17 @@ int virDomainBlockPeek (virDomainPtr dom,
void *buffer, void *buffer,
unsigned int flags); 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 * defined but not running domains
*/ */

View File

@ -537,6 +537,17 @@ int virDomainBlockPeek (virDomainPtr dom,
void *buffer, void *buffer,
unsigned int flags); 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 * 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/*.la
rm -f $RPM_BUILD_ROOT%{_libdir}/python*/site-packages/*.a 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}/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 # 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 # because if the admin wants to delete the default network completely, we don't
@ -202,6 +203,7 @@ fi
%dir %{_datadir}/libvirt/networks/ %dir %{_datadir}/libvirt/networks/
%{_datadir}/libvirt/networks/default.xml %{_datadir}/libvirt/networks/default.xml
%dir %{_localstatedir}/run/libvirt/ %dir %{_localstatedir}/run/libvirt/
%dir %{_localstatedir}/cache/libvirt/
%dir %{_localstatedir}/lib/libvirt/ %dir %{_localstatedir}/lib/libvirt/
%if %{with_polkit} %if %{with_polkit}
%{_datadir}/PolicyKit/policy/libvirtd.policy %{_datadir}/PolicyKit/policy/libvirtd.policy

View File

@ -51,6 +51,8 @@ RETVAL=0
start() { start() {
echo -n $"Starting $SERVICE daemon: " 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 KRB5_KTNAME=$KRB5_KTNAME daemon --check $SERVICE $PROCESS --daemon $LIBVIRTD_CONFIG_ARGS $LIBVIRTD_ARGS
RETVAL=$? RETVAL=$?
echo echo
@ -66,6 +68,7 @@ stop() {
if [ $RETVAL -eq 0 ]; then if [ $RETVAL -eq 0 ]; then
rm -f @localstatedir@/lock/subsys/$SERVICE rm -f @localstatedir@/lock/subsys/$SERVICE
rm -f @localstatedir@/run/$SERVICE.pid rm -f @localstatedir@/run/$SERVICE.pid
rm -rf @localstatedir@/cache/libvirt/*
fi fi
} }

View File

@ -938,6 +938,53 @@ remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED,
return 0; 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 static int
remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED, remoteDispatchDomainAttachDevice (struct qemud_server *server ATTRIBUTE_UNUSED,
struct qemud_client *client, 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_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_args lv_remote_network_lookup_by_name_args;
remote_network_lookup_by_name_ret lv_remote_network_lookup_by_name_ret; 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_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_args lv_remote_domain_block_stats_args;
remote_domain_block_stats_ret lv_remote_domain_block_stats_ret; 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; 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); memset (&lv_remote_domain_lookup_by_uuid_ret, 0, sizeof lv_remote_domain_lookup_by_uuid_ret);
break; 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: case REMOTE_PROC_DOMAIN_MIGRATE_FINISH:
fn = (dispatch_fn) remoteDispatchDomainMigrateFinish; fn = (dispatch_fn) remoteDispatchDomainMigrateFinish;
args_filter = (xdrproc_t) xdr_remote_domain_migrate_finish_args; 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 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 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 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 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 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); 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; 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 bool_t
xdr_remote_list_domains_args (XDR *xdrs, remote_list_domains_args *objp) 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_SASL_DATA_MAX 65536
#define REMOTE_AUTH_TYPE_LIST_MAX 20 #define REMOTE_AUTH_TYPE_LIST_MAX 20
#define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536 #define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536
#define REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX 65536
typedef char remote_uuid[VIR_UUID_BUFLEN]; 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; 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 { struct remote_list_domains_args {
int maxids; int maxids;
}; };
@ -1157,6 +1174,7 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, 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,
}; };
typedef enum remote_procedure remote_procedure; 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_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_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_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_args (XDR *, remote_list_domains_args*);
extern bool_t xdr_remote_list_domains_ret (XDR *, remote_list_domains_ret*); 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_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_interface_stats_ret ();
extern bool_t xdr_remote_domain_block_peek_args (); extern bool_t xdr_remote_domain_block_peek_args ();
extern bool_t xdr_remote_domain_block_peek_ret (); 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_args ();
extern bool_t xdr_remote_list_domains_ret (); extern bool_t xdr_remote_list_domains_ret ();
extern bool_t xdr_remote_num_of_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 */ /* Maximum number of auth types */
const REMOTE_AUTH_TYPE_LIST_MAX = 20; 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 * Note applications need to be aware of this limit and issue multiple
* requests for large amounts of data. * requests for large amounts of data.
*/ */
const REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX = 65536; 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 */ /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */
typedef opaque remote_uuid[VIR_UUID_BUFLEN]; 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>; 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 { struct remote_list_domains_args {
int maxids; int maxids;
}; };
@ -1056,7 +1073,8 @@ enum remote_procedure {
REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101,
REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, 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. */ /* Custom RPC structure. */

View File

@ -149,4 +149,8 @@ else
EXTRA_DIST += parthelper.c EXTRA_DIST += parthelper.c
endif 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 CLEANFILES = *.gcov .libs/*.gcda .libs/*.gcno *.gcno *.gcda

View File

@ -233,6 +233,13 @@ typedef int
void *buffer, void *buffer,
unsigned int flags); unsigned int flags);
typedef int
(*virDrvDomainMemoryPeek)
(virDomainPtr domain,
unsigned long long start, size_t size,
void *buffer,
unsigned int flags);
typedef int typedef int
(*virDrvDomainMigratePrepare) (*virDrvDomainMigratePrepare)
(virConnectPtr dconn, (virConnectPtr dconn,
@ -346,6 +353,7 @@ struct _virDriver {
virDrvDomainBlockStats domainBlockStats; virDrvDomainBlockStats domainBlockStats;
virDrvDomainInterfaceStats domainInterfaceStats; virDrvDomainInterfaceStats domainInterfaceStats;
virDrvDomainBlockPeek domainBlockPeek; virDrvDomainBlockPeek domainBlockPeek;
virDrvDomainMemoryPeek domainMemoryPeek;
virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory; virDrvNodeGetCellsFreeMemory nodeGetCellsFreeMemory;
virDrvNodeGetFreeMemory getFreeMemory; 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. * '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. * Returns: 0 in case of success or -1 in case of failure.
*/ */
int int
@ -2666,6 +2670,96 @@ virDomainBlockPeek (virDomainPtr dom,
return -1; 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; virDomainBlockStats;
virDomainInterfaceStats; virDomainInterfaceStats;
virDomainBlockPeek; virDomainBlockPeek;
virDomainMemoryPeek;
virDomainAttachDevice; virDomainAttachDevice;
virDomainDetachDevice; virDomainDetachDevice;

View File

@ -66,6 +66,9 @@
#include "capabilities.h" #include "capabilities.h"
#include "memory.h" #include "memory.h"
/* For storing short-lived temporary files. */
#define TEMPDIR LOCAL_STATE_DIR "/cache/libvirt"
static int qemudShutdown(void); static int qemudShutdown(void);
/* qemudDebug statements should be changed to use this macro instead. */ /* qemudDebug statements should be changed to use this macro instead. */
@ -3221,6 +3224,68 @@ found:
return ret; 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, static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED,
const unsigned char *uuid) { const unsigned char *uuid) {
struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData;
@ -3580,6 +3645,7 @@ static virDriver qemuDriver = {
qemudDomainBlockStats, /* domainBlockStats */ qemudDomainBlockStats, /* domainBlockStats */
qemudDomainInterfaceStats, /* domainInterfaceStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */
qemudDomainBlockPeek, /* domainBlockPeek */ qemudDomainBlockPeek, /* domainBlockPeek */
qemudDomainMemoryPeek, /* domainMemoryPeek */
#if HAVE_NUMACTL #if HAVE_NUMACTL
qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */
qemudNodeGetFreeMemory, /* getFreeMemory */ qemudNodeGetFreeMemory, /* getFreeMemory */

View File

@ -2416,6 +2416,50 @@ remoteDomainBlockPeek (virDomainPtr domain,
return 0; 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 static int
@ -4824,6 +4868,7 @@ static virDriver driver = {
.domainBlockStats = remoteDomainBlockStats, .domainBlockStats = remoteDomainBlockStats,
.domainInterfaceStats = remoteDomainInterfaceStats, .domainInterfaceStats = remoteDomainInterfaceStats,
.domainBlockPeek = remoteDomainBlockPeek, .domainBlockPeek = remoteDomainBlockPeek,
.domainMemoryPeek = remoteDomainMemoryPeek,
.nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory, .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory,
.getFreeMemory = remoteNodeGetFreeMemory, .getFreeMemory = remoteNodeGetFreeMemory,
}; };

View File

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