* [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots
@ 2018-02-27 11:56 Richard Palethorpe
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer Richard Palethorpe
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Richard Palethorpe @ 2018-02-27 11:56 UTC (permalink / raw)
To: qemu-devel
Cc: berrange, qemu-block, armbru, dgilbert, eblake, quintela, mreitz,
Richard Palethorpe
Hello,
Following on from the discussion about creating savevm/loadvm QMP
equivalents. I decided to take the advice given that we should use external
snapshots. However reverting to a snapshot currently requires QEMU to be
restarted with "-incoming". Restarting QEMU requires a fair bit of book
keeping to be done by the management application and may take measurably more
time.
Also to quote the previous discussion:
>>> > Then you could just use the regular migrate QMP commands for loading
>>> > and saving snapshots. Might need a little extra work on the incoming
>>> > side, since we need to be able to load snapshots, despite QEMU not
>>> > being started with '-incoming defer', but might still be doable ?
>>> > This would theoretically give us progress monitoring, cancellation,
>>> > etc for free.
>>>
>>> What actually stops this working other than the sanity check in
>>> migrate_incoming ?
>>
>> No idea really - not looked closely at the code implications.
>
> It would be a plus for migration code, right now there are _two_
> implementations, and savevm/loadvm one gets less love.
>
> And we will check "much more" the way to load migration in a
> non-pristine qemu, so ....
>
> Later, Juan.
This patch just changes a few lines which shuts down the currently running VM
and puts the QEMU instance into a state where it can accept an incoming
migration. I haven't tested it yet with more complex scenarios, but it
appears to work fine so far.
I have also started work on a new migration test, which is almost identical to
the existing post-copy test, but migrates to a non-pristine QEMU. It works on
X86, but not yet on PPC64 because the serial output is different. It needs
quite a lot more work, but before I continue, I would like to know first if
this is something people fundamentally object to?
Richard Palethorpe (2):
migrate: Allow incoming migration without defer
migrate: Tests for migrating to an already used QEMU
migration/migration.c | 12 +++---
tests/migration-test.c | 113 +++++++++++++++++++++++++++++++++++++------------
vl.c | 2 +
3 files changed, 92 insertions(+), 35 deletions(-)
--
2.16.2
^ permalink raw reply [flat|nested] 9+ messages in thread
* [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer
2018-02-27 11:56 [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots Richard Palethorpe
@ 2018-02-27 11:56 ` Richard Palethorpe
2018-03-01 16:59 ` Dr. David Alan Gilbert
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 2/2] migrate: Tests for migrating to an already used QEMU Richard Palethorpe
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Richard Palethorpe @ 2018-02-27 11:56 UTC (permalink / raw)
To: qemu-devel
Cc: berrange, qemu-block, armbru, dgilbert, eblake, quintela, mreitz,
Richard Palethorpe
Allow a QEMU instance which has been started and used without the "-incoming"
flag to accept an incoming migration with the "migrate-incoming" QMP
command. This allows the user to dump the VM state to an external file then
revert to that state at a later time without restarting QEMU.
---
migration/migration.c | 12 +++++-------
vl.c | 2 ++
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/migration/migration.c b/migration/migration.c
index 0aa596f867..05595a4cec 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -1321,14 +1321,14 @@ void migrate_del_blocker(Error *reason)
void qmp_migrate_incoming(const char *uri, Error **errp)
{
Error *local_err = NULL;
- static bool once = true;
- if (!deferred_incoming) {
- error_setg(errp, "For use with '-incoming defer'");
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ error_setg(errp, "The incoming migration has already been started");
return;
}
- if (!once) {
- error_setg(errp, "The incoming migration has already been started");
+
+ if (!deferred_incoming) {
+ vm_stop(RUN_STATE_INMIGRATE);
}
qemu_start_incoming_migration(uri, &local_err);
@@ -1337,8 +1337,6 @@ void qmp_migrate_incoming(const char *uri, Error **errp)
error_propagate(errp, local_err);
return;
}
-
- once = false;
}
bool migration_is_blocked(Error **errp)
diff --git a/vl.c b/vl.c
index 9e7235df6d..a91eda039e 100644
--- a/vl.c
+++ b/vl.c
@@ -634,6 +634,7 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_PAUSED, RUN_STATE_POSTMIGRATE },
{ RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH },
{ RUN_STATE_PAUSED, RUN_STATE_COLO},
+ { RUN_STATE_PAUSED, RUN_STATE_INMIGRATE },
{ RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
{ RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
@@ -665,6 +666,7 @@ static const RunStateTransition runstate_transitions_def[] = {
{ RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
{ RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED },
{ RUN_STATE_RUNNING, RUN_STATE_COLO},
+ { RUN_STATE_RUNNING, RUN_STATE_INMIGRATE },
{ RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
--
2.16.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [Qemu-devel] [RFC PATCH 2/2] migrate: Tests for migrating to an already used QEMU
2018-02-27 11:56 [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots Richard Palethorpe
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer Richard Palethorpe
@ 2018-02-27 11:56 ` Richard Palethorpe
2018-03-01 17:32 ` Dr. David Alan Gilbert
2018-02-27 16:07 ` [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots no-reply
2018-03-02 16:15 ` [Qemu-devel] [Qemu-block] " Roman Kagan
3 siblings, 1 reply; 9+ messages in thread
From: Richard Palethorpe @ 2018-02-27 11:56 UTC (permalink / raw)
To: qemu-devel
Cc: berrange, qemu-block, armbru, dgilbert, eblake, quintela, mreitz,
Richard Palethorpe
Currently this appears to work for X86_64, but PPC64 fails due to some
unexpected data on the serial port after migration. This probably requires
quite a bit more work.
---
tests/migration-test.c | 113 +++++++++++++++++++++++++++++++++++++------------
1 file changed, 85 insertions(+), 28 deletions(-)
diff --git a/tests/migration-test.c b/tests/migration-test.c
index 74f9361bdd..8217d2e83e 100644
--- a/tests/migration-test.c
+++ b/tests/migration-test.c
@@ -125,19 +125,17 @@ static void init_bootfile_ppc(const char *bootpath)
* we get an 'A' followed by an endless string of 'B's
* but on the destination we won't have the A.
*/
-static void wait_for_serial(const char *side)
+static void wait_for_serial(const char *side, gboolean started)
{
char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
FILE *serialfile = fopen(serialpath, "r");
const char *arch = qtest_get_arch();
- int started = (strcmp(side, "src_serial") == 0 &&
- strcmp(arch, "ppc64") == 0) ? 0 : 1;
g_free(serialpath);
do {
int readvalue = fgetc(serialfile);
- if (!started) {
+ if (!started && !strcmp(arch, "ppc64")) {
/* SLOF prints its banner before starting test,
* to ignore it, mark the start of the test with '_',
* ignore all characters until this marker
@@ -358,16 +356,21 @@ static void migrate_set_capability(QTestState *who, const char *capability,
QDECREF(rsp);
}
-static void migrate(QTestState *who, const char *uri)
+static void migrate(QTestState *who, const char *uri, gboolean incoming)
{
QDict *rsp;
+ const gchar *cmd_name = incoming ? "migrate-incoming" : "migrate";
gchar *cmd;
- cmd = g_strdup_printf("{ 'execute': 'migrate',"
+ cmd = g_strdup_printf("{ 'execute': '%s',"
"'arguments': { 'uri': '%s' } }",
- uri);
+ cmd_name, uri);
rsp = qtest_qmp(who, cmd);
g_free(cmd);
+ while (qdict_haskey(rsp, "event")) {
+ QDECREF(rsp);
+ rsp = qtest_qmp_receive(who);
+ }
g_assert(qdict_haskey(rsp, "return"));
QDECREF(rsp);
}
@@ -382,15 +385,22 @@ static void migrate_start_postcopy(QTestState *who)
}
static void test_migrate_start(QTestState **from, QTestState **to,
- const char *uri)
+ const char *uri, gboolean incoming)
{
- gchar *cmd_src, *cmd_dst;
+ gchar *cmd_src;
+ GString *cmd_dst = g_string_new(NULL);
char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
+ char *bootpath_dst;
const char *arch = qtest_get_arch();
const char *accel = "kvm:tcg";
got_stop = false;
+ if (incoming)
+ bootpath_dst = bootpath;
+ else
+ bootpath_dst = g_strdup_printf("%s/bootsect_dst", tmpfs);
+
if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
init_bootfile_x86(bootpath);
cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
@@ -398,12 +408,14 @@ static void test_migrate_start(QTestState **from, QTestState **to,
" -serial file:%s/src_serial"
" -drive file=%s,format=raw",
accel, tmpfs, bootpath);
- cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
- " -name target,debug-threads=on"
- " -serial file:%s/dest_serial"
- " -drive file=%s,format=raw"
- " -incoming %s",
- accel, tmpfs, bootpath, uri);
+ if (!incoming)
+ init_bootfile_x86(bootpath_dst);
+
+ g_string_printf(cmd_dst, "-machine accel=%s -m 150M"
+ " -name target,debug-threads=on"
+ " -serial file:%s/dest_serial"
+ " -drive file=%s,format=raw",
+ accel, tmpfs, bootpath_dst);
} else if (strcmp(arch, "ppc64") == 0) {
/* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
@@ -416,22 +428,29 @@ static void test_migrate_start(QTestState **from, QTestState **to,
" -serial file:%s/src_serial"
" -drive file=%s,if=pflash,format=raw",
accel, tmpfs, bootpath);
- cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
- " -name target,debug-threads=on"
- " -serial file:%s/dest_serial"
- " -incoming %s",
- accel, tmpfs, uri);
+ g_string_printf(cmd_dst, "-machine accel=%s -m 256M"
+ " -name target,debug-threads=on"
+ " -serial file:%s/dest_serial",
+ accel, tmpfs);
+ if (!incoming) {
+ g_string_append_printf(cmd_dst,
+ " -drive file=%s,if=pflash,format=raw",
+ bootpath);
+ }
} else {
g_assert_not_reached();
}
+ if (incoming)
+ g_string_append_printf(cmd_dst, " -incoming %s", uri);
+
g_free(bootpath);
*from = qtest_start(cmd_src);
g_free(cmd_src);
- *to = qtest_init(cmd_dst);
- g_free(cmd_dst);
+ *to = qtest_init(cmd_dst->str);
+ g_string_free(cmd_dst, TRUE);
}
static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
@@ -518,7 +537,7 @@ static void test_migrate(void)
char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
QTestState *from, *to;
- test_migrate_start(&from, &to, uri);
+ test_migrate_start(&from, &to, uri, TRUE);
migrate_set_capability(from, "postcopy-ram", "true");
migrate_set_capability(to, "postcopy-ram", "true");
@@ -531,9 +550,9 @@ static void test_migrate(void)
migrate_set_parameter(from, "downtime-limit", "1");
/* Wait for the first serial output from the source */
- wait_for_serial("src_serial");
+ wait_for_serial("src_serial", FALSE);
- migrate(from, uri);
+ migrate(from, uri, FALSE);
wait_for_migration_pass(from);
@@ -545,7 +564,7 @@ static void test_migrate(void)
qtest_qmp_eventwait(to, "RESUME");
- wait_for_serial("dest_serial");
+ wait_for_serial("dest_serial", TRUE);
wait_for_migration_complete(from);
g_free(uri);
@@ -560,8 +579,8 @@ static void test_baddest(void)
const char *status;
bool failed;
- test_migrate_start(&from, &to, "tcp:0:0");
- migrate(from, "tcp:0:0");
+ test_migrate_start(&from, &to, "tcp:0:0", TRUE);
+ migrate(from, "tcp:0:0", FALSE);
do {
rsp = wait_command(from, "{ 'execute': 'query-migrate' }");
rsp_return = qdict_get_qdict(rsp, "return");
@@ -584,6 +603,43 @@ static void test_baddest(void)
test_migrate_end(from, to, false);
}
+static void test_migrate_to_used(void)
+{
+ char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
+ QTestState *from, *to;
+
+ test_migrate_start(&from, &to, uri, FALSE);
+
+ migrate_set_capability(from, "postcopy-ram", "true");
+ migrate_set_capability(to, "postcopy-ram", "true");
+
+ migrate_set_parameter(from, "max-bandwidth", "100000000");
+ migrate_set_parameter(from, "downtime-limit", "1");
+
+ wait_for_serial("dest_serial", FALSE);
+ migrate(to, uri, TRUE);
+
+ wait_for_serial("src_serial", FALSE);
+ migrate(from, uri, FALSE);
+
+ wait_for_migration_pass(from);
+
+ migrate_start_postcopy(from);
+
+ if (!got_stop) {
+ qtest_qmp_eventwait(from, "STOP");
+ }
+
+ qtest_qmp_eventwait(to, "RESUME");
+
+ wait_for_serial("dest_serial", TRUE);
+ wait_for_migration_complete(from);
+
+ g_free(uri);
+
+ test_migrate_end(from, to, true);
+}
+
int main(int argc, char **argv)
{
char template[] = "/tmp/migration-test-XXXXXX";
@@ -604,6 +660,7 @@ int main(int argc, char **argv)
module_call_init(MODULE_INIT_QOM);
qtest_add_func("/migration/postcopy/unix", test_migrate);
+ qtest_add_func("/migration/postcopy/to_used", test_migrate_to_used);
qtest_add_func("/migration/deprecated", test_deprecated);
qtest_add_func("/migration/bad_dest", test_baddest);
--
2.16.2
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots
2018-02-27 11:56 [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots Richard Palethorpe
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer Richard Palethorpe
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 2/2] migrate: Tests for migrating to an already used QEMU Richard Palethorpe
@ 2018-02-27 16:07 ` no-reply
2018-03-02 16:15 ` [Qemu-devel] [Qemu-block] " Roman Kagan
3 siblings, 0 replies; 9+ messages in thread
From: no-reply @ 2018-02-27 16:07 UTC (permalink / raw)
To: rpalethorpe
Cc: famz, qemu-devel, qemu-block, quintela, armbru, dgilbert, mreitz
Hi,
This series seems to have some coding style problems. See output below for
more information:
Type: series
Message-id: 20180227115651.30762-1-rpalethorpe@suse.com
Subject: [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots
=== TEST SCRIPT BEGIN ===
#!/bin/bash
BASE=base
n=1
total=$(git log --oneline $BASE.. | wc -l)
failed=0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
commits="$(git log --format=%H --reverse $BASE..)"
for c in $commits; do
echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; then
failed=1
echo
fi
n=$((n+1))
done
exit $failed
=== TEST SCRIPT END ===
Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
From https://github.com/patchew-project/qemu
* [new tag] patchew/1519726932-13833-1-git-send-email-liran.alon@oracle.com -> patchew/1519726932-13833-1-git-send-email-liran.alon@oracle.com
* [new tag] patchew/20180227115651.30762-1-rpalethorpe@suse.com -> patchew/20180227115651.30762-1-rpalethorpe@suse.com
Switched to a new branch 'test'
cac7611aaa migrate: Tests for migrating to an already used QEMU
e1df946e98 migrate: Allow incoming migration without defer
=== OUTPUT BEGIN ===
Checking PATCH 1/2: migrate: Allow incoming migration without defer...
Checking PATCH 2/2: migrate: Tests for migrating to an already used QEMU...
ERROR: braces {} are necessary for all arms of this statement
#97: FILE: tests/migration-test.c:411:
+ if (!incoming)
[...]
ERROR: braces {} are necessary for all arms of this statement
#130: FILE: tests/migration-test.c:444:
+ if (incoming)
[...]
ERROR: Missing Signed-off-by: line(s)
total: 3 errors, 0 warnings, 212 lines checked
Your patch has style problems, please review. If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
=== OUTPUT END ===
Test command exited with code: 1
---
Email generated automatically by Patchew [http://patchew.org/].
Please send your feedback to patchew-devel@freelists.org
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer Richard Palethorpe
@ 2018-03-01 16:59 ` Dr. David Alan Gilbert
2018-03-05 15:33 ` Richard Palethorpe
0 siblings, 1 reply; 9+ messages in thread
From: Dr. David Alan Gilbert @ 2018-03-01 16:59 UTC (permalink / raw)
To: Richard Palethorpe
Cc: qemu-devel, berrange, qemu-block, armbru, eblake, quintela,
mreitz
* Richard Palethorpe (rpalethorpe@suse.com) wrote:
> Allow a QEMU instance which has been started and used without the "-incoming"
> flag to accept an incoming migration with the "migrate-incoming" QMP
> command. This allows the user to dump the VM state to an external file then
> revert to that state at a later time without restarting QEMU.
> ---
> migration/migration.c | 12 +++++-------
> vl.c | 2 ++
> 2 files changed, 7 insertions(+), 7 deletions(-)
>
> diff --git a/migration/migration.c b/migration/migration.c
> index 0aa596f867..05595a4cec 100644
> --- a/migration/migration.c
> +++ b/migration/migration.c
> @@ -1321,14 +1321,14 @@ void migrate_del_blocker(Error *reason)
> void qmp_migrate_incoming(const char *uri, Error **errp)
> {
> Error *local_err = NULL;
> - static bool once = true;
>
> - if (!deferred_incoming) {
> - error_setg(errp, "For use with '-incoming defer'");
> + if (runstate_check(RUN_STATE_INMIGRATE)) {
> + error_setg(errp, "The incoming migration has already been started");
> return;
> }
> - if (!once) {
> - error_setg(errp, "The incoming migration has already been started");
> +
> + if (!deferred_incoming) {
> + vm_stop(RUN_STATE_INMIGRATE);
> }
>
> qemu_start_incoming_migration(uri, &local_err);
> @@ -1337,8 +1337,6 @@ void qmp_migrate_incoming(const char *uri, Error **errp)
> error_propagate(errp, local_err);
> return;
> }
> -
> - once = false;
> }
That's...interesting. I think it will work, but I bet there's a whole
bunch of corner cases [many of which loadvm will hit as well!].
For starters there's probably devices that are active and still looking
at RAM, even though vm_stop is in place (hopefully none of them are
writing to it, but I wouldn't actually trust them). Also, you probably
need to inactivate the block devices?
Also, I think this means there's no protection against this happening
during an outgoing migration (which has an existing check to make sure
you can't start an outgoing migration while an incoming one is waiting).
> bool migration_is_blocked(Error **errp)
> diff --git a/vl.c b/vl.c
> index 9e7235df6d..a91eda039e 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -634,6 +634,7 @@ static const RunStateTransition runstate_transitions_def[] = {
> { RUN_STATE_PAUSED, RUN_STATE_POSTMIGRATE },
> { RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH },
> { RUN_STATE_PAUSED, RUN_STATE_COLO},
> + { RUN_STATE_PAUSED, RUN_STATE_INMIGRATE },
>
> { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
> { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
> @@ -665,6 +666,7 @@ static const RunStateTransition runstate_transitions_def[] = {
> { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
> { RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED },
> { RUN_STATE_RUNNING, RUN_STATE_COLO},
> + { RUN_STATE_RUNNING, RUN_STATE_INMIGRATE },
Experience suggests that you'll find out the hard way that there's other
states you'll need to allow or check for.
For example, do you want to be able to loadvm from a GUEST_PANICKED or
PRELAUNCH state?
Dave
> { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
>
> --
> 2.16.2
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 2/2] migrate: Tests for migrating to an already used QEMU
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 2/2] migrate: Tests for migrating to an already used QEMU Richard Palethorpe
@ 2018-03-01 17:32 ` Dr. David Alan Gilbert
0 siblings, 0 replies; 9+ messages in thread
From: Dr. David Alan Gilbert @ 2018-03-01 17:32 UTC (permalink / raw)
To: Richard Palethorpe
Cc: qemu-devel, berrange, qemu-block, armbru, eblake, quintela,
mreitz
* Richard Palethorpe (rpalethorpe@suse.com) wrote:
> Currently this appears to work for X86_64, but PPC64 fails due to some
> unexpected data on the serial port after migration. This probably requires
> quite a bit more work.
I think the challenge is you need to drain the serial output to make
sure you aren't seeing anything from the first run, and then we need to
go back around to the point where on ppc you're expecting the banner
again; which I think I see you've tried to do.
Also, you don't want to misinterpret the succesful output of the 1st
boot as the reception of the migration.
> ---
> tests/migration-test.c | 113 +++++++++++++++++++++++++++++++++++++------------
> 1 file changed, 85 insertions(+), 28 deletions(-)
>
> diff --git a/tests/migration-test.c b/tests/migration-test.c
> index 74f9361bdd..8217d2e83e 100644
> --- a/tests/migration-test.c
> +++ b/tests/migration-test.c
> @@ -125,19 +125,17 @@ static void init_bootfile_ppc(const char *bootpath)
> * we get an 'A' followed by an endless string of 'B's
> * but on the destination we won't have the A.
> */
> -static void wait_for_serial(const char *side)
> +static void wait_for_serial(const char *side, gboolean started)
> {
> char *serialpath = g_strdup_printf("%s/%s", tmpfs, side);
> FILE *serialfile = fopen(serialpath, "r");
> const char *arch = qtest_get_arch();
> - int started = (strcmp(side, "src_serial") == 0 &&
> - strcmp(arch, "ppc64") == 0) ? 0 : 1;
>
> g_free(serialpath);
> do {
> int readvalue = fgetc(serialfile);
>
> - if (!started) {
> + if (!started && !strcmp(arch, "ppc64")) {
> /* SLOF prints its banner before starting test,
> * to ignore it, mark the start of the test with '_',
> * ignore all characters until this marker
> @@ -358,16 +356,21 @@ static void migrate_set_capability(QTestState *who, const char *capability,
> QDECREF(rsp);
> }
>
> -static void migrate(QTestState *who, const char *uri)
> +static void migrate(QTestState *who, const char *uri, gboolean incoming)
> {
> QDict *rsp;
> + const gchar *cmd_name = incoming ? "migrate-incoming" : "migrate";
> gchar *cmd;
>
> - cmd = g_strdup_printf("{ 'execute': 'migrate',"
> + cmd = g_strdup_printf("{ 'execute': '%s',"
> "'arguments': { 'uri': '%s' } }",
> - uri);
> + cmd_name, uri);
> rsp = qtest_qmp(who, cmd);
> g_free(cmd);
> + while (qdict_haskey(rsp, "event")) {
> + QDECREF(rsp);
> + rsp = qtest_qmp_receive(who);
> + }
> g_assert(qdict_haskey(rsp, "return"));
> QDECREF(rsp);
> }
> @@ -382,15 +385,22 @@ static void migrate_start_postcopy(QTestState *who)
> }
>
> static void test_migrate_start(QTestState **from, QTestState **to,
> - const char *uri)
> + const char *uri, gboolean incoming)
> {
> - gchar *cmd_src, *cmd_dst;
> + gchar *cmd_src;
> + GString *cmd_dst = g_string_new(NULL);
> char *bootpath = g_strdup_printf("%s/bootsect", tmpfs);
> + char *bootpath_dst;
> const char *arch = qtest_get_arch();
> const char *accel = "kvm:tcg";
>
> got_stop = false;
>
> + if (incoming)
> + bootpath_dst = bootpath;
> + else
> + bootpath_dst = g_strdup_printf("%s/bootsect_dst", tmpfs);
> +
Are you intending to run a separate bootsector file? You _could_ if you
wanted to make sure you couldn't confuse the two; but other than that
you could probably share the binary.
> if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
> init_bootfile_x86(bootpath);
> cmd_src = g_strdup_printf("-machine accel=%s -m 150M"
> @@ -398,12 +408,14 @@ static void test_migrate_start(QTestState **from, QTestState **to,
> " -serial file:%s/src_serial"
> " -drive file=%s,format=raw",
> accel, tmpfs, bootpath);
> - cmd_dst = g_strdup_printf("-machine accel=%s -m 150M"
> - " -name target,debug-threads=on"
> - " -serial file:%s/dest_serial"
> - " -drive file=%s,format=raw"
> - " -incoming %s",
> - accel, tmpfs, bootpath, uri);
> + if (!incoming)
> + init_bootfile_x86(bootpath_dst);
> +
> + g_string_printf(cmd_dst, "-machine accel=%s -m 150M"
> + " -name target,debug-threads=on"
> + " -serial file:%s/dest_serial"
> + " -drive file=%s,format=raw",
> + accel, tmpfs, bootpath_dst);
> } else if (strcmp(arch, "ppc64") == 0) {
>
> /* On ppc64, the test only works with kvm-hv, but not with kvm-pr */
> @@ -416,22 +428,29 @@ static void test_migrate_start(QTestState **from, QTestState **to,
> " -serial file:%s/src_serial"
> " -drive file=%s,if=pflash,format=raw",
> accel, tmpfs, bootpath);
> - cmd_dst = g_strdup_printf("-machine accel=%s -m 256M"
> - " -name target,debug-threads=on"
> - " -serial file:%s/dest_serial"
> - " -incoming %s",
> - accel, tmpfs, uri);
> + g_string_printf(cmd_dst, "-machine accel=%s -m 256M"
> + " -name target,debug-threads=on"
> + " -serial file:%s/dest_serial",
> + accel, tmpfs);
> + if (!incoming) {
> + g_string_append_printf(cmd_dst,
> + " -drive file=%s,if=pflash,format=raw",
> + bootpath);
> + }
> } else {
> g_assert_not_reached();
> }
>
> + if (incoming)
> + g_string_append_printf(cmd_dst, " -incoming %s", uri);
> +
> g_free(bootpath);
>
> *from = qtest_start(cmd_src);
> g_free(cmd_src);
>
> - *to = qtest_init(cmd_dst);
> - g_free(cmd_dst);
> + *to = qtest_init(cmd_dst->str);
> + g_string_free(cmd_dst, TRUE);
> }
>
> static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
> @@ -518,7 +537,7 @@ static void test_migrate(void)
> char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
> QTestState *from, *to;
>
> - test_migrate_start(&from, &to, uri);
> + test_migrate_start(&from, &to, uri, TRUE);
>
> migrate_set_capability(from, "postcopy-ram", "true");
> migrate_set_capability(to, "postcopy-ram", "true");
> @@ -531,9 +550,9 @@ static void test_migrate(void)
> migrate_set_parameter(from, "downtime-limit", "1");
>
> /* Wait for the first serial output from the source */
> - wait_for_serial("src_serial");
> + wait_for_serial("src_serial", FALSE);
>
> - migrate(from, uri);
> + migrate(from, uri, FALSE);
>
> wait_for_migration_pass(from);
>
> @@ -545,7 +564,7 @@ static void test_migrate(void)
>
> qtest_qmp_eventwait(to, "RESUME");
>
> - wait_for_serial("dest_serial");
> + wait_for_serial("dest_serial", TRUE);
> wait_for_migration_complete(from);
>
> g_free(uri);
> @@ -560,8 +579,8 @@ static void test_baddest(void)
> const char *status;
> bool failed;
>
> - test_migrate_start(&from, &to, "tcp:0:0");
> - migrate(from, "tcp:0:0");
> + test_migrate_start(&from, &to, "tcp:0:0", TRUE);
> + migrate(from, "tcp:0:0", FALSE);
> do {
> rsp = wait_command(from, "{ 'execute': 'query-migrate' }");
> rsp_return = qdict_get_qdict(rsp, "return");
> @@ -584,6 +603,43 @@ static void test_baddest(void)
> test_migrate_end(from, to, false);
> }
>
> +static void test_migrate_to_used(void)
> +{
> + char *uri = g_strdup_printf("unix:%s/migsocket", tmpfs);
> + QTestState *from, *to;
> +
> + test_migrate_start(&from, &to, uri, FALSE);
> +
> + migrate_set_capability(from, "postcopy-ram", "true");
> + migrate_set_capability(to, "postcopy-ram", "true");
> +
> + migrate_set_parameter(from, "max-bandwidth", "100000000");
> + migrate_set_parameter(from, "downtime-limit", "1");
> +
> + wait_for_serial("dest_serial", FALSE);
> + migrate(to, uri, TRUE);
> +
> + wait_for_serial("src_serial", FALSE);
> + migrate(from, uri, FALSE);
> +
> + wait_for_migration_pass(from);
> +
> + migrate_start_postcopy(from);
It's brave/good that you're doing this with postcopy; but with postcopy
we really really need to make sure any devices aren't reading memory
after they enter the paused state, although we've got so few devices
in this test we probably wont hit that.
Dave
> + if (!got_stop) {
> + qtest_qmp_eventwait(from, "STOP");
> + }
> +
> + qtest_qmp_eventwait(to, "RESUME");
> +
> + wait_for_serial("dest_serial", TRUE);
> + wait_for_migration_complete(from);
> +
> + g_free(uri);
> +
> + test_migrate_end(from, to, true);
> +}
> +
> int main(int argc, char **argv)
> {
> char template[] = "/tmp/migration-test-XXXXXX";
> @@ -604,6 +660,7 @@ int main(int argc, char **argv)
> module_call_init(MODULE_INIT_QOM);
>
> qtest_add_func("/migration/postcopy/unix", test_migrate);
> + qtest_add_func("/migration/postcopy/to_used", test_migrate_to_used);
> qtest_add_func("/migration/deprecated", test_deprecated);
> qtest_add_func("/migration/bad_dest", test_baddest);
>
> --
> 2.16.2
>
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [Qemu-block] [RFC PATCH 0/2] Increase usability of external snapshots
2018-02-27 11:56 [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots Richard Palethorpe
` (2 preceding siblings ...)
2018-02-27 16:07 ` [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots no-reply
@ 2018-03-02 16:15 ` Roman Kagan
2018-03-05 14:38 ` Richard Palethorpe
3 siblings, 1 reply; 9+ messages in thread
From: Roman Kagan @ 2018-03-02 16:15 UTC (permalink / raw)
To: Richard Palethorpe
Cc: qemu-devel, berrange, qemu-block, quintela, armbru, dgilbert,
mreitz
On Tue, Feb 27, 2018 at 12:56:49PM +0100, Richard Palethorpe wrote:
> Following on from the discussion about creating savevm/loadvm QMP
> equivalents. I decided to take the advice given that we should use external
> snapshots. However reverting to a snapshot currently requires QEMU to be
> restarted with "-incoming". Restarting QEMU requires a fair bit of
> book keeping to be done by the management application and may take
> measurably more time.
AFAICT "-incoming" is not the only reason for starting QEMU anew. The
block devices will need to be pointed at different nodes in the backing
chains. Moreover the snapshot you're reverting to may have been taken
at a point where the VM had different configuration than it has now.
So the management application will need to do a lot of bookkeeping stuff
anyway, and it'll probably have harder time applying all of the
configuration changes to a live QEMU instance.
Is the cost of killing the old QEMU process and starting a new one big
enough to be worth all the hassle?
Thanks,
Roman.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [Qemu-block] [RFC PATCH 0/2] Increase usability of external snapshots
2018-03-02 16:15 ` [Qemu-devel] [Qemu-block] " Roman Kagan
@ 2018-03-05 14:38 ` Richard Palethorpe
0 siblings, 0 replies; 9+ messages in thread
From: Richard Palethorpe @ 2018-03-05 14:38 UTC (permalink / raw)
To: Roman Kagan
Cc: rpalethorpe, qemu-block, qemu-devel, armbru, berrange, dgilbert,
mreitz, quintela
Hello Roman,
Roman Kagan writes:
> On Tue, Feb 27, 2018 at 12:56:49PM +0100, Richard Palethorpe wrote:
>> Following on from the discussion about creating savevm/loadvm QMP
>> equivalents. I decided to take the advice given that we should use external
>> snapshots. However reverting to a snapshot currently requires QEMU to be
>> restarted with "-incoming". Restarting QEMU requires a fair bit of
>> book keeping to be done by the management application and may take
>> measurably more time.
>
> AFAICT "-incoming" is not the only reason for starting QEMU anew. The
> block devices will need to be pointed at different nodes in the backing
> chains. Moreover the snapshot you're reverting to may have been taken
> at a point where the VM had different configuration than it has now.
OK, so contrary to what I thought, it looks like there is no QMP command
to simply drop the current active layer and repoint the block device to
the previous node in the chain. We would have to recreate the block
device with the desired backing store and overlays or create a new
command. I am not sure that is a showstopper though.
>
> So the management application will need to do a lot of bookkeeping stuff
> anyway, and it'll probably have harder time applying all of the
> configuration changes to a live QEMU instance.
Well in our use case, configuration changes between snapshots would not
be possible. For other use cases the management app will have to restart
QEMU when necessary. AFAICT, with or without this patch it is possible for
someone to try accepting an incoming migration with an invalid
configuration. So I would hope that this is not introducing a new
problem?
>
> Is the cost of killing the old QEMU process and starting a new one big
> enough to be worth all the hassle?
I doubt I can justify it based on performance, atleast not for our use
case, but terminating the QEMU process will interrupt a number of socket
connections and such. I am sure this is a technically easier problem to
solve than modifying QEMU, but there is one QEMU and many management
apps so *maybe* the effort is better spent on QEMU if it avoids more work
in the management apps and is not introducing features to QEMU outside
of its scope. QEMU already supports reverting to internal snapshots in a
live instance, so I don't think I am increasing its scope.
>
> Thanks,
> Roman.
--
Thank you,
Richard.
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer
2018-03-01 16:59 ` Dr. David Alan Gilbert
@ 2018-03-05 15:33 ` Richard Palethorpe
0 siblings, 0 replies; 9+ messages in thread
From: Richard Palethorpe @ 2018-03-05 15:33 UTC (permalink / raw)
To: Dr. David Alan Gilbert
Cc: rpalethorpe, qemu-block, qemu-devel, armbru, berrange, eblake,
mreitz, quintela
hello David,
Dr. David Alan Gilbert writes:
> * Richard Palethorpe (rpalethorpe@suse.com) wrote:
>> Allow a QEMU instance which has been started and used without the "-incoming"
>> flag to accept an incoming migration with the "migrate-incoming" QMP
>> command. This allows the user to dump the VM state to an external file then
>> revert to that state at a later time without restarting QEMU.
>> ---
>> migration/migration.c | 12 +++++-------
>> vl.c | 2 ++
>> 2 files changed, 7 insertions(+), 7 deletions(-)
>>
>> diff --git a/migration/migration.c b/migration/migration.c
>> index 0aa596f867..05595a4cec 100644
>> --- a/migration/migration.c
>> +++ b/migration/migration.c
>> @@ -1321,14 +1321,14 @@ void migrate_del_blocker(Error *reason)
>> void qmp_migrate_incoming(const char *uri, Error **errp)
>> {
>> Error *local_err = NULL;
>> - static bool once = true;
>>
>> - if (!deferred_incoming) {
>> - error_setg(errp, "For use with '-incoming defer'");
>> + if (runstate_check(RUN_STATE_INMIGRATE)) {
>> + error_setg(errp, "The incoming migration has already been started");
>> return;
>> }
>> - if (!once) {
>> - error_setg(errp, "The incoming migration has already been started");
>> +
>> + if (!deferred_incoming) {
>> + vm_stop(RUN_STATE_INMIGRATE);
>> }
>>
>> qemu_start_incoming_migration(uri, &local_err);
>> @@ -1337,8 +1337,6 @@ void qmp_migrate_incoming(const char *uri, Error **errp)
>> error_propagate(errp, local_err);
>> return;
>> }
>> -
>> - once = false;
>> }
>
> That's...interesting. I think it will work, but I bet there's a whole
> bunch of corner cases [many of which loadvm will hit as well!].
It wouldn't surprise me if we have hit some of those corner cases with
our extensive use of loadvm :-) Unfortunately I don't have much data to
show what went wrong though.
> For starters there's probably devices that are active and still looking
> at RAM, even though vm_stop is in place (hopefully none of them are
> writing to it, but I wouldn't actually trust them).
I suppose that might be a showstopper.
> Also, you probably
> need to inactivate the block devices?
They are at least flushed by vm_stop. I would expect the user to
recreate them, or at least recreate the active layer before starting the
migration.
>
> Also, I think this means there's no protection against this happening
> during an outgoing migration (which has an existing check to make sure
> you can't start an outgoing migration while an incoming one is waiting).
>
>> bool migration_is_blocked(Error **errp)
>> diff --git a/vl.c b/vl.c
>> index 9e7235df6d..a91eda039e 100644
>> --- a/vl.c
>> +++ b/vl.c
>> @@ -634,6 +634,7 @@ static const RunStateTransition runstate_transitions_def[] = {
>> { RUN_STATE_PAUSED, RUN_STATE_POSTMIGRATE },
>> { RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH },
>> { RUN_STATE_PAUSED, RUN_STATE_COLO},
>> + { RUN_STATE_PAUSED, RUN_STATE_INMIGRATE },
>>
>> { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING },
>> { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE },
>> @@ -665,6 +666,7 @@ static const RunStateTransition runstate_transitions_def[] = {
>> { RUN_STATE_RUNNING, RUN_STATE_WATCHDOG },
>> { RUN_STATE_RUNNING, RUN_STATE_GUEST_PANICKED },
>> { RUN_STATE_RUNNING, RUN_STATE_COLO},
>> + { RUN_STATE_RUNNING, RUN_STATE_INMIGRATE },
>
> Experience suggests that you'll find out the hard way that there's other
> states you'll need to allow or check for.
> For example, do you want to be able to loadvm from a GUEST_PANICKED or
> PRELAUNCH state?
Yes, I would add GUEST_PANICKED at least.
>
> Dave
>
>> { RUN_STATE_SAVE_VM, RUN_STATE_RUNNING },
>>
>> --
>> 2.16.2
>>
--
Thank you,
Richard.
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2018-03-05 15:33 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-02-27 11:56 [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots Richard Palethorpe
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 1/2] migrate: Allow incoming migration without defer Richard Palethorpe
2018-03-01 16:59 ` Dr. David Alan Gilbert
2018-03-05 15:33 ` Richard Palethorpe
2018-02-27 11:56 ` [Qemu-devel] [RFC PATCH 2/2] migrate: Tests for migrating to an already used QEMU Richard Palethorpe
2018-03-01 17:32 ` Dr. David Alan Gilbert
2018-02-27 16:07 ` [Qemu-devel] [RFC PATCH 0/2] Increase usability of external snapshots no-reply
2018-03-02 16:15 ` [Qemu-devel] [Qemu-block] " Roman Kagan
2018-03-05 14:38 ` Richard Palethorpe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).