All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors
@ 2015-05-06  4:52 Fam Zheng
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 1/6] mirror: Discard target sectors if not allocated at source side Fam Zheng
                   ` (6 more replies)
  0 siblings, 7 replies; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

v2: Fix typo and add Eric's rev-by in patch 3.
    Add patch 1 to discard target in mirror job. (Paolo)
    Add patch 6 to improve iotests.wait_ready. (John)

This fixes the mirror assert failure reported by wangxiaolong:

https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg04458.html

The direct cause is that hbitmap code couldn't handle unset of bits *after*
iterator's current position. We could fix that, but the bdrv_reset_dirty() call
is more questionable:

Before, if guest discarded some sectors during migration, it could see
different data after moving to dest side, depending on block backends of the
src and the dest. This is IMO worse than mirroring the actual reading as done
in this series, because we don't know what the guest is doing.

For example if a guest first issues WRITE SAME to wipe out the area then issues
UNMAP to discard it, just to get rid of some sensitive data completely, we may
miss both operations and leave stale data on dest image.


Fam Zheng (6):
  mirror: Discard target sectors if not allocated at source side
  block: Fix dirty bitmap in bdrv_co_discard
  block: Remove bdrv_reset_dirty
  qemu-iotests: Make block job methods common
  qemu-iotests: Add test case for mirror with unmap
  iotests: Use event_wait in wait_ready

 block.c                       | 12 --------
 block/io.c                    |  4 +--
 block/mirror.c                | 12 ++++++--
 include/block/block_int.h     |  2 --
 tests/qemu-iotests/041        | 66 ++++++++++---------------------------------
 tests/qemu-iotests/131        | 59 ++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/131.out    |  5 ++++
 tests/qemu-iotests/group      |  1 +
 tests/qemu-iotests/iotests.py | 23 +++++++++++++++
 9 files changed, 115 insertions(+), 69 deletions(-)
 create mode 100644 tests/qemu-iotests/131
 create mode 100644 tests/qemu-iotests/131.out

-- 
1.9.3

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 1/6] mirror: Discard target sectors if not allocated at source side
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
@ 2015-05-06  4:52 ` Fam Zheng
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard Fam Zheng
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

If guest discards a source cluster during mirror, we would want to
discard target side as well.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 block/mirror.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/block/mirror.c b/block/mirror.c
index 58f391a..37a5b61 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -163,6 +163,7 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
     int64_t end, sector_num, next_chunk, next_sector, hbitmap_next_sector;
     uint64_t delay_ns = 0;
     MirrorOp *op;
+    int pnum;
 
     s->sector_num = hbitmap_iter_next(&s->hbi);
     if (s->sector_num < 0) {
@@ -289,8 +290,15 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
     s->in_flight++;
     s->sectors_in_flight += nb_sectors;
     trace_mirror_one_iteration(s, sector_num, nb_sectors);
-    bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
-                   mirror_read_complete, op);
+
+    if (!bdrv_is_allocated_above(source, NULL, sector_num,
+                                 nb_sectors, &pnum)) {
+        bdrv_aio_discard(s->target, sector_num, nb_sectors,
+                         mirror_write_complete, op);
+    } else {
+        bdrv_aio_readv(source, sector_num, &op->qiov, nb_sectors,
+                       mirror_read_complete, op);
+    }
     return delay_ns;
 }
 
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 1/6] mirror: Discard target sectors if not allocated at source side Fam Zheng
@ 2015-05-06  4:52 ` Fam Zheng
  2015-05-11 19:22   ` John Snow
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 3/6] block: Remove bdrv_reset_dirty Fam Zheng
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

Unsetting dirty globally with discard is not very correct. The discard may zero
out sectors (depending on can_write_zeroes_with_unmap), we should replicate
this change to destinition side to make sure that the guest sees the same data.

Calling bdrv_reset_dirty also troubles mirror job because the hbitmap iterator
doesn't expect unsetting of bits after current position.

So let's do it the opposite way which fixes both problems: set the dirty bits
if we are to discard it.

Reported-by: wangxiaolong@ucloud.cn
Signed-off-by: Fam Zheng <famz@redhat.com>
---
 block/io.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/block/io.c b/block/io.c
index 1ce62c4..809688b 100644
--- a/block/io.c
+++ b/block/io.c
@@ -2343,8 +2343,6 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
         return -EROFS;
     }
 
-    bdrv_reset_dirty(bs, sector_num, nb_sectors);
-
     /* Do nothing if disabled.  */
     if (!(bs->open_flags & BDRV_O_UNMAP)) {
         return 0;
@@ -2354,6 +2352,8 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
         return 0;
     }
 
+    bdrv_set_dirty(bs, sector_num, nb_sectors);
+
     max_discard = MIN_NON_ZERO(bs->bl.max_discard, BDRV_REQUEST_MAX_SECTORS);
     while (nb_sectors > 0) {
         int ret;
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 3/6] block: Remove bdrv_reset_dirty
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 1/6] mirror: Discard target sectors if not allocated at source side Fam Zheng
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard Fam Zheng
@ 2015-05-06  4:52 ` Fam Zheng
  2015-05-11 19:11   ` John Snow
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 4/6] qemu-iotests: Make block job methods common Fam Zheng
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

Using this function would always be wrong because a dirty bitmap must
have a specific owner that consumes the dirty bits and calls
bdrv_reset_dirty_bitmap().

Remove the unused function to avoid future misuse.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
---
 block.c                   | 12 ------------
 include/block/block_int.h |  2 --
 2 files changed, 14 deletions(-)

diff --git a/block.c b/block.c
index 7904098..511e13c 100644
--- a/block.c
+++ b/block.c
@@ -3324,18 +3324,6 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
     }
 }
 
-void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
-                      int nr_sectors)
-{
-    BdrvDirtyBitmap *bitmap;
-    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
-        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
-            continue;
-        }
-        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
-    }
-}
-
 /**
  * Advance an HBitmapIter to an arbitrary offset.
  */
diff --git a/include/block/block_int.h b/include/block/block_int.h
index db29b74..aaed2fa 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -635,7 +635,5 @@ bool blk_dev_is_medium_locked(BlockBackend *blk);
 void blk_dev_resize_cb(BlockBackend *blk);
 
 void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
-void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
-                      int nr_sectors);
 
 #endif /* BLOCK_INT_H */
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 4/6] qemu-iotests: Make block job methods common
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
                   ` (2 preceding siblings ...)
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 3/6] block: Remove bdrv_reset_dirty Fam Zheng
@ 2015-05-06  4:52 ` Fam Zheng
  2015-05-11 19:55   ` John Snow
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 5/6] qemu-iotests: Add test case for mirror with unmap Fam Zheng
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/qemu-iotests/041        | 66 ++++++++++---------------------------------
 tests/qemu-iotests/iotests.py | 28 ++++++++++++++++++
 2 files changed, 43 insertions(+), 51 deletions(-)

diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index 59a8f73..3d46ed7 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -34,38 +34,8 @@ quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img')
 quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img')
 quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img')
 
-class ImageMirroringTestCase(iotests.QMPTestCase):
-    '''Abstract base class for image mirroring test cases'''
 
-    def wait_ready(self, drive='drive0'):
-        '''Wait until a block job BLOCK_JOB_READY event'''
-        ready = False
-        while not ready:
-            for event in self.vm.get_qmp_events(wait=True):
-                if event['event'] == 'BLOCK_JOB_READY':
-                    self.assert_qmp(event, 'data/type', 'mirror')
-                    self.assert_qmp(event, 'data/device', drive)
-                    ready = True
-
-    def wait_ready_and_cancel(self, drive='drive0'):
-        self.wait_ready(drive=drive)
-        event = self.cancel_and_wait(drive=drive)
-        self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
-        self.assert_qmp(event, 'data/type', 'mirror')
-        self.assert_qmp(event, 'data/offset', event['data']['len'])
-
-    def complete_and_wait(self, drive='drive0', wait_ready=True):
-        '''Complete a block job and wait for it to finish'''
-        if wait_ready:
-            self.wait_ready(drive=drive)
-
-        result = self.vm.qmp('block-job-complete', device=drive)
-        self.assert_qmp(result, 'return', {})
-
-        event = self.wait_until_completed(drive=drive)
-        self.assert_qmp(event, 'data/type', 'mirror')
-
-class TestSingleDrive(ImageMirroringTestCase):
+class TestSingleDrive(iotests.QMPTestCase):
     image_len = 1 * 1024 * 1024 # MB
 
     def setUp(self):
@@ -221,17 +191,9 @@ class TestSingleDriveUnalignedLength(TestSingleDrive):
     test_small_buffer2 = None
     test_large_cluster = None
 
-class TestMirrorNoBacking(ImageMirroringTestCase):
+class TestMirrorNoBacking(iotests.QMPTestCase):
     image_len = 2 * 1024 * 1024 # MB
 
-    def complete_and_wait(self, drive='drive0', wait_ready=True):
-        iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
-        return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
-
-    def compare_images(self, img1, img2):
-        iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
-        return iotests.compare_images(img1, img2)
-
     def setUp(self):
         iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
@@ -242,7 +204,10 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
         self.vm.shutdown()
         os.remove(test_img)
         os.remove(backing_img)
-        os.remove(target_backing_img)
+        try:
+            os.remove(target_backing_img)
+        except:
+            pass
         os.remove(target_img)
 
     def test_complete(self):
@@ -257,7 +222,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
         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),
+        self.assertTrue(iotests.compare_images(test_img, target_img),
                         'target image does not match source after mirroring')
 
     def test_cancel(self):
@@ -272,7 +237,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
         result = self.vm.qmp('query-block')
         self.assert_qmp(result, 'return[0]/inserted/file', test_img)
         self.vm.shutdown()
-        self.assertTrue(self.compare_images(test_img, target_img),
+        self.assertTrue(iotests.compare_images(test_img, target_img),
                         'target image does not match source after mirroring')
 
     def test_large_cluster(self):
@@ -283,7 +248,6 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
                         %(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)
@@ -293,10 +257,10 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
         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),
+        self.assertTrue(iotests.compare_images(test_img, target_img),
                         'target image does not match source after mirroring')
 
-class TestMirrorResized(ImageMirroringTestCase):
+class TestMirrorResized(iotests.QMPTestCase):
     backing_len = 1 * 1024 * 1024 # MB
     image_len = 2 * 1024 * 1024 # MB
 
@@ -344,7 +308,7 @@ class TestMirrorResized(ImageMirroringTestCase):
         self.assertTrue(iotests.compare_images(test_img, target_img),
                         'target image does not match source after mirroring')
 
-class TestReadErrors(ImageMirroringTestCase):
+class TestReadErrors(iotests.QMPTestCase):
     image_len = 2 * 1024 * 1024 # MB
 
     # this should be a multiple of twice the default granularity
@@ -498,7 +462,7 @@ new_state = "1"
         self.assert_no_active_block_jobs()
         self.vm.shutdown()
 
-class TestWriteErrors(ImageMirroringTestCase):
+class TestWriteErrors(iotests.QMPTestCase):
     image_len = 2 * 1024 * 1024 # MB
 
     # this should be a multiple of twice the default granularity
@@ -624,7 +588,7 @@ new_state = "1"
         self.assert_no_active_block_jobs()
         self.vm.shutdown()
 
-class TestSetSpeed(ImageMirroringTestCase):
+class TestSetSpeed(iotests.QMPTestCase):
     image_len = 80 * 1024 * 1024 # MB
 
     def setUp(self):
@@ -690,7 +654,7 @@ class TestSetSpeed(ImageMirroringTestCase):
 
         self.wait_ready_and_cancel()
 
-class TestUnbackedSource(ImageMirroringTestCase):
+class TestUnbackedSource(iotests.QMPTestCase):
     image_len = 2 * 1024 * 1024 # MB
 
     def setUp(self):
@@ -731,7 +695,7 @@ class TestUnbackedSource(ImageMirroringTestCase):
         self.complete_and_wait()
         self.assert_no_active_block_jobs()
 
-class TestRepairQuorum(ImageMirroringTestCase):
+class TestRepairQuorum(iotests.QMPTestCase):
     """ This class test quorum file repair using drive-mirror.
         It's mostly a fork of TestSingleDrive """
     image_len = 1 * 1024 * 1024 # MB
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index e93e623..2e07cc4 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -326,6 +326,34 @@ class QMPTestCase(unittest.TestCase):
         self.assert_no_active_block_jobs()
         return event
 
+    def wait_ready(self, drive='drive0'):
+        '''Wait until a block job BLOCK_JOB_READY event'''
+        ready = False
+        while not ready:
+            for event in self.vm.get_qmp_events(wait=True):
+                if event['event'] == 'BLOCK_JOB_READY':
+                    self.assert_qmp(event, 'data/type', 'mirror')
+                    self.assert_qmp(event, 'data/device', drive)
+                    ready = True
+
+    def wait_ready_and_cancel(self, drive='drive0'):
+        self.wait_ready(drive=drive)
+        event = self.cancel_and_wait(drive=drive)
+        self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
+        self.assert_qmp(event, 'data/type', 'mirror')
+        self.assert_qmp(event, 'data/offset', event['data']['len'])
+
+    def complete_and_wait(self, drive='drive0', wait_ready=True):
+        '''Complete a block job and wait for it to finish'''
+        if wait_ready:
+            self.wait_ready(drive=drive)
+
+        result = self.vm.qmp('block-job-complete', device=drive)
+        self.assert_qmp(result, 'return', {})
+
+        event = self.wait_until_completed(drive=drive)
+        self.assert_qmp(event, 'data/type', 'mirror')
+
 def notrun(reason):
     '''Skip this test suite'''
     # Each test in qemu-iotests has a number ("seq")
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 5/6] qemu-iotests: Add test case for mirror with unmap
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
                   ` (3 preceding siblings ...)
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 4/6] qemu-iotests: Make block job methods common Fam Zheng
@ 2015-05-06  4:52 ` Fam Zheng
  2015-05-11 19:59   ` John Snow
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 6/6] iotests: Use event_wait in wait_ready Fam Zheng
  2015-05-07 13:20 ` [Qemu-devel] [Qemu-block] [PATCH v2 0/6] block: Mirror discarded sectors Stefan Hajnoczi
  6 siblings, 1 reply; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

This checks that the discard on mirror source that effectively zeroes
data is also reflected by the data of target.

Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/qemu-iotests/131     | 59 ++++++++++++++++++++++++++++++++++++++++++++++
 tests/qemu-iotests/131.out |  5 ++++
 tests/qemu-iotests/group   |  1 +
 3 files changed, 65 insertions(+)
 create mode 100644 tests/qemu-iotests/131
 create mode 100644 tests/qemu-iotests/131.out

diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131
new file mode 100644
index 0000000..f53ef6e
--- /dev/null
+++ b/tests/qemu-iotests/131
@@ -0,0 +1,59 @@
+#!/usr/bin/env python
+#
+# Test mirror with unmap
+#
+# Copyright (C) 2015 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/>.
+#
+
+import time
+import os
+import iotests
+from iotests import qemu_img, qemu_io
+
+test_img = os.path.join(iotests.test_dir, 'test.img')
+target_img = os.path.join(iotests.test_dir, 'target.img')
+
+class TestSingleDrive(iotests.QMPTestCase):
+    image_len = 2 * 1024 * 1024 # MB
+
+    def setUp(self):
+        # Write data to the image so we can compare later
+        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
+        qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 2M', test_img)
+
+        self.vm = iotests.VM().add_drive(test_img, 'discard=unmap')
+        self.vm.launch()
+
+    def tearDown(self):
+        self.vm.shutdown()
+        os.remove(test_img)
+        try:
+            os.remove(target_img)
+        except OSError:
+            pass
+
+    def test_mirror_discard(self):
+        result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
+                             target=target_img)
+        self.assert_qmp(result, 'return', {})
+        self.vm.hmp_qemu_io('drive0', 'discard 0 64k')
+        self.complete_and_wait('drive0')
+        self.vm.shutdown()
+        self.assertTrue(iotests.compare_images(test_img, target_img),
+                        'target image does not match source after mirroring')
+
+if __name__ == '__main__':
+    iotests.main(supported_fmts=['raw', 'qcow2'])
diff --git a/tests/qemu-iotests/131.out b/tests/qemu-iotests/131.out
new file mode 100644
index 0000000..ae1213e
--- /dev/null
+++ b/tests/qemu-iotests/131.out
@@ -0,0 +1,5 @@
+.
+----------------------------------------------------------------------
+Ran 1 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 6ca3466..34b16cb 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -128,3 +128,4 @@
 128 rw auto quick
 129 rw auto quick
 130 rw auto quick
+131 rw auto quick
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [Qemu-devel] [PATCH v2 6/6] iotests: Use event_wait in wait_ready
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
                   ` (4 preceding siblings ...)
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 5/6] qemu-iotests: Add test case for mirror with unmap Fam Zheng
@ 2015-05-06  4:52 ` Fam Zheng
  2015-05-11 20:34   ` John Snow
  2015-05-07 13:20 ` [Qemu-devel] [Qemu-block] [PATCH v2 0/6] block: Mirror discarded sectors Stefan Hajnoczi
  6 siblings, 1 reply; 15+ messages in thread
From: Fam Zheng @ 2015-05-06  4:52 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, qemu-block, Stefan Hajnoczi, pbonzini, jsnow, wangxiaolong

Only poll the specific type of event we are interested in, to avoid
stealing events that should be consumed by someone else.

Suggested-by: John Snow <jsnow@redhat.com>
Signed-off-by: Fam Zheng <famz@redhat.com>
---
 tests/qemu-iotests/iotests.py | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 2e07cc4..0ddc513 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -328,13 +328,8 @@ class QMPTestCase(unittest.TestCase):
 
     def wait_ready(self, drive='drive0'):
         '''Wait until a block job BLOCK_JOB_READY event'''
-        ready = False
-        while not ready:
-            for event in self.vm.get_qmp_events(wait=True):
-                if event['event'] == 'BLOCK_JOB_READY':
-                    self.assert_qmp(event, 'data/type', 'mirror')
-                    self.assert_qmp(event, 'data/device', drive)
-                    ready = True
+        f = {'data': {'type': 'mirror', 'device': drive } }
+        event = self.vm.event_wait(name='BLOCK_JOB_READY', match=f)
 
     def wait_ready_and_cancel(self, drive='drive0'):
         self.wait_ready(drive=drive)
-- 
1.9.3

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH v2 0/6] block: Mirror discarded sectors
  2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
                   ` (5 preceding siblings ...)
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 6/6] iotests: Use event_wait in wait_ready Fam Zheng
@ 2015-05-07 13:20 ` Stefan Hajnoczi
  2015-05-08  2:58   ` Fam Zheng
  6 siblings, 1 reply; 15+ messages in thread
From: Stefan Hajnoczi @ 2015-05-07 13:20 UTC (permalink / raw)
  To: Fam Zheng
  Cc: qemu-block, Jeff Cody, qemu-devel, Stefan Hajnoczi, pbonzini,
	wangxiaolong

[-- Attachment #1: Type: text/plain, Size: 2094 bytes --]

On Wed, May 06, 2015 at 12:52:02PM +0800, Fam Zheng wrote:
> v2: Fix typo and add Eric's rev-by in patch 3.
>     Add patch 1 to discard target in mirror job. (Paolo)
>     Add patch 6 to improve iotests.wait_ready. (John)
> 
> This fixes the mirror assert failure reported by wangxiaolong:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg04458.html
> 
> The direct cause is that hbitmap code couldn't handle unset of bits *after*
> iterator's current position. We could fix that, but the bdrv_reset_dirty() call
> is more questionable:
> 
> Before, if guest discarded some sectors during migration, it could see
> different data after moving to dest side, depending on block backends of the
> src and the dest. This is IMO worse than mirroring the actual reading as done
> in this series, because we don't know what the guest is doing.
> 
> For example if a guest first issues WRITE SAME to wipe out the area then issues
> UNMAP to discard it, just to get rid of some sensitive data completely, we may
> miss both operations and leave stale data on dest image.
> 
> 
> Fam Zheng (6):
>   mirror: Discard target sectors if not allocated at source side
>   block: Fix dirty bitmap in bdrv_co_discard
>   block: Remove bdrv_reset_dirty
>   qemu-iotests: Make block job methods common
>   qemu-iotests: Add test case for mirror with unmap
>   iotests: Use event_wait in wait_ready
> 
>  block.c                       | 12 --------
>  block/io.c                    |  4 +--
>  block/mirror.c                | 12 ++++++--
>  include/block/block_int.h     |  2 --
>  tests/qemu-iotests/041        | 66 ++++++++++---------------------------------
>  tests/qemu-iotests/131        | 59 ++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/131.out    |  5 ++++
>  tests/qemu-iotests/group      |  1 +
>  tests/qemu-iotests/iotests.py | 23 +++++++++++++++
>  9 files changed, 115 insertions(+), 69 deletions(-)
>  create mode 100644 tests/qemu-iotests/131
>  create mode 100644 tests/qemu-iotests/131.out

CCing Jeff Cody for block jobs

[-- Attachment #2: Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [Qemu-block] [PATCH v2 0/6] block: Mirror discarded sectors
  2015-05-07 13:20 ` [Qemu-devel] [Qemu-block] [PATCH v2 0/6] block: Mirror discarded sectors Stefan Hajnoczi
@ 2015-05-08  2:58   ` Fam Zheng
  0 siblings, 0 replies; 15+ messages in thread
From: Fam Zheng @ 2015-05-08  2:58 UTC (permalink / raw)
  To: Stefan Hajnoczi
  Cc: qemu-block, Jeff Cody, qemu-devel, Stefan Hajnoczi, pbonzini,
	wangxiaolong

On Thu, 05/07 14:20, Stefan Hajnoczi wrote:
> On Wed, May 06, 2015 at 12:52:02PM +0800, Fam Zheng wrote:
> > v2: Fix typo and add Eric's rev-by in patch 3.
> >     Add patch 1 to discard target in mirror job. (Paolo)
> >     Add patch 6 to improve iotests.wait_ready. (John)
> > 
> > This fixes the mirror assert failure reported by wangxiaolong:
> > 
> > https://lists.gnu.org/archive/html/qemu-devel/2015-04/msg04458.html
> > 
> > The direct cause is that hbitmap code couldn't handle unset of bits *after*
> > iterator's current position. We could fix that, but the bdrv_reset_dirty() call
> > is more questionable:
> > 
> > Before, if guest discarded some sectors during migration, it could see
> > different data after moving to dest side, depending on block backends of the
> > src and the dest. This is IMO worse than mirroring the actual reading as done
> > in this series, because we don't know what the guest is doing.
> > 
> > For example if a guest first issues WRITE SAME to wipe out the area then issues
> > UNMAP to discard it, just to get rid of some sensitive data completely, we may
> > miss both operations and leave stale data on dest image.
> > 
> > 
> > Fam Zheng (6):
> >   mirror: Discard target sectors if not allocated at source side
> >   block: Fix dirty bitmap in bdrv_co_discard
> >   block: Remove bdrv_reset_dirty
> >   qemu-iotests: Make block job methods common
> >   qemu-iotests: Add test case for mirror with unmap
> >   iotests: Use event_wait in wait_ready
> > 
> >  block.c                       | 12 --------
> >  block/io.c                    |  4 +--
> >  block/mirror.c                | 12 ++++++--
> >  include/block/block_int.h     |  2 --
> >  tests/qemu-iotests/041        | 66 ++++++++++---------------------------------
> >  tests/qemu-iotests/131        | 59 ++++++++++++++++++++++++++++++++++++++
> >  tests/qemu-iotests/131.out    |  5 ++++
> >  tests/qemu-iotests/group      |  1 +
> >  tests/qemu-iotests/iotests.py | 23 +++++++++++++++
> >  9 files changed, 115 insertions(+), 69 deletions(-)
> >  create mode 100644 tests/qemu-iotests/131
> >  create mode 100644 tests/qemu-iotests/131.out
> 
> CCing Jeff Cody for block jobs

Thanks,

Note that in the discussion of v1 Paolo pointed out that discard on target is
not safe in some cases, I need to fix that in v3.

Fam

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 3/6] block: Remove bdrv_reset_dirty
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 3/6] block: Remove bdrv_reset_dirty Fam Zheng
@ 2015-05-11 19:11   ` John Snow
  0 siblings, 0 replies; 15+ messages in thread
From: John Snow @ 2015-05-11 19:11 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, pbonzini, Stefan Hajnoczi, qemu-block, wangxiaolong



On 05/06/2015 12:52 AM, Fam Zheng wrote:
> Using this function would always be wrong because a dirty bitmap must
> have a specific owner that consumes the dirty bits and calls
> bdrv_reset_dirty_bitmap().
> 

Good point.

> Remove the unused function to avoid future misuse.
> 
> Reviewed-by: Eric Blake <eblake@redhat.com>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  block.c                   | 12 ------------
>  include/block/block_int.h |  2 --
>  2 files changed, 14 deletions(-)
> 
> diff --git a/block.c b/block.c
> index 7904098..511e13c 100644
> --- a/block.c
> +++ b/block.c
> @@ -3324,18 +3324,6 @@ void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector,
>      }
>  }
>  
> -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
> -                      int nr_sectors)
> -{
> -    BdrvDirtyBitmap *bitmap;
> -    QLIST_FOREACH(bitmap, &bs->dirty_bitmaps, list) {
> -        if (!bdrv_dirty_bitmap_enabled(bitmap)) {
> -            continue;
> -        }
> -        hbitmap_reset(bitmap->bitmap, cur_sector, nr_sectors);
> -    }
> -}
> -
>  /**
>   * Advance an HBitmapIter to an arbitrary offset.
>   */
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index db29b74..aaed2fa 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -635,7 +635,5 @@ bool blk_dev_is_medium_locked(BlockBackend *blk);
>  void blk_dev_resize_cb(BlockBackend *blk);
>  
>  void bdrv_set_dirty(BlockDriverState *bs, int64_t cur_sector, int nr_sectors);
> -void bdrv_reset_dirty(BlockDriverState *bs, int64_t cur_sector,
> -                      int nr_sectors);
>  
>  #endif /* BLOCK_INT_H */
> 

Reviewed-by: John Snow <jsnow@redhat.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard Fam Zheng
@ 2015-05-11 19:22   ` John Snow
  2015-05-12  6:21     ` Fam Zheng
  0 siblings, 1 reply; 15+ messages in thread
From: John Snow @ 2015-05-11 19:22 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, pbonzini, Stefan Hajnoczi, qemu-block, wangxiaolong



On 05/06/2015 12:52 AM, Fam Zheng wrote:
> Unsetting dirty globally with discard is not very correct. The discard may zero
> out sectors (depending on can_write_zeroes_with_unmap), we should replicate
> this change to destinition side to make sure that the guest sees the same data.
> 
> Calling bdrv_reset_dirty also troubles mirror job because the hbitmap iterator
> doesn't expect unsetting of bits after current position.
> 
> So let's do it the opposite way which fixes both problems: set the dirty bits
> if we are to discard it.
> 
> Reported-by: wangxiaolong@ucloud.cn
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  block/io.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/block/io.c b/block/io.c
> index 1ce62c4..809688b 100644
> --- a/block/io.c
> +++ b/block/io.c
> @@ -2343,8 +2343,6 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
>          return -EROFS;
>      }
>  
> -    bdrv_reset_dirty(bs, sector_num, nb_sectors);
> -
>      /* Do nothing if disabled.  */
>      if (!(bs->open_flags & BDRV_O_UNMAP)) {
>          return 0;
> @@ -2354,6 +2352,8 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
>          return 0;
>      }
>  
> +    bdrv_set_dirty(bs, sector_num, nb_sectors);
> +
>      max_discard = MIN_NON_ZERO(bs->bl.max_discard, BDRV_REQUEST_MAX_SECTORS);
>      while (nb_sectors > 0) {
>          int ret;
> 

For the clueless: will discard *always* change the data, or is it
possible that some implementations might do nothing?

Is it possible to just omit a set/reset from this function altogether
and let whatever function that is called later (e.g. a write_zeroes
call) worry about setting the dirty bits?

What I wonder about: Is it possible that we are needlessly marking data
as dirty when it has not changed?

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 4/6] qemu-iotests: Make block job methods common
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 4/6] qemu-iotests: Make block job methods common Fam Zheng
@ 2015-05-11 19:55   ` John Snow
  0 siblings, 0 replies; 15+ messages in thread
From: John Snow @ 2015-05-11 19:55 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, pbonzini, Stefan Hajnoczi, qemu-block, wangxiaolong



On 05/06/2015 12:52 AM, Fam Zheng wrote:
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  tests/qemu-iotests/041        | 66 ++++++++++---------------------------------
>  tests/qemu-iotests/iotests.py | 28 ++++++++++++++++++
>  2 files changed, 43 insertions(+), 51 deletions(-)
> 
> diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
> index 59a8f73..3d46ed7 100755
> --- a/tests/qemu-iotests/041
> +++ b/tests/qemu-iotests/041
> @@ -34,38 +34,8 @@ quorum_img3 = os.path.join(iotests.test_dir, 'quorum3.img')
>  quorum_repair_img = os.path.join(iotests.test_dir, 'quorum_repair.img')
>  quorum_snapshot_file = os.path.join(iotests.test_dir, 'quorum_snapshot.img')
>  
> -class ImageMirroringTestCase(iotests.QMPTestCase):
> -    '''Abstract base class for image mirroring test cases'''
>  
> -    def wait_ready(self, drive='drive0'):
> -        '''Wait until a block job BLOCK_JOB_READY event'''
> -        ready = False
> -        while not ready:
> -            for event in self.vm.get_qmp_events(wait=True):
> -                if event['event'] == 'BLOCK_JOB_READY':
> -                    self.assert_qmp(event, 'data/type', 'mirror')
> -                    self.assert_qmp(event, 'data/device', drive)
> -                    ready = True
> -
> -    def wait_ready_and_cancel(self, drive='drive0'):
> -        self.wait_ready(drive=drive)
> -        event = self.cancel_and_wait(drive=drive)
> -        self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
> -        self.assert_qmp(event, 'data/type', 'mirror')
> -        self.assert_qmp(event, 'data/offset', event['data']['len'])

> -
> -    def complete_and_wait(self, drive='drive0', wait_ready=True):
> -        '''Complete a block job and wait for it to finish'''
> -        if wait_ready:
> -            self.wait_ready(drive=drive)
> -
> -        result = self.vm.qmp('block-job-complete', device=drive)
> -        self.assert_qmp(result, 'return', {})
> -
> -        event = self.wait_until_completed(drive=drive)
> -        self.assert_qmp(event, 'data/type', 'mirror')
> -
> -class TestSingleDrive(ImageMirroringTestCase):
> +class TestSingleDrive(iotests.QMPTestCase):
>      image_len = 1 * 1024 * 1024 # MB
>  
>      def setUp(self):
> @@ -221,17 +191,9 @@ class TestSingleDriveUnalignedLength(TestSingleDrive):
>      test_small_buffer2 = None
>      test_large_cluster = None
>  
> -class TestMirrorNoBacking(ImageMirroringTestCase):
> +class TestMirrorNoBacking(iotests.QMPTestCase):
>      image_len = 2 * 1024 * 1024 # MB
>  
> -    def complete_and_wait(self, drive='drive0', wait_ready=True):
> -        iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
> -        return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
> -
> -    def compare_images(self, img1, img2):
> -        iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
> -        return iotests.compare_images(img1, img2)
> -
>      def setUp(self):
>          iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
>          qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
> @@ -242,7 +204,10 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
>          self.vm.shutdown()
>          os.remove(test_img)
>          os.remove(backing_img)
> -        os.remove(target_backing_img)
> +        try:
> +            os.remove(target_backing_img)
> +        except:
> +            pass
>          os.remove(target_img)
>  
>      def test_complete(self):
> @@ -257,7 +222,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
>          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),
> +        self.assertTrue(iotests.compare_images(test_img, target_img),
>                          'target image does not match source after mirroring')
>  
>      def test_cancel(self):
> @@ -272,7 +237,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
>          result = self.vm.qmp('query-block')
>          self.assert_qmp(result, 'return[0]/inserted/file', test_img)
>          self.vm.shutdown()
> -        self.assertTrue(self.compare_images(test_img, target_img),
> +        self.assertTrue(iotests.compare_images(test_img, target_img),
>                          'target image does not match source after mirroring')
>  
>      def test_large_cluster(self):
> @@ -283,7 +248,6 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
>                          %(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)
> @@ -293,10 +257,10 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
>          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),
> +        self.assertTrue(iotests.compare_images(test_img, target_img),
>                          'target image does not match source after mirroring')
>  
> -class TestMirrorResized(ImageMirroringTestCase):
> +class TestMirrorResized(iotests.QMPTestCase):
>      backing_len = 1 * 1024 * 1024 # MB
>      image_len = 2 * 1024 * 1024 # MB
>  
> @@ -344,7 +308,7 @@ class TestMirrorResized(ImageMirroringTestCase):
>          self.assertTrue(iotests.compare_images(test_img, target_img),
>                          'target image does not match source after mirroring')
>  
> -class TestReadErrors(ImageMirroringTestCase):
> +class TestReadErrors(iotests.QMPTestCase):
>      image_len = 2 * 1024 * 1024 # MB
>  
>      # this should be a multiple of twice the default granularity
> @@ -498,7 +462,7 @@ new_state = "1"
>          self.assert_no_active_block_jobs()
>          self.vm.shutdown()
>  
> -class TestWriteErrors(ImageMirroringTestCase):
> +class TestWriteErrors(iotests.QMPTestCase):
>      image_len = 2 * 1024 * 1024 # MB
>  
>      # this should be a multiple of twice the default granularity
> @@ -624,7 +588,7 @@ new_state = "1"
>          self.assert_no_active_block_jobs()
>          self.vm.shutdown()
>  
> -class TestSetSpeed(ImageMirroringTestCase):
> +class TestSetSpeed(iotests.QMPTestCase):
>      image_len = 80 * 1024 * 1024 # MB
>  
>      def setUp(self):
> @@ -690,7 +654,7 @@ class TestSetSpeed(ImageMirroringTestCase):
>  
>          self.wait_ready_and_cancel()
>  
> -class TestUnbackedSource(ImageMirroringTestCase):
> +class TestUnbackedSource(iotests.QMPTestCase):
>      image_len = 2 * 1024 * 1024 # MB
>  
>      def setUp(self):
> @@ -731,7 +695,7 @@ class TestUnbackedSource(ImageMirroringTestCase):
>          self.complete_and_wait()
>          self.assert_no_active_block_jobs()
>  
> -class TestRepairQuorum(ImageMirroringTestCase):
> +class TestRepairQuorum(iotests.QMPTestCase):
>      """ This class test quorum file repair using drive-mirror.
>          It's mostly a fork of TestSingleDrive """
>      image_len = 1 * 1024 * 1024 # MB
> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index e93e623..2e07cc4 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -326,6 +326,34 @@ class QMPTestCase(unittest.TestCase):
>          self.assert_no_active_block_jobs()
>          return event
>  
> +    def wait_ready(self, drive='drive0'):
> +        '''Wait until a block job BLOCK_JOB_READY event'''
> +        ready = False
> +        while not ready:
> +            for event in self.vm.get_qmp_events(wait=True):
> +                if event['event'] == 'BLOCK_JOB_READY':
> +                    self.assert_qmp(event, 'data/type', 'mirror')
> +                    self.assert_qmp(event, 'data/device', drive)
> +                    ready = True
> +
> +    def wait_ready_and_cancel(self, drive='drive0'):
> +        self.wait_ready(drive=drive)
> +        event = self.cancel_and_wait(drive=drive)
> +        self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
> +        self.assert_qmp(event, 'data/type', 'mirror')
> +        self.assert_qmp(event, 'data/offset', event['data']['len'])
> +
> +    def complete_and_wait(self, drive='drive0', wait_ready=True):
> +        '''Complete a block job and wait for it to finish'''
> +        if wait_ready:
> +            self.wait_ready(drive=drive)
> +
> +        result = self.vm.qmp('block-job-complete', device=drive)
> +        self.assert_qmp(result, 'return', {})
> +
> +        event = self.wait_until_completed(drive=drive)
> +        self.assert_qmp(event, 'data/type', 'mirror')
> +
>  def notrun(reason):
>      '''Skip this test suite'''
>      # Each test in qemu-iotests has a number ("seq")
> 

Reviewed-by: John Snow <jsnow@redhat.com>

Side-note: we should at some point clean up the images this tests leaves
laying around. Not caused by this patch, though.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 5/6] qemu-iotests: Add test case for mirror with unmap
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 5/6] qemu-iotests: Add test case for mirror with unmap Fam Zheng
@ 2015-05-11 19:59   ` John Snow
  0 siblings, 0 replies; 15+ messages in thread
From: John Snow @ 2015-05-11 19:59 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, pbonzini, Stefan Hajnoczi, qemu-block, wangxiaolong



On 05/06/2015 12:52 AM, Fam Zheng wrote:
> This checks that the discard on mirror source that effectively zeroes
> data is also reflected by the data of target.
> 
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  tests/qemu-iotests/131     | 59 ++++++++++++++++++++++++++++++++++++++++++++++
>  tests/qemu-iotests/131.out |  5 ++++
>  tests/qemu-iotests/group   |  1 +
>  3 files changed, 65 insertions(+)
>  create mode 100644 tests/qemu-iotests/131
>  create mode 100644 tests/qemu-iotests/131.out
> 
> diff --git a/tests/qemu-iotests/131 b/tests/qemu-iotests/131
> new file mode 100644
> index 0000000..f53ef6e
> --- /dev/null
> +++ b/tests/qemu-iotests/131
> @@ -0,0 +1,59 @@
> +#!/usr/bin/env python
> +#
> +# Test mirror with unmap
> +#
> +# Copyright (C) 2015 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/>.
> +#
> +
> +import time
> +import os
> +import iotests
> +from iotests import qemu_img, qemu_io
> +
> +test_img = os.path.join(iotests.test_dir, 'test.img')
> +target_img = os.path.join(iotests.test_dir, 'target.img')
> +
> +class TestSingleDrive(iotests.QMPTestCase):
> +    image_len = 2 * 1024 * 1024 # MB
> +
> +    def setUp(self):
> +        # Write data to the image so we can compare later
> +        qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
> +        qemu_io('-f', iotests.imgfmt, '-c', 'write -P0x5d 0 2M', test_img)
> +
> +        self.vm = iotests.VM().add_drive(test_img, 'discard=unmap')
> +        self.vm.launch()
> +
> +    def tearDown(self):
> +        self.vm.shutdown()
> +        os.remove(test_img)
> +        try:
> +            os.remove(target_img)
> +        except OSError:
> +            pass
> +
> +    def test_mirror_discard(self):
> +        result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
> +                             target=target_img)
> +        self.assert_qmp(result, 'return', {})
> +        self.vm.hmp_qemu_io('drive0', 'discard 0 64k')
> +        self.complete_and_wait('drive0')
> +        self.vm.shutdown()
> +        self.assertTrue(iotests.compare_images(test_img, target_img),
> +                        'target image does not match source after mirroring')
> +
> +if __name__ == '__main__':
> +    iotests.main(supported_fmts=['raw', 'qcow2'])
> diff --git a/tests/qemu-iotests/131.out b/tests/qemu-iotests/131.out
> new file mode 100644
> index 0000000..ae1213e
> --- /dev/null
> +++ b/tests/qemu-iotests/131.out
> @@ -0,0 +1,5 @@
> +.
> +----------------------------------------------------------------------
> +Ran 1 tests
> +
> +OK
> diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
> index 6ca3466..34b16cb 100644
> --- a/tests/qemu-iotests/group
> +++ b/tests/qemu-iotests/group
> @@ -128,3 +128,4 @@
>  128 rw auto quick
>  129 rw auto quick
>  130 rw auto quick
> +131 rw auto quick
> 

Reviewed-by: John Snow <jsnow@redhat.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 6/6] iotests: Use event_wait in wait_ready
  2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 6/6] iotests: Use event_wait in wait_ready Fam Zheng
@ 2015-05-11 20:34   ` John Snow
  0 siblings, 0 replies; 15+ messages in thread
From: John Snow @ 2015-05-11 20:34 UTC (permalink / raw)
  To: Fam Zheng, qemu-devel
  Cc: Kevin Wolf, pbonzini, Stefan Hajnoczi, qemu-block, wangxiaolong



On 05/06/2015 12:52 AM, Fam Zheng wrote:
> Only poll the specific type of event we are interested in, to avoid
> stealing events that should be consumed by someone else.
> 
> Suggested-by: John Snow <jsnow@redhat.com>
> Signed-off-by: Fam Zheng <famz@redhat.com>
> ---
>  tests/qemu-iotests/iotests.py | 9 ++-------
>  1 file changed, 2 insertions(+), 7 deletions(-)
> 
> diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
> index 2e07cc4..0ddc513 100644
> --- a/tests/qemu-iotests/iotests.py
> +++ b/tests/qemu-iotests/iotests.py
> @@ -328,13 +328,8 @@ class QMPTestCase(unittest.TestCase):
>  
>      def wait_ready(self, drive='drive0'):
>          '''Wait until a block job BLOCK_JOB_READY event'''
> -        ready = False
> -        while not ready:
> -            for event in self.vm.get_qmp_events(wait=True):
> -                if event['event'] == 'BLOCK_JOB_READY':
> -                    self.assert_qmp(event, 'data/type', 'mirror')
> -                    self.assert_qmp(event, 'data/device', drive)
> -                    ready = True
> +        f = {'data': {'type': 'mirror', 'device': drive } }
> +        event = self.vm.event_wait(name='BLOCK_JOB_READY', match=f)
>  
>      def wait_ready_and_cancel(self, drive='drive0'):
>          self.wait_ready(drive=drive)
> 

Thanks for appeasing me :)

Reviewed-by: John Snow <jsnow@redhat.com>

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard
  2015-05-11 19:22   ` John Snow
@ 2015-05-12  6:21     ` Fam Zheng
  0 siblings, 0 replies; 15+ messages in thread
From: Fam Zheng @ 2015-05-12  6:21 UTC (permalink / raw)
  To: John Snow
  Cc: Kevin Wolf, qemu-block, qemu-devel, Stefan Hajnoczi, pbonzini,
	wangxiaolong

On Mon, 05/11 15:22, John Snow wrote:
> 
> 
> On 05/06/2015 12:52 AM, Fam Zheng wrote:
> > Unsetting dirty globally with discard is not very correct. The discard may zero
> > out sectors (depending on can_write_zeroes_with_unmap), we should replicate
> > this change to destinition side to make sure that the guest sees the same data.
> > 
> > Calling bdrv_reset_dirty also troubles mirror job because the hbitmap iterator
> > doesn't expect unsetting of bits after current position.
> > 
> > So let's do it the opposite way which fixes both problems: set the dirty bits
> > if we are to discard it.
> > 
> > Reported-by: wangxiaolong@ucloud.cn
> > Signed-off-by: Fam Zheng <famz@redhat.com>
> > ---
> >  block/io.c | 4 ++--
> >  1 file changed, 2 insertions(+), 2 deletions(-)
> > 
> > diff --git a/block/io.c b/block/io.c
> > index 1ce62c4..809688b 100644
> > --- a/block/io.c
> > +++ b/block/io.c
> > @@ -2343,8 +2343,6 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
> >          return -EROFS;
> >      }
> >  
> > -    bdrv_reset_dirty(bs, sector_num, nb_sectors);
> > -
> >      /* Do nothing if disabled.  */
> >      if (!(bs->open_flags & BDRV_O_UNMAP)) {
> >          return 0;
> > @@ -2354,6 +2352,8 @@ int coroutine_fn bdrv_co_discard(BlockDriverState *bs, int64_t sector_num,
> >          return 0;
> >      }
> >  
> > +    bdrv_set_dirty(bs, sector_num, nb_sectors);
> > +
> >      max_discard = MIN_NON_ZERO(bs->bl.max_discard, BDRV_REQUEST_MAX_SECTORS);
> >      while (nb_sectors > 0) {
> >          int ret;
> > 
> 
> For the clueless: will discard *always* change the data, or is it
> possible that some implementations might do nothing?

It could be nop, partial discard, or an effective write same, depending on the
protocol. For raw, it depends on the host file system.

> 
> Is it possible to just omit a set/reset from this function altogether
> and let whatever function that is called later (e.g. a write_zeroes
> call) worry about setting the dirty bits?
> 
> What I wonder about: Is it possible that we are needlessly marking data
> as dirty when it has not changed?
> 

No. Because write zeroes path is not involved at all, it's this function that
changes image data. We have to set the dirty bitmap here.

Fam

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2015-05-12  6:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-06  4:52 [Qemu-devel] [PATCH v2 0/6] block: Mirror discarded sectors Fam Zheng
2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 1/6] mirror: Discard target sectors if not allocated at source side Fam Zheng
2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 2/6] block: Fix dirty bitmap in bdrv_co_discard Fam Zheng
2015-05-11 19:22   ` John Snow
2015-05-12  6:21     ` Fam Zheng
2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 3/6] block: Remove bdrv_reset_dirty Fam Zheng
2015-05-11 19:11   ` John Snow
2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 4/6] qemu-iotests: Make block job methods common Fam Zheng
2015-05-11 19:55   ` John Snow
2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 5/6] qemu-iotests: Add test case for mirror with unmap Fam Zheng
2015-05-11 19:59   ` John Snow
2015-05-06  4:52 ` [Qemu-devel] [PATCH v2 6/6] iotests: Use event_wait in wait_ready Fam Zheng
2015-05-11 20:34   ` John Snow
2015-05-07 13:20 ` [Qemu-devel] [Qemu-block] [PATCH v2 0/6] block: Mirror discarded sectors Stefan Hajnoczi
2015-05-08  2:58   ` Fam Zheng

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.