mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-07 01:33:56 -06:00
mirror: perform COW if the cluster size is bigger than the granularity
When mirroring runs, the backing files for the target may not yet be ready. However, this means that a copy-on-write operation on the target would fill the missing sectors with zeros. Copy-on-write only happens if the granularity of the dirty bitmap is smaller than the cluster size (and only for clusters that are allocated in the source after the job has started copying). So far, the granularity was fixed to 1MB; to avoid the problem we detected the situation and required the backing files to be available in that case only. However, we want to lower the granularity for efficiency, so we need a better solution. The solution is to always copy a whole cluster the first time it is touched. The code keeps a bitmap of clusters that have already been allocated by the mirroring job, and only does "manual" copy-on-write if the chunk being copied is zero in the bitmap. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
343bded4ec
commit
b812f6719c
5 changed files with 109 additions and 23 deletions
|
@ -292,6 +292,27 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
|
|||
self.assertTrue(self.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
def test_large_cluster(self):
|
||||
self.assert_no_active_mirrors()
|
||||
|
||||
# qemu-img create fails if the image is not there
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
|
||||
%(TestMirrorNoBacking.image_len), target_backing_img)
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
|
||||
% (TestMirrorNoBacking.image_len, target_backing_img), target_img)
|
||||
os.remove(target_backing_img)
|
||||
|
||||
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
|
||||
mode='existing', target=target_img)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
self.complete_and_wait()
|
||||
result = self.vm.qmp('query-block')
|
||||
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
|
||||
self.vm.shutdown()
|
||||
self.assertTrue(self.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
class TestReadErrors(ImageMirroringTestCase):
|
||||
image_len = 2 * 1024 * 1024 # MB
|
||||
|
||||
|
@ -330,6 +351,9 @@ new_state = "1"
|
|||
'-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
|
||||
% (self.blkdebug_file, backing_img),
|
||||
test_img)
|
||||
# Write something for tests that use sync='top'
|
||||
qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
|
||||
test_img)
|
||||
self.vm = iotests.VM().add_drive(test_img)
|
||||
self.vm.launch()
|
||||
|
||||
|
@ -383,6 +407,32 @@ new_state = "1"
|
|||
self.complete_and_wait()
|
||||
self.vm.shutdown()
|
||||
|
||||
def test_large_cluster(self):
|
||||
self.assert_no_active_mirrors()
|
||||
|
||||
# Test COW into the target image. The first half of the
|
||||
# cluster at MIRROR_GRANULARITY has to be copied from
|
||||
# backing_img, even though sync='top'.
|
||||
qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
|
||||
result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
|
||||
on_source_error='ignore',
|
||||
mode='existing', target=target_img)
|
||||
self.assert_qmp(result, 'return', {})
|
||||
|
||||
event = self.vm.get_qmp_event(wait=True)
|
||||
self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
|
||||
self.assert_qmp(event, 'data/device', 'drive0')
|
||||
self.assert_qmp(event, 'data/operation', 'read')
|
||||
result = self.vm.qmp('query-block-jobs')
|
||||
self.assert_qmp(result, 'return[0]/paused', False)
|
||||
self.complete_and_wait()
|
||||
self.vm.shutdown()
|
||||
|
||||
# Detach blkdebug to compare images successfully
|
||||
qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
|
||||
self.assertTrue(self.compare_images(test_img, target_img),
|
||||
'target image does not match source after mirroring')
|
||||
|
||||
def test_stop_read(self):
|
||||
self.assert_no_active_mirrors()
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
..................
|
||||
....................
|
||||
----------------------------------------------------------------------
|
||||
Ran 18 tests
|
||||
Ran 20 tests
|
||||
|
||||
OK
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue