From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:51101) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Upgw3-0001rB-Im for qemu-devel@nongnu.org; Thu, 20 Jun 2013 11:38:09 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Upgvz-0008Vs-Nw for qemu-devel@nongnu.org; Thu, 20 Jun 2013 11:38:07 -0400 Message-ID: <51C321DA.9060600@suse.de> Date: Thu, 20 Jun 2013 17:38:02 +0200 From: =?ISO-8859-15?Q?Andreas_F=E4rber?= MIME-Version: 1.0 References: <1371674435-14973-1-git-send-email-aliguori@us.ibm.com> <1371674435-14973-5-git-send-email-aliguori@us.ibm.com> In-Reply-To: <1371674435-14973-5-git-send-email-aliguori@us.ibm.com> Content-Type: text/plain; charset=ISO-8859-15 Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH 04/12] qtest: add interface to save/restore List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: Alexey Kardashevskiy , Paul Mackerras , qemu-ppc@nongnu.org, qemu-devel@nongnu.org, Alex Graf 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. >=20 > We an then sprinkle calls to qtest_save_restore() thorough test > cases to validate that we are properly saving and restoring state. >=20 > Signed-off-by: Anthony Liguori > --- > tests/libqtest.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++ > tests/libqtest.h | 46 +++++++++++++++++++++++++++++++++++++++ > 2 files changed, 111 insertions(+) >=20 > 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; > }; > =20 > #define g_assert_no_errno(ret) do { \ > @@ -104,6 +105,14 @@ static pid_t qtest_qemu_pid(QTestState *s) > return pid; > } > =20 > +void qtest_qmp_wait_event(QTestState *s, const char *event) > +{ > + char *d; > + /* This is cheating */ > + d =3D 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) > =20 > s =3D g_malloc(sizeof(*s)); > =20 > + s->extra_args =3D g_strdup(extra_args); > s->socket_path =3D g_strdup_printf("/tmp/qtest-%d.sock", getpid())= ; > s->qmp_socket_path =3D g_strdup_printf("/tmp/qtest-%d.qmp", getpid= ()); > pid_file =3D 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 =3D g_strdup_printf("/tmp/qtest-%d.savevm", getpid()); > + > + /* Start migration to a temporary file */ > + d =3D qtest_qmp(s, > + "{ 'execute': 'migrate', " > + " 'arguments': { 'uri': 'exec:dd of=3D%s 2>/dev/nul= l' } }", > + 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 comman= d until > + * we've completed migration by virtue of the fact that STOP has b= een sent > + * but it's good to be rigorious. */ > + do { > + d =3D qtest_qmp(s, "{ 'execute': 'query-migrate' }"); > + p =3D strstr(d, "\"status\": \"completed\","); > + g_free(d); > + if (!p) { > + g_usleep(100); > + } > + } while (p =3D=3D NULL); > + > + /* Save arguments to this qtest instance */ > + extra_args =3D s->extra_args; > + s->extra_args =3D NULL; > + > + /* Quit src instance */ > + qtest_quit(s); > + > + /* Spawn destination */ > + n =3D g_strdup_printf("%s -incoming exec:\"dd if=3D%s 2>/dev/null\= "", > + extra_args, filename); > + s =3D 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 =3D extra_args; > + > + g_free(filename); > + > + return s; > } > =20 > 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); > =20 > /** > + * 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 st= ep); > int64_t qtest_clock_set(QTestState *s, int64_t val); > =20 > /** > + * 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 becau= se > + * 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) > } > =20 > /** > + * 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); > } > =20 > +/** > + * 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 becau= se > + * this function is called, the savevm code for the device is broken. > + */ > +static inline void save_restore(void) > +{ > + global_qtest =3D 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); >=20 --=20 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 N=FCrnberg, Germany GF: Jeff Hawn, Jennifer Guild, Felix Imend=F6rffer; HRB 16746 AG N=FCrnbe= rg