mirror of https://github.com/xemu-project/xemu.git
iotests: prepare 124 and 257 bitmap querying for backup-top filter
After backup-top filter appearing it's not possible to see dirty bitmaps in top node, so use node-name instead. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Reviewed-by: Max Reitz <mreitz@redhat.com> Message-id: 20190920142056.12778-10-vsementsov@virtuozzo.com Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
d10529a2b7
commit
5c4343b89d
|
@ -105,7 +105,7 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
|
||||||
# Create a base image with a distinctive patterning
|
# Create a base image with a distinctive patterning
|
||||||
drive0 = self.add_node('drive0')
|
drive0 = self.add_node('drive0')
|
||||||
self.img_create(drive0['file'], drive0['fmt'])
|
self.img_create(drive0['file'], drive0['fmt'])
|
||||||
self.vm.add_drive(drive0['file'])
|
self.vm.add_drive(drive0['file'], opts='node-name=node0')
|
||||||
self.write_default_pattern(drive0['file'])
|
self.write_default_pattern(drive0['file'])
|
||||||
self.vm.launch()
|
self.vm.launch()
|
||||||
|
|
||||||
|
@ -348,12 +348,14 @@ class TestIncrementalBackup(TestIncrementalBackupBase):
|
||||||
('0xfe', '16M', '256k'),
|
('0xfe', '16M', '256k'),
|
||||||
('0x64', '32736k', '64k')))
|
('0x64', '32736k', '64k')))
|
||||||
# Check the dirty bitmap stats
|
# Check the dirty bitmap stats
|
||||||
result = self.vm.qmp('query-block')
|
self.assertTrue(self.vm.check_bitmap_status(
|
||||||
self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/name', 'bitmap0')
|
'node0', bitmap0.name, {
|
||||||
self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/count', 458752)
|
'name': 'bitmap0',
|
||||||
self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/granularity', 65536)
|
'count': 458752,
|
||||||
self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/status', 'active')
|
'granularity': 65536,
|
||||||
self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/persistent', False)
|
'status': 'active',
|
||||||
|
'persistent': False
|
||||||
|
}))
|
||||||
|
|
||||||
# Prepare a cluster_size=128k backup target without a backing file.
|
# Prepare a cluster_size=128k backup target without a backing file.
|
||||||
(target, _) = bitmap0.new_target()
|
(target, _) = bitmap0.new_target()
|
||||||
|
@ -670,9 +672,8 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
drive0 = self.drives[0]
|
drive0 = self.drives[0]
|
||||||
# NB: The blkdebug script here looks for a "flush, read, read" pattern.
|
# NB: The blkdebug script here looks for a "flush, read" pattern.
|
||||||
# The flush occurs in hmp_io_writes, the first read in device_add, and
|
# The flush occurs in hmp_io_writes, and the read during the block job.
|
||||||
# the last read during the block job.
|
|
||||||
result = self.vm.qmp('blockdev-add',
|
result = self.vm.qmp('blockdev-add',
|
||||||
node_name=drive0['id'],
|
node_name=drive0['id'],
|
||||||
driver=drive0['fmt'],
|
driver=drive0['fmt'],
|
||||||
|
@ -686,15 +687,11 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
|
||||||
'event': 'flush_to_disk',
|
'event': 'flush_to_disk',
|
||||||
'state': 1,
|
'state': 1,
|
||||||
'new_state': 2
|
'new_state': 2
|
||||||
},{
|
|
||||||
'event': 'read_aio',
|
|
||||||
'state': 2,
|
|
||||||
'new_state': 3
|
|
||||||
}],
|
}],
|
||||||
'inject-error': [{
|
'inject-error': [{
|
||||||
'event': 'read_aio',
|
'event': 'read_aio',
|
||||||
'errno': 5,
|
'errno': 5,
|
||||||
'state': 3,
|
'state': 2,
|
||||||
'immediately': False,
|
'immediately': False,
|
||||||
'once': True
|
'once': True
|
||||||
}],
|
}],
|
||||||
|
@ -708,23 +705,15 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
|
||||||
('0xfe', '16M', '256k'),
|
('0xfe', '16M', '256k'),
|
||||||
('0x64', '32736k', '64k')))
|
('0x64', '32736k', '64k')))
|
||||||
|
|
||||||
# For the purposes of query-block visibility of bitmaps, add a drive
|
|
||||||
# frontend after we've written data; otherwise we can't use hmp-io
|
|
||||||
result = self.vm.qmp("device_add",
|
|
||||||
id="device0",
|
|
||||||
drive=drive0['id'],
|
|
||||||
driver="virtio-blk")
|
|
||||||
self.assert_qmp(result, 'return', {})
|
|
||||||
|
|
||||||
# Bitmap Status Check
|
# Bitmap Status Check
|
||||||
query = self.vm.qmp('query-block')
|
self.assertTrue(self.vm.check_bitmap_status(
|
||||||
ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
|
drive0['id'], bitmap.name, {
|
||||||
if bmap.get('name') == bitmap.name][0]
|
'count': 458752,
|
||||||
self.assert_qmp(ret, 'count', 458752)
|
'granularity': 65536,
|
||||||
self.assert_qmp(ret, 'granularity', 65536)
|
'status': 'active',
|
||||||
self.assert_qmp(ret, 'status', 'active')
|
'busy': False,
|
||||||
self.assert_qmp(ret, 'busy', False)
|
'recording': True
|
||||||
self.assert_qmp(ret, 'recording', True)
|
}))
|
||||||
|
|
||||||
# Start backup
|
# Start backup
|
||||||
parent, _ = bitmap.last_target()
|
parent, _ = bitmap.last_target()
|
||||||
|
@ -748,14 +737,14 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
|
||||||
'operation': 'read'})
|
'operation': 'read'})
|
||||||
|
|
||||||
# Bitmap Status Check
|
# Bitmap Status Check
|
||||||
query = self.vm.qmp('query-block')
|
self.assertTrue(self.vm.check_bitmap_status(
|
||||||
ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
|
drive0['id'], bitmap.name, {
|
||||||
if bmap.get('name') == bitmap.name][0]
|
'count': 458752,
|
||||||
self.assert_qmp(ret, 'count', 458752)
|
'granularity': 65536,
|
||||||
self.assert_qmp(ret, 'granularity', 65536)
|
'status': 'frozen',
|
||||||
self.assert_qmp(ret, 'status', 'frozen')
|
'busy': True,
|
||||||
self.assert_qmp(ret, 'busy', True)
|
'recording': True
|
||||||
self.assert_qmp(ret, 'recording', True)
|
}))
|
||||||
|
|
||||||
# Resume and check incremental backup for consistency
|
# Resume and check incremental backup for consistency
|
||||||
res = self.vm.qmp('block-job-resume', device=bitmap.drive['id'])
|
res = self.vm.qmp('block-job-resume', device=bitmap.drive['id'])
|
||||||
|
@ -763,14 +752,14 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
|
||||||
self.wait_qmp_backup(bitmap.drive['id'])
|
self.wait_qmp_backup(bitmap.drive['id'])
|
||||||
|
|
||||||
# Bitmap Status Check
|
# Bitmap Status Check
|
||||||
query = self.vm.qmp('query-block')
|
self.assertTrue(self.vm.check_bitmap_status(
|
||||||
ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
|
drive0['id'], bitmap.name, {
|
||||||
if bmap.get('name') == bitmap.name][0]
|
'count': 0,
|
||||||
self.assert_qmp(ret, 'count', 0)
|
'granularity': 65536,
|
||||||
self.assert_qmp(ret, 'granularity', 65536)
|
'status': 'active',
|
||||||
self.assert_qmp(ret, 'status', 'active')
|
'busy': False,
|
||||||
self.assert_qmp(ret, 'busy', False)
|
'recording': True
|
||||||
self.assert_qmp(ret, 'recording', True)
|
}))
|
||||||
|
|
||||||
# Finalize / Cleanup
|
# Finalize / Cleanup
|
||||||
self.make_reference_backup(bitmap)
|
self.make_reference_backup(bitmap)
|
||||||
|
|
|
@ -188,25 +188,6 @@ class Drive:
|
||||||
self.size = size
|
self.size = size
|
||||||
self.node = name
|
self.node = name
|
||||||
|
|
||||||
def query_bitmaps(vm):
|
|
||||||
res = vm.qmp("query-block")
|
|
||||||
return {"bitmaps": {device['device'] or device['qdev']:
|
|
||||||
device.get('dirty-bitmaps', []) for
|
|
||||||
device in res['return']}}
|
|
||||||
|
|
||||||
def get_bitmap(bitmaps, drivename, name, recording=None):
|
|
||||||
"""
|
|
||||||
get a specific bitmap from the object returned by query_bitmaps.
|
|
||||||
:param recording: If specified, filter results by the specified value.
|
|
||||||
"""
|
|
||||||
for bitmap in bitmaps['bitmaps'][drivename]:
|
|
||||||
if bitmap.get('name', '') == name:
|
|
||||||
if recording is None:
|
|
||||||
return bitmap
|
|
||||||
elif bitmap.get('recording') == recording:
|
|
||||||
return bitmap
|
|
||||||
return None
|
|
||||||
|
|
||||||
def blockdev_backup(vm, device, target, sync, **kwargs):
|
def blockdev_backup(vm, device, target, sync, **kwargs):
|
||||||
# Strip any arguments explicitly nulled by the caller:
|
# Strip any arguments explicitly nulled by the caller:
|
||||||
kwargs = {key: val for key, val in kwargs.items() if val is not None}
|
kwargs = {key: val for key, val in kwargs.items() if val is not None}
|
||||||
|
@ -249,8 +230,8 @@ def perform_writes(drive, n):
|
||||||
pattern.size)
|
pattern.size)
|
||||||
log(cmd)
|
log(cmd)
|
||||||
log(drive.vm.hmp_qemu_io(drive.name, cmd))
|
log(drive.vm.hmp_qemu_io(drive.name, cmd))
|
||||||
bitmaps = query_bitmaps(drive.vm)
|
bitmaps = drive.vm.query_bitmaps()
|
||||||
log(bitmaps, indent=2)
|
log({'bitmaps': bitmaps}, indent=2)
|
||||||
log('')
|
log('')
|
||||||
return bitmaps
|
return bitmaps
|
||||||
|
|
||||||
|
@ -370,7 +351,7 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
|
||||||
# 1 - Writes and Reference Backup
|
# 1 - Writes and Reference Backup
|
||||||
bitmaps = perform_writes(drive0, 1)
|
bitmaps = perform_writes(drive0, 1)
|
||||||
ebitmap.dirty_group(1)
|
ebitmap.dirty_group(1)
|
||||||
bitmap = get_bitmap(bitmaps, drive0.device, 'bitmap0')
|
bitmap = vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)
|
||||||
ebitmap.compare(bitmap)
|
ebitmap.compare(bitmap)
|
||||||
reference_backup(drive0, 1, fbackup1)
|
reference_backup(drive0, 1, fbackup1)
|
||||||
|
|
||||||
|
@ -388,12 +369,13 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
|
||||||
log('')
|
log('')
|
||||||
bitmaps = perform_writes(drive0, 2)
|
bitmaps = perform_writes(drive0, 2)
|
||||||
# Named bitmap (static, should be unchanged)
|
# Named bitmap (static, should be unchanged)
|
||||||
ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
|
ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0',
|
||||||
|
bitmaps=bitmaps))
|
||||||
# Anonymous bitmap (dynamic, shows new writes)
|
# Anonymous bitmap (dynamic, shows new writes)
|
||||||
anonymous = EmulatedBitmap()
|
anonymous = EmulatedBitmap()
|
||||||
anonymous.dirty_group(2)
|
anonymous.dirty_group(2)
|
||||||
anonymous.compare(get_bitmap(bitmaps, drive0.device, '',
|
anonymous.compare(vm.get_bitmap(drive0.node, '', recording=True,
|
||||||
recording=True))
|
bitmaps=bitmaps))
|
||||||
|
|
||||||
# Simulate the order in which this will happen:
|
# Simulate the order in which this will happen:
|
||||||
# group 1 gets cleared first, then group two gets written.
|
# group 1 gets cleared first, then group two gets written.
|
||||||
|
@ -405,8 +387,8 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
|
||||||
vm.run_job(job, auto_dismiss=True, auto_finalize=False,
|
vm.run_job(job, auto_dismiss=True, auto_finalize=False,
|
||||||
pre_finalize=_callback,
|
pre_finalize=_callback,
|
||||||
cancel=(failure == 'simulated'))
|
cancel=(failure == 'simulated'))
|
||||||
bitmaps = query_bitmaps(vm)
|
bitmaps = vm.query_bitmaps()
|
||||||
log(bitmaps, indent=2)
|
log({'bitmaps': bitmaps}, indent=2)
|
||||||
log('')
|
log('')
|
||||||
|
|
||||||
if bsync_mode == 'always' and failure == 'intermediate':
|
if bsync_mode == 'always' and failure == 'intermediate':
|
||||||
|
@ -423,29 +405,30 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
|
||||||
ebitmap.clear()
|
ebitmap.clear()
|
||||||
ebitmap.dirty_bits(range(fail_bit, SIZE // GRANULARITY))
|
ebitmap.dirty_bits(range(fail_bit, SIZE // GRANULARITY))
|
||||||
|
|
||||||
ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
|
ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps))
|
||||||
|
|
||||||
# 2 - Writes and Reference Backup
|
# 2 - Writes and Reference Backup
|
||||||
bitmaps = perform_writes(drive0, 3)
|
bitmaps = perform_writes(drive0, 3)
|
||||||
ebitmap.dirty_group(3)
|
ebitmap.dirty_group(3)
|
||||||
ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
|
ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps))
|
||||||
reference_backup(drive0, 2, fbackup2)
|
reference_backup(drive0, 2, fbackup2)
|
||||||
|
|
||||||
# 2 - Bitmap Backup (In failure modes, this is a recovery.)
|
# 2 - Bitmap Backup (In failure modes, this is a recovery.)
|
||||||
job = backup(drive0, 2, bsync2, "bitmap",
|
job = backup(drive0, 2, bsync2, "bitmap",
|
||||||
bitmap="bitmap0", bitmap_mode=bsync_mode)
|
bitmap="bitmap0", bitmap_mode=bsync_mode)
|
||||||
vm.run_job(job, auto_dismiss=True, auto_finalize=False)
|
vm.run_job(job, auto_dismiss=True, auto_finalize=False)
|
||||||
bitmaps = query_bitmaps(vm)
|
bitmaps = vm.query_bitmaps()
|
||||||
log(bitmaps, indent=2)
|
log({'bitmaps': bitmaps}, indent=2)
|
||||||
log('')
|
log('')
|
||||||
if bsync_mode != 'never':
|
if bsync_mode != 'never':
|
||||||
ebitmap.clear()
|
ebitmap.clear()
|
||||||
ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
|
ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps))
|
||||||
|
|
||||||
log('--- Cleanup ---\n')
|
log('--- Cleanup ---\n')
|
||||||
vm.qmp_log("block-dirty-bitmap-remove",
|
vm.qmp_log("block-dirty-bitmap-remove",
|
||||||
node=drive0.name, name="bitmap0")
|
node=drive0.name, name="bitmap0")
|
||||||
log(query_bitmaps(vm), indent=2)
|
bitmaps = vm.query_bitmaps()
|
||||||
|
log({'bitmaps': bitmaps}, indent=2)
|
||||||
vm.shutdown()
|
vm.shutdown()
|
||||||
log('')
|
log('')
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -641,6 +641,33 @@ class VM(qtest.QEMUQtestMachine):
|
||||||
return x
|
return x
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def query_bitmaps(self):
|
||||||
|
res = self.qmp("query-named-block-nodes")
|
||||||
|
return {device['node-name']: device['dirty-bitmaps']
|
||||||
|
for device in res['return'] if 'dirty-bitmaps' in device}
|
||||||
|
|
||||||
|
def get_bitmap(self, node_name, bitmap_name, recording=None, bitmaps=None):
|
||||||
|
"""
|
||||||
|
get a specific bitmap from the object returned by query_bitmaps.
|
||||||
|
:param recording: If specified, filter results by the specified value.
|
||||||
|
:param bitmaps: If specified, use it instead of call query_bitmaps()
|
||||||
|
"""
|
||||||
|
if bitmaps is None:
|
||||||
|
bitmaps = self.query_bitmaps()
|
||||||
|
|
||||||
|
for bitmap in bitmaps[node_name]:
|
||||||
|
if bitmap.get('name', '') == bitmap_name:
|
||||||
|
if recording is None:
|
||||||
|
return bitmap
|
||||||
|
elif bitmap.get('recording') == recording:
|
||||||
|
return bitmap
|
||||||
|
return None
|
||||||
|
|
||||||
|
def check_bitmap_status(self, node_name, bitmap_name, fields):
|
||||||
|
ret = self.get_bitmap(node_name, bitmap_name)
|
||||||
|
|
||||||
|
return fields.items() <= ret.items()
|
||||||
|
|
||||||
|
|
||||||
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
|
index_re = re.compile(r'([^\[]+)\[([^\]]+)\]')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue