Commit 5c4343b8 authored by Vladimir Sementsov-Ogievskiy's avatar Vladimir Sementsov-Ogievskiy Committed by Max Reitz
Browse files

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: default avatarVladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: default avatarMax Reitz <mreitz@redhat.com>
Message-id: 20190920142056.12778-10-vsementsov@virtuozzo.com
Signed-off-by: default avatarMax Reitz <mreitz@redhat.com>
parent d10529a2
Loading
Loading
Loading
Loading
+36 −47
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ class TestIncrementalBackupBase(iotests.QMPTestCase):
        # Create a base image with a distinctive patterning
        drive0 = self.add_node('drive0')
        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.vm.launch()

@@ -348,12 +348,14 @@ class TestIncrementalBackup(TestIncrementalBackupBase):
                            ('0xfe', '16M', '256k'),
                            ('0x64', '32736k', '64k')))
        # Check the dirty bitmap stats
        result = self.vm.qmp('query-block')
        self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/name', 'bitmap0')
        self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/count', 458752)
        self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/granularity', 65536)
        self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/status', 'active')
        self.assert_qmp(result, 'return[0]/dirty-bitmaps[0]/persistent', False)
        self.assertTrue(self.vm.check_bitmap_status(
            'node0', bitmap0.name, {
                'name': 'bitmap0',
                'count': 458752,
                'granularity': 65536,
                'status': 'active',
                'persistent': False
            }))

        # Prepare a cluster_size=128k backup target without a backing file.
        (target, _) = bitmap0.new_target()
@@ -670,9 +672,8 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
        """

        drive0 = self.drives[0]
        # NB: The blkdebug script here looks for a "flush, read, read" pattern.
        # The flush occurs in hmp_io_writes, the first read in device_add, and
        # the last read during the block job.
        # NB: The blkdebug script here looks for a "flush, read" pattern.
        # The flush occurs in hmp_io_writes, and the read during the block job.
        result = self.vm.qmp('blockdev-add',
                             node_name=drive0['id'],
                             driver=drive0['fmt'],
@@ -686,15 +687,11 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
                                     'event': 'flush_to_disk',
                                     'state': 1,
                                     'new_state': 2
                                 },{
                                     'event': 'read_aio',
                                     'state': 2,
                                     'new_state': 3
                                 }],
                                 'inject-error': [{
                                     'event': 'read_aio',
                                     'errno': 5,
                                     'state': 3,
                                     'state': 2,
                                     'immediately': False,
                                     'once': True
                                 }],
@@ -708,23 +705,15 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
                                          ('0xfe', '16M', '256k'),
                                          ('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
        query = self.vm.qmp('query-block')
        ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
               if bmap.get('name') == bitmap.name][0]
        self.assert_qmp(ret, 'count', 458752)
        self.assert_qmp(ret, 'granularity', 65536)
        self.assert_qmp(ret, 'status', 'active')
        self.assert_qmp(ret, 'busy', False)
        self.assert_qmp(ret, 'recording', True)
        self.assertTrue(self.vm.check_bitmap_status(
            drive0['id'], bitmap.name, {
                'count': 458752,
                'granularity': 65536,
                'status': 'active',
                'busy': False,
                'recording': True
            }))

        # Start backup
        parent, _ = bitmap.last_target()
@@ -748,14 +737,14 @@ class TestIncrementalBackupBlkdebug(TestIncrementalBackupBase):
                                        'operation': 'read'})

        # Bitmap Status Check
        query = self.vm.qmp('query-block')
        ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
               if bmap.get('name') == bitmap.name][0]
        self.assert_qmp(ret, 'count', 458752)
        self.assert_qmp(ret, 'granularity', 65536)
        self.assert_qmp(ret, 'status', 'frozen')
        self.assert_qmp(ret, 'busy', True)
        self.assert_qmp(ret, 'recording', True)
        self.assertTrue(self.vm.check_bitmap_status(
            drive0['id'], bitmap.name, {
                'count': 458752,
                'granularity': 65536,
                'status': 'frozen',
                'busy': True,
                'recording': True
            }))

        # Resume and check incremental backup for consistency
        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'])

        # Bitmap Status Check
        query = self.vm.qmp('query-block')
        ret = [bmap for bmap in query['return'][0]['dirty-bitmaps']
               if bmap.get('name') == bitmap.name][0]
        self.assert_qmp(ret, 'count', 0)
        self.assert_qmp(ret, 'granularity', 65536)
        self.assert_qmp(ret, 'status', 'active')
        self.assert_qmp(ret, 'busy', False)
        self.assert_qmp(ret, 'recording', True)
        self.assertTrue(self.vm.check_bitmap_status(
            drive0['id'], bitmap.name, {
                'count': 0,
                'granularity': 65536,
                'status': 'active',
                'busy': False,
                'recording': True
            }))

        # Finalize / Cleanup
        self.make_reference_backup(bitmap)
+16 −33
Original line number Diff line number Diff line
@@ -188,25 +188,6 @@ class Drive:
        self.size = size
        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):
    # Strip any arguments explicitly nulled by the caller:
    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)
        log(cmd)
        log(drive.vm.hmp_qemu_io(drive.name, cmd))
    bitmaps = query_bitmaps(drive.vm)
    log(bitmaps, indent=2)
    bitmaps = drive.vm.query_bitmaps()
    log({'bitmaps': bitmaps}, indent=2)
    log('')
    return bitmaps

@@ -370,7 +351,7 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
        # 1 - Writes and Reference Backup
        bitmaps = perform_writes(drive0, 1)
        ebitmap.dirty_group(1)
        bitmap = get_bitmap(bitmaps, drive0.device, 'bitmap0')
        bitmap = vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps)
        ebitmap.compare(bitmap)
        reference_backup(drive0, 1, fbackup1)

@@ -388,12 +369,13 @@ def test_bitmap_sync(bsync_mode, msync_mode='bitmap', failure=None):
            log('')
            bitmaps = perform_writes(drive0, 2)
            # 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 = EmulatedBitmap()
            anonymous.dirty_group(2)
            anonymous.compare(get_bitmap(bitmaps, drive0.device, '',
                                         recording=True))
            anonymous.compare(vm.get_bitmap(drive0.node, '', recording=True,
                                            bitmaps=bitmaps))

            # Simulate the order in which this will happen:
            # 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,
                   pre_finalize=_callback,
                   cancel=(failure == 'simulated'))
        bitmaps = query_bitmaps(vm)
        log(bitmaps, indent=2)
        bitmaps = vm.query_bitmaps()
        log({'bitmaps': bitmaps}, indent=2)
        log('')

        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.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
        bitmaps = perform_writes(drive0, 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)

        # 2 - Bitmap Backup (In failure modes, this is a recovery.)
        job = backup(drive0, 2, bsync2, "bitmap",
                     bitmap="bitmap0", bitmap_mode=bsync_mode)
        vm.run_job(job, auto_dismiss=True, auto_finalize=False)
        bitmaps = query_bitmaps(vm)
        log(bitmaps, indent=2)
        bitmaps = vm.query_bitmaps()
        log({'bitmaps': bitmaps}, indent=2)
        log('')
        if bsync_mode != 'never':
            ebitmap.clear()
        ebitmap.compare(get_bitmap(bitmaps, drive0.device, 'bitmap0'))
        ebitmap.compare(vm.get_bitmap(drive0.node, 'bitmap0', bitmaps=bitmaps))

        log('--- Cleanup ---\n')
        vm.qmp_log("block-dirty-bitmap-remove",
                   node=drive0.name, name="bitmap0")
        log(query_bitmaps(vm), indent=2)
        bitmaps = vm.query_bitmaps()
        log({'bitmaps': bitmaps}, indent=2)
        vm.shutdown()
        log('')

+140 −224

File changed.

Preview size limit exceeded, changes collapsed.

+27 −0
Original line number Diff line number Diff line
@@ -641,6 +641,33 @@ class VM(qtest.QEMUQtestMachine):
                return x
        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'([^\[]+)\[([^\]]+)\]')