1
The following changes since commit bfec359afba088aaacc7d316f43302f28c6e642a:
1
The following changes since commit 8c1ecb590497b0349c550607db923972b37f6963:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qdev-2017-04-21' into staging (2017-04-21 11:42:03 +0100)
3
Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-next-280519-2' into staging (2019-05-28 17:38:32 +0100)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://github.com/XanClic/qemu.git tags/pull-block-2019-05-28
8
8
9
for you to fetch changes up to 1507631e438930bc07f776f303af127a9cdb4d41:
9
for you to fetch changes up to a2d665c1bc3624a8375e2f9a7d569f7565cc1358:
10
10
11
qemu-iotests: _cleanup_qemu must be called on exit (2017-04-21 08:32:44 -0400)
11
blockdev: loosen restrictions on drive-backup source node (2019-05-28 20:30:55 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
14
Block patches:
15
Block patches for 2.10
15
- qcow2: Use threads for encrypted I/O
16
- qemu-img rebase: Optimizations
17
- backup job: Allow any source node, and some refactoring
18
- Some general simplifications in the block layer
16
19
17
----------------------------------------------------------------
20
----------------------------------------------------------------
21
Alberto Garcia (2):
22
block: Use bdrv_unref_child() for all children in bdrv_close()
23
block: Make bdrv_root_attach_child() unref child_bs on failure
18
24
19
Ashish Mittal (2):
25
Andrey Shinkevich (1):
20
block/vxhs.c: Add support for a new block device type called "vxhs"
26
qcow2-bitmap: initialize bitmap directory alignment
21
block/vxhs.c: Add qemu-iotests for new block device type "vxhs"
22
27
23
Jeff Cody (10):
28
Anton Nefedov (1):
24
qemu-iotests: exclude vxhs from image creation via protocol
29
qcow2: skip writing zero buffers to empty COW areas
25
block: add bdrv_set_read_only() helper function
26
block: do not set BDS read_only if copy_on_read enabled
27
block: honor BDRV_O_ALLOW_RDWR when clearing bs->read_only
28
block: code movement
29
block: introduce bdrv_can_set_read_only()
30
block: use bdrv_can_set_read_only() during reopen
31
block/rbd - update variable names to more apt names
32
block/rbd: Add support for reopen()
33
qemu-iotests: _cleanup_qemu must be called on exit
34
30
35
block.c | 56 +++-
31
John Snow (1):
36
block/Makefile.objs | 2 +
32
blockdev: loosen restrictions on drive-backup source node
37
block/bochs.c | 5 +-
33
38
block/cloop.c | 5 +-
34
Sam Eiderman (3):
39
block/dmg.c | 6 +-
35
qemu-img: rebase: Reuse parent BlockDriverState
40
block/rbd.c | 65 +++--
36
qemu-img: rebase: Reduce reads on in-chain rebase
41
block/trace-events | 17 ++
37
qemu-img: rebase: Reuse in-chain BlockDriverState
42
block/vvfat.c | 19 +-
38
43
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++
39
Vladimir Sementsov-Ogievskiy (13):
44
configure | 39 +++
40
qcow2.h: add missing include
45
include/block/block.h | 2 +
41
qcow2: add separate file for threaded data processing functions
46
qapi/block-core.json | 23 +-
42
qcow2-threads: use thread_pool_submit_co
47
tests/qemu-iotests/017 | 1 +
43
qcow2-threads: qcow2_co_do_compress: protect queuing by mutex
48
tests/qemu-iotests/020 | 1 +
44
qcow2-threads: split out generic path
49
tests/qemu-iotests/028 | 1 +
45
qcow2: qcow2_co_preadv: improve locking
50
tests/qemu-iotests/029 | 1 +
46
qcow2: bdrv_co_pwritev: move encryption code out of the lock
51
tests/qemu-iotests/073 | 1 +
47
qcow2: do encryption in threads
52
tests/qemu-iotests/094 | 11 +-
48
block/backup: simplify backup_incremental_init_copy_bitmap
53
tests/qemu-iotests/102 | 5 +-
49
block/backup: move to copy_bitmap with granularity
54
tests/qemu-iotests/109 | 1 +
50
block/backup: refactor and tolerate unallocated cluster skipping
55
tests/qemu-iotests/114 | 1 +
51
block/backup: unify different modes code path
56
tests/qemu-iotests/117 | 1 +
52
block/backup: refactor: split out backup_calculate_cluster_size
57
tests/qemu-iotests/130 | 2 +
53
58
tests/qemu-iotests/134 | 1 +
54
block/Makefile.objs | 2 +-
59
tests/qemu-iotests/140 | 1 +
55
qapi/block-core.json | 4 +-
60
tests/qemu-iotests/141 | 1 +
56
block/qcow2.h | 26 ++-
61
tests/qemu-iotests/143 | 1 +
57
block.c | 46 +++---
62
tests/qemu-iotests/156 | 2 +
58
block/backup.c | 243 ++++++++++++---------------
63
tests/qemu-iotests/158 | 1 +
59
block/block-backend.c | 3 +-
64
tests/qemu-iotests/common | 6 +
60
block/qcow2-bitmap.c | 3 +-
65
tests/qemu-iotests/common.config | 13 +
61
block/qcow2-cache.c | 1 -
66
tests/qemu-iotests/common.filter | 1 +
62
block/qcow2-cluster.c | 10 +-
67
tests/qemu-iotests/common.rc | 19 ++
63
block/qcow2-refcount.c | 1 -
68
33 files changed, 844 insertions(+), 42 deletions(-)
64
block/qcow2-snapshot.c | 1 -
69
create mode 100644 block/vxhs.c
65
block/qcow2-threads.c | 268 ++++++++++++++++++++++++++++++
66
block/qcow2.c | 320 +++++++++++++-----------------------
67
block/quorum.c | 1 -
68
blockdev.c | 7 +-
69
blockjob.c | 2 +-
70
qemu-img.c | 85 ++++++----
71
tests/test-bdrv-drain.c | 6 -
72
tests/test-bdrv-graph-mod.c | 1 -
73
block/trace-events | 1 +
74
tests/qemu-iotests/056 | 2 +-
75
tests/qemu-iotests/060 | 7 +-
76
tests/qemu-iotests/060.out | 5 +-
77
23 files changed, 615 insertions(+), 430 deletions(-)
78
create mode 100644 block/qcow2-threads.c
70
79
71
--
80
--
72
2.9.3
81
2.21.0
73
82
74
83
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
qcow2.h depends on block_int.h. Compilation isn't broken currently only
4
due to block_int.h always included before qcow2.h. Though, it seems
5
better to directly include block_int.h in qcow2.h.
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20190506142741.41731-2-vsementsov@virtuozzo.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
block/qcow2.h | 1 +
14
block/qcow2-bitmap.c | 1 -
15
block/qcow2-cache.c | 1 -
16
block/qcow2-cluster.c | 1 -
17
block/qcow2-refcount.c | 1 -
18
block/qcow2-snapshot.c | 1 -
19
block/qcow2.c | 1 -
20
7 files changed, 1 insertion(+), 6 deletions(-)
21
22
diff --git a/block/qcow2.h b/block/qcow2.h
23
index XXXXXXX..XXXXXXX 100644
24
--- a/block/qcow2.h
25
+++ b/block/qcow2.h
26
@@ -XXX,XX +XXX,XX @@
27
#include "crypto/block.h"
28
#include "qemu/coroutine.h"
29
#include "qemu/units.h"
30
+#include "block/block_int.h"
31
32
//#define DEBUG_ALLOC
33
//#define DEBUG_ALLOC2
34
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/qcow2-bitmap.c
37
+++ b/block/qcow2-bitmap.c
38
@@ -XXX,XX +XXX,XX @@
39
#include "qapi/error.h"
40
#include "qemu/cutils.h"
41
42
-#include "block/block_int.h"
43
#include "qcow2.h"
44
45
/* NOTICE: BME here means Bitmaps Extension and used as a namespace for
46
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/qcow2-cache.c
49
+++ b/block/qcow2-cache.c
50
@@ -XXX,XX +XXX,XX @@
51
*/
52
53
#include "qemu/osdep.h"
54
-#include "block/block_int.h"
55
#include "qemu-common.h"
56
#include "qcow2.h"
57
#include "trace.h"
58
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
59
index XXXXXXX..XXXXXXX 100644
60
--- a/block/qcow2-cluster.c
61
+++ b/block/qcow2-cluster.c
62
@@ -XXX,XX +XXX,XX @@
63
64
#include "qapi/error.h"
65
#include "qemu-common.h"
66
-#include "block/block_int.h"
67
#include "qcow2.h"
68
#include "qemu/bswap.h"
69
#include "trace.h"
70
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/qcow2-refcount.c
73
+++ b/block/qcow2-refcount.c
74
@@ -XXX,XX +XXX,XX @@
75
#include "qemu/osdep.h"
76
#include "qapi/error.h"
77
#include "qemu-common.h"
78
-#include "block/block_int.h"
79
#include "qcow2.h"
80
#include "qemu/range.h"
81
#include "qemu/bswap.h"
82
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/block/qcow2-snapshot.c
85
+++ b/block/qcow2-snapshot.c
86
@@ -XXX,XX +XXX,XX @@
87
88
#include "qemu/osdep.h"
89
#include "qapi/error.h"
90
-#include "block/block_int.h"
91
#include "qcow2.h"
92
#include "qemu/bswap.h"
93
#include "qemu/error-report.h"
94
diff --git a/block/qcow2.c b/block/qcow2.c
95
index XXXXXXX..XXXXXXX 100644
96
--- a/block/qcow2.c
97
+++ b/block/qcow2.c
98
@@ -XXX,XX +XXX,XX @@
99
#define ZLIB_CONST
100
#include <zlib.h>
101
102
-#include "block/block_int.h"
103
#include "block/qdict.h"
104
#include "sysemu/block-backend.h"
105
#include "qemu/module.h"
106
--
107
2.21.0
108
109
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Source code for the qnio library that this code loads can be downloaded from:
3
Move compression-on-threads to separate file. Encryption will be in it
4
https://github.com/VeritasHyperScale/libqnio.git
4
too.
5
5
6
Sample command line using JSON syntax:
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
./x86_64-softmmu/qemu-system-x86_64 -name instance-00000008 -S -vnc 0.0.0.0:0
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
-k en-us -vga cirrus -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
-msg timestamp=on
9
Message-id: 20190506142741.41731-3-vsementsov@virtuozzo.com
10
'json:{"driver":"vxhs","vdisk-id":"c3e9095a-a5ee-4dce-afeb-2a59fb387410",
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
"server":{"host":"172.172.17.4","port":"9999"}}'
12
13
Sample command line using URI syntax:
14
qemu-img convert -f raw -O raw -n
15
/var/lib/nova/instances/_base/0c5eacd5ebea5ed914b6a3e7b18f1ce734c386ad
16
vxhs://192.168.0.1:9999/c6718f6b-0401-441d-a8c3-1f0064d75ee0
17
18
Sample command line using TLS credentials (run in secure mode):
19
./qemu-io --object
20
tls-creds-x509,id=tls0,dir=/etc/pki/qemu/vxhs,endpoint=client -c 'read
21
-v 66000 2.5k' 'json:{"server.host": "127.0.0.1", "server.port": "9999",
22
"vdisk-id": "/test.raw", "driver": "vxhs", "tls-creds":"tls0"}'
23
24
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
25
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
26
Reviewed-by: Jeff Cody <jcody@redhat.com>
27
Signed-off-by: Jeff Cody <jcody@redhat.com>
28
Message-id: 1491277689-24949-2-git-send-email-Ashish.Mittal@veritas.com
29
---
11
---
30
block/Makefile.objs | 2 +
12
block/Makefile.objs | 2 +-
31
block/trace-events | 17 ++
13
block/qcow2.h | 7 ++
32
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
14
block/qcow2-threads.c | 201 ++++++++++++++++++++++++++++++++++++++++++
33
configure | 39 ++++
15
block/qcow2.c | 169 -----------------------------------
34
qapi/block-core.json | 23 ++-
16
4 files changed, 209 insertions(+), 170 deletions(-)
35
5 files changed, 654 insertions(+), 2 deletions(-)
17
create mode 100644 block/qcow2-threads.c
36
create mode 100644 block/vxhs.c
37
18
38
diff --git a/block/Makefile.objs b/block/Makefile.objs
19
diff --git a/block/Makefile.objs b/block/Makefile.objs
39
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
40
--- a/block/Makefile.objs
21
--- a/block/Makefile.objs
41
+++ b/block/Makefile.objs
22
+++ b/block/Makefile.objs
42
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
23
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_BOCHS) += bochs.o
43
block-obj-$(CONFIG_CURL) += curl.o
24
block-obj-$(CONFIG_VVFAT) += vvfat.o
44
block-obj-$(CONFIG_RBD) += rbd.o
25
block-obj-$(CONFIG_DMG) += dmg.o
45
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
26
46
+block-obj-$(CONFIG_VXHS) += vxhs.o
27
-block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
47
block-obj-$(CONFIG_LIBSSH2) += ssh.o
28
+block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o qcow2-threads.o
48
block-obj-y += accounting.o dirty-bitmap.o
29
block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
49
block-obj-y += write-threshold.o
30
block-obj-$(CONFIG_QED) += qed-check.o
50
@@ -XXX,XX +XXX,XX @@ rbd.o-cflags := $(RBD_CFLAGS)
31
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
51
rbd.o-libs := $(RBD_LIBS)
32
diff --git a/block/qcow2.h b/block/qcow2.h
52
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
53
gluster.o-libs := $(GLUSTERFS_LIBS)
54
+vxhs.o-libs := $(VXHS_LIBS)
55
ssh.o-cflags := $(LIBSSH2_CFLAGS)
56
ssh.o-libs := $(LIBSSH2_LIBS)
57
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
58
diff --git a/block/trace-events b/block/trace-events
59
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
60
--- a/block/trace-events
34
--- a/block/qcow2.h
61
+++ b/block/trace-events
35
+++ b/block/qcow2.h
62
@@ -XXX,XX +XXX,XX @@ qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s
36
@@ -XXX,XX +XXX,XX @@ void qcow2_remove_persistent_dirty_bitmap(BlockDriverState *bs,
63
qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
37
const char *name,
64
qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
38
Error **errp);
65
qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
39
66
+
40
+ssize_t coroutine_fn
67
+# block/vxhs.c
41
+qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
68
+vxhs_iio_callback(int error) "ctx is NULL: error %d"
42
+ const void *src, size_t src_size);
69
+vxhs_iio_callback_chnfail(int err, int error) "QNIO channel failed, no i/o %d, %d"
43
+ssize_t coroutine_fn
70
+vxhs_iio_callback_unknwn(int opcode, int err) "unexpected opcode %d, errno %d"
44
+qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
71
+vxhs_aio_rw_invalid(int req) "Invalid I/O request iodir %d"
45
+ const void *src, size_t src_size);
72
+vxhs_aio_rw_ioerr(char *guid, int iodir, uint64_t size, uint64_t off, void *acb, int ret, int err) "IO ERROR (vDisk %s) FOR : Read/Write = %d size = %lu offset = %lu ACB = %p. Error = %d, errno = %d"
46
+
73
+vxhs_get_vdisk_stat_err(char *guid, int ret, int err) "vDisk (%s) stat ioctl failed, ret = %d, errno = %d"
47
#endif
74
+vxhs_get_vdisk_stat(char *vdisk_guid, uint64_t vdisk_size) "vDisk %s stat ioctl returned size %lu"
48
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
75
+vxhs_complete_aio(void *acb, uint64_t ret) "aio failed acb %p ret %ld"
76
+vxhs_parse_uri_filename(const char *filename) "URI passed via bdrv_parse_filename %s"
77
+vxhs_open_vdiskid(const char *vdisk_id) "Opening vdisk-id %s"
78
+vxhs_open_hostinfo(char *of_vsa_addr, int port) "Adding host %s:%d to BDRVVXHSState"
79
+vxhs_open_iio_open(const char *host) "Failed to connect to storage agent on host %s"
80
+vxhs_parse_uri_hostinfo(char *host, int port) "Host: IP %s, Port %d"
81
+vxhs_close(char *vdisk_guid) "Closing vdisk %s"
82
+vxhs_get_creds(const char *cacert, const char *client_key, const char *client_cert) "cacert %s, client_key %s, client_cert %s"
83
diff --git a/block/vxhs.c b/block/vxhs.c
84
new file mode 100644
49
new file mode 100644
85
index XXXXXXX..XXXXXXX
50
index XXXXXXX..XXXXXXX
86
--- /dev/null
51
--- /dev/null
87
+++ b/block/vxhs.c
52
+++ b/block/qcow2-threads.c
88
@@ -XXX,XX +XXX,XX @@
53
@@ -XXX,XX +XXX,XX @@
89
+/*
54
+/*
90
+ * QEMU Block driver for Veritas HyperScale (VxHS)
55
+ * Threaded data processing for Qcow2: compression, encryption
91
+ *
56
+ *
92
+ * Copyright (c) 2017 Veritas Technologies LLC.
57
+ * Copyright (c) 2004-2006 Fabrice Bellard
93
+ *
58
+ * Copyright (c) 2018 Virtuozzo International GmbH. All rights reserved.
94
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
59
+ *
95
+ * See the COPYING file in the top-level directory.
60
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
96
+ *
61
+ * of this software and associated documentation files (the "Software"), to deal
62
+ * in the Software without restriction, including without limitation the rights
63
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
64
+ * copies of the Software, and to permit persons to whom the Software is
65
+ * furnished to do so, subject to the following conditions:
66
+ *
67
+ * The above copyright notice and this permission notice shall be included in
68
+ * all copies or substantial portions of the Software.
69
+ *
70
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
71
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
72
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
73
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
74
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
75
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
76
+ * THE SOFTWARE.
97
+ */
77
+ */
98
+
78
+
99
+#include "qemu/osdep.h"
79
+#include "qemu/osdep.h"
100
+#include <qnio/qnio_api.h>
80
+
101
+#include <sys/param.h>
81
+#define ZLIB_CONST
102
+#include "block/block_int.h"
82
+#include <zlib.h>
103
+#include "qapi/qmp/qerror.h"
83
+
104
+#include "qapi/qmp/qdict.h"
84
+#include "qcow2.h"
105
+#include "qapi/qmp/qstring.h"
85
+#include "block/thread-pool.h"
106
+#include "trace.h"
86
+
107
+#include "qemu/uri.h"
87
+#define MAX_COMPRESS_THREADS 4
108
+#include "qapi/error.h"
88
+
109
+#include "qemu/uuid.h"
89
+typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
110
+#include "crypto/tlscredsx509.h"
90
+ const void *src, size_t src_size);
111
+
91
+typedef struct Qcow2CompressData {
112
+#define VXHS_OPT_FILENAME "filename"
92
+ void *dest;
113
+#define VXHS_OPT_VDISK_ID "vdisk-id"
93
+ size_t dest_size;
114
+#define VXHS_OPT_SERVER "server"
94
+ const void *src;
115
+#define VXHS_OPT_HOST "host"
95
+ size_t src_size;
116
+#define VXHS_OPT_PORT "port"
96
+ ssize_t ret;
117
+
97
+
118
+/* Only accessed under QEMU global mutex */
98
+ Qcow2CompressFunc func;
119
+static uint32_t vxhs_ref;
99
+} Qcow2CompressData;
120
+
121
+typedef enum {
122
+ VDISK_AIO_READ,
123
+ VDISK_AIO_WRITE,
124
+} VDISKAIOCmd;
125
+
100
+
126
+/*
101
+/*
127
+ * HyperScale AIO callbacks structure
102
+ * qcow2_compress()
103
+ *
104
+ * @dest - destination buffer, @dest_size bytes
105
+ * @src - source buffer, @src_size bytes
106
+ *
107
+ * Returns: compressed size on success
108
+ * -ENOMEM destination buffer is not enough to store compressed data
109
+ * -EIO on any other error
128
+ */
110
+ */
129
+typedef struct VXHSAIOCB {
111
+static ssize_t qcow2_compress(void *dest, size_t dest_size,
130
+ BlockAIOCB common;
112
+ const void *src, size_t src_size)
131
+ int err;
113
+{
132
+} VXHSAIOCB;
114
+ ssize_t ret;
133
+
115
+ z_stream strm;
134
+typedef struct VXHSvDiskHostsInfo {
116
+
135
+ void *dev_handle; /* Device handle */
117
+ /* best compression, small window, no zlib header */
136
+ char *host; /* Host name or IP */
118
+ memset(&strm, 0, sizeof(strm));
137
+ int port; /* Host's port number */
119
+ ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
138
+} VXHSvDiskHostsInfo;
120
+ -12, 9, Z_DEFAULT_STRATEGY);
121
+ if (ret != Z_OK) {
122
+ return -EIO;
123
+ }
124
+
125
+ /*
126
+ * strm.next_in is not const in old zlib versions, such as those used on
127
+ * OpenBSD/NetBSD, so cast the const away
128
+ */
129
+ strm.avail_in = src_size;
130
+ strm.next_in = (void *) src;
131
+ strm.avail_out = dest_size;
132
+ strm.next_out = dest;
133
+
134
+ ret = deflate(&strm, Z_FINISH);
135
+ if (ret == Z_STREAM_END) {
136
+ ret = dest_size - strm.avail_out;
137
+ } else {
138
+ ret = (ret == Z_OK ? -ENOMEM : -EIO);
139
+ }
140
+
141
+ deflateEnd(&strm);
142
+
143
+ return ret;
144
+}
139
+
145
+
140
+/*
146
+/*
141
+ * Structure per vDisk maintained for state
147
+ * qcow2_decompress()
148
+ *
149
+ * Decompress some data (not more than @src_size bytes) to produce exactly
150
+ * @dest_size bytes.
151
+ *
152
+ * @dest - destination buffer, @dest_size bytes
153
+ * @src - source buffer, @src_size bytes
154
+ *
155
+ * Returns: 0 on success
156
+ * -1 on fail
142
+ */
157
+ */
143
+typedef struct BDRVVXHSState {
158
+static ssize_t qcow2_decompress(void *dest, size_t dest_size,
144
+ VXHSvDiskHostsInfo vdisk_hostinfo; /* Per host info */
159
+ const void *src, size_t src_size)
145
+ char *vdisk_guid;
160
+{
146
+ char *tlscredsid; /* tlscredsid */
147
+} BDRVVXHSState;
148
+
149
+static void vxhs_complete_aio_bh(void *opaque)
150
+{
151
+ VXHSAIOCB *acb = opaque;
152
+ BlockCompletionFunc *cb = acb->common.cb;
153
+ void *cb_opaque = acb->common.opaque;
154
+ int ret = 0;
161
+ int ret = 0;
155
+
162
+ z_stream strm;
156
+ if (acb->err != 0) {
163
+
157
+ trace_vxhs_complete_aio(acb, acb->err);
164
+ memset(&strm, 0, sizeof(strm));
158
+ ret = (-EIO);
165
+ strm.avail_in = src_size;
159
+ }
166
+ strm.next_in = (void *) src;
160
+
167
+ strm.avail_out = dest_size;
161
+ qemu_aio_unref(acb);
168
+ strm.next_out = dest;
162
+ cb(cb_opaque, ret);
169
+
163
+}
170
+ ret = inflateInit2(&strm, -12);
164
+
171
+ if (ret != Z_OK) {
165
+/*
172
+ return -1;
166
+ * Called from a libqnio thread
173
+ }
167
+ */
174
+
168
+static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error)
175
+ ret = inflate(&strm, Z_FINISH);
169
+{
176
+ if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
170
+ VXHSAIOCB *acb = NULL;
171
+
172
+ switch (opcode) {
173
+ case IRP_READ_REQUEST:
174
+ case IRP_WRITE_REQUEST:
175
+
176
+ /*
177
+ /*
177
+ * ctx is VXHSAIOCB*
178
+ * We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
178
+ * ctx is NULL if error is QNIOERROR_CHANNEL_HUP
179
+ * @src buffer may be processed partly (because in qcow2 we know size of
180
+ * compressed data with precision of one sector)
179
+ */
181
+ */
180
+ if (ctx) {
182
+ ret = -1;
181
+ acb = ctx;
183
+ }
182
+ } else {
184
+
183
+ trace_vxhs_iio_callback(error);
185
+ inflateEnd(&strm);
184
+ goto out;
186
+
185
+ }
187
+ return ret;
186
+
188
+}
187
+ if (error) {
189
+
188
+ if (!acb->err) {
190
+static int qcow2_compress_pool_func(void *opaque)
189
+ acb->err = error;
191
+{
190
+ }
192
+ Qcow2CompressData *data = opaque;
191
+ trace_vxhs_iio_callback(error);
193
+
192
+ }
194
+ data->ret = data->func(data->dest, data->dest_size,
193
+
195
+ data->src, data->src_size);
194
+ aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
196
+
195
+ vxhs_complete_aio_bh, acb);
197
+ return 0;
196
+ break;
198
+}
197
+
199
+
198
+ default:
200
+static void qcow2_compress_complete(void *opaque, int ret)
199
+ if (error == QNIOERROR_HUP) {
201
+{
200
+ /*
202
+ qemu_coroutine_enter(opaque);
201
+ * Channel failed, spontaneous notification,
203
+}
202
+ * not in response to I/O
204
+
203
+ */
205
+static ssize_t coroutine_fn
204
+ trace_vxhs_iio_callback_chnfail(error, errno);
206
+qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
205
+ } else {
207
+ const void *src, size_t src_size, Qcow2CompressFunc func)
206
+ trace_vxhs_iio_callback_unknwn(opcode, error);
208
+{
207
+ }
209
+ BDRVQcow2State *s = bs->opaque;
208
+ break;
210
+ BlockAIOCB *acb;
209
+ }
211
+ ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
210
+out:
212
+ Qcow2CompressData arg = {
211
+ return;
213
+ .dest = dest,
212
+}
214
+ .dest_size = dest_size,
213
+
215
+ .src = src,
214
+static QemuOptsList runtime_opts = {
216
+ .src_size = src_size,
215
+ .name = "vxhs",
217
+ .func = func,
216
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
218
+ };
217
+ .desc = {
219
+
218
+ {
220
+ while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) {
219
+ .name = VXHS_OPT_FILENAME,
221
+ qemu_co_queue_wait(&s->compress_wait_queue, NULL);
220
+ .type = QEMU_OPT_STRING,
222
+ }
221
+ .help = "URI to the Veritas HyperScale image",
223
+
222
+ },
224
+ s->nb_compress_threads++;
223
+ {
225
+ acb = thread_pool_submit_aio(pool, qcow2_compress_pool_func, &arg,
224
+ .name = VXHS_OPT_VDISK_ID,
226
+ qcow2_compress_complete,
225
+ .type = QEMU_OPT_STRING,
227
+ qemu_coroutine_self());
226
+ .help = "UUID of the VxHS vdisk",
228
+
227
+ },
229
+ if (!acb) {
228
+ {
230
+ s->nb_compress_threads--;
229
+ .name = "tls-creds",
230
+ .type = QEMU_OPT_STRING,
231
+ .help = "ID of the TLS/SSL credentials to use",
232
+ },
233
+ { /* end of list */ }
234
+ },
235
+};
236
+
237
+static QemuOptsList runtime_tcp_opts = {
238
+ .name = "vxhs_tcp",
239
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head),
240
+ .desc = {
241
+ {
242
+ .name = VXHS_OPT_HOST,
243
+ .type = QEMU_OPT_STRING,
244
+ .help = "host address (ipv4 addresses)",
245
+ },
246
+ {
247
+ .name = VXHS_OPT_PORT,
248
+ .type = QEMU_OPT_NUMBER,
249
+ .help = "port number on which VxHSD is listening (default 9999)",
250
+ .def_value_str = "9999"
251
+ },
252
+ { /* end of list */ }
253
+ },
254
+};
255
+
256
+/*
257
+ * Parse incoming URI and populate *options with the host
258
+ * and device information
259
+ */
260
+static int vxhs_parse_uri(const char *filename, QDict *options)
261
+{
262
+ URI *uri = NULL;
263
+ char *port;
264
+ int ret = 0;
265
+
266
+ trace_vxhs_parse_uri_filename(filename);
267
+ uri = uri_parse(filename);
268
+ if (!uri || !uri->server || !uri->path) {
269
+ uri_free(uri);
270
+ return -EINVAL;
231
+ return -EINVAL;
271
+ }
232
+ }
272
+
233
+ qemu_coroutine_yield();
273
+ qdict_put(options, VXHS_OPT_SERVER".host", qstring_from_str(uri->server));
234
+ s->nb_compress_threads--;
274
+
235
+ qemu_co_queue_next(&s->compress_wait_queue);
275
+ if (uri->port) {
236
+
276
+ port = g_strdup_printf("%d", uri->port);
237
+ return arg.ret;
277
+ qdict_put(options, VXHS_OPT_SERVER".port", qstring_from_str(port));
238
+}
278
+ g_free(port);
239
+
279
+ }
240
+ssize_t coroutine_fn
280
+
241
+qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
281
+ qdict_put(options, "vdisk-id", qstring_from_str(uri->path));
242
+ const void *src, size_t src_size)
282
+
243
+{
283
+ trace_vxhs_parse_uri_hostinfo(uri->server, uri->port);
244
+ return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
284
+ uri_free(uri);
245
+ qcow2_compress);
285
+
246
+}
286
+ return ret;
247
+
287
+}
248
+ssize_t coroutine_fn
288
+
249
+qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
289
+static void vxhs_parse_filename(const char *filename, QDict *options,
250
+ const void *src, size_t src_size)
290
+ Error **errp)
251
+{
291
+{
252
+ return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
292
+ if (qdict_haskey(options, "vdisk-id") || qdict_haskey(options, "server")) {
253
+ qcow2_decompress);
293
+ error_setg(errp, "vdisk-id/server and a file name may not be specified "
254
+}
294
+ "at the same time");
255
diff --git a/block/qcow2.c b/block/qcow2.c
295
+ return;
296
+ }
297
+
298
+ if (strstr(filename, "://")) {
299
+ int ret = vxhs_parse_uri(filename, options);
300
+ if (ret < 0) {
301
+ error_setg(errp, "Invalid URI. URI should be of the form "
302
+ " vxhs://<host_ip>:<port>/<vdisk-id>");
303
+ }
304
+ }
305
+}
306
+
307
+static int vxhs_init_and_ref(void)
308
+{
309
+ if (vxhs_ref++ == 0) {
310
+ if (iio_init(QNIO_VERSION, vxhs_iio_callback)) {
311
+ return -ENODEV;
312
+ }
313
+ }
314
+ return 0;
315
+}
316
+
317
+static void vxhs_unref(void)
318
+{
319
+ if (--vxhs_ref == 0) {
320
+ iio_fini();
321
+ }
322
+}
323
+
324
+static void vxhs_get_tls_creds(const char *id, char **cacert,
325
+ char **key, char **cert, Error **errp)
326
+{
327
+ Object *obj;
328
+ QCryptoTLSCreds *creds;
329
+ QCryptoTLSCredsX509 *creds_x509;
330
+
331
+ obj = object_resolve_path_component(
332
+ object_get_objects_root(), id);
333
+
334
+ if (!obj) {
335
+ error_setg(errp, "No TLS credentials with id '%s'",
336
+ id);
337
+ return;
338
+ }
339
+
340
+ creds_x509 = (QCryptoTLSCredsX509 *)
341
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS_X509);
342
+
343
+ if (!creds_x509) {
344
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
345
+ id);
346
+ return;
347
+ }
348
+
349
+ creds = &creds_x509->parent_obj;
350
+
351
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
352
+ error_setg(errp,
353
+ "Expecting TLS credentials with a client endpoint");
354
+ return;
355
+ }
356
+
357
+ /*
358
+ * Get the cacert, client_cert and client_key file names.
359
+ */
360
+ if (!creds->dir) {
361
+ error_setg(errp, "TLS object missing 'dir' property value");
362
+ return;
363
+ }
364
+
365
+ *cacert = g_strdup_printf("%s/%s", creds->dir,
366
+ QCRYPTO_TLS_CREDS_X509_CA_CERT);
367
+ *cert = g_strdup_printf("%s/%s", creds->dir,
368
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
369
+ *key = g_strdup_printf("%s/%s", creds->dir,
370
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
371
+}
372
+
373
+static int vxhs_open(BlockDriverState *bs, QDict *options,
374
+ int bdrv_flags, Error **errp)
375
+{
376
+ BDRVVXHSState *s = bs->opaque;
377
+ void *dev_handlep;
378
+ QDict *backing_options = NULL;
379
+ QemuOpts *opts = NULL;
380
+ QemuOpts *tcp_opts = NULL;
381
+ char *of_vsa_addr = NULL;
382
+ Error *local_err = NULL;
383
+ const char *vdisk_id_opt;
384
+ const char *server_host_opt;
385
+ int ret = 0;
386
+ char *cacert = NULL;
387
+ char *client_key = NULL;
388
+ char *client_cert = NULL;
389
+
390
+ ret = vxhs_init_and_ref();
391
+ if (ret < 0) {
392
+ ret = -EINVAL;
393
+ goto out;
394
+ }
395
+
396
+ /* Create opts info from runtime_opts and runtime_tcp_opts list */
397
+ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
398
+ tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort);
399
+
400
+ qemu_opts_absorb_qdict(opts, options, &local_err);
401
+ if (local_err) {
402
+ ret = -EINVAL;
403
+ goto out;
404
+ }
405
+
406
+ /* vdisk-id is the disk UUID */
407
+ vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID);
408
+ if (!vdisk_id_opt) {
409
+ error_setg(&local_err, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID);
410
+ ret = -EINVAL;
411
+ goto out;
412
+ }
413
+
414
+ /* vdisk-id may contain a leading '/' */
415
+ if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) {
416
+ error_setg(&local_err, "vdisk-id cannot be more than %d characters",
417
+ UUID_FMT_LEN);
418
+ ret = -EINVAL;
419
+ goto out;
420
+ }
421
+
422
+ s->vdisk_guid = g_strdup(vdisk_id_opt);
423
+ trace_vxhs_open_vdiskid(vdisk_id_opt);
424
+
425
+ /* get the 'server.' arguments */
426
+ qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER".");
427
+
428
+ qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err);
429
+ if (local_err != NULL) {
430
+ ret = -EINVAL;
431
+ goto out;
432
+ }
433
+
434
+ server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST);
435
+ if (!server_host_opt) {
436
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
437
+ VXHS_OPT_SERVER"."VXHS_OPT_HOST);
438
+ ret = -EINVAL;
439
+ goto out;
440
+ }
441
+
442
+ if (strlen(server_host_opt) > MAXHOSTNAMELEN) {
443
+ error_setg(&local_err, "server.host cannot be more than %d characters",
444
+ MAXHOSTNAMELEN);
445
+ ret = -EINVAL;
446
+ goto out;
447
+ }
448
+
449
+ /* check if we got tls-creds via the --object argument */
450
+ s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds"));
451
+ if (s->tlscredsid) {
452
+ vxhs_get_tls_creds(s->tlscredsid, &cacert, &client_key,
453
+ &client_cert, &local_err);
454
+ if (local_err != NULL) {
455
+ ret = -EINVAL;
456
+ goto out;
457
+ }
458
+ trace_vxhs_get_creds(cacert, client_key, client_cert);
459
+ }
460
+
461
+ s->vdisk_hostinfo.host = g_strdup(server_host_opt);
462
+ s->vdisk_hostinfo.port = g_ascii_strtoll(qemu_opt_get(tcp_opts,
463
+ VXHS_OPT_PORT),
464
+ NULL, 0);
465
+
466
+ trace_vxhs_open_hostinfo(s->vdisk_hostinfo.host,
467
+ s->vdisk_hostinfo.port);
468
+
469
+ of_vsa_addr = g_strdup_printf("of://%s:%d",
470
+ s->vdisk_hostinfo.host,
471
+ s->vdisk_hostinfo.port);
472
+
473
+ /*
474
+ * Open qnio channel to storage agent if not opened before
475
+ */
476
+ dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0,
477
+ cacert, client_key, client_cert);
478
+ if (dev_handlep == NULL) {
479
+ trace_vxhs_open_iio_open(of_vsa_addr);
480
+ ret = -ENODEV;
481
+ goto out;
482
+ }
483
+ s->vdisk_hostinfo.dev_handle = dev_handlep;
484
+
485
+out:
486
+ g_free(of_vsa_addr);
487
+ QDECREF(backing_options);
488
+ qemu_opts_del(tcp_opts);
489
+ qemu_opts_del(opts);
490
+ g_free(cacert);
491
+ g_free(client_key);
492
+ g_free(client_cert);
493
+
494
+ if (ret < 0) {
495
+ vxhs_unref();
496
+ error_propagate(errp, local_err);
497
+ g_free(s->vdisk_hostinfo.host);
498
+ g_free(s->vdisk_guid);
499
+ g_free(s->tlscredsid);
500
+ s->vdisk_guid = NULL;
501
+ }
502
+
503
+ return ret;
504
+}
505
+
506
+static const AIOCBInfo vxhs_aiocb_info = {
507
+ .aiocb_size = sizeof(VXHSAIOCB)
508
+};
509
+
510
+/*
511
+ * This allocates QEMU-VXHS callback for each IO
512
+ * and is passed to QNIO. When QNIO completes the work,
513
+ * it will be passed back through the callback.
514
+ */
515
+static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
516
+ QEMUIOVector *qiov, int nb_sectors,
517
+ BlockCompletionFunc *cb, void *opaque,
518
+ VDISKAIOCmd iodir)
519
+{
520
+ VXHSAIOCB *acb = NULL;
521
+ BDRVVXHSState *s = bs->opaque;
522
+ size_t size;
523
+ uint64_t offset;
524
+ int iio_flags = 0;
525
+ int ret = 0;
526
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
527
+
528
+ offset = sector_num * BDRV_SECTOR_SIZE;
529
+ size = nb_sectors * BDRV_SECTOR_SIZE;
530
+ acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque);
531
+
532
+ /*
533
+ * Initialize VXHSAIOCB.
534
+ */
535
+ acb->err = 0;
536
+
537
+ iio_flags = IIO_FLAG_ASYNC;
538
+
539
+ switch (iodir) {
540
+ case VDISK_AIO_WRITE:
541
+ ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov,
542
+ offset, (uint64_t)size, iio_flags);
543
+ break;
544
+ case VDISK_AIO_READ:
545
+ ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov,
546
+ offset, (uint64_t)size, iio_flags);
547
+ break;
548
+ default:
549
+ trace_vxhs_aio_rw_invalid(iodir);
550
+ goto errout;
551
+ }
552
+
553
+ if (ret != 0) {
554
+ trace_vxhs_aio_rw_ioerr(s->vdisk_guid, iodir, size, offset,
555
+ acb, ret, errno);
556
+ goto errout;
557
+ }
558
+ return &acb->common;
559
+
560
+errout:
561
+ qemu_aio_unref(acb);
562
+ return NULL;
563
+}
564
+
565
+static BlockAIOCB *vxhs_aio_readv(BlockDriverState *bs,
566
+ int64_t sector_num, QEMUIOVector *qiov,
567
+ int nb_sectors,
568
+ BlockCompletionFunc *cb, void *opaque)
569
+{
570
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
571
+ opaque, VDISK_AIO_READ);
572
+}
573
+
574
+static BlockAIOCB *vxhs_aio_writev(BlockDriverState *bs,
575
+ int64_t sector_num, QEMUIOVector *qiov,
576
+ int nb_sectors,
577
+ BlockCompletionFunc *cb, void *opaque)
578
+{
579
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors,
580
+ cb, opaque, VDISK_AIO_WRITE);
581
+}
582
+
583
+static void vxhs_close(BlockDriverState *bs)
584
+{
585
+ BDRVVXHSState *s = bs->opaque;
586
+
587
+ trace_vxhs_close(s->vdisk_guid);
588
+
589
+ g_free(s->vdisk_guid);
590
+ s->vdisk_guid = NULL;
591
+
592
+ /*
593
+ * Close vDisk device
594
+ */
595
+ if (s->vdisk_hostinfo.dev_handle) {
596
+ iio_close(s->vdisk_hostinfo.dev_handle);
597
+ s->vdisk_hostinfo.dev_handle = NULL;
598
+ }
599
+
600
+ vxhs_unref();
601
+
602
+ /*
603
+ * Free the dynamically allocated host string etc
604
+ */
605
+ g_free(s->vdisk_hostinfo.host);
606
+ g_free(s->tlscredsid);
607
+ s->tlscredsid = NULL;
608
+ s->vdisk_hostinfo.host = NULL;
609
+ s->vdisk_hostinfo.port = 0;
610
+}
611
+
612
+static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s)
613
+{
614
+ int64_t vdisk_size = -1;
615
+ int ret = 0;
616
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
617
+
618
+ ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0);
619
+ if (ret < 0) {
620
+ trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno);
621
+ return -EIO;
622
+ }
623
+
624
+ trace_vxhs_get_vdisk_stat(s->vdisk_guid, vdisk_size);
625
+ return vdisk_size;
626
+}
627
+
628
+/*
629
+ * Returns the size of vDisk in bytes. This is required
630
+ * by QEMU block upper block layer so that it is visible
631
+ * to guest.
632
+ */
633
+static int64_t vxhs_getlength(BlockDriverState *bs)
634
+{
635
+ BDRVVXHSState *s = bs->opaque;
636
+ int64_t vdisk_size;
637
+
638
+ vdisk_size = vxhs_get_vdisk_stat(s);
639
+ if (vdisk_size < 0) {
640
+ return -EIO;
641
+ }
642
+
643
+ return vdisk_size;
644
+}
645
+
646
+static BlockDriver bdrv_vxhs = {
647
+ .format_name = "vxhs",
648
+ .protocol_name = "vxhs",
649
+ .instance_size = sizeof(BDRVVXHSState),
650
+ .bdrv_file_open = vxhs_open,
651
+ .bdrv_parse_filename = vxhs_parse_filename,
652
+ .bdrv_close = vxhs_close,
653
+ .bdrv_getlength = vxhs_getlength,
654
+ .bdrv_aio_readv = vxhs_aio_readv,
655
+ .bdrv_aio_writev = vxhs_aio_writev,
656
+};
657
+
658
+static void bdrv_vxhs_init(void)
659
+{
660
+ bdrv_register(&bdrv_vxhs);
661
+}
662
+
663
+block_init(bdrv_vxhs_init);
664
diff --git a/configure b/configure
665
index XXXXXXX..XXXXXXX 100755
666
--- a/configure
667
+++ b/configure
668
@@ -XXX,XX +XXX,XX @@ numa=""
669
tcmalloc="no"
670
jemalloc="no"
671
replication="yes"
672
+vxhs=""
673
674
supported_cpu="no"
675
supported_os="no"
676
@@ -XXX,XX +XXX,XX @@ for opt do
677
;;
678
--enable-replication) replication="yes"
679
;;
680
+ --disable-vxhs) vxhs="no"
681
+ ;;
682
+ --enable-vxhs) vxhs="yes"
683
+ ;;
684
*)
685
echo "ERROR: unknown option $opt"
686
echo "Try '$0 --help' for more information"
687
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
688
xfsctl xfsctl support
689
qom-cast-debug cast debugging support
690
tools build qemu-io, qemu-nbd and qemu-image tools
691
+ vxhs Veritas HyperScale vDisk backend support
692
693
NOTE: The object files are built at the place where configure is launched
694
EOF
695
@@ -XXX,XX +XXX,XX @@ if compile_prog "" "" ; then
696
fi
697
698
##########################################
699
+# Veritas HyperScale block driver VxHS
700
+# Check if libvxhs is installed
701
+
702
+if test "$vxhs" != "no" ; then
703
+ cat > $TMPC <<EOF
704
+#include <stdint.h>
705
+#include <qnio/qnio_api.h>
706
+
707
+void *vxhs_callback;
708
+
709
+int main(void) {
710
+ iio_init(QNIO_VERSION, vxhs_callback);
711
+ return 0;
712
+}
713
+EOF
714
+ vxhs_libs="-lvxhs -lssl"
715
+ if compile_prog "" "$vxhs_libs" ; then
716
+ vxhs=yes
717
+ else
718
+ if test "$vxhs" = "yes" ; then
719
+ feature_not_found "vxhs block device" "Install libvxhs See github"
720
+ fi
721
+ vxhs=no
722
+ fi
723
+fi
724
+
725
+##########################################
726
# End of CC checks
727
# After here, no more $cc or $ld runs
728
729
@@ -XXX,XX +XXX,XX @@ echo "tcmalloc support $tcmalloc"
730
echo "jemalloc support $jemalloc"
731
echo "avx2 optimization $avx2_opt"
732
echo "replication support $replication"
733
+echo "VxHS block device $vxhs"
734
735
if test "$sdl_too_old" = "yes"; then
736
echo "-> Your SDL version is too old - please upgrade to have SDL support"
737
@@ -XXX,XX +XXX,XX @@ if test "$pthread_setname_np" = "yes" ; then
738
echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
739
fi
740
741
+if test "$vxhs" = "yes" ; then
742
+ echo "CONFIG_VXHS=y" >> $config_host_mak
743
+ echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak
744
+fi
745
+
746
if test "$tcg_interpreter" = "yes"; then
747
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
748
elif test "$ARCH" = "sparc64" ; then
749
diff --git a/qapi/block-core.json b/qapi/block-core.json
750
index XXXXXXX..XXXXXXX 100644
256
index XXXXXXX..XXXXXXX 100644
751
--- a/qapi/block-core.json
257
--- a/block/qcow2.c
752
+++ b/qapi/block-core.json
258
+++ b/block/qcow2.c
753
@@ -XXX,XX +XXX,XX @@
259
@@ -XXX,XX +XXX,XX @@
754
#
260
755
# Drivers that are supported in block device operations.
261
#include "qemu/osdep.h"
756
#
262
757
+# @vxhs: Since 2.10
263
-#define ZLIB_CONST
758
+#
264
-#include <zlib.h>
759
# Since: 2.9
265
-
760
##
266
#include "block/qdict.h"
761
{ 'enum': 'BlockdevDriver',
267
#include "sysemu/block-backend.h"
268
#include "qemu/module.h"
762
@@ -XXX,XX +XXX,XX @@
269
@@ -XXX,XX +XXX,XX @@
763
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
270
#include "qapi/qobject-input-visitor.h"
764
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
271
#include "qapi/qapi-visit-block-core.h"
765
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
272
#include "crypto.h"
766
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
273
-#include "block/thread-pool.h"
767
+ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
274
768
275
/*
769
##
276
Differences with QCOW:
770
# @BlockdevOptionsFile:
277
@@ -XXX,XX +XXX,XX @@ fail:
771
@@ -XXX,XX +XXX,XX @@
278
return ret;
772
'data': { '*offset': 'int', '*size': 'int' } }
279
}
773
280
774
##
281
-/*
775
+# @BlockdevOptionsVxHS:
282
- * qcow2_compress()
776
+#
283
- *
777
+# Driver specific block device options for VxHS
284
- * @dest - destination buffer, @dest_size bytes
778
+#
285
- * @src - source buffer, @src_size bytes
779
+# @vdisk-id: UUID of VxHS volume
286
- *
780
+# @server: vxhs server IP, port
287
- * Returns: compressed size on success
781
+# @tls-creds: TLS credentials ID
288
- * -ENOMEM destination buffer is not enough to store compressed data
782
+#
289
- * -EIO on any other error
783
+# Since: 2.10
290
- */
784
+##
291
-static ssize_t qcow2_compress(void *dest, size_t dest_size,
785
+{ 'struct': 'BlockdevOptionsVxHS',
292
- const void *src, size_t src_size)
786
+ 'data': { 'vdisk-id': 'str',
293
-{
787
+ 'server': 'InetSocketAddressBase',
294
- ssize_t ret;
788
+ '*tls-creds': 'str' } }
295
- z_stream strm;
789
+
296
-
790
+##
297
- /* best compression, small window, no zlib header */
791
# @BlockdevOptions:
298
- memset(&strm, 0, sizeof(strm));
792
#
299
- ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
793
# Options for creating a block device. Many options are available for all
300
- -12, 9, Z_DEFAULT_STRATEGY);
794
@@ -XXX,XX +XXX,XX @@
301
- if (ret != Z_OK) {
795
'vhdx': 'BlockdevOptionsGenericFormat',
302
- return -EIO;
796
'vmdk': 'BlockdevOptionsGenericCOWFormat',
303
- }
797
'vpc': 'BlockdevOptionsGenericFormat',
304
-
798
- 'vvfat': 'BlockdevOptionsVVFAT'
305
- /* strm.next_in is not const in old zlib versions, such as those used on
799
+ 'vvfat': 'BlockdevOptionsVVFAT',
306
- * OpenBSD/NetBSD, so cast the const away */
800
+ 'vxhs': 'BlockdevOptionsVxHS'
307
- strm.avail_in = src_size;
801
} }
308
- strm.next_in = (void *) src;
802
309
- strm.avail_out = dest_size;
803
##
310
- strm.next_out = dest;
311
-
312
- ret = deflate(&strm, Z_FINISH);
313
- if (ret == Z_STREAM_END) {
314
- ret = dest_size - strm.avail_out;
315
- } else {
316
- ret = (ret == Z_OK ? -ENOMEM : -EIO);
317
- }
318
-
319
- deflateEnd(&strm);
320
-
321
- return ret;
322
-}
323
-
324
-/*
325
- * qcow2_decompress()
326
- *
327
- * Decompress some data (not more than @src_size bytes) to produce exactly
328
- * @dest_size bytes.
329
- *
330
- * @dest - destination buffer, @dest_size bytes
331
- * @src - source buffer, @src_size bytes
332
- *
333
- * Returns: 0 on success
334
- * -1 on fail
335
- */
336
-static ssize_t qcow2_decompress(void *dest, size_t dest_size,
337
- const void *src, size_t src_size)
338
-{
339
- int ret = 0;
340
- z_stream strm;
341
-
342
- memset(&strm, 0, sizeof(strm));
343
- strm.avail_in = src_size;
344
- strm.next_in = (void *) src;
345
- strm.avail_out = dest_size;
346
- strm.next_out = dest;
347
-
348
- ret = inflateInit2(&strm, -12);
349
- if (ret != Z_OK) {
350
- return -1;
351
- }
352
-
353
- ret = inflate(&strm, Z_FINISH);
354
- if ((ret != Z_STREAM_END && ret != Z_BUF_ERROR) || strm.avail_out != 0) {
355
- /* We approve Z_BUF_ERROR because we need @dest buffer to be filled, but
356
- * @src buffer may be processed partly (because in qcow2 we know size of
357
- * compressed data with precision of one sector) */
358
- ret = -1;
359
- }
360
-
361
- inflateEnd(&strm);
362
-
363
- return ret;
364
-}
365
-
366
-#define MAX_COMPRESS_THREADS 4
367
-
368
-typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
369
- const void *src, size_t src_size);
370
-typedef struct Qcow2CompressData {
371
- void *dest;
372
- size_t dest_size;
373
- const void *src;
374
- size_t src_size;
375
- ssize_t ret;
376
-
377
- Qcow2CompressFunc func;
378
-} Qcow2CompressData;
379
-
380
-static int qcow2_compress_pool_func(void *opaque)
381
-{
382
- Qcow2CompressData *data = opaque;
383
-
384
- data->ret = data->func(data->dest, data->dest_size,
385
- data->src, data->src_size);
386
-
387
- return 0;
388
-}
389
-
390
-static void qcow2_compress_complete(void *opaque, int ret)
391
-{
392
- qemu_coroutine_enter(opaque);
393
-}
394
-
395
-static ssize_t coroutine_fn
396
-qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
397
- const void *src, size_t src_size, Qcow2CompressFunc func)
398
-{
399
- BDRVQcow2State *s = bs->opaque;
400
- BlockAIOCB *acb;
401
- ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
402
- Qcow2CompressData arg = {
403
- .dest = dest,
404
- .dest_size = dest_size,
405
- .src = src,
406
- .src_size = src_size,
407
- .func = func,
408
- };
409
-
410
- while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) {
411
- qemu_co_queue_wait(&s->compress_wait_queue, NULL);
412
- }
413
-
414
- s->nb_compress_threads++;
415
- acb = thread_pool_submit_aio(pool, qcow2_compress_pool_func, &arg,
416
- qcow2_compress_complete,
417
- qemu_coroutine_self());
418
-
419
- if (!acb) {
420
- s->nb_compress_threads--;
421
- return -EINVAL;
422
- }
423
- qemu_coroutine_yield();
424
- s->nb_compress_threads--;
425
- qemu_co_queue_next(&s->compress_wait_queue);
426
-
427
- return arg.ret;
428
-}
429
-
430
-static ssize_t coroutine_fn
431
-qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
432
- const void *src, size_t src_size)
433
-{
434
- return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
435
- qcow2_compress);
436
-}
437
-
438
-static ssize_t coroutine_fn
439
-qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
440
- const void *src, size_t src_size)
441
-{
442
- return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
443
- qcow2_decompress);
444
-}
445
-
446
/* XXX: put compressed sectors first, then all the cluster aligned
447
tables to avoid losing bytes in alignment */
448
static coroutine_fn int
804
--
449
--
805
2.9.3
450
2.21.0
806
451
807
452
diff view generated by jsdifflib
1
Move bdrv_is_read_only() up with its friends.
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
Use thread_pool_submit_co, instead of reinventing it here. Note, that
4
Reviewed-by: John Snow <jsnow@redhat.com>
4
thread_pool_submit_aio() never returns NULL, so checking it was an
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
5
extra thing.
6
Message-id: 73b2399459760c32506f9407efb9dddb3a2789de.1491597120.git.jcody@redhat.com
6
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Message-id: 20190506142741.41731-4-vsementsov@virtuozzo.com
11
Signed-off-by: Max Reitz <mreitz@redhat.com>
7
---
12
---
8
block.c | 10 +++++-----
13
block/qcow2-threads.c | 17 ++---------------
9
1 file changed, 5 insertions(+), 5 deletions(-)
14
1 file changed, 2 insertions(+), 15 deletions(-)
10
15
11
diff --git a/block.c b/block.c
16
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
12
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
18
--- a/block/qcow2-threads.c
14
+++ b/block.c
19
+++ b/block/qcow2-threads.c
15
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
20
@@ -XXX,XX +XXX,XX @@ static int qcow2_compress_pool_func(void *opaque)
16
}
21
return 0;
17
}
22
}
18
23
19
+bool bdrv_is_read_only(BlockDriverState *bs)
24
-static void qcow2_compress_complete(void *opaque, int ret)
20
+{
21
+ return bs->read_only;
22
+}
23
+
24
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
25
{
26
/* Do not set read_only if copy_on_read is enabled */
27
@@ -XXX,XX +XXX,XX @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
28
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
29
}
30
31
-bool bdrv_is_read_only(BlockDriverState *bs)
32
-{
25
-{
33
- return bs->read_only;
26
- qemu_coroutine_enter(opaque);
34
-}
27
-}
35
-
28
-
36
bool bdrv_is_sg(BlockDriverState *bs)
29
static ssize_t coroutine_fn
30
qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
31
const void *src, size_t src_size, Qcow2CompressFunc func)
37
{
32
{
38
return bs->sg;
33
BDRVQcow2State *s = bs->opaque;
34
- BlockAIOCB *acb;
35
ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
36
Qcow2CompressData arg = {
37
.dest = dest,
38
@@ -XXX,XX +XXX,XX @@ qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
39
}
40
41
s->nb_compress_threads++;
42
- acb = thread_pool_submit_aio(pool, qcow2_compress_pool_func, &arg,
43
- qcow2_compress_complete,
44
- qemu_coroutine_self());
45
-
46
- if (!acb) {
47
- s->nb_compress_threads--;
48
- return -EINVAL;
49
- }
50
- qemu_coroutine_yield();
51
+ thread_pool_submit_co(pool, qcow2_compress_pool_func, &arg);
52
s->nb_compress_threads--;
53
+
54
qemu_co_queue_next(&s->compress_wait_queue);
55
56
return arg.ret;
39
--
57
--
40
2.9.3
58
2.21.0
41
59
42
60
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Drop dependence on AioContext lock.
4
5
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190506142741.41731-5-vsementsov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2-threads.c | 10 +++++++---
13
1 file changed, 7 insertions(+), 3 deletions(-)
14
15
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2-threads.c
18
+++ b/block/qcow2-threads.c
19
@@ -XXX,XX +XXX,XX @@ qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
20
.func = func,
21
};
22
23
+ qemu_co_mutex_lock(&s->lock);
24
while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) {
25
- qemu_co_queue_wait(&s->compress_wait_queue, NULL);
26
+ qemu_co_queue_wait(&s->compress_wait_queue, &s->lock);
27
}
28
-
29
s->nb_compress_threads++;
30
+ qemu_co_mutex_unlock(&s->lock);
31
+
32
thread_pool_submit_co(pool, qcow2_compress_pool_func, &arg);
33
- s->nb_compress_threads--;
34
35
+ qemu_co_mutex_lock(&s->lock);
36
+ s->nb_compress_threads--;
37
qemu_co_queue_next(&s->compress_wait_queue);
38
+ qemu_co_mutex_unlock(&s->lock);
39
40
return arg.ret;
41
}
42
--
43
2.21.0
44
45
diff view generated by jsdifflib
1
The protocol VXHS does not support image creation. Some tests expect
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
to be able to create images through the protocol. Exclude VXHS from
3
these tests.
4
2
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
Move generic part out of qcow2_co_do_compress, to reuse it for
4
encryption and rename things that would be shared with encryption path.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190506142741.41731-6-vsementsov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
6
---
11
---
7
tests/qemu-iotests/017 | 1 +
12
block/qcow2.h | 4 ++--
8
tests/qemu-iotests/020 | 1 +
13
block/qcow2-threads.c | 47 ++++++++++++++++++++++++++++---------------
9
tests/qemu-iotests/029 | 1 +
14
block/qcow2.c | 2 +-
10
tests/qemu-iotests/073 | 1 +
15
3 files changed, 34 insertions(+), 19 deletions(-)
11
tests/qemu-iotests/114 | 1 +
12
tests/qemu-iotests/130 | 1 +
13
tests/qemu-iotests/134 | 1 +
14
tests/qemu-iotests/156 | 1 +
15
tests/qemu-iotests/158 | 1 +
16
9 files changed, 9 insertions(+)
17
16
18
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
17
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100755
18
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/017
19
--- a/block/qcow2.h
21
+++ b/tests/qemu-iotests/017
20
+++ b/block/qcow2.h
22
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
21
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVQcow2State {
23
# Any format supporting backing files
22
char *image_backing_format;
24
_supported_fmt qcow qcow2 vmdk qed
23
char *image_data_file;
25
_supported_proto generic
24
26
+_unsupported_proto vxhs
25
- CoQueue compress_wait_queue;
27
_supported_os Linux
26
- int nb_compress_threads;
28
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
27
+ CoQueue thread_task_queue;
29
28
+ int nb_threads;
30
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
29
31
index XXXXXXX..XXXXXXX 100755
30
BdrvChild *data_file;
32
--- a/tests/qemu-iotests/020
31
} BDRVQcow2State;
33
+++ b/tests/qemu-iotests/020
32
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
34
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
33
index XXXXXXX..XXXXXXX 100644
35
# Any format supporting backing files
34
--- a/block/qcow2-threads.c
36
_supported_fmt qcow qcow2 vmdk qed
35
+++ b/block/qcow2-threads.c
37
_supported_proto generic
36
@@ -XXX,XX +XXX,XX @@
38
+_unsupported_proto vxhs
37
#include "qcow2.h"
39
_supported_os Linux
38
#include "block/thread-pool.h"
40
_unsupported_imgopts "subformat=monolithicFlat" \
39
41
"subformat=twoGbMaxExtentFlat" \
40
-#define MAX_COMPRESS_THREADS 4
42
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
41
+#define QCOW2_MAX_THREADS 4
43
index XXXXXXX..XXXXXXX 100755
42
+
44
--- a/tests/qemu-iotests/029
43
+static int coroutine_fn
45
+++ b/tests/qemu-iotests/029
44
+qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
46
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
45
+{
47
# Any format supporting intenal snapshots
46
+ int ret;
48
_supported_fmt qcow2
47
+ BDRVQcow2State *s = bs->opaque;
49
_supported_proto generic
48
+ ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
50
+_unsupported_proto vxhs
49
+
51
_supported_os Linux
50
+ qemu_co_mutex_lock(&s->lock);
52
# Internal snapshots are (currently) impossible with refcount_bits=1
51
+ while (s->nb_threads >= QCOW2_MAX_THREADS) {
53
_unsupported_imgopts 'refcount_bits=1[^0-9]'
52
+ qemu_co_queue_wait(&s->thread_task_queue, &s->lock);
54
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
53
+ }
55
index XXXXXXX..XXXXXXX 100755
54
+ s->nb_threads++;
56
--- a/tests/qemu-iotests/073
55
+ qemu_co_mutex_unlock(&s->lock);
57
+++ b/tests/qemu-iotests/073
56
+
58
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
57
+ ret = thread_pool_submit_co(pool, func, arg);
59
58
+
60
_supported_fmt qcow2
59
+ qemu_co_mutex_lock(&s->lock);
61
_supported_proto generic
60
+ s->nb_threads--;
62
+_unsupported_proto vxhs
61
+ qemu_co_queue_next(&s->thread_task_queue);
63
_supported_os Linux
62
+ qemu_co_mutex_unlock(&s->lock);
64
63
+
65
CLUSTER_SIZE=64k
64
+ return ret;
66
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
65
+}
67
index XXXXXXX..XXXXXXX 100755
66
+
68
--- a/tests/qemu-iotests/114
67
+
69
+++ b/tests/qemu-iotests/114
68
+/*
70
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
69
+ * Compression
71
70
+ */
72
_supported_fmt qcow2
71
73
_supported_proto generic
72
typedef ssize_t (*Qcow2CompressFunc)(void *dest, size_t dest_size,
74
+_unsupported_proto vxhs
73
const void *src, size_t src_size);
75
_supported_os Linux
74
@@ -XXX,XX +XXX,XX @@ static ssize_t coroutine_fn
76
75
qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
77
76
const void *src, size_t src_size, Qcow2CompressFunc func)
78
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
77
{
79
index XXXXXXX..XXXXXXX 100755
78
- BDRVQcow2State *s = bs->opaque;
80
--- a/tests/qemu-iotests/130
79
- ThreadPool *pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
81
+++ b/tests/qemu-iotests/130
80
Qcow2CompressData arg = {
82
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
81
.dest = dest,
83
82
.dest_size = dest_size,
84
_supported_fmt qcow2
83
@@ -XXX,XX +XXX,XX @@ qcow2_co_do_compress(BlockDriverState *bs, void *dest, size_t dest_size,
85
_supported_proto generic
84
.func = func,
86
+_unsupported_proto vxhs
85
};
87
_supported_os Linux
86
88
87
- qemu_co_mutex_lock(&s->lock);
89
qemu_comm_method="monitor"
88
- while (s->nb_compress_threads >= MAX_COMPRESS_THREADS) {
90
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
89
- qemu_co_queue_wait(&s->compress_wait_queue, &s->lock);
91
index XXXXXXX..XXXXXXX 100755
90
- }
92
--- a/tests/qemu-iotests/134
91
- s->nb_compress_threads++;
93
+++ b/tests/qemu-iotests/134
92
- qemu_co_mutex_unlock(&s->lock);
94
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
93
-
95
94
- thread_pool_submit_co(pool, qcow2_compress_pool_func, &arg);
96
_supported_fmt qcow2
95
-
97
_supported_proto generic
96
- qemu_co_mutex_lock(&s->lock);
98
+_unsupported_proto vxhs
97
- s->nb_compress_threads--;
99
_supported_os Linux
98
- qemu_co_queue_next(&s->compress_wait_queue);
100
99
- qemu_co_mutex_unlock(&s->lock);
101
100
+ qcow2_co_process(bs, qcow2_compress_pool_func, &arg);
102
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
101
103
index XXXXXXX..XXXXXXX 100755
102
return arg.ret;
104
--- a/tests/qemu-iotests/156
103
}
105
+++ b/tests/qemu-iotests/156
104
diff --git a/block/qcow2.c b/block/qcow2.c
106
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
105
index XXXXXXX..XXXXXXX 100644
107
106
--- a/block/qcow2.c
108
_supported_fmt qcow2 qed
107
+++ b/block/qcow2.c
109
_supported_proto generic
108
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
110
+_unsupported_proto vxhs
109
}
111
_supported_os Linux
110
#endif
112
111
113
# Create source disk
112
- qemu_co_queue_init(&s->compress_wait_queue);
114
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
113
+ qemu_co_queue_init(&s->thread_task_queue);
115
index XXXXXXX..XXXXXXX 100755
114
116
--- a/tests/qemu-iotests/158
115
return ret;
117
+++ b/tests/qemu-iotests/158
118
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
119
120
_supported_fmt qcow2
121
_supported_proto generic
122
+_unsupported_proto vxhs
123
_supported_os Linux
124
125
116
126
--
117
--
127
2.9.3
118
2.21.0
128
119
129
120
diff view generated by jsdifflib
1
We have a helper wrapper for checking for the BDS read_only flag,
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
add a helper wrapper to set the read_only flag as well.
3
2
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
Background: decryption will be done in threads, to take benefit of it,
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
4
we should move it out of the lock first.
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
7
Message-id: 9b18972d05f5fa2ac16c014f0af98d680553048d.1491597120.git.jcody@redhat.com
6
But let's go further: it turns out, that only
7
qcow2_get_cluster_offset() needs locking, so reduce locking to it.
8
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
Message-id: 20190506142741.41731-7-vsementsov@virtuozzo.com
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
13
---
9
block.c | 5 +++++
14
block/qcow2.c | 12 ++----------
10
block/bochs.c | 2 +-
15
1 file changed, 2 insertions(+), 10 deletions(-)
11
block/cloop.c | 2 +-
12
block/dmg.c | 2 +-
13
block/rbd.c | 2 +-
14
block/vvfat.c | 4 ++--
15
include/block/block.h | 1 +
16
7 files changed, 12 insertions(+), 6 deletions(-)
17
16
18
diff --git a/block.c b/block.c
17
diff --git a/block/qcow2.c b/block/qcow2.c
19
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
19
--- a/block/qcow2.c
21
+++ b/block.c
20
+++ b/block/qcow2.c
22
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
21
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
23
}
22
24
}
23
qemu_iovec_init(&hd_qiov, qiov->niov);
25
24
26
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
25
- qemu_co_mutex_lock(&s->lock);
27
+{
26
-
28
+ bs->read_only = read_only;
27
while (bytes != 0) {
29
+}
28
30
+
29
/* prepare next request */
31
void bdrv_get_full_backing_filename_from_filename(const char *backed,
30
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
32
const char *backing,
31
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
33
char *dest, size_t sz,
32
}
34
diff --git a/block/bochs.c b/block/bochs.c
33
35
index XXXXXXX..XXXXXXX 100644
34
+ qemu_co_mutex_lock(&s->lock);
36
--- a/block/bochs.c
35
ret = qcow2_get_cluster_offset(bs, offset, &cur_bytes, &cluster_offset);
37
+++ b/block/bochs.c
36
+ qemu_co_mutex_unlock(&s->lock);
38
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
39
return -EINVAL;
40
}
41
42
- bs->read_only = true; /* no write support yet */
43
+ bdrv_set_read_only(bs, true); /* no write support yet */
44
45
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
46
if (ret < 0) {
47
diff --git a/block/cloop.c b/block/cloop.c
48
index XXXXXXX..XXXXXXX 100644
49
--- a/block/cloop.c
50
+++ b/block/cloop.c
51
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
52
return -EINVAL;
53
}
54
55
- bs->read_only = true;
56
+ bdrv_set_read_only(bs, true);
57
58
/* read header */
59
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
60
diff --git a/block/dmg.c b/block/dmg.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/dmg.c
63
+++ b/block/dmg.c
64
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
65
}
66
67
block_module_load_one("dmg-bz2");
68
- bs->read_only = true;
69
+ bdrv_set_read_only(bs, true);
70
71
s->n_chunks = 0;
72
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
73
diff --git a/block/rbd.c b/block/rbd.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/rbd.c
76
+++ b/block/rbd.c
77
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
78
goto failed_open;
79
}
80
81
- bs->read_only = (s->snap != NULL);
82
+ bdrv_set_read_only(bs, (s->snap != NULL));
83
84
qemu_opts_del(opts);
85
return 0;
86
diff --git a/block/vvfat.c b/block/vvfat.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/vvfat.c
89
+++ b/block/vvfat.c
90
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
91
s->current_cluster=0xffffffff;
92
93
/* read only is the default for safety */
94
- bs->read_only = true;
95
+ bdrv_set_read_only(bs, true);
96
s->qcow = NULL;
97
s->qcow_filename = NULL;
98
s->fat2 = NULL;
99
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
100
if (ret < 0) {
37
if (ret < 0) {
101
goto fail;
38
goto fail;
102
}
39
}
103
- bs->read_only = false;
40
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
104
+ bdrv_set_read_only(bs, false);
41
105
}
42
if (bs->backing) {
106
43
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
107
bs->total_sectors = cyls * heads * secs;
44
- qemu_co_mutex_unlock(&s->lock);
108
diff --git a/include/block/block.h b/include/block/block.h
45
ret = bdrv_co_preadv(bs->backing, offset, cur_bytes,
109
index XXXXXXX..XXXXXXX 100644
46
&hd_qiov, 0);
110
--- a/include/block/block.h
47
- qemu_co_mutex_lock(&s->lock);
111
+++ b/include/block/block.h
48
if (ret < 0) {
112
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
49
goto fail;
113
int64_t sector_num, int nb_sectors, int *pnum);
50
}
114
51
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
115
bool bdrv_is_read_only(BlockDriverState *bs);
52
break;
116
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
53
117
bool bdrv_is_sg(BlockDriverState *bs);
54
case QCOW2_CLUSTER_COMPRESSED:
118
bool bdrv_is_inserted(BlockDriverState *bs);
55
- qemu_co_mutex_unlock(&s->lock);
119
int bdrv_media_changed(BlockDriverState *bs);
56
ret = qcow2_co_preadv_compressed(bs, cluster_offset,
57
offset, cur_bytes,
58
&hd_qiov);
59
- qemu_co_mutex_lock(&s->lock);
60
if (ret < 0) {
61
goto fail;
62
}
63
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
64
}
65
66
BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);
67
- qemu_co_mutex_unlock(&s->lock);
68
ret = bdrv_co_preadv(s->data_file,
69
cluster_offset + offset_in_cluster,
70
cur_bytes, &hd_qiov, 0);
71
- qemu_co_mutex_lock(&s->lock);
72
if (ret < 0) {
73
goto fail;
74
}
75
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
76
ret = 0;
77
78
fail:
79
- qemu_co_mutex_unlock(&s->lock);
80
-
81
qemu_iovec_destroy(&hd_qiov);
82
qemu_vfree(cluster_data);
83
120
--
84
--
121
2.9.3
85
2.21.0
122
86
123
87
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Encryption will be done in threads, to take benefit of it, we should
4
move it out of the lock first.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190506142741.41731-8-vsementsov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2.c | 35 +++++++++++++++++++++--------------
13
1 file changed, 21 insertions(+), 14 deletions(-)
14
15
diff --git a/block/qcow2.c b/block/qcow2.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/qcow2.c
18
+++ b/block/qcow2.c
19
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
20
ret = qcow2_alloc_cluster_offset(bs, offset, &cur_bytes,
21
&cluster_offset, &l2meta);
22
if (ret < 0) {
23
- goto fail;
24
+ goto out_locked;
25
}
26
27
assert((cluster_offset & 511) == 0);
28
29
+ ret = qcow2_pre_write_overlap_check(bs, 0,
30
+ cluster_offset + offset_in_cluster,
31
+ cur_bytes, true);
32
+ if (ret < 0) {
33
+ goto out_locked;
34
+ }
35
+
36
+ qemu_co_mutex_unlock(&s->lock);
37
+
38
qemu_iovec_reset(&hd_qiov);
39
qemu_iovec_concat(&hd_qiov, qiov, bytes_done, cur_bytes);
40
41
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
42
* s->cluster_size);
43
if (cluster_data == NULL) {
44
ret = -ENOMEM;
45
- goto fail;
46
+ goto out_unlocked;
47
}
48
}
49
50
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
51
cluster_data,
52
cur_bytes, NULL) < 0) {
53
ret = -EIO;
54
- goto fail;
55
+ goto out_unlocked;
56
}
57
58
qemu_iovec_reset(&hd_qiov);
59
qemu_iovec_add(&hd_qiov, cluster_data, cur_bytes);
60
}
61
62
- ret = qcow2_pre_write_overlap_check(bs, 0,
63
- cluster_offset + offset_in_cluster, cur_bytes, true);
64
- if (ret < 0) {
65
- goto fail;
66
- }
67
-
68
/* If we need to do COW, check if it's possible to merge the
69
* writing of the guest data together with that of the COW regions.
70
* If it's not possible (or not necessary) then write the
71
* guest data now. */
72
if (!merge_cow(offset, cur_bytes, &hd_qiov, l2meta)) {
73
- qemu_co_mutex_unlock(&s->lock);
74
BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);
75
trace_qcow2_writev_data(qemu_coroutine_self(),
76
cluster_offset + offset_in_cluster);
77
ret = bdrv_co_pwritev(s->data_file,
78
cluster_offset + offset_in_cluster,
79
cur_bytes, &hd_qiov, 0);
80
- qemu_co_mutex_lock(&s->lock);
81
if (ret < 0) {
82
- goto fail;
83
+ goto out_unlocked;
84
}
85
}
86
87
+ qemu_co_mutex_lock(&s->lock);
88
+
89
ret = qcow2_handle_l2meta(bs, &l2meta, true);
90
if (ret) {
91
- goto fail;
92
+ goto out_locked;
93
}
94
95
bytes -= cur_bytes;
96
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
97
trace_qcow2_writev_done_part(qemu_coroutine_self(), cur_bytes);
98
}
99
ret = 0;
100
+ goto out_locked;
101
102
-fail:
103
+out_unlocked:
104
+ qemu_co_mutex_lock(&s->lock);
105
+
106
+out_locked:
107
qcow2_handle_l2meta(bs, &l2meta, false);
108
109
qemu_co_mutex_unlock(&s->lock);
110
--
111
2.21.0
112
113
diff view generated by jsdifflib
New patch
1
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
3
Do encryption/decryption in threads, like it is already done for
4
compression. This improves asynchronous encrypted io.
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
9
Message-id: 20190506142741.41731-9-vsementsov@virtuozzo.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
11
---
12
block/qcow2.h | 8 ++++++
13
block/qcow2-cluster.c | 7 ++---
14
block/qcow2-threads.c | 65 +++++++++++++++++++++++++++++++++++++++++--
15
block/qcow2.c | 22 +++++----------
16
4 files changed, 81 insertions(+), 21 deletions(-)
17
18
diff --git a/block/qcow2.h b/block/qcow2.h
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/qcow2.h
21
+++ b/block/qcow2.h
22
@@ -XXX,XX +XXX,XX @@ typedef struct Qcow2BitmapHeaderExt {
23
uint64_t bitmap_directory_offset;
24
} QEMU_PACKED Qcow2BitmapHeaderExt;
25
26
+#define QCOW2_MAX_THREADS 4
27
+
28
typedef struct BDRVQcow2State {
29
int cluster_bits;
30
int cluster_size;
31
@@ -XXX,XX +XXX,XX @@ qcow2_co_compress(BlockDriverState *bs, void *dest, size_t dest_size,
32
ssize_t coroutine_fn
33
qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
34
const void *src, size_t src_size);
35
+int coroutine_fn
36
+qcow2_co_encrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
37
+ uint64_t offset, void *buf, size_t len);
38
+int coroutine_fn
39
+qcow2_co_decrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
40
+ uint64_t offset, void *buf, size_t len);
41
42
#endif
43
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/block/qcow2-cluster.c
46
+++ b/block/qcow2-cluster.c
47
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn do_perform_cow_encrypt(BlockDriverState *bs,
48
{
49
if (bytes && bs->encrypted) {
50
BDRVQcow2State *s = bs->opaque;
51
- int64_t offset = (s->crypt_physical_offset ?
52
- (cluster_offset + offset_in_cluster) :
53
- (src_cluster_offset + offset_in_cluster));
54
assert((offset_in_cluster & ~BDRV_SECTOR_MASK) == 0);
55
assert((bytes & ~BDRV_SECTOR_MASK) == 0);
56
assert(s->crypto);
57
- if (qcrypto_block_encrypt(s->crypto, offset, buffer, bytes, NULL) < 0) {
58
+ if (qcow2_co_encrypt(bs, cluster_offset,
59
+ src_cluster_offset + offset_in_cluster,
60
+ buffer, bytes) < 0) {
61
return false;
62
}
63
}
64
diff --git a/block/qcow2-threads.c b/block/qcow2-threads.c
65
index XXXXXXX..XXXXXXX 100644
66
--- a/block/qcow2-threads.c
67
+++ b/block/qcow2-threads.c
68
@@ -XXX,XX +XXX,XX @@
69
70
#include "qcow2.h"
71
#include "block/thread-pool.h"
72
-
73
-#define QCOW2_MAX_THREADS 4
74
+#include "crypto.h"
75
76
static int coroutine_fn
77
qcow2_co_process(BlockDriverState *bs, ThreadPoolFunc *func, void *arg)
78
@@ -XXX,XX +XXX,XX @@ qcow2_co_decompress(BlockDriverState *bs, void *dest, size_t dest_size,
79
return qcow2_co_do_compress(bs, dest, dest_size, src, src_size,
80
qcow2_decompress);
81
}
82
+
83
+
84
+/*
85
+ * Cryptography
86
+ */
87
+
88
+/*
89
+ * Qcow2EncDecFunc: common prototype of qcrypto_block_encrypt() and
90
+ * qcrypto_block_decrypt() functions.
91
+ */
92
+typedef int (*Qcow2EncDecFunc)(QCryptoBlock *block, uint64_t offset,
93
+ uint8_t *buf, size_t len, Error **errp);
94
+
95
+typedef struct Qcow2EncDecData {
96
+ QCryptoBlock *block;
97
+ uint64_t offset;
98
+ uint8_t *buf;
99
+ size_t len;
100
+
101
+ Qcow2EncDecFunc func;
102
+} Qcow2EncDecData;
103
+
104
+static int qcow2_encdec_pool_func(void *opaque)
105
+{
106
+ Qcow2EncDecData *data = opaque;
107
+
108
+ return data->func(data->block, data->offset, data->buf, data->len, NULL);
109
+}
110
+
111
+static int coroutine_fn
112
+qcow2_co_encdec(BlockDriverState *bs, uint64_t file_cluster_offset,
113
+ uint64_t offset, void *buf, size_t len, Qcow2EncDecFunc func)
114
+{
115
+ BDRVQcow2State *s = bs->opaque;
116
+ Qcow2EncDecData arg = {
117
+ .block = s->crypto,
118
+ .offset = s->crypt_physical_offset ?
119
+ file_cluster_offset + offset_into_cluster(s, offset) :
120
+ offset,
121
+ .buf = buf,
122
+ .len = len,
123
+ .func = func,
124
+ };
125
+
126
+ return qcow2_co_process(bs, qcow2_encdec_pool_func, &arg);
127
+}
128
+
129
+int coroutine_fn
130
+qcow2_co_encrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
131
+ uint64_t offset, void *buf, size_t len)
132
+{
133
+ return qcow2_co_encdec(bs, file_cluster_offset, offset, buf, len,
134
+ qcrypto_block_encrypt);
135
+}
136
+
137
+int coroutine_fn
138
+qcow2_co_decrypt(BlockDriverState *bs, uint64_t file_cluster_offset,
139
+ uint64_t offset, void *buf, size_t len)
140
+{
141
+ return qcow2_co_encdec(bs, file_cluster_offset, offset, buf, len,
142
+ qcrypto_block_decrypt);
143
+}
144
diff --git a/block/qcow2.c b/block/qcow2.c
145
index XXXXXXX..XXXXXXX 100644
146
--- a/block/qcow2.c
147
+++ b/block/qcow2.c
148
@@ -XXX,XX +XXX,XX @@ static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
149
}
150
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
151
qcow2_crypto_hdr_read_func,
152
- bs, cflags, 1, errp);
153
+ bs, cflags, QCOW2_MAX_THREADS, errp);
154
if (!s->crypto) {
155
return -EINVAL;
156
}
157
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
158
cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;
159
}
160
s->crypto = qcrypto_block_open(s->crypto_opts, "encrypt.",
161
- NULL, NULL, cflags, 1, errp);
162
+ NULL, NULL, cflags,
163
+ QCOW2_MAX_THREADS, errp);
164
if (!s->crypto) {
165
ret = -EINVAL;
166
goto fail;
167
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_preadv(BlockDriverState *bs, uint64_t offset,
168
assert(s->crypto);
169
assert((offset & (BDRV_SECTOR_SIZE - 1)) == 0);
170
assert((cur_bytes & (BDRV_SECTOR_SIZE - 1)) == 0);
171
- if (qcrypto_block_decrypt(s->crypto,
172
- (s->crypt_physical_offset ?
173
- cluster_offset + offset_in_cluster :
174
- offset),
175
- cluster_data,
176
- cur_bytes,
177
- NULL) < 0) {
178
+ if (qcow2_co_decrypt(bs, cluster_offset, offset,
179
+ cluster_data, cur_bytes) < 0) {
180
ret = -EIO;
181
goto fail;
182
}
183
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
184
QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
185
qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);
186
187
- if (qcrypto_block_encrypt(s->crypto,
188
- (s->crypt_physical_offset ?
189
- cluster_offset + offset_in_cluster :
190
- offset),
191
- cluster_data,
192
- cur_bytes, NULL) < 0) {
193
+ if (qcow2_co_encrypt(bs, cluster_offset, offset,
194
+ cluster_data, cur_bytes) < 0) {
195
ret = -EIO;
196
goto out_unlocked;
197
}
198
--
199
2.21.0
200
201
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
These changes use a vxhs test server that is a part of the following
3
Simplify backup_incremental_init_copy_bitmap using the function
4
repository:
4
bdrv_dirty_bitmap_next_dirty_area.
5
https://github.com/VeritasHyperScale/libqnio.git
6
5
7
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
6
Note: move to job->len instead of bitmap size: it should not matter but
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
less code.
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
8
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
Message-id: 1491277689-24949-3-git-send-email-Ashish.Mittal@veritas.com
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
11
Message-id: 20190429090842.57910-2-vsementsov@virtuozzo.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
13
---
13
tests/qemu-iotests/common | 6 ++++++
14
block/backup.c | 40 ++++++++++++----------------------------
14
tests/qemu-iotests/common.config | 13 +++++++++++++
15
1 file changed, 12 insertions(+), 28 deletions(-)
15
tests/qemu-iotests/common.filter | 1 +
16
tests/qemu-iotests/common.rc | 19 +++++++++++++++++++
17
4 files changed, 39 insertions(+)
18
16
19
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
17
diff --git a/block/backup.c b/block/backup.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/common
19
--- a/block/backup.c
22
+++ b/tests/qemu-iotests/common
20
+++ b/block/backup.c
23
@@ -XXX,XX +XXX,XX @@ check options
21
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
24
-ssh test ssh
22
/* init copy_bitmap from sync_bitmap */
25
-nfs test nfs
23
static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
26
-luks test luks
24
{
27
+ -vxhs test vxhs
25
- BdrvDirtyBitmapIter *dbi;
28
-xdiff graphical mode diff
26
- int64_t offset;
29
-nocache use O_DIRECT on backing file
27
- int64_t end = DIV_ROUND_UP(bdrv_dirty_bitmap_size(job->sync_bitmap),
30
-misalign misalign memory allocations
28
- job->cluster_size);
31
@@ -XXX,XX +XXX,XX @@ testlist options
29
-
32
xpand=false
30
- dbi = bdrv_dirty_iter_new(job->sync_bitmap);
33
;;
31
- while ((offset = bdrv_dirty_iter_next(dbi)) != -1) {
34
32
- int64_t cluster = offset / job->cluster_size;
35
+ -vxhs)
33
- int64_t next_cluster;
36
+ IMGPROTO=vxhs
34
-
37
+ xpand=false
35
- offset += bdrv_dirty_bitmap_granularity(job->sync_bitmap);
38
+ ;;
36
- if (offset >= bdrv_dirty_bitmap_size(job->sync_bitmap)) {
37
- hbitmap_set(job->copy_bitmap, cluster, end - cluster);
38
- break;
39
- }
40
+ uint64_t offset = 0;
41
+ uint64_t bytes = job->len;
42
43
- offset = bdrv_dirty_bitmap_next_zero(job->sync_bitmap, offset,
44
- UINT64_MAX);
45
- if (offset == -1) {
46
- hbitmap_set(job->copy_bitmap, cluster, end - cluster);
47
- break;
48
- }
49
+ while (bdrv_dirty_bitmap_next_dirty_area(job->sync_bitmap,
50
+ &offset, &bytes))
51
+ {
52
+ uint64_t cluster = offset / job->cluster_size;
53
+ uint64_t end_cluster = DIV_ROUND_UP(offset + bytes, job->cluster_size);
54
55
- next_cluster = DIV_ROUND_UP(offset, job->cluster_size);
56
- hbitmap_set(job->copy_bitmap, cluster, next_cluster - cluster);
57
- if (next_cluster >= end) {
58
+ hbitmap_set(job->copy_bitmap, cluster, end_cluster - cluster);
39
+
59
+
40
-ssh)
60
+ offset = end_cluster * job->cluster_size;
41
IMGPROTO=ssh
61
+ if (offset >= job->len) {
42
xpand=false
62
break;
43
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
63
}
44
index XXXXXXX..XXXXXXX 100644
64
-
45
--- a/tests/qemu-iotests/common.config
65
- bdrv_set_dirty_iter(dbi, next_cluster * job->cluster_size);
46
+++ b/tests/qemu-iotests/common.config
66
+ bytes = job->len - offset;
47
@@ -XXX,XX +XXX,XX @@ if [ -z "$QEMU_NBD_PROG" ]; then
67
}
48
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
68
49
fi
69
/* TODO job_progress_set_remaining() would make more sense */
50
70
job_progress_update(&job->common.job,
51
+if [ -z "$QEMU_VXHS_PROG" ]; then
71
job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size);
52
+ export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
72
-
53
+fi
73
- bdrv_dirty_iter_free(dbi);
54
+
55
_qemu_wrapper()
56
{
57
(
58
@@ -XXX,XX +XXX,XX @@ _qemu_nbd_wrapper()
59
)
60
}
74
}
61
75
62
+_qemu_vxhs_wrapper()
76
static int coroutine_fn backup_run(Job *job, Error **errp)
63
+{
64
+ (
65
+ echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
66
+ exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
67
+ )
68
+}
69
+
70
export QEMU=_qemu_wrapper
71
export QEMU_IMG=_qemu_img_wrapper
72
export QEMU_IO=_qemu_io_wrapper
73
export QEMU_NBD=_qemu_nbd_wrapper
74
+export QEMU_VXHS=_qemu_vxhs_wrapper
75
76
QEMU_IMG_EXTRA_ARGS=
77
if [ "$IMGOPTSSYNTAX" = "true" ]; then
78
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
79
index XXXXXXX..XXXXXXX 100644
80
--- a/tests/qemu-iotests/common.filter
81
+++ b/tests/qemu-iotests/common.filter
82
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
83
-e "s#$TEST_DIR#TEST_DIR#g" \
84
-e "s#$IMGFMT#IMGFMT#g" \
85
-e 's#nbd://127.0.0.1:10810$#TEST_DIR/t.IMGFMT#g' \
86
+ -e 's#json.*vdisk-id.*vxhs"}}#TEST_DIR/t.IMGFMT#' \
87
-e "/encrypted: yes/d" \
88
-e "/cluster_size: [0-9]\\+/d" \
89
-e "/table_size: [0-9]\\+/d" \
90
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
91
index XXXXXXX..XXXXXXX 100644
92
--- a/tests/qemu-iotests/common.rc
93
+++ b/tests/qemu-iotests/common.rc
94
@@ -XXX,XX +XXX,XX @@ else
95
elif [ "$IMGPROTO" = "nfs" ]; then
96
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
97
TEST_IMG=$TEST_DIR/t.$IMGFMT
98
+ elif [ "$IMGPROTO" = "vxhs" ]; then
99
+ TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
100
+ TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT"
101
else
102
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
103
fi
104
@@ -XXX,XX +XXX,XX @@ _make_test_img()
105
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
106
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
107
fi
108
+
109
+ # Start QNIO server on image directory for vxhs protocol
110
+ if [ $IMGPROTO = "vxhs" ]; then
111
+ eval "$QEMU_VXHS -d $TEST_DIR > /dev/null &"
112
+ sleep 1 # Wait for server to come up.
113
+ fi
114
}
115
116
_rm_test_img()
117
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img()
118
fi
119
rm -f "$TEST_IMG_FILE"
120
;;
121
+ vxhs)
122
+ if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then
123
+ local QEMU_VXHS_PID
124
+ read QEMU_VXHS_PID < "${TEST_DIR}/qemu-vxhs.pid"
125
+ kill ${QEMU_VXHS_PID} >/dev/null 2>&1
126
+ rm -f "${TEST_DIR}/qemu-vxhs.pid"
127
+ fi
128
+ rm -f "$TEST_IMG_FILE"
129
+ ;;
130
+
131
file)
132
_rm_test_img "$TEST_DIR/t.$IMGFMT"
133
_rm_test_img "$TEST_DIR/t.$IMGFMT.orig"
134
--
77
--
135
2.9.3
78
2.21.0
136
79
137
80
diff view generated by jsdifflib
1
Update 'clientname' to be 'user', which tracks better with both
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
the QAPI and rados variable naming.
3
2
4
Update 'name' to be 'image_name', as it indicates the rbd image.
3
We are going to share this bitmap between backup and backup-top filter
5
Naming it 'image' would have been ideal, but we are using that for
4
driver, so let's share something more meaningful. It also simplifies
6
the rados_image_t value returned by rbd_open().
5
some calculations.
7
6
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
Reviewed-by: John Snow <jsnow@redhat.com>
9
Message-id: 20190429090842.57910-3-vsementsov@virtuozzo.com
11
Message-id: b7ec1fb2e1cf36f9b6911631447a5b0422590b7d.1491597120.git.jcody@redhat.com
10
Signed-off-by: Max Reitz <mreitz@redhat.com>
12
---
11
---
13
block/rbd.c | 33 +++++++++++++++++----------------
12
block/backup.c | 48 +++++++++++++++++++++++-------------------------
14
1 file changed, 17 insertions(+), 16 deletions(-)
13
1 file changed, 23 insertions(+), 25 deletions(-)
15
14
16
diff --git a/block/rbd.c b/block/rbd.c
15
diff --git a/block/backup.c b/block/backup.c
17
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
18
--- a/block/rbd.c
17
--- a/block/backup.c
19
+++ b/block/rbd.c
18
+++ b/block/backup.c
20
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
19
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
21
rados_t cluster;
20
int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
22
rados_ioctx_t io_ctx;
21
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
23
rbd_image_t image;
22
24
- char *name;
23
- hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1);
25
+ char *image_name;
24
+ assert(QEMU_IS_ALIGNED(start, job->cluster_size));
26
char *snap;
25
+ hbitmap_reset(job->copy_bitmap, start, job->cluster_size);
27
} BDRVRBDState;
26
nbytes = MIN(job->cluster_size, job->len - start);
28
27
if (!*bounce_buffer) {
29
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
28
*bounce_buffer = blk_blockalign(blk, job->cluster_size);
30
int64_t bytes = 0;
29
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
31
int64_t objsize;
30
32
int obj_order = 0;
31
return nbytes;
33
- const char *pool, *name, *conf, *clientname, *keypairs;
32
fail:
34
+ const char *pool, *image_name, *conf, *user, *keypairs;
33
- hbitmap_set(job->copy_bitmap, start / job->cluster_size, 1);
35
const char *secretid;
34
+ hbitmap_set(job->copy_bitmap, start, job->cluster_size);
36
rados_t cluster;
35
return ret;
37
rados_ioctx_t io_ctx;
36
38
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
37
}
39
*/
38
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
40
pool = qdict_get_try_str(options, "pool");
39
int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
41
conf = qdict_get_try_str(options, "conf");
40
42
- clientname = qdict_get_try_str(options, "user");
41
assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size));
43
- name = qdict_get_try_str(options, "image");
42
+ assert(QEMU_IS_ALIGNED(start, job->cluster_size));
44
+ user = qdict_get_try_str(options, "user");
43
nbytes = MIN(job->copy_range_size, end - start);
45
+ image_name = qdict_get_try_str(options, "image");
44
nr_clusters = DIV_ROUND_UP(nbytes, job->cluster_size);
46
keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
45
- hbitmap_reset(job->copy_bitmap, start / job->cluster_size,
47
46
- nr_clusters);
48
- ret = rados_create(&cluster, clientname);
47
+ hbitmap_reset(job->copy_bitmap, start, job->cluster_size * nr_clusters);
49
+ ret = rados_create(&cluster, user);
48
ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
49
read_flags, write_flags);
50
if (ret < 0) {
50
if (ret < 0) {
51
error_setg_errno(errp, -ret, "error initializing");
51
trace_backup_do_cow_copy_range_fail(job, start, ret);
52
goto exit;
52
- hbitmap_set(job->copy_bitmap, start / job->cluster_size,
53
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
53
- nr_clusters);
54
goto shutdown;
54
+ hbitmap_set(job->copy_bitmap, start, job->cluster_size * nr_clusters);
55
return ret;
55
}
56
}
56
57
57
- ret = rbd_create(io_ctx, name, bytes, &obj_order);
58
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_do_cow(BackupBlockJob *job,
58
+ ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
59
cow_request_begin(&cow_request, job, start, end);
59
if (ret < 0) {
60
60
error_setg_errno(errp, -ret, "error rbd create");
61
while (start < end) {
62
- if (!hbitmap_get(job->copy_bitmap, start / job->cluster_size)) {
63
+ if (!hbitmap_get(job->copy_bitmap, start)) {
64
trace_backup_do_cow_skip(job, start);
65
start += job->cluster_size;
66
continue; /* already copied */
67
@@ -XXX,XX +XXX,XX @@ static void backup_clean(Job *job)
68
assert(s->target);
69
blk_unref(s->target);
70
s->target = NULL;
71
+
72
+ if (s->copy_bitmap) {
73
+ hbitmap_free(s->copy_bitmap);
74
+ s->copy_bitmap = NULL;
75
+ }
76
}
77
78
void backup_do_checkpoint(BlockJob *job, Error **errp)
79
{
80
BackupBlockJob *backup_job = container_of(job, BackupBlockJob, common);
81
- int64_t len;
82
83
assert(block_job_driver(job) == &backup_job_driver);
84
85
@@ -XXX,XX +XXX,XX @@ void backup_do_checkpoint(BlockJob *job, Error **errp)
86
return;
61
}
87
}
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
88
63
Error **errp)
89
- len = DIV_ROUND_UP(backup_job->len, backup_job->cluster_size);
90
- hbitmap_set(backup_job->copy_bitmap, 0, len);
91
+ hbitmap_set(backup_job->copy_bitmap, 0, backup_job->len);
92
}
93
94
static void backup_drain(BlockJob *job)
95
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
64
{
96
{
65
BDRVRBDState *s = bs->opaque;
97
int ret;
66
- const char *pool, *snap, *conf, *clientname, *name, *keypairs;
98
bool error_is_read;
67
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
99
- int64_t cluster;
68
const char *secretid;
100
+ int64_t offset;
69
QemuOpts *opts;
101
HBitmapIter hbi;
70
Error *local_err = NULL;
102
71
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
103
hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
72
pool = qemu_opt_get(opts, "pool");
104
- while ((cluster = hbitmap_iter_next(&hbi)) != -1) {
73
conf = qemu_opt_get(opts, "conf");
105
+ while ((offset = hbitmap_iter_next(&hbi)) != -1) {
74
snap = qemu_opt_get(opts, "snapshot");
106
do {
75
- clientname = qemu_opt_get(opts, "user");
107
if (yield_and_check(job)) {
76
- name = qemu_opt_get(opts, "image");
108
return 0;
77
+ user = qemu_opt_get(opts, "user");
109
}
78
+ image_name = qemu_opt_get(opts, "image");
110
- ret = backup_do_cow(job, cluster * job->cluster_size,
79
keypairs = qemu_opt_get(opts, "=keyvalue-pairs");
111
+ ret = backup_do_cow(job, offset,
80
112
job->cluster_size, &error_is_read, false);
81
- if (!pool || !name) {
113
if (ret < 0 && backup_error_action(job, error_is_read, -ret) ==
82
+ if (!pool || !image_name) {
114
BLOCK_ERROR_ACTION_REPORT)
83
error_setg(errp, "Parameters 'pool' and 'image' are required");
115
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
84
r = -EINVAL;
116
while (bdrv_dirty_bitmap_next_dirty_area(job->sync_bitmap,
85
goto failed_opts;
117
&offset, &bytes))
118
{
119
- uint64_t cluster = offset / job->cluster_size;
120
- uint64_t end_cluster = DIV_ROUND_UP(offset + bytes, job->cluster_size);
121
+ hbitmap_set(job->copy_bitmap, offset, bytes);
122
123
- hbitmap_set(job->copy_bitmap, cluster, end_cluster - cluster);
124
-
125
- offset = end_cluster * job->cluster_size;
126
+ offset += bytes;
127
if (offset >= job->len) {
128
break;
129
}
130
@@ -XXX,XX +XXX,XX @@ static void backup_incremental_init_copy_bitmap(BackupBlockJob *job)
131
132
/* TODO job_progress_set_remaining() would make more sense */
133
job_progress_update(&job->common.job,
134
- job->len - hbitmap_count(job->copy_bitmap) * job->cluster_size);
135
+ job->len - hbitmap_count(job->copy_bitmap));
136
}
137
138
static int coroutine_fn backup_run(Job *job, Error **errp)
139
{
140
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
141
BlockDriverState *bs = blk_bs(s->common.blk);
142
- int64_t offset, nb_clusters;
143
+ int64_t offset;
144
int ret = 0;
145
146
QLIST_INIT(&s->inflight_reqs);
147
qemu_co_rwlock_init(&s->flush_rwlock);
148
149
- nb_clusters = DIV_ROUND_UP(s->len, s->cluster_size);
150
job_progress_set_remaining(job, s->len);
151
152
- s->copy_bitmap = hbitmap_alloc(nb_clusters, 0);
153
if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
154
backup_incremental_init_copy_bitmap(s);
155
} else {
156
- hbitmap_set(s->copy_bitmap, 0, nb_clusters);
157
+ hbitmap_set(s->copy_bitmap, 0, s->len);
86
}
158
}
87
159
88
- r = rados_create(&s->cluster, clientname);
160
-
89
+ r = rados_create(&s->cluster, user);
161
s->before_write.notify = backup_before_write_notify;
90
if (r < 0) {
162
bdrv_add_before_write_notifier(bs, &s->before_write);
91
error_setg_errno(errp, -r, "error initializing");
163
92
goto failed_opts;
164
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
165
/* wait until pending backup_do_cow() calls have completed */
166
qemu_co_rwlock_wrlock(&s->flush_rwlock);
167
qemu_co_rwlock_unlock(&s->flush_rwlock);
168
- hbitmap_free(s->copy_bitmap);
169
170
return ret;
171
}
172
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
173
} else {
174
job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
93
}
175
}
94
176
+
95
s->snap = g_strdup(snap);
177
+ job->copy_bitmap = hbitmap_alloc(len, ctz32(job->cluster_size));
96
- s->name = g_strdup(name);
178
job->use_copy_range = true;
97
+ s->image_name = g_strdup(image_name);
179
job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk),
98
180
blk_get_max_transfer(job->target));
99
/* try default location when conf=NULL, but ignore failure */
100
r = rados_conf_read_file(s->cluster, conf);
101
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
102
}
103
104
/* rbd_open is always r/w */
105
- r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
106
+ r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
107
if (r < 0) {
108
- error_setg_errno(errp, -r, "error reading header from %s", s->name);
109
+ error_setg_errno(errp, -r, "error reading header from %s",
110
+ s->image_name);
111
goto failed_open;
112
}
113
114
@@ -XXX,XX +XXX,XX @@ failed_open:
115
failed_shutdown:
116
rados_shutdown(s->cluster);
117
g_free(s->snap);
118
- g_free(s->name);
119
+ g_free(s->image_name);
120
failed_opts:
121
qemu_opts_del(opts);
122
g_free(mon_host);
123
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_close(BlockDriverState *bs)
124
rbd_close(s->image);
125
rados_ioctx_destroy(s->io_ctx);
126
g_free(s->snap);
127
- g_free(s->name);
128
+ g_free(s->image_name);
129
rados_shutdown(s->cluster);
130
}
131
132
--
181
--
133
2.9.3
182
2.21.0
134
183
135
184
diff view generated by jsdifflib
1
This adds support for reopen in rbd, for changing between r/w and r/o.
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
Note, that this is only a flag change, but we will block a change from
3
Split allocation checking to separate function and reduce nesting.
4
r/o to r/w if we are using an RBD internal snapshot.
4
Consider bdrv_is_allocated() fail as allocated area, as copying more
5
than needed is not wrong (and we do it anyway) and seems better than
6
fail the whole job. And, most probably we will fail on the next read,
7
if there are real problem with source.
5
8
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
11
Message-id: 20190429090842.57910-4-vsementsov@virtuozzo.com
9
Message-id: d4e87539167ec6527d44c97b164eabcccf96e4f3.1491597120.git.jcody@redhat.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
13
---
11
block/rbd.c | 21 +++++++++++++++++++++
14
block/backup.c | 60 +++++++++++++++++++-------------------------------
12
1 file changed, 21 insertions(+)
15
1 file changed, 23 insertions(+), 37 deletions(-)
13
16
14
diff --git a/block/rbd.c b/block/rbd.c
17
diff --git a/block/backup.c b/block/backup.c
15
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
19
--- a/block/backup.c
17
+++ b/block/rbd.c
20
+++ b/block/backup.c
18
@@ -XXX,XX +XXX,XX @@ failed_opts:
21
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn yield_and_check(BackupBlockJob *job)
19
return r;
22
return false;
20
}
23
}
21
24
25
+static bool bdrv_is_unallocated_range(BlockDriverState *bs,
26
+ int64_t offset, int64_t bytes)
27
+{
28
+ int64_t end = offset + bytes;
22
+
29
+
23
+/* Since RBD is currently always opened R/W via the API,
30
+ while (offset < end && !bdrv_is_allocated(bs, offset, bytes, &bytes)) {
24
+ * we just need to check if we are using a snapshot or not, in
31
+ if (bytes == 0) {
25
+ * order to determine if we will allow it to be R/W */
32
+ return true;
26
+static int qemu_rbd_reopen_prepare(BDRVReopenState *state,
33
+ }
27
+ BlockReopenQueue *queue, Error **errp)
34
+ offset += bytes;
28
+{
35
+ bytes = end - offset;
29
+ BDRVRBDState *s = state->bs->opaque;
30
+ int ret = 0;
31
+
32
+ if (s->snap && state->flags & BDRV_O_RDWR) {
33
+ error_setg(errp,
34
+ "Cannot change node '%s' to r/w when using RBD snapshot",
35
+ bdrv_get_device_or_node_name(state->bs));
36
+ ret = -EINVAL;
37
+ }
36
+ }
38
+
37
+
39
+ return ret;
38
+ return offset >= end;
40
+}
39
+}
41
+
40
+
42
static void qemu_rbd_close(BlockDriverState *bs)
41
static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
43
{
42
{
44
BDRVRBDState *s = bs->opaque;
43
int ret;
45
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
46
.bdrv_parse_filename = qemu_rbd_parse_filename,
45
for (offset = 0; offset < s->len;
47
.bdrv_file_open = qemu_rbd_open,
46
offset += s->cluster_size) {
48
.bdrv_close = qemu_rbd_close,
47
bool error_is_read;
49
+ .bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
48
- int alloced = 0;
50
.bdrv_create = qemu_rbd_create,
49
51
.bdrv_has_zero_init = bdrv_has_zero_init_1,
50
if (yield_and_check(s)) {
52
.bdrv_get_info = qemu_rbd_getinfo,
51
break;
52
}
53
54
- if (s->sync_mode == MIRROR_SYNC_MODE_TOP) {
55
- int i;
56
- int64_t n;
57
-
58
- /* Check to see if these blocks are already in the
59
- * backing file. */
60
-
61
- for (i = 0; i < s->cluster_size;) {
62
- /* bdrv_is_allocated() only returns true/false based
63
- * on the first set of sectors it comes across that
64
- * are are all in the same state.
65
- * For that reason we must verify each sector in the
66
- * backup cluster length. We end up copying more than
67
- * needed but at some point that is always the case. */
68
- alloced =
69
- bdrv_is_allocated(bs, offset + i,
70
- s->cluster_size - i, &n);
71
- i += n;
72
-
73
- if (alloced || n == 0) {
74
- break;
75
- }
76
- }
77
-
78
- /* If the above loop never found any sectors that are in
79
- * the topmost image, skip this backup. */
80
- if (alloced == 0) {
81
- continue;
82
- }
83
- }
84
- /* FULL sync mode we copy the whole drive. */
85
- if (alloced < 0) {
86
- ret = alloced;
87
- } else {
88
- ret = backup_do_cow(s, offset, s->cluster_size,
89
- &error_is_read, false);
90
+ if (s->sync_mode == MIRROR_SYNC_MODE_TOP &&
91
+ bdrv_is_unallocated_range(bs, offset, s->cluster_size))
92
+ {
93
+ continue;
94
}
95
+
96
+ ret = backup_do_cow(s, offset, s->cluster_size,
97
+ &error_is_read, false);
98
if (ret < 0) {
99
/* Depending on error action, fail now or retry cluster */
100
BlockErrorAction action =
53
--
101
--
54
2.9.3
102
2.21.0
55
103
56
104
diff view generated by jsdifflib
1
Introduce check function for setting read_only flags. Will return < 0 on
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
error, with appropriate Error value set. Does not alter any flags.
3
2
4
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
Do full, top and incremental mode copying all in one place. This
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
unifies the code path and helps further improvements.
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
7
Message-id: e2bba34ac3bc76a0c42adc390413f358ae0566e8.1491597120.git.jcody@redhat.com
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-id: 20190429090842.57910-5-vsementsov@virtuozzo.com
9
Signed-off-by: Max Reitz <mreitz@redhat.com>
8
---
10
---
9
block.c | 14 +++++++++++++-
11
block/backup.c | 43 ++++++++++---------------------------------
10
include/block/block.h | 1 +
12
1 file changed, 10 insertions(+), 33 deletions(-)
11
2 files changed, 14 insertions(+), 1 deletion(-)
12
13
13
diff --git a/block.c b/block.c
14
diff --git a/block/backup.c b/block/backup.c
14
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
16
--- a/block/backup.c
16
+++ b/block.c
17
+++ b/block/backup.c
17
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs)
18
@@ -XXX,XX +XXX,XX @@ static bool bdrv_is_unallocated_range(BlockDriverState *bs,
18
return bs->read_only;
19
return offset >= end;
19
}
20
}
20
21
21
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
22
-static int coroutine_fn backup_run_incremental(BackupBlockJob *job)
22
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
23
+static int coroutine_fn backup_loop(BackupBlockJob *job)
23
{
24
{
24
/* Do not set read_only if copy_on_read is enabled */
25
int ret;
25
if (bs->copy_on_read && read_only) {
26
bool error_is_read;
26
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
27
int64_t offset;
27
return -EPERM;
28
HBitmapIter hbi;
29
+ BlockDriverState *bs = blk_bs(job->common.blk);
30
31
hbitmap_iter_init(&hbi, job->copy_bitmap, 0);
32
while ((offset = hbitmap_iter_next(&hbi)) != -1) {
33
+ if (job->sync_mode == MIRROR_SYNC_MODE_TOP &&
34
+ bdrv_is_unallocated_range(bs, offset, job->cluster_size))
35
+ {
36
+ hbitmap_reset(job->copy_bitmap, offset, job->cluster_size);
37
+ continue;
38
+ }
39
+
40
do {
41
if (yield_and_check(job)) {
42
return 0;
43
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
44
{
45
BackupBlockJob *s = container_of(job, BackupBlockJob, common.job);
46
BlockDriverState *bs = blk_bs(s->common.blk);
47
- int64_t offset;
48
int ret = 0;
49
50
QLIST_INIT(&s->inflight_reqs);
51
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_run(Job *job, Error **errp)
52
* notify callback service CoW requests. */
53
job_yield(job);
54
}
55
- } else if (s->sync_mode == MIRROR_SYNC_MODE_INCREMENTAL) {
56
- ret = backup_run_incremental(s);
57
} else {
58
- /* Both FULL and TOP SYNC_MODE's require copying.. */
59
- for (offset = 0; offset < s->len;
60
- offset += s->cluster_size) {
61
- bool error_is_read;
62
-
63
- if (yield_and_check(s)) {
64
- break;
65
- }
66
-
67
- if (s->sync_mode == MIRROR_SYNC_MODE_TOP &&
68
- bdrv_is_unallocated_range(bs, offset, s->cluster_size))
69
- {
70
- continue;
71
- }
72
-
73
- ret = backup_do_cow(s, offset, s->cluster_size,
74
- &error_is_read, false);
75
- if (ret < 0) {
76
- /* Depending on error action, fail now or retry cluster */
77
- BlockErrorAction action =
78
- backup_error_action(s, error_is_read, -ret);
79
- if (action == BLOCK_ERROR_ACTION_REPORT) {
80
- break;
81
- } else {
82
- offset -= s->cluster_size;
83
- continue;
84
- }
85
- }
86
- }
87
+ ret = backup_loop(s);
28
}
88
}
29
89
30
+ return 0;
90
notifier_with_return_remove(&s->before_write);
31
+}
32
+
33
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
34
+{
35
+ int ret = 0;
36
+
37
+ ret = bdrv_can_set_read_only(bs, read_only, errp);
38
+ if (ret < 0) {
39
+ return ret;
40
+ }
41
+
42
bs->read_only = read_only;
43
return 0;
44
}
45
diff --git a/include/block/block.h b/include/block/block.h
46
index XXXXXXX..XXXXXXX 100644
47
--- a/include/block/block.h
48
+++ b/include/block/block.h
49
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
50
int64_t sector_num, int nb_sectors, int *pnum);
51
52
bool bdrv_is_read_only(BlockDriverState *bs);
53
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
54
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
55
bool bdrv_is_sg(BlockDriverState *bs);
56
bool bdrv_is_inserted(BlockDriverState *bs);
57
--
91
--
58
2.9.3
92
2.21.0
59
93
60
94
diff view generated by jsdifflib
1
For the tests that use the common.qemu functions for running a QEMU
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
process, _cleanup_qemu must be called in the exit function.
3
2
4
If it is not, if the qemu process aborts, then not all of the droppings
3
Split out cluster_size calculation. Move copy-bitmap creation above
5
are cleaned up (e.g. pidfile, fifos).
4
block-job creation, as we are going to share it with upcoming
5
backup-top filter, which also should be created before actual block job
6
creation.
6
7
7
This updates those tests that did not have a cleanup in qemu-iotests.
8
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
Message-id: 20190429090842.57910-6-vsementsov@virtuozzo.com
10
[mreitz: Dropped a paragraph from the commit message that was left over
11
from a previous version]
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/backup.c | 82 ++++++++++++++++++++++++++++++++------------------
15
1 file changed, 52 insertions(+), 30 deletions(-)
8
16
9
(I swapped spaces for tabs in test 102 as well)
17
diff --git a/block/backup.c b/block/backup.c
10
18
index XXXXXXX..XXXXXXX 100644
11
Reported-by: Eric Blake <eblake@redhat.com>
19
--- a/block/backup.c
12
Reviewed-by: Eric Blake <eblake@redhat.com>
20
+++ b/block/backup.c
13
Signed-off-by: Jeff Cody <jcody@redhat.com>
21
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver backup_job_driver = {
14
Message-id: d59c2f6ad6c1da8b9b3c7f357c94a7122ccfc55a.1492544096.git.jcody@redhat.com
22
.drain = backup_drain,
15
---
23
};
16
tests/qemu-iotests/028 | 1 +
24
17
tests/qemu-iotests/094 | 11 ++++++++---
25
+static int64_t backup_calculate_cluster_size(BlockDriverState *target,
18
tests/qemu-iotests/102 | 5 +++--
26
+ Error **errp)
19
tests/qemu-iotests/109 | 1 +
20
tests/qemu-iotests/117 | 1 +
21
tests/qemu-iotests/130 | 1 +
22
tests/qemu-iotests/140 | 1 +
23
tests/qemu-iotests/141 | 1 +
24
tests/qemu-iotests/143 | 1 +
25
tests/qemu-iotests/156 | 1 +
26
10 files changed, 19 insertions(+), 5 deletions(-)
27
28
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
29
index XXXXXXX..XXXXXXX 100755
30
--- a/tests/qemu-iotests/028
31
+++ b/tests/qemu-iotests/028
32
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
33
34
_cleanup()
35
{
36
+ _cleanup_qemu
37
rm -f "${TEST_IMG}.copy"
38
_cleanup_test_img
39
}
40
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
41
index XXXXXXX..XXXXXXX 100755
42
--- a/tests/qemu-iotests/094
43
+++ b/tests/qemu-iotests/094
44
@@ -XXX,XX +XXX,XX @@ echo "QA output created by $seq"
45
here="$PWD"
46
status=1    # failure is the default!
47
48
-trap "exit \$status" 0 1 2 3 15
49
+_cleanup()
50
+{
27
+{
51
+ _cleanup_qemu
28
+ int ret;
52
+ _cleanup_test_img
29
+ BlockDriverInfo bdi;
53
+ rm -f "$TEST_DIR/source.$IMGFMT"
30
+
31
+ /*
32
+ * If there is no backing file on the target, we cannot rely on COW if our
33
+ * backup cluster size is smaller than the target cluster size. Even for
34
+ * targets with a backing file, try to avoid COW if possible.
35
+ */
36
+ ret = bdrv_get_info(target, &bdi);
37
+ if (ret == -ENOTSUP && !target->backing) {
38
+ /* Cluster size is not defined */
39
+ warn_report("The target block device doesn't provide "
40
+ "information about the block size and it doesn't have a "
41
+ "backing file. The default block size of %u bytes is "
42
+ "used. If the actual block size of the target exceeds "
43
+ "this default, the backup may be unusable",
44
+ BACKUP_CLUSTER_SIZE_DEFAULT);
45
+ return BACKUP_CLUSTER_SIZE_DEFAULT;
46
+ } else if (ret < 0 && !target->backing) {
47
+ error_setg_errno(errp, -ret,
48
+ "Couldn't determine the cluster size of the target image, "
49
+ "which has no backing file");
50
+ error_append_hint(errp,
51
+ "Aborting, since this may create an unusable destination image\n");
52
+ return ret;
53
+ } else if (ret < 0 && target->backing) {
54
+ /* Not fatal; just trudge on ahead. */
55
+ return BACKUP_CLUSTER_SIZE_DEFAULT;
56
+ }
57
+
58
+ return MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
54
+}
59
+}
55
+
60
+
56
+trap "_cleanup; exit \$status" 0 1 2 3 15
61
BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
57
62
BlockDriverState *target, int64_t speed,
58
# get standard environment, filters and checks
63
MirrorSyncMode sync_mode, BdrvDirtyBitmap *sync_bitmap,
59
. ./common.rc
64
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
60
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
65
JobTxn *txn, Error **errp)
61
62
wait=1 _cleanup_qemu
63
64
-_cleanup_test_img
65
-rm -f "$TEST_DIR/source.$IMGFMT"
66
67
# success, all done
68
echo '*** done'
69
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
70
index XXXXXXX..XXXXXXX 100755
71
--- a/tests/qemu-iotests/102
72
+++ b/tests/qemu-iotests/102
73
@@ -XXX,XX +XXX,XX @@ seq=$(basename $0)
74
echo "QA output created by $seq"
75
76
here=$PWD
77
-status=1    # failure is the default!
78
+status=1 # failure is the default!
79
80
_cleanup()
81
{
66
{
82
-    _cleanup_test_img
67
int64_t len;
83
+ _cleanup_qemu
68
- BlockDriverInfo bdi;
84
+ _cleanup_test_img
69
BackupBlockJob *job = NULL;
85
}
70
int ret;
86
trap "_cleanup; exit \$status" 0 1 2 3 15
71
+ int64_t cluster_size;
87
72
+ HBitmap *copy_bitmap = NULL;
88
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
73
89
index XXXXXXX..XXXXXXX 100755
74
assert(bs);
90
--- a/tests/qemu-iotests/109
75
assert(target);
91
+++ b/tests/qemu-iotests/109
76
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
92
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
77
goto error;
93
78
}
94
_cleanup()
79
95
{
80
+ cluster_size = backup_calculate_cluster_size(target, errp);
96
+ _cleanup_qemu
81
+ if (cluster_size < 0) {
97
rm -f $TEST_IMG.src
82
+ goto error;
98
    _cleanup_test_img
83
+ }
99
}
84
+
100
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
85
+ copy_bitmap = hbitmap_alloc(len, ctz32(cluster_size));
101
index XXXXXXX..XXXXXXX 100755
86
+
102
--- a/tests/qemu-iotests/117
87
/* job->len is fixed, so we can't allow resize */
103
+++ b/tests/qemu-iotests/117
88
job = block_job_create(job_id, &backup_job_driver, txn, bs,
104
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
89
BLK_PERM_CONSISTENT_READ,
105
90
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
106
_cleanup()
91
107
{
92
/* Detect image-fleecing (and similar) schemes */
108
+ _cleanup_qemu
93
job->serialize_target_writes = bdrv_chain_contains(target, bs);
109
    _cleanup_test_img
94
-
110
}
95
- /* If there is no backing file on the target, we cannot rely on COW if our
111
trap "_cleanup; exit \$status" 0 1 2 3 15
96
- * backup cluster size is smaller than the target cluster size. Even for
112
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
97
- * targets with a backing file, try to avoid COW if possible. */
113
index XXXXXXX..XXXXXXX 100755
98
- ret = bdrv_get_info(target, &bdi);
114
--- a/tests/qemu-iotests/130
99
- if (ret == -ENOTSUP && !target->backing) {
115
+++ b/tests/qemu-iotests/130
100
- /* Cluster size is not defined */
116
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
101
- warn_report("The target block device doesn't provide "
117
102
- "information about the block size and it doesn't have a "
118
_cleanup()
103
- "backing file. The default block size of %u bytes is "
119
{
104
- "used. If the actual block size of the target exceeds "
120
+ _cleanup_qemu
105
- "this default, the backup may be unusable",
121
_cleanup_test_img
106
- BACKUP_CLUSTER_SIZE_DEFAULT);
122
}
107
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
123
trap "_cleanup; exit \$status" 0 1 2 3 15
108
- } else if (ret < 0 && !target->backing) {
124
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
109
- error_setg_errno(errp, -ret,
125
index XXXXXXX..XXXXXXX 100755
110
- "Couldn't determine the cluster size of the target image, "
126
--- a/tests/qemu-iotests/140
111
- "which has no backing file");
127
+++ b/tests/qemu-iotests/140
112
- error_append_hint(errp,
128
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
113
- "Aborting, since this may create an unusable destination image\n");
129
114
- goto error;
130
_cleanup()
115
- } else if (ret < 0 && target->backing) {
131
{
116
- /* Not fatal; just trudge on ahead. */
132
+ _cleanup_qemu
117
- job->cluster_size = BACKUP_CLUSTER_SIZE_DEFAULT;
133
_cleanup_test_img
118
- } else {
134
rm -f "$TEST_DIR/nbd"
119
- job->cluster_size = MAX(BACKUP_CLUSTER_SIZE_DEFAULT, bdi.cluster_size);
135
}
120
- }
136
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
121
-
137
index XXXXXXX..XXXXXXX 100755
122
- job->copy_bitmap = hbitmap_alloc(len, ctz32(job->cluster_size));
138
--- a/tests/qemu-iotests/141
123
+ job->cluster_size = cluster_size;
139
+++ b/tests/qemu-iotests/141
124
+ job->copy_bitmap = copy_bitmap;
140
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
125
+ copy_bitmap = NULL;
141
126
job->use_copy_range = true;
142
_cleanup()
127
job->copy_range_size = MIN_NON_ZERO(blk_get_max_transfer(job->common.blk),
143
{
128
blk_get_max_transfer(job->target));
144
+ _cleanup_qemu
129
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
145
_cleanup_test_img
130
return &job->common;
146
rm -f "$TEST_DIR/{b,m,o}.$IMGFMT"
131
147
}
132
error:
148
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
133
+ if (copy_bitmap) {
149
index XXXXXXX..XXXXXXX 100755
134
+ assert(!job || !job->copy_bitmap);
150
--- a/tests/qemu-iotests/143
135
+ hbitmap_free(copy_bitmap);
151
+++ b/tests/qemu-iotests/143
136
+ }
152
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
137
if (sync_bitmap) {
153
138
bdrv_reclaim_dirty_bitmap(bs, sync_bitmap, NULL);
154
_cleanup()
139
}
155
{
156
+ _cleanup_qemu
157
rm -f "$TEST_DIR/nbd"
158
}
159
trap "_cleanup; exit \$status" 0 1 2 3 15
160
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
161
index XXXXXXX..XXXXXXX 100755
162
--- a/tests/qemu-iotests/156
163
+++ b/tests/qemu-iotests/156
164
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
165
166
_cleanup()
167
{
168
+ _cleanup_qemu
169
rm -f "$TEST_IMG{,.target}{,.backing,.overlay}"
170
}
171
trap "_cleanup; exit \$status" 0 1 2 3 15
172
--
140
--
173
2.9.3
141
2.21.0
174
142
175
143
diff view generated by jsdifflib
1
Signed-off-by: Jeff Cody <jcody@redhat.com>
1
From: Alberto Garcia <berto@igalia.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
2
3
Reviewed-by: John Snow <jsnow@redhat.com>
3
bdrv_unref_child() does the following things:
4
Message-id: 00aed7ffdd7be4b9ed9ce1007d50028a72b34ebe.1491597120.git.jcody@redhat.com
4
5
- Updates the child->bs->inherits_from pointer.
6
- Calls bdrv_detach_child() to remove the BdrvChild from bs->children.
7
- Calls bdrv_unref() to unref the child BlockDriverState.
8
9
When bdrv_unref_child() was introduced in commit 33a604075c it was not
10
used in bdrv_close() because the drivers that had additional children
11
(like quorum or blkverify) had already called bdrv_unref() on their
12
children during their own close functions.
13
14
This was changed later (in 0bd6e91a7e for quorum, in 3e586be0b2 for
15
blkverify) so there's no reason not to use bdrv_unref_child() in
16
bdrv_close() anymore.
17
18
After this there's also no need to remove bs->backing and bs->file
19
separately from the rest of the children, so bdrv_close() can be
20
simplified.
21
22
Now bdrv_close() unrefs all children (before this patch it was only
23
bs->file and bs->backing). As a result, none of the callers of
24
brvd_attach_child() should remove their reference to child_bs (because
25
this function effectively steals that reference). This patch updates a
26
couple of tests that were doing their own bdrv_unref().
27
28
Signed-off-by: Alberto Garcia <berto@igalia.com>
29
Message-id: 6d1d5feaa53aa1ab127adb73d605dc4503e3abd5.1557754872.git.berto@igalia.com
30
[mreitz: s/where/were/]
31
Signed-off-by: Max Reitz <mreitz@redhat.com>
5
---
32
---
6
block.c | 14 ++++++++------
33
block.c | 16 +++-------------
7
1 file changed, 8 insertions(+), 6 deletions(-)
34
tests/test-bdrv-drain.c | 6 ------
35
tests/test-bdrv-graph-mod.c | 1 -
36
3 files changed, 3 insertions(+), 20 deletions(-)
8
37
9
diff --git a/block.c b/block.c
38
diff --git a/block.c b/block.c
10
index XXXXXXX..XXXXXXX 100644
39
index XXXXXXX..XXXXXXX 100644
11
--- a/block.c
40
--- a/block.c
12
+++ b/block.c
41
+++ b/block.c
13
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
42
@@ -XXX,XX +XXX,XX @@ static void bdrv_close(BlockDriverState *bs)
14
BlockDriver *drv;
43
bs->drv = NULL;
15
QemuOpts *opts;
16
const char *value;
17
+ bool read_only;
18
19
assert(reopen_state != NULL);
20
assert(reopen_state->bs->drv != NULL);
21
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
22
qdict_put(reopen_state->options, "driver", qstring_from_str(value));
23
}
44
}
24
45
25
- /* if we are to stay read-only, do not allow permission change
46
- bdrv_set_backing_hd(bs, NULL, &error_abort);
26
- * to r/w */
47
-
27
- if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
48
- if (bs->file != NULL) {
28
- reopen_state->flags & BDRV_O_RDWR) {
49
- bdrv_unref_child(bs, bs->file);
29
- error_setg(errp, "Node '%s' is read only",
50
- bs->file = NULL;
30
- bdrv_get_device_or_node_name(reopen_state->bs));
51
- }
31
+ /* If we are to stay read-only, do not allow permission change
52
-
32
+ * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
53
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
33
+ * not set, or if the BDS still has copy_on_read enabled */
54
- /* TODO Remove bdrv_unref() from drivers' close function and use
34
+ read_only = !(reopen_state->flags & BDRV_O_RDWR);
55
- * bdrv_unref_child() here */
35
+ ret = bdrv_can_set_read_only(reopen_state->bs, read_only, &local_err);
56
- if (child->bs->inherits_from == bs) {
36
+ if (local_err) {
57
- child->bs->inherits_from = NULL;
37
+ error_propagate(errp, local_err);
58
- }
38
goto error;
59
- bdrv_detach_child(child);
60
+ bdrv_unref_child(bs, child);
39
}
61
}
40
62
63
+ bs->backing = NULL;
64
+ bs->file = NULL;
65
g_free(bs->opaque);
66
bs->opaque = NULL;
67
atomic_set(&bs->copy_on_read, 0);
68
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/tests/test-bdrv-drain.c
71
+++ b/tests/test-bdrv-drain.c
72
@@ -XXX,XX +XXX,XX @@ static void test_detach_indirect(bool by_parent_cb)
73
bdrv_unref(parent_b);
74
blk_unref(blk);
75
76
- /* XXX Once bdrv_close() unref's children instead of just detaching them,
77
- * this won't be necessary any more. */
78
- bdrv_unref(a);
79
- bdrv_unref(a);
80
- bdrv_unref(c);
81
-
82
g_assert_cmpint(a->refcnt, ==, 1);
83
g_assert_cmpint(b->refcnt, ==, 1);
84
g_assert_cmpint(c->refcnt, ==, 1);
85
diff --git a/tests/test-bdrv-graph-mod.c b/tests/test-bdrv-graph-mod.c
86
index XXXXXXX..XXXXXXX 100644
87
--- a/tests/test-bdrv-graph-mod.c
88
+++ b/tests/test-bdrv-graph-mod.c
89
@@ -XXX,XX +XXX,XX @@ static void test_update_perm_tree(void)
90
g_assert_nonnull(local_err);
91
error_free(local_err);
92
93
- bdrv_unref(bs);
94
blk_unref(root);
95
}
96
41
--
97
--
42
2.9.3
98
2.21.0
43
99
44
100
diff view generated by jsdifflib
1
A few block drivers will set the BDS read_only flag from their
1
From: Alberto Garcia <berto@igalia.com>
2
.bdrv_open() function. This means the bs->read_only flag could
3
be set after we enable copy_on_read, as the BDRV_O_COPY_ON_READ
4
flag check occurs prior to the call to bdrv->bdrv_open().
5
2
6
This adds an error return to bdrv_set_read_only(), and an error will be
3
A consequence of the previous patch is that bdrv_attach_child()
7
return if we try to set the BDS to read_only while copy_on_read is
4
transfers the reference to child_bs from the caller to parent_bs,
8
enabled.
5
which will drop it on bdrv_close() or when someone calls
6
bdrv_unref_child().
9
7
10
This patch also changes the behavior of vvfat. Before, vvfat could
8
But this only happens when bdrv_attach_child() succeeds. If it fails
11
override the drive 'readonly' flag with its own, internal 'rw' flag.
9
then the caller is responsible for dropping the reference to child_bs.
12
10
13
For instance, this -drive parameter would result in a writable image:
11
This patch makes bdrv_attach_child() take the reference also when
12
there is an error, freeing the caller for having to do it.
14
13
15
"-drive format=vvfat,dir=/tmp/vvfat,rw,if=virtio,readonly=on"
14
A similar situation happens with bdrv_root_attach_child(), so the
15
changes on this patch affect both functions.
16
16
17
This is not correct. Now, attempting to use the above -drive parameter
17
Signed-off-by: Alberto Garcia <berto@igalia.com>
18
will result in an error (i.e., 'rw' is incompatible with 'readonly=on').
18
Message-id: 20dfb3d9ccec559cdd1a9690146abad5d204a186.1557754872.git.berto@igalia.com
19
19
[mreitz: Removed now superfluous BdrvChild * variable in
20
Signed-off-by: Jeff Cody <jcody@redhat.com>
20
bdrv_open_child()]
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
21
Signed-off-by: Max Reitz <mreitz@redhat.com>
22
Reviewed-by: John Snow <jsnow@redhat.com>
23
Message-id: 0c5b4c1cc2c651471b131f21376dfd5ea24d2196.1491597120.git.jcody@redhat.com
24
---
22
---
25
block.c | 10 +++++++++-
23
block.c | 30 ++++++++++++++++++------------
26
block/bochs.c | 5 ++++-
24
block/block-backend.c | 3 +--
27
block/cloop.c | 5 ++++-
25
block/quorum.c | 1 -
28
block/dmg.c | 6 +++++-
26
blockjob.c | 2 +-
29
block/rbd.c | 11 ++++++++++-
27
4 files changed, 20 insertions(+), 16 deletions(-)
30
block/vvfat.c | 19 +++++++++++++++----
31
include/block/block.h | 2 +-
32
7 files changed, 48 insertions(+), 10 deletions(-)
33
28
34
diff --git a/block.c b/block.c
29
diff --git a/block.c b/block.c
35
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
36
--- a/block.c
31
--- a/block.c
37
+++ b/block.c
32
+++ b/block.c
38
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
33
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
39
}
34
}
40
}
35
}
41
36
42
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
37
+/*
43
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
38
+ * This function steals the reference to child_bs from the caller.
39
+ * That reference is later dropped by bdrv_root_unref_child().
40
+ *
41
+ * On failure NULL is returned, errp is set and the reference to
42
+ * child_bs is also dropped.
43
+ */
44
BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
45
const char *child_name,
46
const BdrvChildRole *child_role,
47
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
48
ret = bdrv_check_update_perm(child_bs, NULL, perm, shared_perm, NULL, errp);
49
if (ret < 0) {
50
bdrv_abort_perm_update(child_bs);
51
+ bdrv_unref(child_bs);
52
return NULL;
53
}
54
55
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_root_attach_child(BlockDriverState *child_bs,
56
return child;
57
}
58
59
+/*
60
+ * This function transfers the reference to child_bs from the caller
61
+ * to parent_bs. That reference is later dropped by parent_bs on
62
+ * bdrv_close() or if someone calls bdrv_unref_child().
63
+ *
64
+ * On failure NULL is returned, errp is set and the reference to
65
+ * child_bs is also dropped.
66
+ */
67
BdrvChild *bdrv_attach_child(BlockDriverState *parent_bs,
68
BlockDriverState *child_bs,
69
const char *child_name,
70
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
71
/* If backing_hd was already part of bs's backing chain, and
72
* inherits_from pointed recursively to bs then let's update it to
73
* point directly to bs (else it will become NULL). */
74
- if (update_inherits_from) {
75
+ if (bs->backing && update_inherits_from) {
76
backing_hd->inherits_from = bs;
77
}
78
- if (!bs->backing) {
79
- bdrv_unref(backing_hd);
80
- }
81
82
out:
83
bdrv_refresh_limits(bs, NULL);
84
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
85
const BdrvChildRole *child_role,
86
bool allow_none, Error **errp)
44
{
87
{
45
+ /* Do not set read_only if copy_on_read is enabled */
88
- BdrvChild *c;
46
+ if (bs->copy_on_read && read_only) {
89
BlockDriverState *bs;
47
+ error_setg(errp, "Can't set node '%s' to r/o with copy-on-read enabled",
90
48
+ bdrv_get_device_or_node_name(bs));
91
bs = bdrv_open_child_bs(filename, options, bdref_key, parent, child_role,
49
+ return -EINVAL;
92
@@ -XXX,XX +XXX,XX @@ BdrvChild *bdrv_open_child(const char *filename,
50
+ }
93
return NULL;
51
+
94
}
52
bs->read_only = read_only;
95
53
+ return 0;
96
- c = bdrv_attach_child(parent, bs, bdref_key, child_role, errp);
97
- if (!c) {
98
- bdrv_unref(bs);
99
- return NULL;
100
- }
101
-
102
- return c;
103
+ return bdrv_attach_child(parent, bs, bdref_key, child_role, errp);
54
}
104
}
55
105
56
void bdrv_get_full_backing_filename_from_filename(const char *backed,
106
/* TODO Future callers may need to specify parent/child_role in order for
57
diff --git a/block/bochs.c b/block/bochs.c
107
diff --git a/block/block-backend.c b/block/block-backend.c
58
index XXXXXXX..XXXXXXX 100644
108
index XXXXXXX..XXXXXXX 100644
59
--- a/block/bochs.c
109
--- a/block/block-backend.c
60
+++ b/block/bochs.c
110
+++ b/block/block-backend.c
61
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
111
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new_open(const char *filename, const char *reference,
62
return -EINVAL;
112
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
113
perm, BLK_PERM_ALL, blk, errp);
114
if (!blk->root) {
115
- bdrv_unref(bs);
116
blk_unref(blk);
117
return NULL;
63
}
118
}
64
119
@@ -XXX,XX +XXX,XX @@ void blk_remove_bs(BlockBackend *blk)
65
- bdrv_set_read_only(bs, true); /* no write support yet */
120
int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
66
+ ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
121
{
67
+ if (ret < 0) {
122
ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
68
+ return ret;
123
+ bdrv_ref(bs);
69
+ }
124
blk->root = bdrv_root_attach_child(bs, "root", &child_root,
70
125
blk->perm, blk->shared_perm, blk, errp);
71
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
126
if (blk->root == NULL) {
72
if (ret < 0) {
127
return -EPERM;
73
diff --git a/block/cloop.c b/block/cloop.c
128
}
129
- bdrv_ref(bs);
130
131
notifier_list_notify(&blk->insert_bs_notifiers, blk);
132
if (tgm->throttle_state) {
133
diff --git a/block/quorum.c b/block/quorum.c
74
index XXXXXXX..XXXXXXX 100644
134
index XXXXXXX..XXXXXXX 100644
75
--- a/block/cloop.c
135
--- a/block/quorum.c
76
+++ b/block/cloop.c
136
+++ b/block/quorum.c
77
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
137
@@ -XXX,XX +XXX,XX @@ static void quorum_add_child(BlockDriverState *bs, BlockDriverState *child_bs,
78
return -EINVAL;
138
child = bdrv_attach_child(bs, child_bs, indexstr, &child_format, errp);
139
if (child == NULL) {
140
s->next_child_index--;
141
- bdrv_unref(child_bs);
142
goto out;
79
}
143
}
80
144
s->children = g_renew(BdrvChild *, s->children, s->num_children + 1);
81
- bdrv_set_read_only(bs, true);
145
diff --git a/blockjob.c b/blockjob.c
82
+ ret = bdrv_set_read_only(bs, true, errp);
83
+ if (ret < 0) {
84
+ return ret;
85
+ }
86
87
/* read header */
88
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
89
diff --git a/block/dmg.c b/block/dmg.c
90
index XXXXXXX..XXXXXXX 100644
146
index XXXXXXX..XXXXXXX 100644
91
--- a/block/dmg.c
147
--- a/blockjob.c
92
+++ b/block/dmg.c
148
+++ b/blockjob.c
93
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
149
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
94
return -EINVAL;
150
{
151
BdrvChild *c;
152
153
+ bdrv_ref(bs);
154
c = bdrv_root_attach_child(bs, name, &child_job, perm, shared_perm,
155
job, errp);
156
if (c == NULL) {
157
@@ -XXX,XX +XXX,XX @@ int block_job_add_bdrv(BlockJob *job, const char *name, BlockDriverState *bs,
95
}
158
}
96
159
97
+ ret = bdrv_set_read_only(bs, true, errp);
160
job->nodes = g_slist_prepend(job->nodes, c);
98
+ if (ret < 0) {
161
- bdrv_ref(bs);
99
+ return ret;
162
bdrv_op_block_all(bs, job->blocker);
100
+ }
163
101
+
102
block_module_load_one("dmg-bz2");
103
- bdrv_set_read_only(bs, true);
104
105
s->n_chunks = 0;
106
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
107
diff --git a/block/rbd.c b/block/rbd.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/block/rbd.c
110
+++ b/block/rbd.c
111
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
112
goto failed_shutdown;
113
}
114
115
+ /* rbd_open is always r/w */
116
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
117
if (r < 0) {
118
error_setg_errno(errp, -r, "error reading header from %s", s->name);
119
goto failed_open;
120
}
121
122
- bdrv_set_read_only(bs, (s->snap != NULL));
123
+ /* If we are using an rbd snapshot, we must be r/o, otherwise
124
+ * leave as-is */
125
+ if (s->snap != NULL) {
126
+ r = bdrv_set_read_only(bs, true, &local_err);
127
+ if (r < 0) {
128
+ error_propagate(errp, local_err);
129
+ goto failed_open;
130
+ }
131
+ }
132
133
qemu_opts_del(opts);
134
return 0;
164
return 0;
135
diff --git a/block/vvfat.c b/block/vvfat.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/vvfat.c
138
+++ b/block/vvfat.c
139
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
140
141
s->current_cluster=0xffffffff;
142
143
- /* read only is the default for safety */
144
- bdrv_set_read_only(bs, true);
145
s->qcow = NULL;
146
s->qcow_filename = NULL;
147
s->fat2 = NULL;
148
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
149
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
150
151
if (qemu_opt_get_bool(opts, "rw", false)) {
152
- ret = enable_write_target(bs, errp);
153
+ if (!bdrv_is_read_only(bs)) {
154
+ ret = enable_write_target(bs, errp);
155
+ if (ret < 0) {
156
+ goto fail;
157
+ }
158
+ } else {
159
+ ret = -EPERM;
160
+ error_setg(errp,
161
+ "Unable to set VVFAT to 'rw' when drive is read-only");
162
+ goto fail;
163
+ }
164
+ } else {
165
+ /* read only is the default for safety */
166
+ ret = bdrv_set_read_only(bs, true, &local_err);
167
if (ret < 0) {
168
+ error_propagate(errp, local_err);
169
goto fail;
170
}
171
- bdrv_set_read_only(bs, false);
172
}
173
174
bs->total_sectors = cyls * heads * secs;
175
diff --git a/include/block/block.h b/include/block/block.h
176
index XXXXXXX..XXXXXXX 100644
177
--- a/include/block/block.h
178
+++ b/include/block/block.h
179
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
180
int64_t sector_num, int nb_sectors, int *pnum);
181
182
bool bdrv_is_read_only(BlockDriverState *bs);
183
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
184
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
185
bool bdrv_is_sg(BlockDriverState *bs);
186
bool bdrv_is_inserted(BlockDriverState *bs);
187
int bdrv_media_changed(BlockDriverState *bs);
188
--
165
--
189
2.9.3
166
2.21.0
190
167
191
168
diff view generated by jsdifflib
New patch
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
1
2
3
In safe mode we open the entire chain, including the parent backing
4
file of the rebased file.
5
Do not open a new BlockBackend for the parent backing file, which
6
saves opening the rest of the chain twice, which for long chains
7
saves many "pricy" bdrv_open() calls.
8
9
Permissions for blk_new() were copied from blk_new_open() when
10
flags = 0.
11
12
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
13
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
14
Signed-off-by: Sagi Amit <sagi.amit@oracle.com>
15
Co-developed-by: Sagi Amit <sagi.amit@oracle.com>
16
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
17
Message-id: 20190523163337.4497-2-shmuel.eiderman@oracle.com
18
Signed-off-by: Max Reitz <mreitz@redhat.com>
19
---
20
qemu-img.c | 29 +++++++++--------------------
21
1 file changed, 9 insertions(+), 20 deletions(-)
22
23
diff --git a/qemu-img.c b/qemu-img.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/qemu-img.c
26
+++ b/qemu-img.c
27
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
28
29
/* For safe rebasing we need to compare old and new backing file */
30
if (!unsafe) {
31
- char backing_name[PATH_MAX];
32
QDict *options = NULL;
33
+ BlockDriverState *base_bs = backing_bs(bs);
34
35
- if (bs->backing) {
36
- if (bs->backing_format[0] != '\0') {
37
- options = qdict_new();
38
- qdict_put_str(options, "driver", bs->backing_format);
39
- }
40
-
41
- if (force_share) {
42
- if (!options) {
43
- options = qdict_new();
44
- }
45
- qdict_put_bool(options, BDRV_OPT_FORCE_SHARE, true);
46
- }
47
- bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
48
- blk_old_backing = blk_new_open(backing_name, NULL,
49
- options, src_flags, &local_err);
50
- if (!blk_old_backing) {
51
+ if (base_bs) {
52
+ blk_old_backing = blk_new(BLK_PERM_CONSISTENT_READ,
53
+ BLK_PERM_ALL);
54
+ ret = blk_insert_bs(blk_old_backing, base_bs,
55
+ &local_err);
56
+ if (ret < 0) {
57
error_reportf_err(local_err,
58
- "Could not open old backing file '%s': ",
59
- backing_name);
60
- ret = -1;
61
+ "Could not reuse old backing file '%s': ",
62
+ base_bs->filename);
63
goto out;
64
}
65
} else {
66
--
67
2.21.0
68
69
diff view generated by jsdifflib
New patch
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
1
2
3
In the following case:
4
5
(base) A <- B <- C (tip)
6
7
when running:
8
9
qemu-img rebase -b A C
10
11
QEMU would read all sectors not allocated in the file being rebased (C)
12
and compare them to the new base image (A), regardless of whether they
13
were changed or even allocated anywhere along the chain between the new
14
base and the top image (B). This causes many unneeded reads when
15
rebasing an image which represents a small diff of a large disk, as it
16
would read most of the disk's sectors.
17
18
Instead, use bdrv_is_allocated_above() to reduce the number of
19
unnecessary reads.
20
21
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
22
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
23
Signed-off-by: Eyal Moscovici <eyal.moscovici@oracle.com>
24
Message-id: 20190523163337.4497-3-shmuel.eiderman@oracle.com
25
Signed-off-by: Max Reitz <mreitz@redhat.com>
26
---
27
qemu-img.c | 25 ++++++++++++++++++++++++-
28
1 file changed, 24 insertions(+), 1 deletion(-)
29
30
diff --git a/qemu-img.c b/qemu-img.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/qemu-img.c
33
+++ b/qemu-img.c
34
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
35
BlockBackend *blk = NULL, *blk_old_backing = NULL, *blk_new_backing = NULL;
36
uint8_t *buf_old = NULL;
37
uint8_t *buf_new = NULL;
38
- BlockDriverState *bs = NULL;
39
+ BlockDriverState *bs = NULL, *prefix_chain_bs = NULL;
40
char *filename;
41
const char *fmt, *cache, *src_cache, *out_basefmt, *out_baseimg;
42
int c, flags, src_flags, ret;
43
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
44
goto out;
45
}
46
47
+ /*
48
+ * Find out whether we rebase an image on top of a previous image
49
+ * in its chain.
50
+ */
51
+ prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
52
+
53
blk_new_backing = blk_new_open(out_real_path, NULL,
54
options, src_flags, &local_err);
55
g_free(out_real_path);
56
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
57
continue;
58
}
59
60
+ if (prefix_chain_bs) {
61
+ /*
62
+ * If cluster wasn't changed since prefix_chain, we don't need
63
+ * to take action
64
+ */
65
+ ret = bdrv_is_allocated_above(backing_bs(bs), prefix_chain_bs,
66
+ offset, n, &n);
67
+ if (ret < 0) {
68
+ error_report("error while reading image metadata: %s",
69
+ strerror(-ret));
70
+ goto out;
71
+ }
72
+ if (!ret) {
73
+ continue;
74
+ }
75
+ }
76
+
77
/*
78
* Read old and new backing file and take into consideration that
79
* backing files may be smaller than the COW image.
80
--
81
2.21.0
82
83
diff view generated by jsdifflib
New patch
1
From: Sam Eiderman <shmuel.eiderman@oracle.com>
1
2
3
If a chain was detected, don't open a new BlockBackend from the target
4
backing file which will create a new BlockDriverState. Instead, create
5
an empty BlockBackend and attach the already open BlockDriverState.
6
7
Permissions for blk_new() were copied from blk_new_open() when
8
flags = 0.
9
10
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
11
Reviewed-by: Eyal Moscovici <eyal.moscovici@oracle.com>
12
Signed-off-by: Sagi Amit <sagi.amit@oracle.com>
13
Co-developed-by: Sagi Amit <sagi.amit@oracle.com>
14
Signed-off-by: Sam Eiderman <shmuel.eiderman@oracle.com>
15
Message-id: 20190523163337.4497-4-shmuel.eiderman@oracle.com
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
qemu-img.c | 33 +++++++++++++++++++++++----------
19
1 file changed, 23 insertions(+), 10 deletions(-)
20
21
diff --git a/qemu-img.c b/qemu-img.c
22
index XXXXXXX..XXXXXXX 100644
23
--- a/qemu-img.c
24
+++ b/qemu-img.c
25
@@ -XXX,XX +XXX,XX @@ static int img_rebase(int argc, char **argv)
26
* in its chain.
27
*/
28
prefix_chain_bs = bdrv_find_backing_image(bs, out_real_path);
29
-
30
- blk_new_backing = blk_new_open(out_real_path, NULL,
31
- options, src_flags, &local_err);
32
- g_free(out_real_path);
33
- if (!blk_new_backing) {
34
- error_reportf_err(local_err,
35
- "Could not open new backing file '%s': ",
36
- out_baseimg);
37
- ret = -1;
38
- goto out;
39
+ if (prefix_chain_bs) {
40
+ g_free(out_real_path);
41
+ blk_new_backing = blk_new(BLK_PERM_CONSISTENT_READ,
42
+ BLK_PERM_ALL);
43
+ ret = blk_insert_bs(blk_new_backing, prefix_chain_bs,
44
+ &local_err);
45
+ if (ret < 0) {
46
+ error_reportf_err(local_err,
47
+ "Could not reuse backing file '%s': ",
48
+ out_baseimg);
49
+ goto out;
50
+ }
51
+ } else {
52
+ blk_new_backing = blk_new_open(out_real_path, NULL,
53
+ options, src_flags, &local_err);
54
+ g_free(out_real_path);
55
+ if (!blk_new_backing) {
56
+ error_reportf_err(local_err,
57
+ "Could not open new backing file '%s': ",
58
+ out_baseimg);
59
+ ret = -1;
60
+ goto out;
61
+ }
62
}
63
}
64
}
65
--
66
2.21.0
67
68
diff view generated by jsdifflib
New patch
1
1
From: Anton Nefedov <anton.nefedov@virtuozzo.com>
2
3
If COW areas of the newly allocated clusters are zeroes on the backing
4
image, efficient bdrv_write_zeroes(flags=BDRV_REQ_NO_FALLBACK) can be
5
used on the whole cluster instead of writing explicit zero buffers later
6
in perform_cow().
7
8
iotest 060:
9
write to the discarded cluster does not trigger COW anymore.
10
Use a backing image instead.
11
12
Signed-off-by: Anton Nefedov <anton.nefedov@virtuozzo.com>
13
Message-id: 20190516142749.81019-2-anton.nefedov@virtuozzo.com
14
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
15
Reviewed-by: Alberto Garcia <berto@igalia.com>
16
Signed-off-by: Max Reitz <mreitz@redhat.com>
17
---
18
qapi/block-core.json | 4 +-
19
block/qcow2.h | 6 +++
20
block/qcow2-cluster.c | 2 +-
21
block/qcow2.c | 85 ++++++++++++++++++++++++++++++++++++++
22
block/trace-events | 1 +
23
tests/qemu-iotests/060 | 7 +++-
24
tests/qemu-iotests/060.out | 5 ++-
25
7 files changed, 106 insertions(+), 4 deletions(-)
26
27
diff --git a/qapi/block-core.json b/qapi/block-core.json
28
index XXXXXXX..XXXXXXX 100644
29
--- a/qapi/block-core.json
30
+++ b/qapi/block-core.json
31
@@ -XXX,XX +XXX,XX @@
32
#
33
# @cor_write: a write due to copy-on-read (since 2.11)
34
#
35
+# @cluster_alloc_space: an allocation of file space for a cluster (since 4.1)
36
+#
37
# Since: 2.9
38
##
39
{ 'enum': 'BlkdebugEvent', 'prefix': 'BLKDBG',
40
@@ -XXX,XX +XXX,XX @@
41
'pwritev_rmw_tail', 'pwritev_rmw_after_tail', 'pwritev',
42
'pwritev_zero', 'pwritev_done', 'empty_image_prepare',
43
'l1_shrink_write_table', 'l1_shrink_free_l2_clusters',
44
- 'cor_write'] }
45
+ 'cor_write', 'cluster_alloc_space'] }
46
47
##
48
# @BlkdebugInjectErrorOptions:
49
diff --git a/block/qcow2.h b/block/qcow2.h
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block/qcow2.h
52
+++ b/block/qcow2.h
53
@@ -XXX,XX +XXX,XX @@ typedef struct QCowL2Meta
54
*/
55
Qcow2COWRegion cow_end;
56
57
+ /*
58
+ * Indicates that COW regions are already handled and do not require
59
+ * any more processing.
60
+ */
61
+ bool skip_cow;
62
+
63
/**
64
* The I/O vector with the data from the actual guest write request.
65
* If non-NULL, this is meant to be merged together with the data
66
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
67
index XXXXXXX..XXXXXXX 100644
68
--- a/block/qcow2-cluster.c
69
+++ b/block/qcow2-cluster.c
70
@@ -XXX,XX +XXX,XX @@ static int perform_cow(BlockDriverState *bs, QCowL2Meta *m)
71
assert(start->offset + start->nb_bytes <= end->offset);
72
assert(!m->data_qiov || m->data_qiov->size == data_bytes);
73
74
- if (start->nb_bytes == 0 && end->nb_bytes == 0) {
75
+ if ((start->nb_bytes == 0 && end->nb_bytes == 0) || m->skip_cow) {
76
return 0;
77
}
78
79
diff --git a/block/qcow2.c b/block/qcow2.c
80
index XXXXXXX..XXXXXXX 100644
81
--- a/block/qcow2.c
82
+++ b/block/qcow2.c
83
@@ -XXX,XX +XXX,XX @@ static bool merge_cow(uint64_t offset, unsigned bytes,
84
continue;
85
}
86
87
+ /* If COW regions are handled already, skip this too */
88
+ if (m->skip_cow) {
89
+ continue;
90
+ }
91
+
92
/* The data (middle) region must be immediately after the
93
* start region */
94
if (l2meta_cow_start(m) + m->cow_start.nb_bytes != offset) {
95
@@ -XXX,XX +XXX,XX @@ static bool merge_cow(uint64_t offset, unsigned bytes,
96
return false;
97
}
98
99
+static bool is_unallocated(BlockDriverState *bs, int64_t offset, int64_t bytes)
100
+{
101
+ int64_t nr;
102
+ return !bytes ||
103
+ (!bdrv_is_allocated_above(bs, NULL, offset, bytes, &nr) && nr == bytes);
104
+}
105
+
106
+static bool is_zero_cow(BlockDriverState *bs, QCowL2Meta *m)
107
+{
108
+ /*
109
+ * This check is designed for optimization shortcut so it must be
110
+ * efficient.
111
+ * Instead of is_zero(), use is_unallocated() as it is faster (but not
112
+ * as accurate and can result in false negatives).
113
+ */
114
+ return is_unallocated(bs, m->offset + m->cow_start.offset,
115
+ m->cow_start.nb_bytes) &&
116
+ is_unallocated(bs, m->offset + m->cow_end.offset,
117
+ m->cow_end.nb_bytes);
118
+}
119
+
120
+static int handle_alloc_space(BlockDriverState *bs, QCowL2Meta *l2meta)
121
+{
122
+ BDRVQcow2State *s = bs->opaque;
123
+ QCowL2Meta *m;
124
+
125
+ if (!(s->data_file->bs->supported_zero_flags & BDRV_REQ_NO_FALLBACK)) {
126
+ return 0;
127
+ }
128
+
129
+ if (bs->encrypted) {
130
+ return 0;
131
+ }
132
+
133
+ for (m = l2meta; m != NULL; m = m->next) {
134
+ int ret;
135
+
136
+ if (!m->cow_start.nb_bytes && !m->cow_end.nb_bytes) {
137
+ continue;
138
+ }
139
+
140
+ if (!is_zero_cow(bs, m)) {
141
+ continue;
142
+ }
143
+
144
+ /*
145
+ * instead of writing zero COW buffers,
146
+ * efficiently zero out the whole clusters
147
+ */
148
+
149
+ ret = qcow2_pre_write_overlap_check(bs, 0, m->alloc_offset,
150
+ m->nb_clusters * s->cluster_size,
151
+ true);
152
+ if (ret < 0) {
153
+ return ret;
154
+ }
155
+
156
+ BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_SPACE);
157
+ ret = bdrv_co_pwrite_zeroes(s->data_file, m->alloc_offset,
158
+ m->nb_clusters * s->cluster_size,
159
+ BDRV_REQ_NO_FALLBACK);
160
+ if (ret < 0) {
161
+ if (ret != -ENOTSUP && ret != -EAGAIN) {
162
+ return ret;
163
+ }
164
+ continue;
165
+ }
166
+
167
+ trace_qcow2_skip_cow(qemu_coroutine_self(), m->offset, m->nb_clusters);
168
+ m->skip_cow = true;
169
+ }
170
+ return 0;
171
+}
172
+
173
static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
174
uint64_t bytes, QEMUIOVector *qiov,
175
int flags)
176
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow2_co_pwritev(BlockDriverState *bs, uint64_t offset,
177
qemu_iovec_add(&hd_qiov, cluster_data, cur_bytes);
178
}
179
180
+ /* Try to efficiently initialize the physical space with zeroes */
181
+ ret = handle_alloc_space(bs, l2meta);
182
+ if (ret < 0) {
183
+ goto out_unlocked;
184
+ }
185
+
186
/* If we need to do COW, check if it's possible to merge the
187
* writing of the guest data together with that of the COW regions.
188
* If it's not possible (or not necessary) then write the
189
diff --git a/block/trace-events b/block/trace-events
190
index XXXXXXX..XXXXXXX 100644
191
--- a/block/trace-events
192
+++ b/block/trace-events
193
@@ -XXX,XX +XXX,XX @@ qcow2_writev_done_part(void *co, int cur_bytes) "co %p cur_bytes %d"
194
qcow2_writev_data(void *co, uint64_t offset) "co %p offset 0x%" PRIx64
195
qcow2_pwrite_zeroes_start_req(void *co, int64_t offset, int count) "co %p offset 0x%" PRIx64 " count %d"
196
qcow2_pwrite_zeroes(void *co, int64_t offset, int count) "co %p offset 0x%" PRIx64 " count %d"
197
+qcow2_skip_cow(void *co, uint64_t offset, int nb_clusters) "co %p offset 0x%" PRIx64 " nb_clusters %d"
198
199
# qcow2-cluster.c
200
qcow2_alloc_clusters_offset(void *co, uint64_t offset, int bytes) "co %p offset 0x%" PRIx64 " bytes %d"
201
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
202
index XXXXXXX..XXXXXXX 100755
203
--- a/tests/qemu-iotests/060
204
+++ b/tests/qemu-iotests/060
205
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "$OPEN_RO" -c "read -P 1 0 512" | _filter_qemu_io
206
echo
207
echo "=== Testing overlap while COW is in flight ==="
208
echo
209
+BACKING_IMG=$TEST_IMG.base
210
+TEST_IMG=$BACKING_IMG _make_test_img 1G
211
+
212
+$QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io
213
+
214
# compat=0.10 is required in order to make the following discard actually
215
# unallocate the sector rather than make it a zero sector - we want COW, after
216
# all.
217
-IMGOPTS='compat=0.10' _make_test_img 1G
218
+IMGOPTS='compat=0.10' _make_test_img -b "$BACKING_IMG" 1G
219
# Write two clusters, the second one enforces creation of an L2 table after
220
# the first data cluster.
221
$QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io
222
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
223
index XXXXXXX..XXXXXXX 100644
224
--- a/tests/qemu-iotests/060.out
225
+++ b/tests/qemu-iotests/060.out
226
@@ -XXX,XX +XXX,XX @@ read 512/512 bytes at offset 0
227
228
=== Testing overlap while COW is in flight ===
229
230
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
231
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=1073741824
232
+wrote 65536/65536 bytes at offset 0
233
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
234
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file=TEST_DIR/t.IMGFMT.base
235
wrote 65536/65536 bytes at offset 0
236
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
237
wrote 65536/65536 bytes at offset 536870912
238
--
239
2.21.0
240
241
diff view generated by jsdifflib
New patch
1
From: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
1
2
3
Valgrind detects multiple issues in QEMU iotests when the memory is
4
used without being initialized. Valgrind may dump lots of unnecessary
5
reports what makes the memory issue analysis harder. Particularly,
6
that is true for the aligned bitmap directory and can be seen while
7
running the iotest #169. Padding the aligned space with zeros eases
8
the pain.
9
10
Signed-off-by: Andrey Shinkevich <andrey.shinkevich@virtuozzo.com>
11
Message-id: 1558961521-131620-1-git-send-email-andrey.shinkevich@virtuozzo.com
12
Signed-off-by: Max Reitz <mreitz@redhat.com>
13
---
14
block/qcow2-bitmap.c | 2 +-
15
1 file changed, 1 insertion(+), 1 deletion(-)
16
17
diff --git a/block/qcow2-bitmap.c b/block/qcow2-bitmap.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2-bitmap.c
20
+++ b/block/qcow2-bitmap.c
21
@@ -XXX,XX +XXX,XX @@ static int bitmap_list_store(BlockDriverState *bs, Qcow2BitmapList *bm_list,
22
dir_offset = *offset;
23
}
24
25
- dir = g_try_malloc(dir_size);
26
+ dir = g_try_malloc0(dir_size);
27
if (dir == NULL) {
28
return -ENOMEM;
29
}
30
--
31
2.21.0
32
33
diff view generated by jsdifflib
1
The BDRV_O_ALLOW_RDWR flag allows / prohibits the changing of
1
From: John Snow <jsnow@redhat.com>
2
the BDS 'read_only' state, but there are a few places where it
3
is ignored. In the bdrv_set_read_only() helper, make sure to
4
honor the flag.
5
2
6
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
We mandate that the source node must be a root node; but there's no reason
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
I am aware of that it needs to be restricted to such. In some cases, we need
8
Reviewed-by: John Snow <jsnow@redhat.com>
5
to make sure that there's a medium present, but in the general case we can
9
Message-id: be2e5fb2d285cbece2b6d06bed54a6f56520d251.1491597120.git.jcody@redhat.com
6
allow the backup job itself to do the graph checking.
7
8
This patch helps improve the error message when you try to backup from
9
the same node more than once, which is reflected in the change to test
10
056.
11
12
For backups with bitmaps, it will also show a better error message that
13
the bitmap is in use instead of giving you something cryptic like "need
14
a root node."
15
16
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1707303
17
Signed-off-by: John Snow <jsnow@redhat.com>
18
Message-id: 20190521210053.8864-1-jsnow@redhat.com
19
Signed-off-by: Max Reitz <mreitz@redhat.com>
10
---
20
---
11
block.c | 7 +++++++
21
blockdev.c | 7 ++++++-
12
1 file changed, 7 insertions(+)
22
tests/qemu-iotests/056 | 2 +-
23
2 files changed, 7 insertions(+), 2 deletions(-)
13
24
14
diff --git a/block.c b/block.c
25
diff --git a/blockdev.c b/blockdev.c
15
index XXXXXXX..XXXXXXX 100644
26
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
27
--- a/blockdev.c
17
+++ b/block.c
28
+++ b/blockdev.c
18
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
29
@@ -XXX,XX +XXX,XX @@ static BlockJob *do_drive_backup(DriveBackup *backup, JobTxn *txn,
19
return -EINVAL;
30
backup->compress = false;
20
}
31
}
21
32
22
+ /* Do not clear read_only if it is prohibited */
33
- bs = qmp_get_root_bs(backup->device, errp);
23
+ if (!read_only && !(bs->open_flags & BDRV_O_ALLOW_RDWR)) {
34
+ bs = bdrv_lookup_bs(backup->device, backup->device, errp);
24
+ error_setg(errp, "Node '%s' is read only",
35
if (!bs) {
25
+ bdrv_get_device_or_node_name(bs));
36
return NULL;
26
+ return -EPERM;
37
}
38
39
+ if (!bs->drv) {
40
+ error_setg(errp, "Device has no medium");
41
+ return NULL;
27
+ }
42
+ }
28
+
43
+
29
bs->read_only = read_only;
44
aio_context = bdrv_get_aio_context(bs);
30
return 0;
45
aio_context_acquire(aio_context);
31
}
46
47
diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
48
index XXXXXXX..XXXXXXX 100755
49
--- a/tests/qemu-iotests/056
50
+++ b/tests/qemu-iotests/056
51
@@ -XXX,XX +XXX,XX @@ class BackupTest(iotests.QMPTestCase):
52
res = self.vm.qmp('query-block-jobs')
53
self.assert_qmp(res, 'return[0]/status', 'concluded')
54
# Leave zombie job un-dismissed, observe a failure:
55
- res = self.qmp_backup_and_wait(serror='Need a root block node',
56
+ res = self.qmp_backup_and_wait(serror="Node 'drive0' is busy: block device is in use by block job: backup",
57
device='drive0', format=iotests.imgfmt,
58
sync='full', target=self.dest_img,
59
auto_dismiss=False)
32
--
60
--
33
2.9.3
61
2.21.0
34
62
35
63
diff view generated by jsdifflib