From a73a88a19f3a571da6dc9bca958ca18f07d352e0 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Thu, 5 Jun 2008 21:12:26 +0000 Subject: [PATCH] virDomainBlockPeek QEMU and remote support * qemud/remote.c, qemud/remote_protocol.x, src/remote_internal.c: Remote support. * qemud/remote_dispatch_localvars.h, qemud/remote_dispatch_proc_switch.h, qemud/remote_dispatch_prototypes.h, qemud/remote_protocol.c, qemud/remote_protocol.h: Generated files for remote support. * src/xen_unified.c, src/driver.h, src/libvirt.c: Small fix - pass flags around internally. * src/qemu_driver.c: Support for QEMU. * src/xend_internal.c: Remove redundant fstat call from Xen. --- ChangeLog | 16 ++++++++ qemud/remote.c | 48 +++++++++++++++++++++++ qemud/remote_dispatch_localvars.h | 2 + qemud/remote_dispatch_proc_switch.h | 9 +++++ qemud/remote_dispatch_prototypes.h | 1 + qemud/remote_protocol.c | 27 +++++++++++++ qemud/remote_protocol.h | 23 +++++++++++ qemud/remote_protocol.x | 22 ++++++++++- src/driver.h | 3 +- src/libvirt.c | 3 +- src/qemu_driver.c | 60 ++++++++++++++++++++++++++++- src/remote_internal.c | 47 ++++++++++++++++++++++ src/xen_unified.c | 2 +- src/xend_internal.c | 3 +- 14 files changed, 259 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8d99975be..b5e00b5460 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +Thu Jun 5 22:08:00 BST 2008 Richard W.M. Jones + + virDomainBlockPeek QEMU and remote support + * qemud/remote.c, qemud/remote_protocol.x, src/remote_internal.c: + Remote support. + * qemud/remote_dispatch_localvars.h, + qemud/remote_dispatch_proc_switch.h, + qemud/remote_dispatch_prototypes.h, + qemud/remote_protocol.c, + qemud/remote_protocol.h: + Generated files for remote support. + * src/xen_unified.c, src/driver.h, src/libvirt.c: Small fix - + pass flags around internally. + * src/qemu_driver.c: Support for QEMU. + * src/xend_internal.c: Remove redundant fstat call from Xen. + Thu Jun 5 14:10:00 BST 2008 Richard W.M. Jones virDomainBlockPeek call diff --git a/qemud/remote.c b/qemud/remote.c index 2ba91b1a04..6837fdcd54 100644 --- a/qemud/remote.c +++ b/qemud/remote.c @@ -889,6 +889,54 @@ remoteDispatchDomainInterfaceStats (struct qemud_server *server ATTRIBUTE_UNUSED return 0; } +static int +remoteDispatchDomainBlockPeek (struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client, + remote_message_header *req, + remote_domain_block_peek_args *args, + remote_domain_block_peek_ret *ret) +{ + virDomainPtr dom; + char *path; + 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; + } + path = args->path; + offset = args->offset; + size = args->size; + flags = args->flags; + + if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) { + remoteDispatchError (client, req, + "%s", _("size > maximum buffer size")); + return -2; + } + + ret->buffer.buffer_len = size; + ret->buffer.buffer_val = malloc (size); + if (!ret->buffer.buffer_val) { + remoteDispatchError (client, req, "%s", strerror (errno)); + return -2; + } + + if (virDomainBlockPeek (dom, path, 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, diff --git a/qemud/remote_dispatch_localvars.h b/qemud/remote_dispatch_localvars.h index fa5f173209..56963ab053 100644 --- a/qemud/remote_dispatch_localvars.h +++ b/qemud/remote_dispatch_localvars.h @@ -41,6 +41,8 @@ remote_list_domains_ret lv_remote_list_domains_ret; remote_network_define_xml_args lv_remote_network_define_xml_args; remote_network_define_xml_ret lv_remote_network_define_xml_ret; remote_get_type_ret lv_remote_get_type_ret; +remote_domain_block_peek_args lv_remote_domain_block_peek_args; +remote_domain_block_peek_ret lv_remote_domain_block_peek_ret; remote_storage_vol_delete_args lv_remote_storage_vol_delete_args; remote_network_dump_xml_args lv_remote_network_dump_xml_args; remote_network_dump_xml_ret lv_remote_network_dump_xml_ret; diff --git a/qemud/remote_dispatch_proc_switch.h b/qemud/remote_dispatch_proc_switch.h index 4c6e4db6c0..00c98fe94a 100644 --- a/qemud/remote_dispatch_proc_switch.h +++ b/qemud/remote_dispatch_proc_switch.h @@ -47,6 +47,15 @@ case REMOTE_PROC_DOMAIN_ATTACH_DEVICE: args = (char *) &lv_remote_domain_attach_device_args; memset (&lv_remote_domain_attach_device_args, 0, sizeof lv_remote_domain_attach_device_args); break; +case REMOTE_PROC_DOMAIN_BLOCK_PEEK: + fn = (dispatch_fn) remoteDispatchDomainBlockPeek; + args_filter = (xdrproc_t) xdr_remote_domain_block_peek_args; + args = (char *) &lv_remote_domain_block_peek_args; + memset (&lv_remote_domain_block_peek_args, 0, sizeof lv_remote_domain_block_peek_args); + ret_filter = (xdrproc_t) xdr_remote_domain_block_peek_ret; + ret = (char *) &lv_remote_domain_block_peek_ret; + memset (&lv_remote_domain_block_peek_ret, 0, sizeof lv_remote_domain_block_peek_ret); + break; case REMOTE_PROC_DOMAIN_BLOCK_STATS: fn = (dispatch_fn) remoteDispatchDomainBlockStats; args_filter = (xdrproc_t) xdr_remote_domain_block_stats_args; diff --git a/qemud/remote_dispatch_prototypes.h b/qemud/remote_dispatch_prototypes.h index 41d0269065..6d68b8cb4c 100644 --- a/qemud/remote_dispatch_prototypes.h +++ b/qemud/remote_dispatch_prototypes.h @@ -9,6 +9,7 @@ static int remoteDispatchAuthSaslStart (struct qemud_server *server, struct qemu static int remoteDispatchAuthSaslStep (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_auth_sasl_step_args *args, remote_auth_sasl_step_ret *ret); static int remoteDispatchClose (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, void *args, void *ret); static int remoteDispatchDomainAttachDevice (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_attach_device_args *args, void *ret); +static int remoteDispatchDomainBlockPeek (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_block_peek_args *args, remote_domain_block_peek_ret *ret); static int remoteDispatchDomainBlockStats (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_block_stats_args *args, remote_domain_block_stats_ret *ret); static int remoteDispatchDomainCoreDump (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_core_dump_args *args, void *ret); static int remoteDispatchDomainCreate (struct qemud_server *server, struct qemud_client *client, remote_message_header *req, remote_domain_create_args *args, void *ret); diff --git a/qemud/remote_protocol.c b/qemud/remote_protocol.c index 4045801157..69045626e9 100644 --- a/qemud/remote_protocol.c +++ b/qemud/remote_protocol.c @@ -534,6 +534,33 @@ xdr_remote_domain_interface_stats_ret (XDR *xdrs, remote_domain_interface_stats_ return TRUE; } +bool_t +xdr_remote_domain_block_peek_args (XDR *xdrs, remote_domain_block_peek_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_remote_nonnull_string (xdrs, &objp->path)) + 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_block_peek_ret (XDR *xdrs, remote_domain_block_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_BLOCK_PEEK_BUFFER_MAX)) + return FALSE; + return TRUE; +} + bool_t xdr_remote_list_domains_args (XDR *xdrs, remote_list_domains_args *objp) { diff --git a/qemud/remote_protocol.h b/qemud/remote_protocol.h index d42afd8f90..8eeaba2f40 100644 --- a/qemud/remote_protocol.h +++ b/qemud/remote_protocol.h @@ -33,6 +33,7 @@ typedef remote_nonnull_string *remote_string; #define REMOTE_NODE_MAX_CELLS 1024 #define REMOTE_AUTH_SASL_DATA_MAX 65536 #define REMOTE_AUTH_TYPE_LIST_MAX 20 +#define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536 typedef char remote_uuid[VIR_UUID_BUFLEN]; @@ -263,6 +264,23 @@ struct remote_domain_interface_stats_ret { }; typedef struct remote_domain_interface_stats_ret remote_domain_interface_stats_ret; +struct remote_domain_block_peek_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + u_quad_t offset; + u_int size; + u_int flags; +}; +typedef struct remote_domain_block_peek_args remote_domain_block_peek_args; + +struct remote_domain_block_peek_ret { + struct { + u_int buffer_len; + char *buffer_val; + } buffer; +}; +typedef struct remote_domain_block_peek_ret remote_domain_block_peek_ret; + struct remote_list_domains_args { int maxids; }; @@ -1138,6 +1156,7 @@ enum remote_procedure { REMOTE_PROC_STORAGE_VOL_GET_PATH = 100, REMOTE_PROC_NODE_GET_CELLS_FREE_MEMORY = 101, REMOTE_PROC_NODE_GET_FREE_MEMORY = 102, + REMOTE_PROC_DOMAIN_BLOCK_PEEK = 103, }; typedef enum remote_procedure remote_procedure; @@ -1206,6 +1225,8 @@ extern bool_t xdr_remote_domain_block_stats_args (XDR *, remote_domain_block_st extern bool_t xdr_remote_domain_block_stats_ret (XDR *, remote_domain_block_stats_ret*); extern bool_t xdr_remote_domain_interface_stats_args (XDR *, remote_domain_interface_stats_args*); 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_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*); @@ -1381,6 +1402,8 @@ extern bool_t xdr_remote_domain_block_stats_args (); extern bool_t xdr_remote_domain_block_stats_ret (); 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_list_domains_args (); extern bool_t xdr_remote_list_domains_ret (); extern bool_t xdr_remote_num_of_domains_ret (); diff --git a/qemud/remote_protocol.x b/qemud/remote_protocol.x index 9c151432a6..048fcb6825 100644 --- a/qemud/remote_protocol.x +++ b/qemud/remote_protocol.x @@ -96,6 +96,12 @@ 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. + * 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; + /* UUID. VIR_UUID_BUFLEN definition comes from libvirt.h */ typedef opaque remote_uuid[VIR_UUID_BUFLEN]; @@ -322,6 +328,18 @@ struct remote_domain_interface_stats_ret { hyper tx_drop; }; +struct remote_domain_block_peek_args { + remote_nonnull_domain dom; + remote_nonnull_string path; + unsigned hyper offset; + unsigned size; + unsigned flags; +}; + +struct remote_domain_block_peek_ret { + opaque buffer; +}; + struct remote_list_domains_args { int maxids; }; @@ -1036,7 +1054,9 @@ enum remote_procedure { REMOTE_PROC_STORAGE_VOL_GET_PATH = 100, 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 }; /* Custom RPC structure. */ diff --git a/src/driver.h b/src/driver.h index ebdd637e0b..ed6d2e513d 100644 --- a/src/driver.h +++ b/src/driver.h @@ -230,7 +230,8 @@ typedef int (virDomainPtr domain, const char *path, unsigned long long offset, size_t size, - void *buffer); + void *buffer, + unsigned int flags); typedef int (*virDrvDomainMigratePrepare) diff --git a/src/libvirt.c b/src/libvirt.c index 3e349e1faa..53a93e3025 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -2659,7 +2659,8 @@ virDomainBlockPeek (virDomainPtr dom, } if (conn->driver->domainBlockPeek) - return conn->driver->domainBlockPeek (dom, path, offset, size, buffer); + return conn->driver->domainBlockPeek (dom, path, offset, size, + buffer, flags); virLibDomainError (dom, VIR_ERR_NO_SUPPORT, __FUNCTION__); return -1; diff --git a/src/qemu_driver.c b/src/qemu_driver.c index c928027fb3..969c253eda 100644 --- a/src/qemu_driver.c +++ b/src/qemu_driver.c @@ -3163,6 +3163,64 @@ qemudDomainInterfaceStats (virDomainPtr dom, #endif } +static int +qemudDomainBlockPeek (virDomainPtr dom, + const char *path, + unsigned long long offset, size_t size, + void *buffer, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData; + struct qemud_vm *vm = qemudFindVMByUUID (driver, dom->uuid); + int i; + int fd, ret = -1; + + if (!vm) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_DOMAIN, + _("no domain with matching uuid")); + return -1; + } + + if (!path || path[0] == '\0') { + qemudReportError(dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("NULL or empty path")); + return -1; + } + + /* Check the path belongs to this domain. */ + for (i = 0; i < vm->def->ndisks; ++i) { + if (STREQ (vm->def->disks[i].src, path)) goto found; + } + qemudReportError (dom->conn, dom, NULL, VIR_ERR_INVALID_ARG, + _("invalid path")); + return -1; + +found: + /* The path is correct, now try to open it and get its size. */ + fd = open (path, O_RDONLY); + if (fd == -1) { + qemudReportError (dom->conn, dom, NULL, VIR_ERR_SYSTEM_ERROR, + "%s", strerror (errno)); + goto done; + } + + /* Seek and read. */ + /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should + * be 64 bits on all platforms. + */ + if (lseek (fd, offset, SEEK_SET) == (off_t) -1 || + 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); + return ret; +} + static virNetworkPtr qemudNetworkLookupByUUID(virConnectPtr conn ATTRIBUTE_UNUSED, const unsigned char *uuid) { struct qemud_driver *driver = (struct qemud_driver *)conn->networkPrivateData; @@ -3521,7 +3579,7 @@ static virDriver qemuDriver = { NULL, /* domainMigrateFinish */ qemudDomainBlockStats, /* domainBlockStats */ qemudDomainInterfaceStats, /* domainInterfaceStats */ - NULL, /* domainBlockPeek */ + qemudDomainBlockPeek, /* domainBlockPeek */ #if HAVE_NUMACTL qemudNodeGetCellsFreeMemory, /* nodeGetCellsFreeMemory */ qemudNodeGetFreeMemory, /* getFreeMemory */ diff --git a/src/remote_internal.c b/src/remote_internal.c index 4c87ec8632..478c93dc85 100644 --- a/src/remote_internal.c +++ b/src/remote_internal.c @@ -2374,6 +2374,52 @@ remoteDomainInterfaceStats (virDomainPtr domain, const char *path, return 0; } +static int +remoteDomainBlockPeek (virDomainPtr domain, + const char *path, + unsigned long long offset, + size_t size, + void *buffer, + unsigned int flags) +{ + remote_domain_block_peek_args args; + remote_domain_block_peek_ret ret; + GET_PRIVATE (domain->conn, -1); + + if (size > REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX) { + errorf (domain->conn, VIR_ERR_RPC, + _("block peek request too large for remote protocol, %zi > %d"), + size, REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX); + return -1; + } + + make_nonnull_domain (&args.dom, domain); + args.path = (char *) path; + args.offset = offset; + args.size = size; + args.flags = flags; + + memset (&ret, 0, sizeof ret); + if (call (domain->conn, priv, 0, REMOTE_PROC_DOMAIN_BLOCK_PEEK, + (xdrproc_t) xdr_remote_domain_block_peek_args, + (char *) &args, + (xdrproc_t) xdr_remote_domain_block_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 @@ -4784,6 +4830,7 @@ static virDriver driver = { .domainMigrateFinish = remoteDomainMigrateFinish, .domainBlockStats = remoteDomainBlockStats, .domainInterfaceStats = remoteDomainInterfaceStats, + .domainBlockPeek = remoteDomainBlockPeek, .nodeGetCellsFreeMemory = remoteNodeGetCellsFreeMemory, .getFreeMemory = remoteNodeGetFreeMemory, }; diff --git a/src/xen_unified.c b/src/xen_unified.c index b77a0ecfd9..c74e3a9465 100644 --- a/src/xen_unified.c +++ b/src/xen_unified.c @@ -1237,7 +1237,7 @@ xenUnifiedDomainInterfaceStats (virDomainPtr dom, const char *path, static int xenUnifiedDomainBlockPeek (virDomainPtr dom, const char *path, unsigned long long offset, size_t size, - void *buffer) + void *buffer, unsigned int flags ATTRIBUTE_UNUSED) { int r; GET_PRIVATE (dom->conn); diff --git a/src/xend_internal.c b/src/xend_internal.c index 3cb1a3bde7..b30a878542 100644 --- a/src/xend_internal.c +++ b/src/xend_internal.c @@ -4541,7 +4541,6 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, struct sexpr *root; struct check_path_data data; int fd, ret = -1; - struct stat statbuf; priv = (xenUnifiedPrivatePtr) domain->conn->privateData; @@ -4583,7 +4582,7 @@ xenDaemonDomainBlockPeek (virDomainPtr domain, const char *path, /* The path is correct, now try to open it and get its size. */ fd = open (path, O_RDONLY); - if (fd == -1 || fstat (fd, &statbuf) == -1) { + if (fd == -1) { virXendError (domain->conn, VIR_ERR_SYSTEM_ERROR, strerror (errno)); goto done; }