aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-07-28 14:38:17 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-07-28 14:38:17 +0100
commit264991512193ee50e27d43e66f832d5041cf3b28 (patch)
tree1576995ac48671469cb568d9c6ecae70fa3a8f6f /tests
parent1b242c3b1ec7c6011901b4f3b4b0876e31746afb (diff)
parent37931e006f05cb768b78dcc47453b13f76ea43c5 (diff)
downloadqemu-264991512193ee50e27d43e66f832d5041cf3b28.zip
qemu-264991512193ee50e27d43e66f832d5041cf3b28.tar.gz
qemu-264991512193ee50e27d43e66f832d5041cf3b28.tar.bz2
Merge remote-tracking branch 'remotes/ericb/tags/pull-bitmaps-2020-07-27' into staging
bitmaps patches for 2020-07-27 - Improve handling of various post-copy bitmap migration scenarios. A lost bitmap should merely mean that the next backup must be full rather than incremental, rather than abruptly breaking the entire guest migration. - Associated iotest improvements # gpg: Signature made Mon 27 Jul 2020 21:46:17 BST # gpg: using RSA key 71C2CC22B1C4602927D2F3AAA7A16B4A2527436A # gpg: Good signature from "Eric Blake <eblake@redhat.com>" [full] # gpg: aka "Eric Blake (Free Software Programmer) <ebb9@byu.net>" [full] # gpg: aka "[jpeg image of size 6874]" [full] # Primary key fingerprint: 71C2 CC22 B1C4 6029 27D2 F3AA A7A1 6B4A 2527 436A * remotes/ericb/tags/pull-bitmaps-2020-07-27: (24 commits) migration: Fix typos in bitmap migration comments iotests: Adjust which migration tests are quick qemu-iotests/199: add source-killed case to bitmaps postcopy qemu-iotests/199: add early shutdown case to bitmaps postcopy qemu-iotests/199: check persistent bitmaps qemu-iotests/199: prepare for new test-cases addition migration/savevm: don't worry if bitmap migration postcopy failed migration/block-dirty-bitmap: cancel migration on shutdown migration/block-dirty-bitmap: relax error handling in incoming part migration/block-dirty-bitmap: keep bitmap state for all bitmaps migration/block-dirty-bitmap: simplify dirty_bitmap_load_complete migration/block-dirty-bitmap: rename finish_lock to just lock migration/block-dirty-bitmap: refactor state global variables migration/block-dirty-bitmap: move mutex init to dirty_bitmap_mig_init migration/block-dirty-bitmap: rename dirty_bitmap_mig_cleanup migration/block-dirty-bitmap: rename state structure types migration/block-dirty-bitmap: fix dirty_bitmap_mig_before_vm_start qemu-iotests/199: increase postcopy period qemu-iotests/199: change discard patterns qemu-iotests/199: improve performance: set bitmap by discard ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests')
-rwxr-xr-xtests/qemu-iotests/199250
-rw-r--r--tests/qemu-iotests/199.out4
-rw-r--r--tests/qemu-iotests/group12
3 files changed, 204 insertions, 62 deletions
diff --git a/tests/qemu-iotests/199 b/tests/qemu-iotests/199
index 40774ee..58fad87 100755
--- a/tests/qemu-iotests/199
+++ b/tests/qemu-iotests/199
@@ -20,17 +20,76 @@
import os
import iotests
-import time
from iotests import qemu_img
+debug = False
+
disk_a = os.path.join(iotests.test_dir, 'disk_a')
disk_b = os.path.join(iotests.test_dir, 'disk_b')
size = '256G'
fifo = os.path.join(iotests.test_dir, 'mig_fifo')
-class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
+granularity = 512
+nb_bitmaps = 15
+
+GiB = 1024 * 1024 * 1024
+
+discards1 = (
+ (0, GiB),
+ (2 * GiB + 512 * 5, 512),
+ (3 * GiB + 512 * 5, 512),
+ (100 * GiB, GiB)
+)
+
+discards2 = (
+ (3 * GiB + 512 * 8, 512),
+ (4 * GiB + 512 * 8, 512),
+ (50 * GiB, GiB),
+ (100 * GiB + GiB // 2, GiB)
+)
+
+
+def apply_discards(vm, discards):
+ for d in discards:
+ vm.hmp_qemu_io('drive0', 'discard {} {}'.format(*d))
+
+
+def event_seconds(event):
+ return event['timestamp']['seconds'] + \
+ event['timestamp']['microseconds'] / 1000000.0
+
+
+def event_dist(e1, e2):
+ return event_seconds(e2) - event_seconds(e1)
+
+
+def check_bitmaps(vm, count):
+ result = vm.qmp('query-block')
+
+ if count == 0:
+ assert 'dirty-bitmaps' not in result['return'][0]
+ else:
+ assert len(result['return'][0]['dirty-bitmaps']) == count
+
+class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
def tearDown(self):
+ if debug:
+ self.vm_a_events += self.vm_a.get_qmp_events()
+ self.vm_b_events += self.vm_b.get_qmp_events()
+ for e in self.vm_a_events:
+ e['vm'] = 'SRC'
+ for e in self.vm_b_events:
+ e['vm'] = 'DST'
+ events = (self.vm_a_events + self.vm_b_events)
+ events = [(e['timestamp']['seconds'],
+ e['timestamp']['microseconds'],
+ e['vm'],
+ e['event'],
+ e.get('data', '')) for e in events]
+ for e in sorted(events):
+ print('{}.{:06} {} {} {}'.format(*e))
+
self.vm_a.shutdown()
self.vm_b.shutdown()
os.remove(disk_a)
@@ -41,51 +100,66 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
os.mkfifo(fifo)
qemu_img('create', '-f', iotests.imgfmt, disk_a, size)
qemu_img('create', '-f', iotests.imgfmt, disk_b, size)
- self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a)
- self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b)
+ self.vm_a = iotests.VM(path_suffix='a').add_drive(disk_a,
+ 'discard=unmap')
+ self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b,
+ 'discard=unmap')
self.vm_b.add_incoming("exec: cat '" + fifo + "'")
self.vm_a.launch()
self.vm_b.launch()
- def test_postcopy(self):
- write_size = 0x40000000
- granularity = 512
- chunk = 4096
+ # collect received events for debug
+ self.vm_a_events = []
+ self.vm_b_events = []
- result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0',
- name='bitmap', granularity=granularity)
- self.assert_qmp(result, 'return', {});
+ def start_postcopy(self):
+ """ Run migration until RESUME event on target. Return this event. """
+ for i in range(nb_bitmaps):
+ result = self.vm_a.qmp('block-dirty-bitmap-add', node='drive0',
+ name='bitmap{}'.format(i),
+ granularity=granularity,
+ persistent=True)
+ self.assert_qmp(result, 'return', {})
- s = 0
- while s < write_size:
- self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk))
- s += 0x10000
- s = 0x8000
- while s < write_size:
- self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk))
- s += 0x10000
+ result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap0')
+ empty_sha256 = result['return']['sha256']
+
+ apply_discards(self.vm_a, discards1)
result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256',
- node='drive0', name='bitmap')
- sha256 = result['return']['sha256']
-
- result = self.vm_a.qmp('block-dirty-bitmap-clear', node='drive0',
- name='bitmap')
- self.assert_qmp(result, 'return', {});
- s = 0
- while s < write_size:
- self.vm_a.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk))
- s += 0x10000
-
- bitmaps_cap = {'capability': 'dirty-bitmaps', 'state': True}
- events_cap = {'capability': 'events', 'state': True}
-
- result = self.vm_a.qmp('migrate-set-capabilities',
- capabilities=[bitmaps_cap, events_cap])
+ node='drive0', name='bitmap0')
+ self.discards1_sha256 = result['return']['sha256']
+
+ # Check, that updating the bitmap by discards works
+ assert self.discards1_sha256 != empty_sha256
+
+ # We want to calculate resulting sha256. Do it in bitmap0, so, disable
+ # other bitmaps
+ for i in range(1, nb_bitmaps):
+ result = self.vm_a.qmp('block-dirty-bitmap-disable', node='drive0',
+ name='bitmap{}'.format(i))
+ self.assert_qmp(result, 'return', {})
+
+ apply_discards(self.vm_a, discards2)
+
+ result = self.vm_a.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap0')
+ self.all_discards_sha256 = result['return']['sha256']
+
+ # Now, enable some bitmaps, to be updated during migration
+ for i in range(2, nb_bitmaps, 2):
+ result = self.vm_a.qmp('block-dirty-bitmap-enable', node='drive0',
+ name='bitmap{}'.format(i))
+ self.assert_qmp(result, 'return', {})
+
+ caps = [{'capability': 'dirty-bitmaps', 'state': True},
+ {'capability': 'events', 'state': True}]
+
+ result = self.vm_a.qmp('migrate-set-capabilities', capabilities=caps)
self.assert_qmp(result, 'return', {})
- result = self.vm_b.qmp('migrate-set-capabilities',
- capabilities=[bitmaps_cap])
+ result = self.vm_b.qmp('migrate-set-capabilities', capabilities=caps)
self.assert_qmp(result, 'return', {})
result = self.vm_a.qmp('migrate', uri='exec:cat>' + fifo)
@@ -94,26 +168,94 @@ class TestDirtyBitmapPostcopyMigration(iotests.QMPTestCase):
result = self.vm_a.qmp('migrate-start-postcopy')
self.assert_qmp(result, 'return', {})
- while True:
- event = self.vm_a.event_wait('MIGRATION')
- if event['data']['status'] == 'completed':
- break
+ event_resume = self.vm_b.event_wait('RESUME')
+ self.vm_b_events.append(event_resume)
+ return event_resume
+
+ def test_postcopy_success(self):
+ event_resume = self.start_postcopy()
+
+ # enabled bitmaps should be updated
+ apply_discards(self.vm_b, discards2)
+
+ match = {'data': {'status': 'completed'}}
+ event_complete = self.vm_b.event_wait('MIGRATION', match=match)
+ self.vm_b_events.append(event_complete)
+
+ # take queued event, should already been happened
+ event_stop = self.vm_a.event_wait('STOP')
+ self.vm_a_events.append(event_stop)
+
+ downtime = event_dist(event_stop, event_resume)
+ postcopy_time = event_dist(event_resume, event_complete)
+
+ assert downtime * 10 < postcopy_time
+ if debug:
+ print('downtime:', downtime)
+ print('postcopy_time:', postcopy_time)
+
+ # check that there are no bitmaps stored on source
+ self.vm_a_events += self.vm_a.get_qmp_events()
+ self.vm_a.shutdown()
+ self.vm_a.launch()
+ check_bitmaps(self.vm_a, 0)
+
+ # check that bitmaps are migrated and persistence works
+ check_bitmaps(self.vm_b, nb_bitmaps)
+ self.vm_b.shutdown()
+ # recreate vm_b, so there is no incoming option, which prevents
+ # loading bitmaps from disk
+ self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b)
+ self.vm_b.launch()
+ check_bitmaps(self.vm_b, nb_bitmaps)
+
+ # Check content of migrated bitmaps. Still, don't waste time checking
+ # every bitmap
+ for i in range(0, nb_bitmaps, 5):
+ result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256',
+ node='drive0', name='bitmap{}'.format(i))
+ sha = self.discards1_sha256 if i % 2 else self.all_discards_sha256
+ self.assert_qmp(result, 'return/sha256', sha)
+
+ def test_early_shutdown_destination(self):
+ self.start_postcopy()
+
+ self.vm_b_events += self.vm_b.get_qmp_events()
+ self.vm_b.shutdown()
+ # recreate vm_b, so there is no incoming option, which prevents
+ # loading bitmaps from disk
+ self.vm_b = iotests.VM(path_suffix='b').add_drive(disk_b)
+ self.vm_b.launch()
+ check_bitmaps(self.vm_b, 0)
- s = 0x8000
- while s < write_size:
- self.vm_b.hmp_qemu_io('drive0', 'write %d %d' % (s, chunk))
- s += 0x10000
+ # Bitmaps will be lost if we just shutdown the vm, as they are marked
+ # to skip storing to disk when prepared for migration. And that's
+ # correct, as actual data may be modified in target vm, so we play
+ # safe.
+ # Still, this mark would be taken away if we do 'cont', and bitmaps
+ # become persistent again. (see iotest 169 for such behavior case)
+ result = self.vm_a.qmp('query-status')
+ assert not result['return']['running']
+ self.vm_a_events += self.vm_a.get_qmp_events()
+ self.vm_a.shutdown()
+ self.vm_a.launch()
+ check_bitmaps(self.vm_a, 0)
+
+ def test_early_kill_source(self):
+ self.start_postcopy()
+
+ self.vm_a_events = self.vm_a.get_qmp_events()
+ self.vm_a.kill()
+
+ self.vm_a.launch()
- result = self.vm_b.qmp('query-block');
- while len(result['return'][0]['dirty-bitmaps']) > 1:
- time.sleep(2)
- result = self.vm_b.qmp('query-block');
+ match = {'data': {'status': 'completed'}}
+ e_complete = self.vm_b.event_wait('MIGRATION', match=match)
+ self.vm_b_events.append(e_complete)
- result = self.vm_b.qmp('x-debug-block-dirty-bitmap-sha256',
- node='drive0', name='bitmap')
+ check_bitmaps(self.vm_a, 0)
+ check_bitmaps(self.vm_b, 0)
- self.assert_qmp(result, 'return/sha256', sha256);
if __name__ == '__main__':
- iotests.main(supported_fmts=['qcow2'], supported_cache_modes=['none'],
- supported_protocols=['file'])
+ iotests.main(supported_fmts=['qcow2'])
diff --git a/tests/qemu-iotests/199.out b/tests/qemu-iotests/199.out
index ae1213e..8d7e9967 100644
--- a/tests/qemu-iotests/199.out
+++ b/tests/qemu-iotests/199.out
@@ -1,5 +1,5 @@
-.
+...
----------------------------------------------------------------------
-Ran 1 tests
+Ran 3 tests
OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 1d0252e..8060446 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -112,7 +112,7 @@
088 rw quick
089 rw auto quick
090 rw auto quick
-091 rw migration
+091 rw migration quick
092 rw quick
093 throttle
094 rw quick
@@ -186,7 +186,7 @@
162 quick
163 rw
165 rw quick
-169 rw quick migration
+169 rw migration
170 rw auto quick
171 rw quick
172 auto
@@ -197,9 +197,9 @@
177 rw auto quick
178 img
179 rw auto quick
-181 rw auto migration
+181 rw auto migration quick
182 rw quick
-183 rw migration
+183 rw migration quick
184 rw auto quick
185 rw
186 rw auto
@@ -216,9 +216,9 @@
198 rw
199 rw migration
200 rw
-201 rw migration
+201 rw migration quick
202 rw quick
-203 rw auto migration
+203 rw auto migration quick
204 rw quick
205 rw quick
206 rw