mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-07-30 13:53:54 -06:00

When doing a sync=full mirroring, we can skip pre-zeroing the destination if it already reads as zeroes and we are not also trying to punch holes due to detect-zeroes. With this patch, there are fewer scenarios that have to pass in an explicit target-is-zero, while still resulting in a sparse destination remaining sparse. A later patch will then further improve things to skip writing to the destination for parts of the image where the source is zero; but even with just this patch, it is possible to see a difference for any source that does not report itself as fully allocated, coupled with a destination BDS that can quickly report that it already reads as zero. (For a source that reports as fully allocated, such as a file, the rest of mirror_dirty_init() still sets the entire dirty bitmap to true, so even though we avoided the pre-zeroing, we are not yet avoiding all redundant I/O). Iotest 194 detects the difference made by this patch: for a file source (where block status reports the entire image as allocated, and therefore we end up writing zeroes everywhere in the destination anyways), the job length remains the same. But for a qcow2 source and a destination that reads as all zeroes, the dirty bitmap changes to just tracking the allocated portions of the source, which results in faster completion and smaller job statistics. For the test to pass with both ./check -file and -qcow2, a new python filter is needed to mask out the now-varying job amounts (this matches the shell filters _filter_block_job_{offset,len} in common.filter). A later test will also be added which further validates expected sparseness, so it does not matter that 194 is no longer explicitly looking at how many bytes were copied. Signed-off-by: Eric Blake <eblake@redhat.com> Message-ID: <20250509204341.3553601-25-eblake@redhat.com> Reviewed-by: Sunny Zhu <sunnyzhyy@qq.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
109 lines
4.7 KiB
Python
Executable file
109 lines
4.7 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
# group: rw migration quick
|
|
#
|
|
# Copyright (C) 2017 Red Hat, Inc.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# Creator/Owner: Stefan Hajnoczi <stefanha@redhat.com>
|
|
#
|
|
# Non-shared storage migration test using NBD server and drive-mirror
|
|
|
|
import iotests
|
|
|
|
iotests.script_initialize(supported_fmts=['qcow2', 'qed', 'raw'],
|
|
supported_platforms=['linux'])
|
|
|
|
with iotests.FilePath('source.img') as source_img_path, \
|
|
iotests.FilePath('dest.img') as dest_img_path, \
|
|
iotests.FilePath('migration.sock', 'nbd.sock', base_dir=iotests.sock_dir) \
|
|
as (migration_sock_path, nbd_sock_path), \
|
|
iotests.VM('source') as source_vm, \
|
|
iotests.VM('dest') as dest_vm:
|
|
|
|
img_size = '1G'
|
|
iotests.qemu_img_create('-f', iotests.imgfmt, source_img_path, img_size)
|
|
iotests.qemu_io('-f', iotests.imgfmt, '-c', 'write 512M 1M', source_img_path)
|
|
iotests.qemu_img_create('-f', iotests.imgfmt, dest_img_path, img_size)
|
|
|
|
iotests.log('Launching VMs...')
|
|
(source_vm.add_drive(source_img_path)
|
|
.launch())
|
|
(dest_vm.add_drive(dest_img_path)
|
|
.add_incoming('unix:{0}'.format(migration_sock_path))
|
|
.launch())
|
|
|
|
source_vm.qmp_log('block-dirty-bitmap-add', node='drive0', name='bitmap0')
|
|
|
|
iotests.log('Launching NBD server on destination...')
|
|
iotests.log(dest_vm.qmp('nbd-server-start', addr={'type': 'unix', 'data': {'path': nbd_sock_path}}))
|
|
iotests.log(dest_vm.qmp('nbd-server-add', device='drive0', writable=True))
|
|
|
|
iotests.log('Starting `drive-mirror` on source...')
|
|
iotests.log(source_vm.qmp(
|
|
'drive-mirror',
|
|
device='drive0',
|
|
target='nbd+unix:///drive0?socket={0}'.format(nbd_sock_path),
|
|
sync='full',
|
|
format='raw', # always raw, the server handles the format
|
|
mode='existing',
|
|
job_id='mirror-job0'))
|
|
|
|
iotests.log('Waiting for `drive-mirror` to complete...')
|
|
iotests.log(source_vm.event_wait('BLOCK_JOB_READY'),
|
|
filters=[iotests.filter_qmp_event,
|
|
iotests.filter_block_job])
|
|
|
|
iotests.log('Starting migration...')
|
|
capabilities = [{'capability': 'events', 'state': True},
|
|
{'capability': 'dirty-bitmaps', 'state': True}]
|
|
source_vm.qmp('migrate-set-capabilities', capabilities=capabilities)
|
|
dest_vm.qmp('migrate-set-capabilities', capabilities=capabilities)
|
|
iotests.log(source_vm.qmp('migrate', uri='unix:{0}'.format(migration_sock_path)))
|
|
|
|
source_vm.qmp_log('migrate-start-postcopy')
|
|
|
|
while True:
|
|
event1 = source_vm.event_wait('MIGRATION')
|
|
if event1['data']['status'] == 'postcopy-active':
|
|
# This event is racy, it depends do we really do postcopy or bitmap
|
|
# was migrated during downtime (and no data to migrate in postcopy
|
|
# phase). So, don't log it.
|
|
continue
|
|
iotests.log(event1, filters=[iotests.filter_qmp_event])
|
|
if event1['data']['status'] in ('completed', 'failed'):
|
|
iotests.log('Gracefully ending the `drive-mirror` job on source...')
|
|
iotests.log(source_vm.qmp('block-job-cancel', device='mirror-job0'))
|
|
break
|
|
|
|
while True:
|
|
event2 = source_vm.event_wait('BLOCK_JOB_COMPLETED')
|
|
iotests.log(event2, filters=[iotests.filter_qmp_event,
|
|
iotests.filter_block_job])
|
|
if event2['event'] == 'BLOCK_JOB_COMPLETED':
|
|
iotests.log('Stopping the NBD server on destination...')
|
|
iotests.log(dest_vm.qmp('nbd-server-stop'))
|
|
break
|
|
|
|
iotests.log('Wait for migration completion on target...')
|
|
migr_events = (('MIGRATION', {'data': {'status': 'completed'}}),
|
|
('MIGRATION', {'data': {'status': 'failed'}}))
|
|
event = dest_vm.events_wait(migr_events)
|
|
iotests.log(event, filters=[iotests.filter_qmp_event])
|
|
|
|
iotests.log('Check bitmaps on source:')
|
|
iotests.log(source_vm.qmp('query-block')['return'][0]['inserted']['dirty-bitmaps'])
|
|
|
|
iotests.log('Check bitmaps on target:')
|
|
iotests.log(dest_vm.qmp('query-block')['return'][0]['inserted']['dirty-bitmaps'])
|