[libvirt] [PATCH v2 0/5] Introduce virDomainMigrateSetMaxDowntime API

This API call sets maximum tolerable time for which the domain is allowed to be paused at the end of live migration. It's supposed to be called while the domain is being live-migrated as a reaction to migration progress. Changes in version 2: - API renamed to reflect it's maximum downtime - new flags parameter for the future - qemu implementation was fixed so that the call is allowed iff the domain is being migrated - --downtime parameter of virsh migrate command was removed in favor of new virsh migrate-setmaxdowntime which can be run independently - virsh accepts downtime as nanoseconds instead of floating-point seconds (shells don't deal with floating-point numbers well) Jiri Denemark (5): Public virDomainMigrateSetMaxDowntime API Wire protocol and dispatcher for virDomainMigrateSetMaxDowntime Implement virDomainMigrateSetMaxDowntime in remote driver Implement virDomainMigrateSetMaxDowntime in qemu driver Add migrate-setmaxdowntime command to virsh daemon/remote.c | 29 ++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 +++ daemon/remote_dispatch_table.h | 5 ++ include/libvirt/libvirt.h.in | 4 ++ src/libvirt.c | 49 +++++++++++++++++ src/libvirt_public.syms | 5 ++ src/qemu/qemu_driver.c | 70 ++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 15 +++++ src/qemu/qemu_monitor.h | 3 + src/qemu/qemu_monitor_json.c | 29 ++++++++++ src/qemu/qemu_monitor_json.h | 3 + src/qemu/qemu_monitor_text.c | 27 ++++++++++ src/qemu/qemu_monitor_text.h | 3 + src/remote/remote_driver.c | 32 +++++++++++- src/remote/remote_protocol.c | 13 +++++ src/remote/remote_protocol.h | 98 +++++++++++++++++++---------------- src/remote/remote_protocol.x | 10 +++- tools/virsh.c | 66 +++++++++++++++++++++++ tools/virsh.pod | 6 ++ 20 files changed, 429 insertions(+), 47 deletions(-)

--- include/libvirt/libvirt.h.in | 4 +++ src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 3 files changed, 58 insertions(+), 0 deletions(-) diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 0d1b5b5..d983e5f 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -408,6 +408,10 @@ int virDomainMigrateToURI (virDomainPtr domain, const char *duri, unsigned long flags, const char *dname, unsigned long bandwidth); +int virDomainMigrateSetMaxDowntime (virDomainPtr domain, + unsigned long long downtime, + unsigned int flags); + /** * VIR_NODEINFO_MAXCPUS: * @nodeinfo: virNodeInfo instance diff --git a/src/libvirt.c b/src/libvirt.c index 1d9b878..07837a3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11265,3 +11265,52 @@ error: virDispatchError(conn); return -1; } + + +/** + * virDomainMigrateSetMaxDowntime: + * @domain: a domain object + * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @flags: fine-tuning flags, currently unused, use 0 + * + * Sets maximum tolerable time for which the domain is allowed to be paused + * at the end of live migration. It's supposed to be called while the domain is + * being live-migrated as a reaction to migration progress. + * + * Returns 0 in case of success, -1 otherwise. + */ +int +virDomainMigrateSetMaxDowntime(virDomainPtr domain, + unsigned long long downtime, + unsigned int flags) +{ + virConnectPtr conn; + + DEBUG("domain=%p, downtime=%llu, flags=%u", domain, downtime, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (conn->driver->domainMigrateSetMaxDowntime) { + if (conn->driver->domainMigrateSetMaxDowntime(domain, downtime, flags) < 0) + goto error; + return 0; + } + + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 64e7505..6ed79d0 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -358,4 +358,9 @@ LIBVIRT_0.7.7 { virDomainAbortJob; } LIBVIRT_0.7.5; +LIBVIRT_0.7.8 { + global: + virDomainMigrateSetMaxDowntime; +} LIBVIRT_0.7.7; + # .... define new API here using predicted next version number .... -- 1.7.0.2

On Thu, Mar 18, 2010 at 08:12:44PM +0100, Jiri Denemark wrote:
--- include/libvirt/libvirt.h.in | 4 +++ src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 3 files changed, 58 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 0d1b5b5..d983e5f 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -408,6 +408,10 @@ int virDomainMigrateToURI (virDomainPtr domain, const char *duri, unsigned long flags, const char *dname, unsigned long bandwidth);
+int virDomainMigrateSetMaxDowntime (virDomainPtr domain, + unsigned long long downtime, + unsigned int flags); + /** * VIR_NODEINFO_MAXCPUS: * @nodeinfo: virNodeInfo instance diff --git a/src/libvirt.c b/src/libvirt.c index 1d9b878..07837a3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11265,3 +11265,52 @@ error: virDispatchError(conn); return -1; } + + +/** + * virDomainMigrateSetMaxDowntime: + * @domain: a domain object + * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @flags: fine-tuning flags, currently unused, use 0
We discussed that previously, obviously the nanosecond accuracy is not expected but most uses of durations in the API now use nanoseconds and after all it's better to have something too fine grained than too coarse there
+ * Sets maximum tolerable time for which the domain is allowed to be paused + * at the end of live migration. It's supposed to be called while the domain is + * being live-migrated as a reaction to migration progress. + * + * Returns 0 in case of success, -1 otherwise. + */ +int +virDomainMigrateSetMaxDowntime(virDomainPtr domain, + unsigned long long downtime, + unsigned int flags) +{ + virConnectPtr conn; + + DEBUG("domain=%p, downtime=%llu, flags=%u", domain, downtime, flags); + + virResetLastError(); + + if (!VIR_IS_CONNECTED_DOMAIN(domain)) { + virLibDomainError(NULL, VIR_ERR_INVALID_DOMAIN, __FUNCTION__); + virDispatchError(NULL); + return -1; + } + + conn = domain->conn; + if (conn->flags & VIR_CONNECT_RO) { + virLibDomainError(domain, VIR_ERR_OPERATION_DENIED, __FUNCTION__); + goto error; + } + + if (conn->driver->domainMigrateSetMaxDowntime) { + if (conn->driver->domainMigrateSetMaxDowntime(domain, downtime, flags) < 0) + goto error; + return 0; + } + + virLibConnError(conn, VIR_ERR_NO_SUPPORT, __FUNCTION__); + +error: + virDispatchError(conn); + return -1; +} diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms index 64e7505..6ed79d0 100644 --- a/src/libvirt_public.syms +++ b/src/libvirt_public.syms @@ -358,4 +358,9 @@ LIBVIRT_0.7.7 { virDomainAbortJob; } LIBVIRT_0.7.5;
+LIBVIRT_0.7.8 { + global: + virDomainMigrateSetMaxDowntime; +} LIBVIRT_0.7.7; + # .... define new API here using predicted next version number ....
ACK Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

On Fri, Mar 19, 2010 at 11:33:38AM +0100, Daniel Veillard wrote:
On Thu, Mar 18, 2010 at 08:12:44PM +0100, Jiri Denemark wrote:
--- include/libvirt/libvirt.h.in | 4 +++ src/libvirt.c | 49 ++++++++++++++++++++++++++++++++++++++++++ src/libvirt_public.syms | 5 ++++ 3 files changed, 58 insertions(+), 0 deletions(-)
diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in index 0d1b5b5..d983e5f 100644 --- a/include/libvirt/libvirt.h.in +++ b/include/libvirt/libvirt.h.in @@ -408,6 +408,10 @@ int virDomainMigrateToURI (virDomainPtr domain, const char *duri, unsigned long flags, const char *dname, unsigned long bandwidth);
+int virDomainMigrateSetMaxDowntime (virDomainPtr domain, + unsigned long long downtime, + unsigned int flags); + /** * VIR_NODEINFO_MAXCPUS: * @nodeinfo: virNodeInfo instance diff --git a/src/libvirt.c b/src/libvirt.c index 1d9b878..07837a3 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11265,3 +11265,52 @@ error: virDispatchError(conn); return -1; } + + +/** + * virDomainMigrateSetMaxDowntime: + * @domain: a domain object + * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @flags: fine-tuning flags, currently unused, use 0
We discussed that previously, obviously the nanosecond accuracy is not expected but most uses of durations in the API now use nanoseconds and after all it's better to have something too fine grained than too coarse there
The virDomainJobInfo API is measuring in milliseconds actally. I'm not aware of any API using nanoseconds, so I think ms is fine for migrate downtime Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

+/** + * virDomainMigrateSetMaxDowntime: + * @domain: a domain object + * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @flags: fine-tuning flags, currently unused, use 0
We discussed that previously, obviously the nanosecond accuracy is not expected but most uses of durations in the API now use nanoseconds and after all it's better to have something too fine grained than too coarse there
The virDomainJobInfo API is measuring in milliseconds actally. I'm not aware of any API using nanoseconds, so I think ms is fine for migrate downtime
Right, there's no other API taking nanoseconds. On the other hand I didn't want to limit capabilities of hypervisors as, e.g., qemu supports nanoseconds precision (although it won't be able fulfil that for sure). Milliseconds seem to be enough these days and we can always add a flag requesting higher precision in the future if it's required. Jirka

On Fri, Mar 19, 2010 at 12:42:02PM +0100, Jiri Denemark wrote:
+/** + * virDomainMigrateSetMaxDowntime: + * @domain: a domain object + * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @flags: fine-tuning flags, currently unused, use 0
We discussed that previously, obviously the nanosecond accuracy is not expected but most uses of durations in the API now use nanoseconds and after all it's better to have something too fine grained than too coarse there
The virDomainJobInfo API is measuring in milliseconds actally. I'm not aware of any API using nanoseconds, so I think ms is fine for migrate downtime
Right, there's no other API taking nanoseconds. On the other hand I didn't want to limit capabilities of hypervisors as, e.g., qemu supports nanoseconds precision (although it won't be able fulfil that for sure). Milliseconds seem to be enough these days and we can always add a flag requesting higher precision in the future if it's required.
QEMU may support it, but there's no way migration of any active guests will ever complete in < 1 ms, so nanosecond resolution is definitely overkill ! Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

--- daemon/remote.c | 29 ++++++++++ daemon/remote_dispatch_args.h | 1 + daemon/remote_dispatch_prototypes.h | 8 +++ daemon/remote_dispatch_table.h | 5 ++ src/remote/remote_protocol.c | 13 +++++ src/remote/remote_protocol.h | 98 +++++++++++++++++++---------------- src/remote/remote_protocol.x | 10 +++- 7 files changed, 119 insertions(+), 45 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 7c4339f..9ea19c1 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -5463,6 +5463,35 @@ remoteDispatchDomainAbortJob (struct qemud_server *server ATTRIBUTE_UNUSED, } +static int +remoteDispatchDomainMigrateSetMaxDowntime(struct qemud_server *server ATTRIBUTE_UNUSED, + struct qemud_client *client ATTRIBUTE_UNUSED, + virConnectPtr conn, + remote_message_header *hdr ATTRIBUTE_UNUSED, + remote_error *rerr, + remote_domain_migrate_set_max_downtime_args *args, + void *ret ATTRIBUTE_UNUSED) +{ + virDomainPtr dom; + + dom = get_nonnull_domain(conn, args->dom); + if (dom == NULL) { + remoteDispatchConnError(rerr, conn); + return -1; + } + + if (virDomainMigrateSetMaxDowntime(dom, args->downtime, args->flags) == -1) { + virDomainFree(dom); + remoteDispatchConnError(rerr, conn); + return -1; + } + + virDomainFree(dom); + + return 0; +} + + /*----- Helpers. -----*/ /* get_nonnull_domain and get_nonnull_network turn an on-wire diff --git a/daemon/remote_dispatch_args.h b/daemon/remote_dispatch_args.h index f97155b..fa4a1d0 100644 --- a/daemon/remote_dispatch_args.h +++ b/daemon/remote_dispatch_args.h @@ -140,3 +140,4 @@ remote_cpu_baseline_args val_remote_cpu_baseline_args; remote_domain_get_job_info_args val_remote_domain_get_job_info_args; remote_domain_abort_job_args val_remote_domain_abort_job_args; + remote_domain_migrate_set_max_downtime_args val_remote_domain_migrate_set_max_downtime_args; diff --git a/daemon/remote_dispatch_prototypes.h b/daemon/remote_dispatch_prototypes.h index b81c8c3..c94c536 100644 --- a/daemon/remote_dispatch_prototypes.h +++ b/daemon/remote_dispatch_prototypes.h @@ -378,6 +378,14 @@ static int remoteDispatchDomainMigratePrepareTunnel( remote_error *err, remote_domain_migrate_prepare_tunnel_args *args, void *ret); +static int remoteDispatchDomainMigrateSetMaxDowntime( + struct qemud_server *server, + struct qemud_client *client, + virConnectPtr conn, + remote_message_header *hdr, + remote_error *err, + remote_domain_migrate_set_max_downtime_args *args, + void *ret); static int remoteDispatchDomainPinVcpu( struct qemud_server *server, struct qemud_client *client, diff --git a/daemon/remote_dispatch_table.h b/daemon/remote_dispatch_table.h index 5ad6bff..ebba5ab 100644 --- a/daemon/remote_dispatch_table.h +++ b/daemon/remote_dispatch_table.h @@ -827,3 +827,8 @@ .args_filter = (xdrproc_t) xdr_remote_domain_abort_job_args, .ret_filter = (xdrproc_t) xdr_void, }, +{ /* DomainMigrateSetMaxDowntime => 165 */ + .fn = (dispatch_fn) remoteDispatchDomainMigrateSetMaxDowntime, + .args_filter = (xdrproc_t) xdr_remote_domain_migrate_set_max_downtime_args, + .ret_filter = (xdrproc_t) xdr_void, +}, diff --git a/src/remote/remote_protocol.c b/src/remote/remote_protocol.c index 701acab..490ad43 100644 --- a/src/remote/remote_protocol.c +++ b/src/remote/remote_protocol.c @@ -3009,6 +3009,19 @@ xdr_remote_domain_abort_job_args (XDR *xdrs, remote_domain_abort_job_args *objp) } bool_t +xdr_remote_domain_migrate_set_max_downtime_args (XDR *xdrs, remote_domain_migrate_set_max_downtime_args *objp) +{ + + if (!xdr_remote_nonnull_domain (xdrs, &objp->dom)) + return FALSE; + if (!xdr_uint64_t (xdrs, &objp->downtime)) + return FALSE; + if (!xdr_u_int (xdrs, &objp->flags)) + return FALSE; + return TRUE; +} + +bool_t xdr_remote_procedure (XDR *xdrs, remote_procedure *objp) { diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index f76e6e5..34d49fa 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -4,51 +4,51 @@ */ #ifndef _RP_H_RPCGEN -# define _RP_H_RPCGEN +#define _RP_H_RPCGEN -# include <rpc/rpc.h> +#include <rpc/rpc.h> -# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif -# include "internal.h" -# include <arpa/inet.h> -# define REMOTE_MESSAGE_MAX 262144 -# define REMOTE_MESSAGE_HEADER_MAX 24 -# define REMOTE_MESSAGE_PAYLOAD_MAX 262120 -# define REMOTE_STRING_MAX 65536 +#include "internal.h" +#include <arpa/inet.h> +#define REMOTE_MESSAGE_MAX 262144 +#define REMOTE_MESSAGE_HEADER_MAX 24 +#define REMOTE_MESSAGE_PAYLOAD_MAX 262120 +#define REMOTE_STRING_MAX 65536 typedef char *remote_nonnull_string; typedef remote_nonnull_string *remote_string; -# define REMOTE_DOMAIN_ID_LIST_MAX 16384 -# define REMOTE_DOMAIN_NAME_LIST_MAX 1024 -# define REMOTE_CPUMAP_MAX 256 -# define REMOTE_VCPUINFO_MAX 2048 -# define REMOTE_CPUMAPS_MAX 16384 -# define REMOTE_MIGRATE_COOKIE_MAX 256 -# define REMOTE_NETWORK_NAME_LIST_MAX 256 -# define REMOTE_INTERFACE_NAME_LIST_MAX 256 -# define REMOTE_DEFINED_INTERFACE_NAME_LIST_MAX 256 -# define REMOTE_STORAGE_POOL_NAME_LIST_MAX 256 -# define REMOTE_STORAGE_VOL_NAME_LIST_MAX 1024 -# define REMOTE_NODE_DEVICE_NAME_LIST_MAX 16384 -# define REMOTE_NODE_DEVICE_CAPS_LIST_MAX 16384 -# define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16 -# define REMOTE_NODE_MAX_CELLS 1024 -# define REMOTE_AUTH_SASL_DATA_MAX 65536 -# define REMOTE_AUTH_TYPE_LIST_MAX 20 -# define REMOTE_DOMAIN_MEMORY_STATS_MAX 1024 -# define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536 -# define REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX 65536 -# define REMOTE_SECURITY_MODEL_MAX VIR_SECURITY_MODEL_BUFLEN -# define REMOTE_SECURITY_LABEL_MAX VIR_SECURITY_LABEL_BUFLEN -# define REMOTE_SECURITY_DOI_MAX VIR_SECURITY_DOI_BUFLEN -# define REMOTE_SECRET_VALUE_MAX 65536 -# define REMOTE_SECRET_UUID_LIST_MAX 16384 -# define REMOTE_CPU_BASELINE_MAX 256 +#define REMOTE_DOMAIN_ID_LIST_MAX 16384 +#define REMOTE_DOMAIN_NAME_LIST_MAX 1024 +#define REMOTE_CPUMAP_MAX 256 +#define REMOTE_VCPUINFO_MAX 2048 +#define REMOTE_CPUMAPS_MAX 16384 +#define REMOTE_MIGRATE_COOKIE_MAX 256 +#define REMOTE_NETWORK_NAME_LIST_MAX 256 +#define REMOTE_INTERFACE_NAME_LIST_MAX 256 +#define REMOTE_DEFINED_INTERFACE_NAME_LIST_MAX 256 +#define REMOTE_STORAGE_POOL_NAME_LIST_MAX 256 +#define REMOTE_STORAGE_VOL_NAME_LIST_MAX 1024 +#define REMOTE_NODE_DEVICE_NAME_LIST_MAX 16384 +#define REMOTE_NODE_DEVICE_CAPS_LIST_MAX 16384 +#define REMOTE_DOMAIN_SCHEDULER_PARAMETERS_MAX 16 +#define REMOTE_NODE_MAX_CELLS 1024 +#define REMOTE_AUTH_SASL_DATA_MAX 65536 +#define REMOTE_AUTH_TYPE_LIST_MAX 20 +#define REMOTE_DOMAIN_MEMORY_STATS_MAX 1024 +#define REMOTE_DOMAIN_BLOCK_PEEK_BUFFER_MAX 65536 +#define REMOTE_DOMAIN_MEMORY_PEEK_BUFFER_MAX 65536 +#define REMOTE_SECURITY_MODEL_MAX VIR_SECURITY_MODEL_BUFLEN +#define REMOTE_SECURITY_LABEL_MAX VIR_SECURITY_LABEL_BUFLEN +#define REMOTE_SECURITY_DOI_MAX VIR_SECURITY_DOI_BUFLEN +#define REMOTE_SECRET_VALUE_MAX 65536 +#define REMOTE_SECRET_UUID_LIST_MAX 16384 +#define REMOTE_CPU_BASELINE_MAX 256 typedef char remote_uuid[VIR_UUID_BUFLEN]; @@ -1704,8 +1704,15 @@ struct remote_domain_abort_job_args { remote_nonnull_domain dom; }; typedef struct remote_domain_abort_job_args remote_domain_abort_job_args; -# define REMOTE_PROGRAM 0x20008086 -# define REMOTE_PROTOCOL_VERSION 1 + +struct remote_domain_migrate_set_max_downtime_args { + remote_nonnull_domain dom; + uint64_t downtime; + u_int flags; +}; +typedef struct remote_domain_migrate_set_max_downtime_args remote_domain_migrate_set_max_downtime_args; +#define REMOTE_PROGRAM 0x20008086 +#define REMOTE_PROTOCOL_VERSION 1 enum remote_procedure { REMOTE_PROC_OPEN = 1, @@ -1872,6 +1879,7 @@ enum remote_procedure { REMOTE_PROC_CPU_BASELINE = 162, REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, REMOTE_PROC_DOMAIN_ABORT_JOB = 164, + REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 165, }; typedef enum remote_procedure remote_procedure; @@ -1889,7 +1897,7 @@ enum remote_message_status { REMOTE_CONTINUE = 2, }; typedef enum remote_message_status remote_message_status; -# define REMOTE_MESSAGE_HEADER_XDR_LEN 4 +#define REMOTE_MESSAGE_HEADER_XDR_LEN 4 struct remote_message_header { u_int prog; @@ -1903,7 +1911,7 @@ typedef struct remote_message_header remote_message_header; /* the xdr functions */ -# if defined(__STDC__) || defined(__cplusplus) +#if defined(__STDC__) || defined(__cplusplus) extern bool_t xdr_remote_nonnull_string (XDR *, remote_nonnull_string*); extern bool_t xdr_remote_string (XDR *, remote_string*); extern bool_t xdr_remote_uuid (XDR *, remote_uuid); @@ -2181,12 +2189,13 @@ extern bool_t xdr_remote_cpu_baseline_ret (XDR *, remote_cpu_baseline_ret*); extern bool_t xdr_remote_domain_get_job_info_args (XDR *, remote_domain_get_job_info_args*); extern bool_t xdr_remote_domain_get_job_info_ret (XDR *, remote_domain_get_job_info_ret*); extern bool_t xdr_remote_domain_abort_job_args (XDR *, remote_domain_abort_job_args*); +extern bool_t xdr_remote_domain_migrate_set_max_downtime_args (XDR *, remote_domain_migrate_set_max_downtime_args*); extern bool_t xdr_remote_procedure (XDR *, remote_procedure*); extern bool_t xdr_remote_message_type (XDR *, remote_message_type*); extern bool_t xdr_remote_message_status (XDR *, remote_message_status*); extern bool_t xdr_remote_message_header (XDR *, remote_message_header*); -# else /* K&R C */ +#else /* K&R C */ extern bool_t xdr_remote_nonnull_string (); extern bool_t xdr_remote_string (); extern bool_t xdr_remote_uuid (); @@ -2464,15 +2473,16 @@ extern bool_t xdr_remote_cpu_baseline_ret (); extern bool_t xdr_remote_domain_get_job_info_args (); extern bool_t xdr_remote_domain_get_job_info_ret (); extern bool_t xdr_remote_domain_abort_job_args (); +extern bool_t xdr_remote_domain_migrate_set_max_downtime_args (); extern bool_t xdr_remote_procedure (); extern bool_t xdr_remote_message_type (); extern bool_t xdr_remote_message_status (); extern bool_t xdr_remote_message_header (); -# endif /* K&R C */ +#endif /* K&R C */ -# ifdef __cplusplus +#ifdef __cplusplus } -# endif +#endif #endif /* !_RP_H_RPCGEN */ diff --git a/src/remote/remote_protocol.x b/src/remote/remote_protocol.x index 5e33da5..9f6521a 100644 --- a/src/remote/remote_protocol.x +++ b/src/remote/remote_protocol.x @@ -1517,6 +1517,13 @@ struct remote_domain_abort_job_args { }; +struct remote_domain_migrate_set_max_downtime_args { + remote_nonnull_domain dom; + unsigned hyper downtime; + unsigned flags; +}; + + /*----- Protocol. -----*/ /* Define the program number, protocol version and procedure numbers here. */ @@ -1703,7 +1710,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, REMOTE_PROC_CPU_BASELINE = 162, REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, - REMOTE_PROC_DOMAIN_ABORT_JOB = 164 + REMOTE_PROC_DOMAIN_ABORT_JOB = 164, + REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 165 /* * Notice how the entries are grouped in sets of 10 ? -- 1.7.0.2

On Thu, Mar 18, 2010 at 08:12:45PM +0100, Jiri Denemark wrote: [...]
diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index f76e6e5..34d49fa 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -4,51 +4,51 @@ */
#ifndef _RP_H_RPCGEN -# define _RP_H_RPCGEN +#define _RP_H_RPCGEN
-# include <rpc/rpc.h> +#include <rpc/rpc.h>
-# ifdef __cplusplus +#ifdef __cplusplus extern "C" { -# endif +#endif
-# include "internal.h" -# include <arpa/inet.h> -# define REMOTE_MESSAGE_MAX 262144 -# define REMOTE_MESSAGE_HEADER_MAX 24 -# define REMOTE_MESSAGE_PAYLOAD_MAX 262120 -# define REMOTE_STRING_MAX 65536 +#include "internal.h" +#include <arpa/inet.h> +#define REMOTE_MESSAGE_MAX 262144 +#define REMOTE_MESSAGE_HEADER_MAX 24 +#define REMOTE_MESSAGE_PAYLOAD_MAX 262120 +#define REMOTE_STRING_MAX 65536
painful because it's generated, if you don't have cppi installed make "syntax-check" won't complain, but I'm afraid it will for those where this is present. I think the patch is fine, we just need to make sure that generated file is not checked for the cppi test, [...]
@@ -1703,7 +1710,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, REMOTE_PROC_CPU_BASELINE = 162, REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, - REMOTE_PROC_DOMAIN_ABORT_JOB = 164 + REMOTE_PROC_DOMAIN_ABORT_JOB = 164, + REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 165
/* * Notice how the entries are grouped in sets of 10 ?
note that the patch will probably have to be regenerated once Dave Allan new interface is pushed too, as both patches use 165 ACK, but may have to be regenerated Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

diff --git a/src/remote/remote_protocol.h b/src/remote/remote_protocol.h index f76e6e5..34d49fa 100644 --- a/src/remote/remote_protocol.h +++ b/src/remote/remote_protocol.h @@ -4,51 +4,51 @@ */
#ifndef _RP_H_RPCGEN -# define _RP_H_RPCGEN +#define _RP_H_RPCGEN
-# include <rpc/rpc.h> +#include <rpc/rpc.h>
painful because it's generated, if you don't have cppi installed make "syntax-check" won't complain, but I'm afraid it will for those where this is present. I think the patch is fine, we just need to make sure that generated file is not checked for the cppi test,
Actually, it's not really painful. This is probably a result of a massive reindenting of CPP directives which was mistakenly done for generated files. I do have cppi installed and it doesn't complain since the syntax check rule already ignores remote_(driver|protocol)\.h
@@ -1703,7 +1710,8 @@ enum remote_procedure { REMOTE_PROC_DOMAIN_DETACH_DEVICE_FLAGS = 161, REMOTE_PROC_CPU_BASELINE = 162, REMOTE_PROC_DOMAIN_GET_JOB_INFO = 163, - REMOTE_PROC_DOMAIN_ABORT_JOB = 164 + REMOTE_PROC_DOMAIN_ABORT_JOB = 164, + REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME = 165
/* * Notice how the entries are grouped in sets of 10 ?
note that the patch will probably have to be regenerated once Dave Allan new interface is pushed too, as both patches use 165
Sure, I'm aware of those patches. The only question is which patches will be pushed first :-) Jirka

On 03/19/2010 04:37 AM, Daniel Veillard wrote:
-# define REMOTE_STRING_MAX 65536 +#include "internal.h" +#include <arpa/inet.h> +#define REMOTE_MESSAGE_MAX 262144 +#define REMOTE_MESSAGE_HEADER_MAX 24 +#define REMOTE_MESSAGE_PAYLOAD_MAX 262120 +#define REMOTE_STRING_MAX 65536
painful because it's generated, if you don't have cppi installed make "syntax-check" won't complain, but I'm afraid it will for those where this is present. I think the patch is fine, we just need to make sure that generated file is not checked for the cppi test,
Yes, remote_protocol.h is already exempted from the cppi test. I did a global update, knowing that exempted files would be swapped back, but this should still pass 'make syntax-check' even with cppi installed. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org

--- src/remote/remote_driver.c | 32 +++++++++++++++++++++++++++++++- 1 files changed, 31 insertions(+), 1 deletions(-) diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2fb81a1..58f5a9d 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7707,6 +7707,36 @@ done: } +static int +remoteDomainMigrateSetMaxDowntime(virDomainPtr domain, + unsigned long long downtime, + unsigned int flags) +{ + struct private_data *priv = domain->conn->privateData; + remote_domain_migrate_set_max_downtime_args args; + int rv = -1; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.dom, domain); + args.downtime = downtime; + args.flags = flags; + + if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME, + (xdrproc_t) xdr_remote_domain_migrate_set_max_downtime_args, + (char *) &args, + (xdrproc_t) xdr_void, + (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + + /*----------------------------------------------------------------------*/ @@ -9126,7 +9156,7 @@ static virDriver remote_driver = { remoteCPUBaseline, /* cpuBaseline */ remoteDomainGetJobInfo, /* domainGetJobInfo */ remoteDomainAbortJob, /* domainFinishJob */ - NULL, /* domainMigrateSetMaxDowntime */ + remoteDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */ }; static virNetworkDriver network_driver = { -- 1.7.0.2

On Thu, Mar 18, 2010 at 08:12:46PM +0100, Jiri Denemark wrote:
--- src/remote/remote_driver.c | 32 +++++++++++++++++++++++++++++++- 1 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c index 2fb81a1..58f5a9d 100644 --- a/src/remote/remote_driver.c +++ b/src/remote/remote_driver.c @@ -7707,6 +7707,36 @@ done: }
+static int +remoteDomainMigrateSetMaxDowntime(virDomainPtr domain, + unsigned long long downtime, + unsigned int flags) +{ + struct private_data *priv = domain->conn->privateData; + remote_domain_migrate_set_max_downtime_args args; + int rv = -1; + + remoteDriverLock(priv); + + make_nonnull_domain(&args.dom, domain); + args.downtime = downtime; + args.flags = flags; + + if (call(domain->conn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_SET_MAX_DOWNTIME, + (xdrproc_t) xdr_remote_domain_migrate_set_max_downtime_args, + (char *) &args, + (xdrproc_t) xdr_void, + (char *) NULL) == -1) + goto done; + + rv = 0; + +done: + remoteDriverUnlock(priv); + return rv; +} + + /*----------------------------------------------------------------------*/
@@ -9126,7 +9156,7 @@ static virDriver remote_driver = { remoteCPUBaseline, /* cpuBaseline */ remoteDomainGetJobInfo, /* domainGetJobInfo */ remoteDomainAbortJob, /* domainFinishJob */ - NULL, /* domainMigrateSetMaxDowntime */ + remoteDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */ };
static virNetworkDriver network_driver = {
ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

--- src/qemu/qemu_driver.c | 70 +++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 15 +++++++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_json.c | 29 +++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 ++ src/qemu/qemu_monitor_text.c | 27 ++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 ++ 7 files changed, 149 insertions(+), 1 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4cb47f7..d04d9bf 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -99,6 +99,11 @@ enum qemuDomainJob { enum qemuDomainJobSignals { QEMU_JOB_SIGNAL_CANCEL = 1 << 0, /* Request job cancellation */ QEMU_JOB_SIGNAL_SUSPEND = 1 << 1, /* Request VM suspend to finish live migration offline */ + QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME = 1 << 2, /* Request migration downtime change */ +}; + +struct qemuDomainJobSignalsData { + unsigned long long migrateDowntime; /* Data for QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME */ }; typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; @@ -107,6 +112,7 @@ struct _qemuDomainObjPrivate { virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */ enum qemuDomainJob jobActive; /* Currently running job */ unsigned int jobSignals; /* Signals for running job */ + struct qemuDomainJobSignalsData jobSignalsData; /* Signal specific data */ virDomainJobInfo jobInfo; unsigned long long jobStart; @@ -352,6 +358,7 @@ static int qemuDomainObjBeginJob(virDomainObjPtr obj) } priv->jobActive = QEMU_JOB_UNSPECIFIED; priv->jobSignals = 0; + memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); @@ -399,6 +406,7 @@ static int qemuDomainObjBeginJobWithDriver(struct qemud_driver *driver, } priv->jobActive = QEMU_JOB_UNSPECIFIED; priv->jobSignals = 0; + memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); priv->jobStart = (now.tv_sec * 1000ull) + (now.tv_usec / 1000); memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); @@ -424,6 +432,7 @@ static int ATTRIBUTE_RETURN_CHECK qemuDomainObjEndJob(virDomainObjPtr obj) priv->jobActive = QEMU_JOB_NONE; priv->jobSignals = 0; + memset(&priv->jobSignalsData, 0, sizeof(priv->jobSignalsData)); priv->jobStart = 0; memset(&priv->jobInfo, 0, sizeof(priv->jobInfo)); virCondSignal(&priv->jobCond); @@ -4061,6 +4070,17 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr VIR_DEBUG0("Pausing domain for non-live migration"); if (qemuDomainMigrateOffline(driver, vm) < 0) VIR_WARN0("Unable to pause domain"); + } else if (priv->jobSignals & QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME) { + unsigned long long ns = priv->jobSignalsData.migrateDowntime; + + priv->jobSignals ^= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; + priv->jobSignalsData.migrateDowntime = 0; + VIR_DEBUG("Setting migration downtime to %lluns", ns); + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorSetMigrationDowntime(priv->mon, ns); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) + VIR_WARN0("Unable to set migration downtime"); } qemuDomainObjEnterMonitorWithDriver(driver, vm); @@ -9516,6 +9536,54 @@ cleanup: } +static int +qemuDomainMigrateSetMaxDowntime(virDomainPtr dom, + unsigned long long downtime, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + qemuDomainObjPrivatePtr priv; + int ret = -1; + + qemuDriverLock(driver); + vm = virDomainFindByUUID(&driver->domains, dom->uuid); + + if (!vm) { + char uuidstr[VIR_UUID_STRING_BUFLEN]; + virUUIDFormat(dom->uuid, uuidstr); + qemuReportError(VIR_ERR_NO_DOMAIN, + _("no domain with matching uuid '%s'"), uuidstr); + goto cleanup; + } + + if (!virDomainObjIsActive(vm)) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not running")); + goto cleanup; + } + + priv = vm->privateData; + + if (priv->jobActive != QEMU_JOB_MIGRATION) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not being migrated")); + goto cleanup; + } + + VIR_DEBUG("Requesting migration downtime change to %lluns", downtime); + priv->jobSignals |= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; + priv->jobSignalsData.migrateDowntime = downtime; + ret = 0; + +cleanup: + if (vm) + virDomainObjUnlock(vm); + qemuDriverUnlock(driver); + return ret; +} + + static virDriver qemuDriver = { VIR_DRV_QEMU, "QEMU", @@ -9597,7 +9665,7 @@ static virDriver qemuDriver = { qemuCPUBaseline, /* cpuBaseline */ qemuDomainGetJobInfo, /* domainGetJobInfo */ qemuDomainAbortJob, /* domainAbortJob */ - NULL, /* domainMigrateSetMaxDowntime */ + qemuDomainMigrateSetMaxDowntime, /* domainMigrateSetMaxDowntime */ }; diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c index acc841b..6b68db8 100644 --- a/src/qemu/qemu_monitor.c +++ b/src/qemu/qemu_monitor.c @@ -1016,6 +1016,21 @@ int qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon, return ret; } + +int qemuMonitorSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime) +{ + int ret; + DEBUG("mon=%p, fd=%d downtime=%llu", mon, mon->fd, downtime); + + if (mon->json) + ret = qemuMonitorJSONSetMigrationDowntime(mon, downtime); + else + ret = qemuMonitorTextSetMigrationDowntime(mon, downtime); + return ret; +} + + int qemuMonitorGetMigrationStatus(qemuMonitorPtr mon, int *status, unsigned long long *transferred, diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h index cfb76b6..2557fb9 100644 --- a/src/qemu/qemu_monitor.h +++ b/src/qemu/qemu_monitor.h @@ -176,6 +176,9 @@ int qemuMonitorSavePhysicalMemory(qemuMonitorPtr mon, int qemuMonitorSetMigrationSpeed(qemuMonitorPtr mon, unsigned long bandwidth); +int qemuMonitorSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime); + enum { QEMU_MONITOR_MIGRATION_STATUS_INACTIVE, QEMU_MONITOR_MIGRATION_STATUS_ACTIVE, diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index 7a263cb..b259452 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1088,6 +1088,35 @@ int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon, } +int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime) +{ + int ret; + char *downtimestr; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + if (virAsprintf(&downtimestr, "%llun", downtime) < 0) { + virReportOOMError(); + return -1; + } + cmd = qemuMonitorJSONMakeCommand("migrate_set_downtime", + "s:value", downtimestr, + NULL); + VIR_FREE(downtimestr); + if (!cmd) + return -1; + + ret = qemuMonitorJSONCommand(mon, cmd, &reply); + + if (ret == 0) + ret = qemuMonitorJSONCheckError(cmd, reply); + + virJSONValueFree(cmd); + virJSONValueFree(reply); + return ret; +} + + static int qemuMonitorJSONGetMigrationStatusReply(virJSONValuePtr reply, int *status, diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h index 2906fee..fc05153 100644 --- a/src/qemu/qemu_monitor_json.h +++ b/src/qemu/qemu_monitor_json.h @@ -81,6 +81,9 @@ int qemuMonitorJSONSavePhysicalMemory(qemuMonitorPtr mon, int qemuMonitorJSONSetMigrationSpeed(qemuMonitorPtr mon, unsigned long bandwidth); +int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime); + int qemuMonitorJSONGetMigrationStatus(qemuMonitorPtr mon, int *status, unsigned long long *transferred, diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index b7c41a1..ca2fc97 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -999,6 +999,33 @@ cleanup: } +int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime) +{ + char *cmd = NULL; + char *info = NULL; + int ret = -1; + + if (virAsprintf(&cmd, "migrate_set_downtime %llun", downtime) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (qemuMonitorCommand(mon, cmd, &info) < 0) { + qemuReportError(VIR_ERR_OPERATION_FAILED, + "%s", _("could not set maximum migration downtime")); + goto cleanup; + } + + ret = 0; + +cleanup: + VIR_FREE(info); + VIR_FREE(cmd); + return ret; +} + + #define MIGRATION_PREFIX "Migration status: " #define MIGRATION_TRANSFER_PREFIX "transferred ram: " #define MIGRATION_REMAINING_PREFIX "remaining ram: " diff --git a/src/qemu/qemu_monitor_text.h b/src/qemu/qemu_monitor_text.h index 3215cae..4e1939c 100644 --- a/src/qemu/qemu_monitor_text.h +++ b/src/qemu/qemu_monitor_text.h @@ -83,6 +83,9 @@ int qemuMonitorTextSavePhysicalMemory(qemuMonitorPtr mon, int qemuMonitorTextSetMigrationSpeed(qemuMonitorPtr mon, unsigned long bandwidth); +int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime); + int qemuMonitorTextGetMigrationStatus(qemuMonitorPtr mon, int *status, unsigned long long *transferred, -- 1.7.0.2

On Thu, Mar 18, 2010 at 08:12:47PM +0100, Jiri Denemark wrote:
--- src/qemu/qemu_driver.c | 70 +++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 15 +++++++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_json.c | 29 +++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 ++ src/qemu/qemu_monitor_text.c | 27 ++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 ++ 7 files changed, 149 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 4cb47f7..d04d9bf 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -99,6 +99,11 @@ enum qemuDomainJob { enum qemuDomainJobSignals { QEMU_JOB_SIGNAL_CANCEL = 1 << 0, /* Request job cancellation */ QEMU_JOB_SIGNAL_SUSPEND = 1 << 1, /* Request VM suspend to finish live migration offline */ + QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME = 1 << 2, /* Request migration downtime change */ +}; + +struct qemuDomainJobSignalsData { + unsigned long long migrateDowntime; /* Data for QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME */ };
typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; @@ -107,6 +112,7 @@ struct _qemuDomainObjPrivate { virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */ enum qemuDomainJob jobActive; /* Currently running job */ unsigned int jobSignals; /* Signals for running job */ + struct qemuDomainJobSignalsData jobSignalsData; /* Signal specific data */ virDomainJobInfo jobInfo; unsigned long long jobStart;
I think I would have had an easier time understanding the patch if with some explanation that we use jobSignalsData to indicate the user desired change and that it would be applied once the background migration job wakes up and look at the data, then passes it to qemu. [...]
@@ -4061,6 +4070,17 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr VIR_DEBUG0("Pausing domain for non-live migration"); if (qemuDomainMigrateOffline(driver, vm) < 0) VIR_WARN0("Unable to pause domain"); + } else if (priv->jobSignals & QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME) { + unsigned long long ns = priv->jobSignalsData.migrateDowntime; + + priv->jobSignals ^= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; + priv->jobSignalsData.migrateDowntime = 0; + VIR_DEBUG("Setting migration downtime to %lluns", ns); + qemuDomainObjEnterMonitorWithDriver(driver, vm); + rc = qemuMonitorSetMigrationDowntime(priv->mon, ns); + qemuDomainObjExitMonitorWithDriver(driver, vm); + if (rc < 0) + VIR_WARN0("Unable to set migration downtime"); }
qemuDomainObjEnterMonitorWithDriver(driver, vm); @@ -9516,6 +9536,54 @@ cleanup: }
+static int +qemuDomainMigrateSetMaxDowntime(virDomainPtr dom, + unsigned long long downtime, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + qemuDomainObjPrivatePtr priv; + int ret = -1; + + qemuDriverLock(driver); [...] + priv = vm->privateData; + + if (priv->jobActive != QEMU_JOB_MIGRATION) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not being migrated")); + goto cleanup; + } + + VIR_DEBUG("Requesting migration downtime change to %lluns", downtime); + priv->jobSignals |= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; + priv->jobSignalsData.migrateDowntime = downtime;
There is something I donc fully see in this, which is how the producer/consumer for priv->jobSignals are synchronized. I would actually swap those 2 statements if there is no synchronization to make sure we don't pick an uninitialized (or zeroed) value in qemuDomainWaitForMigrationComplete(). I'm not clear if this can be processed by 2 different threads Everything else looks just fine to me, ACK, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

typedef struct _qemuDomainObjPrivate qemuDomainObjPrivate; @@ -107,6 +112,7 @@ struct _qemuDomainObjPrivate { virCond jobCond; /* Use in conjunction with main virDomainObjPtr lock */ enum qemuDomainJob jobActive; /* Currently running job */ unsigned int jobSignals; /* Signals for running job */ + struct qemuDomainJobSignalsData jobSignalsData; /* Signal specific data */ virDomainJobInfo jobInfo; unsigned long long jobStart;
I think I would have had an easier time understanding the patch if with some explanation that we use jobSignalsData to indicate the user desired change and that it would be applied once the background migration job wakes up and look at the data, then passes it to qemu.
Ah yes, sorry about that. There was a description of signals in the patch which introduced them and I forgot to write more about it when I extended them with additional data.
+static int +qemuDomainMigrateSetMaxDowntime(virDomainPtr dom, + unsigned long long downtime, + unsigned int flags ATTRIBUTE_UNUSED) +{ + struct qemud_driver *driver = dom->conn->privateData; + virDomainObjPtr vm; + qemuDomainObjPrivatePtr priv; + int ret = -1; + + qemuDriverLock(driver); [...] + priv = vm->privateData; + + if (priv->jobActive != QEMU_JOB_MIGRATION) { + qemuReportError(VIR_ERR_OPERATION_INVALID, + "%s", _("domain is not being migrated")); + goto cleanup; + } + + VIR_DEBUG("Requesting migration downtime change to %lluns", downtime); + priv->jobSignals |= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; + priv->jobSignalsData.migrateDowntime = downtime;
There is something I donc fully see in this, which is how the producer/consumer for priv->jobSignals are synchronized. I would actually swap those 2 statements if there is no synchronization to make sure we don't pick an uninitialized (or zeroed) value in qemuDomainWaitForMigrationComplete(). I'm not clear if this can be processed by 2 different threads
Well, swapping wouldn't help as CPUs don't guarantee assignment order without synchronizing. Anyway, the two threads are synchronized on the vm object. In the part you removed ([...]) qemuDomainMigrateSetMaxDowntime calls virDomainFindByUUID, which automatically locks the vm object returned. On the other hand qemuDomainWaitForMigrationComplete has the vm object locked all the time except for the time when it communicates with qemu monitor, i.e. between qemuDomainObjEnterMonitorWithDriver and qemuDomainObjExitMonitorWithDriver. Jirka

On Thu, Mar 18, 2010 at 08:12:47PM +0100, Jiri Denemark wrote:
--- src/qemu/qemu_driver.c | 70 +++++++++++++++++++++++++++++++++++++++++- src/qemu/qemu_monitor.c | 15 +++++++++ src/qemu/qemu_monitor.h | 3 ++ src/qemu/qemu_monitor_json.c | 29 +++++++++++++++++ src/qemu/qemu_monitor_json.h | 3 ++ src/qemu/qemu_monitor_text.c | 27 ++++++++++++++++ src/qemu/qemu_monitor_text.h | 3 ++ 7 files changed, 149 insertions(+), 1 deletions(-)
May comment about time scale for virsh CLI just raised a question here in the QEmu driver: [...]
+int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime) +{ + int ret; + char *downtimestr; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + if (virAsprintf(&downtimestr, "%llun", downtime) < 0) {
Hum, just wondering, QEmu interface really takes nanoseconds as its input or shouldn't that be scaled down ? And in case we forgot to scale down, we need to be very careful if the division leads to 0, assuming migrate_set_downtime 0 may mean something completely different from what we asked . Can you confirm QEmu uses nanoseconds input ? Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

+int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, + unsigned long long downtime) +{ + int ret; + char *downtimestr; + virJSONValuePtr cmd; + virJSONValuePtr reply = NULL; + if (virAsprintf(&downtimestr, "%llun", downtime) < 0) {
Hum, just wondering, QEmu interface really takes nanoseconds as its input or shouldn't that be scaled down ? And in case we forgot to scale down, we need to be very careful if the division leads to 0, assuming
migrate_set_downtime 0
may mean something completely different from what we asked .
Can you confirm QEmu uses nanoseconds input ?
Oh crap... I did a mistake here and in text monitor code. QEmu accepts floating-point seconds with possible "ms", "us", or "ns" suffix for milli-, micro-, or nanoseconds. So yes, it accepts nanoseconds, although I should have used "ns" instead of "n" suffix. I'm wondering how it could ever worked as QEmu is supposed to complain about unknown unit suffix. Jirka

--- tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++++ 2 files changed, 72 insertions(+), 0 deletions(-) diff --git a/tools/virsh.c b/tools/virsh.c index aa85ee6..3dd9314 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -227,6 +227,8 @@ static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name); static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found); static char *vshCommandOptString(const vshCmd *cmd, const char *name, int *found); +static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name, + int *found); #if 0 static int vshCommandOptStringList(const vshCmd *cmd, const char *name, char ***data); #endif @@ -2828,6 +2830,51 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) } /* + * "migrate-setmaxdowntime" command + */ +static const vshCmdInfo info_migrate_setmaxdowntime[] = { + {"help", N_("set maximum tolerable downtime")}, + {"desc", N_("Set maximum tolerable downtime of a domain which is being live-migrated to another host.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in nanoseconds) for migration")}, + {NULL, 0, 0, NULL} +}; + +static int +cmdMigrateSetMaxDowntime(vshControl *ctl, const vshCmd *cmd) +{ + virDomainPtr dom = NULL; + long long downtime; + int found; + int ret = FALSE; + + if (!vshConnectionUsability(ctl, ctl->conn, TRUE)) + return FALSE; + + if (!(dom = vshCommandOptDomain(ctl, cmd, NULL))) + return FALSE; + + downtime = vshCommandOptLongLong(cmd, "downtime", &found); + if (!found || downtime < 1) { + vshError(ctl, "%s", _("migrate: Invalid downtime")); + goto done; + } + + if (virDomainMigrateSetMaxDowntime(dom, downtime, 0)) + goto done; + + ret = TRUE; + +done: + virDomainFree(dom); + return ret; +} + +/* * "net-autostart" command */ static const vshCmdInfo info_network_autostart[] = { @@ -7726,6 +7773,7 @@ static const vshCmdDef commands[] = { {"hostname", cmdHostname, NULL, info_hostname}, {"list", cmdList, opts_list, info_list}, {"migrate", cmdMigrate, opts_migrate, info_migrate}, + {"migrate-setmaxdowntime", cmdMigrateSetMaxDowntime, opts_migrate_setmaxdowntime, info_migrate_setmaxdowntime}, {"net-autostart", cmdNetworkAutostart, opts_network_autostart, info_network_autostart}, {"net-create", cmdNetworkCreate, opts_network_create, info_network_create}, @@ -8065,6 +8113,24 @@ vshCommandOptString(const vshCmd *cmd, const char *name, int *found) return arg && arg->data && *arg->data ? arg->data : NULL; } +/* + * Returns option as long long + */ +static long long +vshCommandOptLongLong(const vshCmd *cmd, const char *name, int *found) +{ + vshCmdOpt *arg = vshCommandOpt(cmd, name); + int num_found = FALSE; + long long res = 0; + char *end_p = NULL; + + if ((arg != NULL) && (arg->data != NULL)) + num_found = !virStrToLong_ll(arg->data, &end_p, 10, &res); + if (found) + *found = num_found; + return res; +} + #if 0 static int vshCommandOptStringList(const vshCmd *cmd, const char *name, char ***data) diff --git a/tools/virsh.pod b/tools/virsh.pod index 8f6df19..1c7cfce 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -334,6 +334,12 @@ leaves the domain paused on the destination host. The I<desturi> is the connection URI of the destination host, and I<migrateuri> is the migration URI, which usually can be omitted. +=item B<migrate-setmaxdowntime> I<domain-id> I<downtime> + +Set maximum tolerable downtime for a domain which is being live-migrated to +another host. The I<downtime> is a number of nanoseconds the guest is allowed +to be down at the end of live migration. + =item B<reboot> I<domain-id> Reboot a domain. This acts just as if the domain had the B<reboot> -- 1.7.0.2

On Thu, Mar 18, 2010 at 08:12:48PM +0100, Jiri Denemark wrote:
--- tools/virsh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/virsh.pod | 6 +++++ 2 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/tools/virsh.c b/tools/virsh.c index aa85ee6..3dd9314 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -227,6 +227,8 @@ static vshCmdOpt *vshCommandOpt(const vshCmd *cmd, const char *name); static int vshCommandOptInt(const vshCmd *cmd, const char *name, int *found); static char *vshCommandOptString(const vshCmd *cmd, const char *name, int *found); +static long long vshCommandOptLongLong(const vshCmd *cmd, const char *name, + int *found); #if 0 static int vshCommandOptStringList(const vshCmd *cmd, const char *name, char ***data); #endif @@ -2828,6 +2830,51 @@ cmdMigrate (vshControl *ctl, const vshCmd *cmd) }
/* + * "migrate-setmaxdowntime" command + */ +static const vshCmdInfo info_migrate_setmaxdowntime[] = { + {"help", N_("set maximum tolerable downtime")}, + {"desc", N_("Set maximum tolerable downtime of a domain which is being live-migrated to another host.")}, + {NULL, NULL} +}; + +static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in nanoseconds) for migration")}, + {NULL, 0, 0, NULL} +};
Maybe for virsh command line we could use milliseconds, so that a "setmaxdowntime foo 1" can still have a chance to actually work, instead of blocking forever. [...]
+/* + * Returns option as long long + */ +static long long +vshCommandOptLongLong(const vshCmd *cmd, const char *name, int *found) +{ + vshCmdOpt *arg = vshCommandOpt(cmd, name); + int num_found = FALSE; + long long res = 0; + char *end_p = NULL; + + if ((arg != NULL) && (arg->data != NULL)) + num_found = !virStrToLong_ll(arg->data, &end_p, 10, &res); + if (found) + *found = num_found; + return res; +}
and in that case we could go with a normal int processing there too On one hand from an usability POV it looks more reasonnable to use millisecs here, on the other hand each time we make virsh CLI and libvirt API diverge in some way this leads to confusion. So I'm still undecided :-) Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

+static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in nanoseconds) for migration")}, + {NULL, 0, 0, NULL} +};
Maybe for virsh command line we could use milliseconds, so that a "setmaxdowntime foo 1" can still have a chance to actually work, instead of blocking forever. ... On one hand from an usability POV it looks more reasonnable to use millisecs here, on the other hand each time we make virsh CLI and libvirt API diverge in some way this leads to confusion.
So I'm still undecided :-)
Or we can do what Daniel suggested and use milliseconds in the API as well. Jirka

On Fri, Mar 19, 2010 at 12:45:28PM +0100, Jiri Denemark wrote:
+static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { + {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, + {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in nanoseconds) for migration")}, + {NULL, 0, 0, NULL} +};
Maybe for virsh command line we could use milliseconds, so that a "setmaxdowntime foo 1" can still have a chance to actually work, instead of blocking forever. ... On one hand from an usability POV it looks more reasonnable to use millisecs here, on the other hand each time we make virsh CLI and libvirt API diverge in some way this leads to confusion.
So I'm still undecided :-)
Or we can do what Daniel suggested and use milliseconds in the API as well.
Okay, let's use milleseconds al, the way through ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This API call sets maximum tolerable time for which the domain is allowed to be paused at the end of live migration. It's supposed to be called while the domain is being live-migrated as a reaction to migration progress.
Changes in version 3: - use milliseconds instead of nanoseconds both internally and in API - correct suffix for qemu monitor commands
Changes in version 2: - API renamed to reflect it's maximum downtime - new flags parameter for the future - qemu implementation was fixed so that the call is allowed iff the domain is being migrated - --downtime parameter of virsh migrate command was removed in favor of new virsh migrate-setmaxdowntime which can be run independently - virsh accepts downtime as nanoseconds instead of floating-point seconds (shells don't deal with floating-point numbers well)
Version 3 diff follows: src/libvirt.c | 2 +- src/qemu/qemu_driver.c | 8 ++++---- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_text.c | 2 +- tools/virsh.c | 2 +- tools/virsh.pod | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libvirt.c b/src/libvirt.c index 07837a3..178dbc1 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11270,7 +11270,7 @@ error: /** * virDomainMigrateSetMaxDowntime: * @domain: a domain object - * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @downtime: maximum tolerable downtime for live migration, in milliseconds * @flags: fine-tuning flags, currently unused, use 0 * * Sets maximum tolerable time for which the domain is allowed to be paused diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 322fb3f..2a7b5c0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4074,13 +4074,13 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr if (qemuDomainMigrateOffline(driver, vm) < 0) VIR_WARN0("Unable to pause domain"); } else if (priv->jobSignals & QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME) { - unsigned long long ns = priv->jobSignalsData.migrateDowntime; + unsigned long long ms = priv->jobSignalsData.migrateDowntime; priv->jobSignals ^= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; priv->jobSignalsData.migrateDowntime = 0; - VIR_DEBUG("Setting migration downtime to %lluns", ns); + VIR_DEBUG("Setting migration downtime to %llums", ms); qemuDomainObjEnterMonitorWithDriver(driver, vm); - rc = qemuMonitorSetMigrationDowntime(priv->mon, ns); + rc = qemuMonitorSetMigrationDowntime(priv->mon, ms); qemuDomainObjExitMonitorWithDriver(driver, vm); if (rc < 0) VIR_WARN0("Unable to set migration downtime"); @@ -9574,7 +9574,7 @@ qemuDomainMigrateSetMaxDowntime(virDomainPtr dom, goto cleanup; } - VIR_DEBUG("Requesting migration downtime change to %lluns", downtime); + VIR_DEBUG("Requesting migration downtime change to %llums", downtime); priv->jobSignals |= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; priv->jobSignalsData.migrateDowntime = downtime; ret = 0; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index b259452..4ae8093 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1095,7 +1095,7 @@ int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, char *downtimestr; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; - if (virAsprintf(&downtimestr, "%llun", downtime) < 0) { + if (virAsprintf(&downtimestr, "%llums", downtime) < 0) { virReportOOMError(); return -1; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ca2fc97..1596e59 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1006,7 +1006,7 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, char *info = NULL; int ret = -1; - if (virAsprintf(&cmd, "migrate_set_downtime %llun", downtime) < 0) { + if (virAsprintf(&cmd, "migrate_set_downtime %llums", downtime) < 0) { virReportOOMError(); goto cleanup; } diff --git a/tools/virsh.c b/tools/virsh.c index 3dd9314..cfcc86e 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2840,7 +2840,7 @@ static const vshCmdInfo info_migrate_setmaxdowntime[] = { static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in nanoseconds) for migration")}, + {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in milliseconds) for migration")}, {NULL, 0, 0, NULL} }; diff --git a/tools/virsh.pod b/tools/virsh.pod index 1c7cfce..a6298dd 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -337,7 +337,7 @@ migration URI, which usually can be omitted. =item B<migrate-setmaxdowntime> I<domain-id> I<downtime> Set maximum tolerable downtime for a domain which is being live-migrated to -another host. The I<downtime> is a number of nanoseconds the guest is allowed +another host. The I<downtime> is a number of milliseconds the guest is allowed to be down at the end of live migration. =item B<reboot> I<domain-id>

On Fri, Mar 19, 2010 at 04:51:11PM +0100, Jiri Denemark wrote:
This API call sets maximum tolerable time for which the domain is allowed to be paused at the end of live migration. It's supposed to be called while the domain is being live-migrated as a reaction to migration progress.
Changes in version 3: - use milliseconds instead of nanoseconds both internally and in API - correct suffix for qemu monitor commands
Changes in version 2: - API renamed to reflect it's maximum downtime - new flags parameter for the future - qemu implementation was fixed so that the call is allowed iff the domain is being migrated - --downtime parameter of virsh migrate command was removed in favor of new virsh migrate-setmaxdowntime which can be run independently - virsh accepts downtime as nanoseconds instead of floating-point seconds (shells don't deal with floating-point numbers well)
Version 3 diff follows:
src/libvirt.c | 2 +- src/qemu/qemu_driver.c | 8 ++++---- src/qemu/qemu_monitor_json.c | 2 +- src/qemu/qemu_monitor_text.c | 2 +- tools/virsh.c | 2 +- tools/virsh.pod | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/src/libvirt.c b/src/libvirt.c index 07837a3..178dbc1 100644 --- a/src/libvirt.c +++ b/src/libvirt.c @@ -11270,7 +11270,7 @@ error: /** * virDomainMigrateSetMaxDowntime: * @domain: a domain object - * @downtime: maximum tolerable downtime for live migration, in nanoseconds + * @downtime: maximum tolerable downtime for live migration, in milliseconds * @flags: fine-tuning flags, currently unused, use 0 * * Sets maximum tolerable time for which the domain is allowed to be paused diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 322fb3f..2a7b5c0 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -4074,13 +4074,13 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr if (qemuDomainMigrateOffline(driver, vm) < 0) VIR_WARN0("Unable to pause domain"); } else if (priv->jobSignals & QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME) { - unsigned long long ns = priv->jobSignalsData.migrateDowntime; + unsigned long long ms = priv->jobSignalsData.migrateDowntime;
priv->jobSignals ^= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; priv->jobSignalsData.migrateDowntime = 0; - VIR_DEBUG("Setting migration downtime to %lluns", ns); + VIR_DEBUG("Setting migration downtime to %llums", ms); qemuDomainObjEnterMonitorWithDriver(driver, vm); - rc = qemuMonitorSetMigrationDowntime(priv->mon, ns); + rc = qemuMonitorSetMigrationDowntime(priv->mon, ms); qemuDomainObjExitMonitorWithDriver(driver, vm); if (rc < 0) VIR_WARN0("Unable to set migration downtime"); @@ -9574,7 +9574,7 @@ qemuDomainMigrateSetMaxDowntime(virDomainPtr dom, goto cleanup; }
- VIR_DEBUG("Requesting migration downtime change to %lluns", downtime); + VIR_DEBUG("Requesting migration downtime change to %llums", downtime); priv->jobSignals |= QEMU_JOB_SIGNAL_MIGRATE_DOWNTIME; priv->jobSignalsData.migrateDowntime = downtime; ret = 0; diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c index b259452..4ae8093 100644 --- a/src/qemu/qemu_monitor_json.c +++ b/src/qemu/qemu_monitor_json.c @@ -1095,7 +1095,7 @@ int qemuMonitorJSONSetMigrationDowntime(qemuMonitorPtr mon, char *downtimestr; virJSONValuePtr cmd; virJSONValuePtr reply = NULL; - if (virAsprintf(&downtimestr, "%llun", downtime) < 0) { + if (virAsprintf(&downtimestr, "%llums", downtime) < 0) { virReportOOMError(); return -1; } diff --git a/src/qemu/qemu_monitor_text.c b/src/qemu/qemu_monitor_text.c index ca2fc97..1596e59 100644 --- a/src/qemu/qemu_monitor_text.c +++ b/src/qemu/qemu_monitor_text.c @@ -1006,7 +1006,7 @@ int qemuMonitorTextSetMigrationDowntime(qemuMonitorPtr mon, char *info = NULL; int ret = -1;
- if (virAsprintf(&cmd, "migrate_set_downtime %llun", downtime) < 0) { + if (virAsprintf(&cmd, "migrate_set_downtime %llums", downtime) < 0) { virReportOOMError(); goto cleanup; } diff --git a/tools/virsh.c b/tools/virsh.c index 3dd9314..cfcc86e 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2840,7 +2840,7 @@ static const vshCmdInfo info_migrate_setmaxdowntime[] = {
static const vshCmdOptDef opts_migrate_setmaxdowntime[] = { {"domain", VSH_OT_DATA, VSH_OFLAG_REQ, N_("domain name, id or uuid")}, - {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in nanoseconds) for migration")}, + {"downtime", VSH_OT_DATA, VSH_OFLAG_REQ, N_("maximum tolerable downtime (in milliseconds) for migration")}, {NULL, 0, 0, NULL} };
diff --git a/tools/virsh.pod b/tools/virsh.pod index 1c7cfce..a6298dd 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -337,7 +337,7 @@ migration URI, which usually can be omitted. =item B<migrate-setmaxdowntime> I<domain-id> I<downtime>
Set maximum tolerable downtime for a domain which is being live-migrated to -another host. The I<downtime> is a number of nanoseconds the guest is allowed +another host. The I<downtime> is a number of milliseconds the guest is allowed to be down at the end of live migration.
=item B<reboot> I<domain-id>
ACK, looks fine to me now ! Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/

This API call sets maximum tolerable time for which the domain is allowed to be paused at the end of live migration. It's supposed to be called while the domain is being live-migrated as a reaction to migration progress.
Changes in version 3: - use milliseconds instead of nanoseconds both internally and in API - correct suffix for qemu monitor commands
Changes in version 2: - API renamed to reflect it's maximum downtime - new flags parameter for the future - qemu implementation was fixed so that the call is allowed iff the domain is being migrated - --downtime parameter of virsh migrate command was removed in favor of new virsh migrate-setmaxdowntime which can be run independently - virsh accepts downtime as nanoseconds instead of floating-point seconds (shells don't deal with floating-point numbers well)
ACK,
looks fine to me now !
Ah, I forgot to send a note here... I fixed virDomainMigrateSetMaxDowntime implementation in qemu driver to complain in case flags != 0 and pushed the patchset on Friday. Jirka
participants (4)
-
Daniel P. Berrange
-
Daniel Veillard
-
Eric Blake
-
Jiri Denemark