[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-ppc] [Qemu-devel] [PATCH 04/12] qtest: add interface to save/r
From: |
Andreas Färber |
Subject: |
Re: [Qemu-ppc] [Qemu-devel] [PATCH 04/12] qtest: add interface to save/restore |
Date: |
Thu, 20 Jun 2013 17:38:02 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130510 Thunderbird/17.0.6 |
Am 19.06.2013 22:40, schrieb Anthony Liguori:
> The idea here is pretty simple. We have a synchronous interface
> that when called, does a migration to a file, kills the QEMU
> instance, and spawns a new one using the saved file state.
>
> We an then sprinkle calls to qtest_save_restore() thorough test
> cases to validate that we are properly saving and restoring state.
>
> Signed-off-by: Anthony Liguori <address@hidden>
> ---
> tests/libqtest.c | 65
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> tests/libqtest.h | 46 +++++++++++++++++++++++++++++++++++++++
> 2 files changed, 111 insertions(+)
>
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 235ec62..bc2e84e 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -44,6 +44,7 @@ struct QTestState
> gchar *pid_file; /* QEMU PID file */
> int child_pid; /* Child process created to execute QEMU */
> char *socket_path, *qmp_socket_path;
> + char *extra_args;
> };
>
> #define g_assert_no_errno(ret) do { \
> @@ -104,6 +105,14 @@ static pid_t qtest_qemu_pid(QTestState *s)
> return pid;
> }
>
> +void qtest_qmp_wait_event(QTestState *s, const char *event)
> +{
> + char *d;
> + /* This is cheating */
> + d = qtest_qmp(s, "");
This reminds me that I was unable to use GCC_FMT_ATTR(2, 3) on
qtest_qmp() because of the "" argument that gcc would warn about.
Otherwise code looks okay, although I'm not too familiar with the events.
Regards,
Andreas
> + g_free(d);
> +}
> +
> QTestState *qtest_init(const char *extra_args)
> {
> QTestState *s;
> @@ -118,6 +127,7 @@ QTestState *qtest_init(const char *extra_args)
>
> s = g_malloc(sizeof(*s));
>
> + s->extra_args = g_strdup(extra_args);
> s->socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
> s->qmp_socket_path = g_strdup_printf("/tmp/qtest-%d.qmp", getpid());
> pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
> @@ -177,6 +187,61 @@ void qtest_quit(QTestState *s)
> g_free(s->pid_file);
> g_free(s->socket_path);
> g_free(s->qmp_socket_path);
> + g_free(s->extra_args);
> +}
> +
> +QTestState *qtest_save_restore(QTestState *s)
> +{
> + char *filename;
> + char *d, *p, *extra_args;
> + char *n;
> +
> + filename = g_strdup_printf("/tmp/qtest-%d.savevm", getpid());
> +
> + /* Start migration to a temporary file */
> + d = qtest_qmp(s,
> + "{ 'execute': 'migrate', "
> + " 'arguments': { 'uri': 'exec:dd of=%s 2>/dev/null' } }",
> + filename);
> + g_free(d);
> +
> + /* Wait for critical section to be entered */
> + qtest_qmp_wait_event(s, "STOP");
> +
> + /* Not strictly needed as we can't possibly respond to this command until
> + * we've completed migration by virtue of the fact that STOP has been
> sent
> + * but it's good to be rigorious. */
> + do {
> + d = qtest_qmp(s, "{ 'execute': 'query-migrate' }");
> + p = strstr(d, "\"status\": \"completed\",");
> + g_free(d);
> + if (!p) {
> + g_usleep(100);
> + }
> + } while (p == NULL);
> +
> + /* Save arguments to this qtest instance */
> + extra_args = s->extra_args;
> + s->extra_args = NULL;
> +
> + /* Quit src instance */
> + qtest_quit(s);
> +
> + /* Spawn destination */
> + n = g_strdup_printf("%s -incoming exec:\"dd if=%s 2>/dev/null\"",
> + extra_args, filename);
> + s = qtest_init(n);
> +
> + /* Wait for incoming migration to complete */
> + qtest_qmp_wait_event(s, "RESUME");
> +
> + /* Fixup extra arg so we can call repeatedly */
> + g_free(s->extra_args);
> + s->extra_args = extra_args;
> +
> + g_free(filename);
> +
> + return s;
> }
>
> static void socket_sendf(int fd, const char *fmt, va_list ap)
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index 5cdcae7..f2c6e52 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -67,6 +67,15 @@ char *qtest_qmp(QTestState *s, const char *fmt, ...);
> char *qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
>
> /**
> + * qtest_qmp_wait_event:
> + * @s: #QTestState instance to operate on.
> + * @event: the event to wait for.
> + *
> + * Waits for a specific QMP event to occur.
> + */
> +void qtest_qmp_wait_event(QTestState *s, const char *event);
> +
> +/**
> * qtest_get_irq:
> * @s: #QTestState instance to operate on.
> * @num: Interrupt to observe.
> @@ -291,6 +300,19 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
> int64_t qtest_clock_set(QTestState *s, int64_t val);
>
> /**
> + * qtest_save_restore:
> + * @s: QTest instance to operate on.
> + *
> + * This function will save and restore the state of the running QEMU
> + * instance. If the savevm code is implemented correctly for a device,
> + * this function should behave like a nop. If a test case fails because
> + * this function is called, the savevm code for the device is broken.
> + *
> + * Returns: the new QTest instance
> + */
> +QTestState *qtest_save_restore(QTestState *s);
> +
> +/**
> * qtest_spapr_hcall9:
> * @s: QTestState instance to operate on.
> * @nr: The hypercall index
> @@ -337,6 +359,17 @@ static inline QTestState *qtest_start(const char *args)
> }
>
> /**
> + * qmp_wait_event:
> + * @event: the event to wait for.
> + *
> + * Waits for a specific QMP event to occur.
> + */
> +static inline void qmp_wait_event(const char *event)
> +{
> + qtest_qmp_wait_event(global_qtest, event);
> +}
> +
> +/**
> * qmp:
> * @fmt...: QMP message to send to qemu
> *
> @@ -628,6 +661,19 @@ static inline int64_t clock_set(int64_t val)
> return qtest_clock_set(global_qtest, val);
> }
>
> +/**
> + * save_restore:
> + *
> + * This function will save and restore the state of the running QEMU
> + * instance. If the savevm code is implemented correctly for a device,
> + * this function should behave like a nop. If a test case fails because
> + * this function is called, the savevm code for the device is broken.
> + */
> +static inline void save_restore(void)
> +{
> + global_qtest = qtest_save_restore(global_qtest);
> +}
> +
> static inline uint64_t spapr_hcall0(uint64_t nr)
> {
> return qtest_spapr_hcall9(global_qtest, nr, 0, 0, 0, 0, 0, 0, 0, 0, 0);
>
--
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg
- Re: [Qemu-ppc] [Qemu-devel] [PATCH 09/12] spapr-vio: move special case handling for reg=0 to vio, (continued)
- [Qemu-ppc] [PATCH 12/12] spapr-vty: remove unfixable FIXME, Anthony Liguori, 2013/06/19
- [Qemu-ppc] [PATCH 10/12] spapr-vty: refactor the code to improve consistency, Anthony Liguori, 2013/06/19
- [Qemu-ppc] [PATCH 04/12] qtest: add interface to save/restore, Anthony Liguori, 2013/06/19
- Re: [Qemu-ppc] [Qemu-devel] [PATCH 04/12] qtest: add interface to save/restore,
Andreas Färber <=
- [Qemu-ppc] [PATCH 07/12] spapr-rtas: add CPU argument to RTAS calls, Anthony Liguori, 2013/06/19
- [Qemu-ppc] [PATCH 11/12] spapr-vio: pass type to spapr_vio_find_by_reg(), Anthony Liguori, 2013/06/19
- [Qemu-ppc] [PATCH 05/12] spapr-vty: add qtest test case, Anthony Liguori, 2013/06/19