1
The following changes since commit eda1df0345f5a1e337e30367124dcb0e802bdfde:
1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-pflash-2019-03-11' into staging (2019-03-12 11:12:36 +0000)
3
Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20200430' into staging (2020-04-30 14:00:36 +0100)
4
4
5
are available in the Git repository at:
5
are available in the Git repository at:
6
6
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
7
git://repo.or.cz/qemu/kevin.git tags/for-upstream
8
8
9
for you to fetch changes up to c31dfeb02a1d155bdb961edeb61a137a589c174b:
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
10
10
11
qemu-iotests: Test the x-blockdev-reopen QMP command (2019-03-12 17:58:37 +0100)
11
qemu-storage-daemon: Fix non-string --object properties (2020-04-30 17:51:07 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches:
14
Block layer patches:
15
15
16
- file-posix: Make auto-read-only dynamic
16
- Fix resize (extending) of short overlays
17
- Add x-blockdev-reopen QMP command
17
- nvme: introduce PMR support from NVMe 1.4 spec
18
- Finalize block-latency-histogram QMP command
18
- qemu-storage-daemon: Fix non-string --object properties
19
- gluster: Build fixes for newer lib version
20
19
21
----------------------------------------------------------------
20
----------------------------------------------------------------
22
Alberto Garcia (13):
21
Alberto Garcia (1):
23
block: Allow freezing BdrvChild links
22
qcow2: Add incompatibility note between backing files and raw external data files
24
block: Freeze the backing chain for the duration of the commit job
25
block: Freeze the backing chain for the duration of the mirror job
26
block: Freeze the backing chain for the duration of the stream job
27
block: Add 'keep_old_opts' parameter to bdrv_reopen_queue()
28
block: Handle child references in bdrv_reopen_queue()
29
block: Allow omitting the 'backing' option in certain cases
30
block: Allow changing the backing file on reopen
31
block: Add a 'mutable_opts' field to BlockDriver
32
block: Add bdrv_reset_options_allowed()
33
block: Remove the AioContext parameter from bdrv_reopen_multiple()
34
block: Add an 'x-blockdev-reopen' QMP command
35
qemu-iotests: Test the x-blockdev-reopen QMP command
36
23
37
Keith Busch (1):
24
Andrzej Jakowski (1):
38
nvme: fix write zeroes offset and count
25
nvme: introduce PMR support from NVMe 1.4 spec
39
26
40
Kevin Wolf (10):
27
Kevin Wolf (12):
41
tests/virtio-blk-test: Disable auto-read-only
28
block: Add flags to BlockDriver.bdrv_co_truncate()
42
qemu-iotests: commit to backing file with auto-read-only
29
block: Add flags to bdrv(_co)_truncate()
43
block: Avoid useless local_err
30
block-backend: Add flags to blk_truncate()
44
block: Make permission changes in reopen less wrong
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
45
file-posix: Fix bdrv_open_flags() for snapshot=on
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
46
file-posix: Factor out raw_reconfigure_getfd()
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
47
file-posix: Store BDRVRawState.reopen_state during reopen
34
block: truncate: Don't make backing file data visible
48
file-posix: Lock new fd in raw_reopen_prepare()
35
iotests: Filter testfiles out in filter_img_info()
49
file-posix: Prepare permission code for fd switching
36
iotests: Test committing to short backing file
50
file-posix: Make auto-read-only dynamic
37
qcow2: Forward ZERO_WRITE flag for full preallocation
38
qom: Factor out user_creatable_add_dict()
39
qemu-storage-daemon: Fix non-string --object properties
51
40
52
Niels de Vos (1):
41
Paolo Bonzini (1):
53
gluster: the glfs_io_cbk callback function pointer adds pre/post stat args
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
54
43
55
Prasanna Kumar Kalever (1):
44
docs/interop/qcow2.txt | 3 +
56
gluster: Handle changed glfs_ftruncate signature
45
hw/block/nvme.h | 2 +
46
include/block/block.h | 5 +-
47
include/block/block_int.h | 10 +-
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
49
include/qom/object_interfaces.h | 16 +++
50
include/sysemu/block-backend.h | 2 +-
51
block.c | 3 +-
52
block/block-backend.c | 4 +-
53
block/commit.c | 4 +-
54
block/crypto.c | 7 +-
55
block/file-posix.c | 6 +-
56
block/file-win32.c | 2 +-
57
block/gluster.c | 1 +
58
block/io.c | 43 ++++++-
59
block/iscsi.c | 2 +-
60
block/mirror.c | 2 +-
61
block/nfs.c | 3 +-
62
block/parallels.c | 6 +-
63
block/qcow.c | 4 +-
64
block/qcow2-cluster.c | 2 +-
65
block/qcow2-refcount.c | 2 +-
66
block/qcow2.c | 73 +++++++++--
67
block/qed.c | 3 +-
68
block/raw-format.c | 6 +-
69
block/rbd.c | 1 +
70
block/sheepdog.c | 4 +-
71
block/ssh.c | 2 +-
72
block/vdi.c | 2 +-
73
block/vhdx-log.c | 2 +-
74
block/vhdx.c | 6 +-
75
block/vmdk.c | 8 +-
76
block/vpc.c | 2 +-
77
blockdev.c | 2 +-
78
hw/block/nvme.c | 109 ++++++++++++++++
79
qemu-img.c | 2 +-
80
qemu-io-cmds.c | 2 +-
81
qemu-storage-daemon.c | 4 +-
82
qom/object_interfaces.c | 31 +++++
83
qom/qom-qmp-cmds.c | 24 +---
84
tests/test-block-iothread.c | 9 +-
85
tests/qemu-iotests/iotests.py | 5 +-
86
hw/block/Makefile.objs | 2 +-
87
hw/block/trace-events | 4 +
88
tests/qemu-iotests/244 | 10 +-
89
tests/qemu-iotests/244.out | 9 +-
90
tests/qemu-iotests/274 | 155 +++++++++++++++++++++++
91
tests/qemu-iotests/274.out | 268 ++++++++++++++++++++++++++++++++++++++++
92
tests/qemu-iotests/group | 1 +
93
49 files changed, 951 insertions(+), 96 deletions(-)
94
create mode 100755 tests/qemu-iotests/274
95
create mode 100644 tests/qemu-iotests/274.out
57
96
58
Vladimir Sementsov-Ogievskiy (2):
59
qapi: move to QOM path for x-block-latency-histogram-set
60
qapi: drop x- from x-block-latency-histogram-set
61
97
62
qapi/block-core.json | 66 ++-
63
configure | 42 ++
64
include/block/block.h | 13 +-
65
include/block/block_int.h | 14 +
66
block.c | 440 +++++++++++++++++--
67
block/commit.c | 16 +
68
block/file-posix.c | 254 ++++++++---
69
block/gluster.c | 10 +-
70
block/mirror.c | 8 +
71
block/qapi.c | 12 +-
72
block/qcow2.c | 25 ++
73
block/raw-format.c | 3 +
74
block/replication.c | 7 +-
75
block/stream.c | 21 +
76
blockdev.c | 61 ++-
77
hw/block/nvme.c | 6 +-
78
qemu-io-cmds.c | 4 +-
79
tests/virtio-blk-test.c | 2 +-
80
tests/qemu-iotests/051 | 7 +
81
tests/qemu-iotests/051.out | 9 +
82
tests/qemu-iotests/051.pc.out | 9 +
83
tests/qemu-iotests/232 | 31 ++
84
tests/qemu-iotests/232.out | 32 +-
85
tests/qemu-iotests/245 | 991 ++++++++++++++++++++++++++++++++++++++++++
86
tests/qemu-iotests/245.out | 5 +
87
tests/qemu-iotests/group | 1 +
88
26 files changed, 1929 insertions(+), 160 deletions(-)
89
create mode 100644 tests/qemu-iotests/245
90
create mode 100644 tests/qemu-iotests/245.out
91
diff view generated by jsdifflib
Deleted patch
1
From: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
2
1
3
New versions of Glusters libgfapi.so have an updated glfs_ftruncate()
4
function that returns additional 'struct stat' structures to enable
5
advanced caching of attributes. This is useful for file servers, not so
6
much for QEMU. Nevertheless, the API has changed and needs to be
7
adopted.
8
9
Signed-off-by: Prasanna Kumar Kalever <prasanna.kalever@redhat.com>
10
Signed-off-by: Niels de Vos <ndevos@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
configure | 18 ++++++++++++++++++
14
block/gluster.c | 4 ++++
15
2 files changed, 22 insertions(+)
16
17
diff --git a/configure b/configure
18
index XXXXXXX..XXXXXXX 100755
19
--- a/configure
20
+++ b/configure
21
@@ -XXX,XX +XXX,XX @@ glusterfs_xlator_opt="no"
22
glusterfs_discard="no"
23
glusterfs_fallocate="no"
24
glusterfs_zerofill="no"
25
+glusterfs_ftruncate_has_stat="no"
26
gtk=""
27
gtk_gl="no"
28
tls_priority="NORMAL"
29
@@ -XXX,XX +XXX,XX @@ if test "$glusterfs" != "no" ; then
30
glusterfs_fallocate="yes"
31
glusterfs_zerofill="yes"
32
fi
33
+ cat > $TMPC << EOF
34
+#include <glusterfs/api/glfs.h>
35
+
36
+int
37
+main(void)
38
+{
39
+    /* new glfs_ftruncate() passes two additional args */
40
+    return glfs_ftruncate(NULL, 0, NULL, NULL);
41
+}
42
+EOF
43
+ if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
44
+ glusterfs_ftruncate_has_stat="yes"
45
+ fi
46
else
47
if test "$glusterfs" = "yes" ; then
48
feature_not_found "GlusterFS backend support" \
49
@@ -XXX,XX +XXX,XX @@ if test "$glusterfs_zerofill" = "yes" ; then
50
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
51
fi
52
53
+if test "$glusterfs_ftruncate_has_stat" = "yes" ; then
54
+ echo "CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT=y" >> $config_host_mak
55
+fi
56
+
57
if test "$libssh2" = "yes" ; then
58
echo "CONFIG_LIBSSH2=m" >> $config_host_mak
59
echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
60
diff --git a/block/gluster.c b/block/gluster.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/gluster.c
63
+++ b/block/gluster.c
64
@@ -XXX,XX +XXX,XX @@
65
#include "qemu/option.h"
66
#include "qemu/cutils.h"
67
68
+#ifdef CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT
69
+# define glfs_ftruncate(fd, offset) glfs_ftruncate(fd, offset, NULL, NULL)
70
+#endif
71
+
72
#define GLUSTER_OPT_FILENAME "filename"
73
#define GLUSTER_OPT_VOLUME "volume"
74
#define GLUSTER_OPT_PATH "path"
75
--
76
2.20.1
77
78
diff view generated by jsdifflib
Deleted patch
1
From: Niels de Vos <ndevos@redhat.com>
2
1
3
The glfs_*_async() functions do a callback once finished. This callback
4
has changed its arguments, pre- and post-stat structures have been
5
added. This makes it possible to improve caching, which is useful for
6
Samba and NFS-Ganesha, but not so much for QEMU. Gluster 6 is the first
7
release that includes these new arguments.
8
9
With an additional detection in ./configure, the new arguments can
10
conditionally get included in the glfs_io_cbk handler.
11
12
Signed-off-by: Niels de Vos <ndevos@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
15
configure | 24 ++++++++++++++++++++++++
16
block/gluster.c | 6 +++++-
17
2 files changed, 29 insertions(+), 1 deletion(-)
18
19
diff --git a/configure b/configure
20
index XXXXXXX..XXXXXXX 100755
21
--- a/configure
22
+++ b/configure
23
@@ -XXX,XX +XXX,XX @@ glusterfs_discard="no"
24
glusterfs_fallocate="no"
25
glusterfs_zerofill="no"
26
glusterfs_ftruncate_has_stat="no"
27
+glusterfs_iocb_has_stat="no"
28
gtk=""
29
gtk_gl="no"
30
tls_priority="NORMAL"
31
@@ -XXX,XX +XXX,XX @@ EOF
32
if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
33
glusterfs_ftruncate_has_stat="yes"
34
fi
35
+ cat > $TMPC << EOF
36
+#include <glusterfs/api/glfs.h>
37
+
38
+/* new glfs_io_cbk() passes two additional glfs_stat structs */
39
+static void
40
+glusterfs_iocb(glfs_fd_t *fd, ssize_t ret, struct glfs_stat *prestat, struct glfs_stat *poststat, void *data)
41
+{}
42
+
43
+int
44
+main(void)
45
+{
46
+    glfs_io_cbk iocb = &glusterfs_iocb;
47
+    iocb(NULL, 0 , NULL, NULL, NULL);
48
+    return 0;
49
+}
50
+EOF
51
+ if compile_prog "$glusterfs_cflags" "$glusterfs_libs" ; then
52
+ glusterfs_iocb_has_stat="yes"
53
+ fi
54
else
55
if test "$glusterfs" = "yes" ; then
56
feature_not_found "GlusterFS backend support" \
57
@@ -XXX,XX +XXX,XX @@ if test "$glusterfs_ftruncate_has_stat" = "yes" ; then
58
echo "CONFIG_GLUSTERFS_FTRUNCATE_HAS_STAT=y" >> $config_host_mak
59
fi
60
61
+if test "$glusterfs_iocb_has_stat" = "yes" ; then
62
+ echo "CONFIG_GLUSTERFS_IOCB_HAS_STAT=y" >> $config_host_mak
63
+fi
64
+
65
if test "$libssh2" = "yes" ; then
66
echo "CONFIG_LIBSSH2=m" >> $config_host_mak
67
echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
68
diff --git a/block/gluster.c b/block/gluster.c
69
index XXXXXXX..XXXXXXX 100644
70
--- a/block/gluster.c
71
+++ b/block/gluster.c
72
@@ -XXX,XX +XXX,XX @@ static struct glfs *qemu_gluster_init(BlockdevOptionsGluster *gconf,
73
/*
74
* AIO callback routine called from GlusterFS thread.
75
*/
76
-static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
77
+static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret,
78
+#ifdef CONFIG_GLUSTERFS_IOCB_HAS_STAT
79
+ struct glfs_stat *pre, struct glfs_stat *post,
80
+#endif
81
+ void *arg)
82
{
83
GlusterAIOCB *acb = (GlusterAIOCB *)arg;
84
85
--
86
2.20.1
87
88
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
qapi/block-core.json | 4 ++--
7
blockdev.c | 12 ++++++------
8
2 files changed, 8 insertions(+), 8 deletions(-)
9
10
diff --git a/qapi/block-core.json b/qapi/block-core.json
11
index XXXXXXX..XXXXXXX 100644
12
--- a/qapi/block-core.json
13
+++ b/qapi/block-core.json
14
@@ -XXX,XX +XXX,XX @@
15
# If only @device parameter is specified, remove all present latency histograms
16
# for the device. Otherwise, add/reset some of (or all) latency histograms.
17
#
18
-# @device: device name to set latency histogram for.
19
+# @id: The name or QOM path of the guest device.
20
#
21
# @boundaries: list of interval boundary values (see description in
22
# BlockLatencyHistogramInfo definition). If specified, all
23
@@ -XXX,XX +XXX,XX @@
24
# <- { "return": {} }
25
##
26
{ 'command': 'x-block-latency-histogram-set',
27
- 'data': {'device': 'str',
28
+ 'data': {'id': 'str',
29
'*boundaries': ['uint64'],
30
'*boundaries-read': ['uint64'],
31
'*boundaries-write': ['uint64'],
32
diff --git a/blockdev.c b/blockdev.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/blockdev.c
35
+++ b/blockdev.c
36
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
37
}
38
39
void qmp_x_block_latency_histogram_set(
40
- const char *device,
41
+ const char *id,
42
bool has_boundaries, uint64List *boundaries,
43
bool has_boundaries_read, uint64List *boundaries_read,
44
bool has_boundaries_write, uint64List *boundaries_write,
45
bool has_boundaries_flush, uint64List *boundaries_flush,
46
Error **errp)
47
{
48
- BlockBackend *blk = blk_by_name(device);
49
+ BlockBackend *blk = qmp_get_blk(NULL, id, errp);
50
BlockAcctStats *stats;
51
int ret;
52
53
if (!blk) {
54
- error_setg(errp, "Device '%s' not found", device);
55
return;
56
}
57
+
58
stats = blk_get_stats(blk);
59
60
if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
61
@@ -XXX,XX +XXX,XX @@ void qmp_x_block_latency_histogram_set(
62
stats, BLOCK_ACCT_READ,
63
has_boundaries_read ? boundaries_read : boundaries);
64
if (ret) {
65
- error_setg(errp, "Device '%s' set read boundaries fail", device);
66
+ error_setg(errp, "Device '%s' set read boundaries fail", id);
67
return;
68
}
69
}
70
@@ -XXX,XX +XXX,XX @@ void qmp_x_block_latency_histogram_set(
71
stats, BLOCK_ACCT_WRITE,
72
has_boundaries_write ? boundaries_write : boundaries);
73
if (ret) {
74
- error_setg(errp, "Device '%s' set write boundaries fail", device);
75
+ error_setg(errp, "Device '%s' set write boundaries fail", id);
76
return;
77
}
78
}
79
@@ -XXX,XX +XXX,XX @@ void qmp_x_block_latency_histogram_set(
80
stats, BLOCK_ACCT_FLUSH,
81
has_boundaries_flush ? boundaries_flush : boundaries);
82
if (ret) {
83
- error_setg(errp, "Device '%s' set flush boundaries fail", device);
84
+ error_setg(errp, "Device '%s' set flush boundaries fail", id);
85
return;
86
}
87
}
88
--
89
2.20.1
90
91
diff view generated by jsdifflib
Deleted patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
1
3
Drop x- and x_ prefixes for latency histograms and update version to
4
3.1
5
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
qapi/block-core.json | 20 ++++++++++----------
10
block/qapi.c | 12 ++++++------
11
blockdev.c | 2 +-
12
3 files changed, 17 insertions(+), 17 deletions(-)
13
14
diff --git a/qapi/block-core.json b/qapi/block-core.json
15
index XXXXXXX..XXXXXXX 100644
16
--- a/qapi/block-core.json
17
+++ b/qapi/block-core.json
18
@@ -XXX,XX +XXX,XX @@
19
# +------------------
20
# 10 50 100
21
#
22
-# Since: 2.12
23
+# Since: 4.0
24
##
25
{ 'struct': 'BlockLatencyHistogramInfo',
26
'data': {'boundaries': ['uint64'], 'bins': ['uint64'] } }
27
28
##
29
-# @x-block-latency-histogram-set:
30
+# @block-latency-histogram-set:
31
#
32
# Manage read, write and flush latency histograms for the device.
33
#
34
@@ -XXX,XX +XXX,XX @@
35
#
36
# Returns: error if device is not found or any boundary arrays are invalid.
37
#
38
-# Since: 2.12
39
+# Since: 4.0
40
#
41
# Example: set new histograms for all io types with intervals
42
# [0, 10), [10, 50), [50, 100), [100, +inf):
43
@@ -XXX,XX +XXX,XX @@
44
# "arguments": { "device": "drive0" } }
45
# <- { "return": {} }
46
##
47
-{ 'command': 'x-block-latency-histogram-set',
48
+{ 'command': 'block-latency-histogram-set',
49
'data': {'id': 'str',
50
'*boundaries': ['uint64'],
51
'*boundaries-read': ['uint64'],
52
@@ -XXX,XX +XXX,XX @@
53
# @timed_stats: Statistics specific to the set of previously defined
54
# intervals of time (Since 2.5)
55
#
56
-# @x_rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
57
+# @rd_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
58
#
59
-# @x_wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
60
+# @wr_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
61
#
62
-# @x_flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 2.12)
63
+# @flush_latency_histogram: @BlockLatencyHistogramInfo. (Since 4.0)
64
#
65
# Since: 0.14.0
66
##
67
@@ -XXX,XX +XXX,XX @@
68
'invalid_wr_operations': 'int', 'invalid_flush_operations': 'int',
69
'account_invalid': 'bool', 'account_failed': 'bool',
70
'timed_stats': ['BlockDeviceTimedStats'],
71
- '*x_rd_latency_histogram': 'BlockLatencyHistogramInfo',
72
- '*x_wr_latency_histogram': 'BlockLatencyHistogramInfo',
73
- '*x_flush_latency_histogram': 'BlockLatencyHistogramInfo' } }
74
+ '*rd_latency_histogram': 'BlockLatencyHistogramInfo',
75
+ '*wr_latency_histogram': 'BlockLatencyHistogramInfo',
76
+ '*flush_latency_histogram': 'BlockLatencyHistogramInfo' } }
77
78
##
79
# @BlockStats:
80
diff --git a/block/qapi.c b/block/qapi.c
81
index XXXXXXX..XXXXXXX 100644
82
--- a/block/qapi.c
83
+++ b/block/qapi.c
84
@@ -XXX,XX +XXX,XX @@ static void bdrv_query_blk_stats(BlockDeviceStats *ds, BlockBackend *blk)
85
}
86
87
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_READ],
88
- &ds->has_x_rd_latency_histogram,
89
- &ds->x_rd_latency_histogram);
90
+ &ds->has_rd_latency_histogram,
91
+ &ds->rd_latency_histogram);
92
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_WRITE],
93
- &ds->has_x_wr_latency_histogram,
94
- &ds->x_wr_latency_histogram);
95
+ &ds->has_wr_latency_histogram,
96
+ &ds->wr_latency_histogram);
97
bdrv_latency_histogram_stats(&stats->latency_histogram[BLOCK_ACCT_FLUSH],
98
- &ds->has_x_flush_latency_histogram,
99
- &ds->x_flush_latency_histogram);
100
+ &ds->has_flush_latency_histogram,
101
+ &ds->flush_latency_histogram);
102
}
103
104
static BlockStats *bdrv_query_bds_stats(BlockDriverState *bs,
105
diff --git a/blockdev.c b/blockdev.c
106
index XXXXXXX..XXXXXXX 100644
107
--- a/blockdev.c
108
+++ b/blockdev.c
109
@@ -XXX,XX +XXX,XX @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
110
aio_context_release(old_context);
111
}
112
113
-void qmp_x_block_latency_histogram_set(
114
+void qmp_block_latency_histogram_set(
115
const char *id,
116
bool has_boundaries, uint64List *boundaries,
117
bool has_boundaries_read, uint64List *boundaries_read,
118
--
119
2.20.1
120
121
diff view generated by jsdifflib
Deleted patch
1
tests/virtio-blk-test uses a temporary image file that it deletes while
2
QEMU is still running, so it can't be reopened when writers are
3
attached or detached. Disable auto-read-only to keep it always writable.
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
7
---
8
tests/virtio-blk-test.c | 2 +-
9
1 file changed, 1 insertion(+), 1 deletion(-)
10
11
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
12
index XXXXXXX..XXXXXXX 100644
13
--- a/tests/virtio-blk-test.c
14
+++ b/tests/virtio-blk-test.c
15
@@ -XXX,XX +XXX,XX @@ static void *virtio_blk_test_setup(GString *cmd_line, void *arg)
16
char *tmp_path = drive_create();
17
18
g_string_append_printf(cmd_line,
19
- " -drive if=none,id=drive0,file=%s,format=raw "
20
+ " -drive if=none,id=drive0,file=%s,format=raw,auto-read-only=off "
21
"-drive if=none,id=drive1,file=null-co://,format=raw ",
22
tmp_path);
23
24
--
25
2.20.1
26
27
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Eric Blake <eblake@redhat.com>
3
---
4
tests/qemu-iotests/232 | 31 +++++++++++++++++++++++++++++++
5
tests/qemu-iotests/232.out | 20 ++++++++++++++++++++
6
2 files changed, 51 insertions(+)
7
1
8
diff --git a/tests/qemu-iotests/232 b/tests/qemu-iotests/232
9
index XXXXXXX..XXXXXXX 100755
10
--- a/tests/qemu-iotests/232
11
+++ b/tests/qemu-iotests/232
12
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
13
_cleanup()
14
{
15
_cleanup_test_img
16
+ rm -f $TEST_IMG.[01234]
17
}
18
trap "_cleanup; exit \$status" 0 1 2 3 15
19
20
@@ -XXX,XX +XXX,XX @@ run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,a
21
run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0,auto-read-only=on
22
run_qemu_info_block -blockdev driver=file,filename="$TEST_IMG",node-name=node0
23
24
+echo
25
+echo "=== Try commit to backing file with auto-read-only ==="
26
+echo
27
+
28
+TEST_IMG="$TEST_IMG.0" _make_test_img $size
29
+TEST_IMG="$TEST_IMG.1" _make_test_img $size
30
+TEST_IMG="$TEST_IMG.2" _make_test_img $size
31
+TEST_IMG="$TEST_IMG.3" _make_test_img $size
32
+TEST_IMG="$TEST_IMG.4" _make_test_img $size
33
+
34
+(cat <<EOF
35
+{"execute":"qmp_capabilities"}
36
+{"execute":"block-commit",
37
+ "arguments":{"device":"format-4", "top-node": "format-2", "base-node":"format-0", "job-id":"job0"}}
38
+EOF
39
+sleep 1
40
+echo '{"execute":"quit"}'
41
+) | $QEMU -qmp stdio -nographic -nodefaults \
42
+ -blockdev file,node-name=file-0,filename=$TEST_IMG.0,auto-read-only=on \
43
+ -blockdev qcow2,node-name=format-0,file=file-0,read-only=on \
44
+ -blockdev file,node-name=file-1,filename=$TEST_IMG.1,auto-read-only=on \
45
+ -blockdev qcow2,node-name=format-1,file=file-1,read-only=on,backing=format-0 \
46
+ -blockdev file,node-name=file-2,filename=$TEST_IMG.2,auto-read-only=on \
47
+ -blockdev qcow2,node-name=format-2,file=file-2,read-only=on,backing=format-1 \
48
+ -blockdev file,node-name=file-3,filename=$TEST_IMG.3,auto-read-only=on \
49
+ -blockdev qcow2,node-name=format-3,file=file-3,read-only=on,backing=format-2 \
50
+ -blockdev file,node-name=file-4,filename=$TEST_IMG.4,auto-read-only=on \
51
+ -blockdev qcow2,node-name=format-4,file=file-4,read-only=on,backing=format-3 |
52
+ _filter_qmp
53
+
54
# success, all done
55
echo "*** done"
56
rm -f $seq.full
57
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
58
index XXXXXXX..XXXXXXX 100644
59
--- a/tests/qemu-iotests/232.out
60
+++ b/tests/qemu-iotests/232.out
61
@@ -XXX,XX +XXX,XX @@ QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read
62
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
63
node0: TEST_DIR/t.IMGFMT (file, read-only)
64
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
65
+
66
+=== Try commit to backing file with auto-read-only ===
67
+
68
+Formatting 'TEST_DIR/t.IMGFMT.0', fmt=IMGFMT size=134217728
69
+Formatting 'TEST_DIR/t.IMGFMT.1', fmt=IMGFMT size=134217728
70
+Formatting 'TEST_DIR/t.IMGFMT.2', fmt=IMGFMT size=134217728
71
+Formatting 'TEST_DIR/t.IMGFMT.3', fmt=IMGFMT size=134217728
72
+Formatting 'TEST_DIR/t.IMGFMT.4', fmt=IMGFMT size=134217728
73
+QMP_VERSION
74
+{"return": {}}
75
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "created", "id": "job0"}}
76
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "running", "id": "job0"}}
77
+{"return": {}}
78
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "waiting", "id": "job0"}}
79
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "pending", "id": "job0"}}
80
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "job0", "len": 134217728, "offset": 134217728, "speed": 0, "type": "commit"}}
81
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "concluded", "id": "job0"}}
82
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "JOB_STATUS_CHANGE", "data": {"status": "null", "id": "job0"}}
83
+{"return": {}}
84
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN", "data": {"guest": false, "reason": "host-qmp-quit"}}
85
*** done
86
--
87
2.20.1
88
89
diff view generated by jsdifflib
Deleted patch
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
Reviewed-by: Alberto Garcia <berto@igalia.com>
3
Reviewed-by: Eric Blake <eblake@redhat.com>
4
---
5
block.c | 4 +---
6
1 file changed, 1 insertion(+), 3 deletions(-)
7
1
8
diff --git a/block.c b/block.c
9
index XXXXXXX..XXXXXXX 100644
10
--- a/block.c
11
+++ b/block.c
12
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
13
{
14
int ret = -1;
15
BlockReopenQueueEntry *bs_entry, *next;
16
- Error *local_err = NULL;
17
18
assert(bs_queue != NULL);
19
20
QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
21
assert(bs_entry->state.bs->quiesce_counter > 0);
22
- if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, &local_err)) {
23
- error_propagate(errp, local_err);
24
+ if (bdrv_reopen_prepare(&bs_entry->state, bs_queue, errp)) {
25
goto cleanup;
26
}
27
bs_entry->prepared = true;
28
--
29
2.20.1
30
31
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Alberto Garcia <berto@igalia.com>
2
2
3
This command allows reopening an arbitrary BlockDriverState with a
3
Backing files and raw external data files are mutually exclusive.
4
new set of options. Some options (e.g node-name) cannot be changed
4
The documentation of the raw external data bit (in autoclear_features)
5
and some block drivers don't allow reopening, but otherwise this
5
already indicates that, but we should also mention it on the other
6
command is modelled after 'blockdev-add' and the state of the reopened
6
side.
7
BlockDriverState should generally be the same as if it had just been
8
added by 'blockdev-add' with the same set of options.
9
7
10
One notable exception is the 'backing' option: 'x-blockdev-reopen'
8
Suggested-by: Eric Blake <eblake@redhat.com>
11
requires that it is always present unless the BlockDriverState in
12
question doesn't have a current or default backing file.
13
14
This command allows reconfiguring the graph by using the appropriate
15
options to change the children of a node. At the moment it's possible
16
to change a backing file by setting the 'backing' option to the name
17
of the new node, but it should also be possible to add a similar
18
functionality to other block drivers (e.g. Quorum, blkverify).
19
20
Although the API is unlikely to change, this command is marked
21
experimental for the time being so there's room to see if the
22
semantics need changes.
23
24
Signed-off-by: Alberto Garcia <berto@igalia.com>
9
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
Message-Id: <20200410121816.8334-1-berto@igalia.com>
11
Reviewed-by: Eric Blake <eblake@redhat.com>
25
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
26
---
13
---
27
qapi/block-core.json | 42 +++++++++++++++++++++++++++++++++++++++
14
docs/interop/qcow2.txt | 3 +++
28
blockdev.c | 47 ++++++++++++++++++++++++++++++++++++++++++++
15
1 file changed, 3 insertions(+)
29
2 files changed, 89 insertions(+)
30
16
31
diff --git a/qapi/block-core.json b/qapi/block-core.json
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
32
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
33
--- a/qapi/block-core.json
19
--- a/docs/interop/qcow2.txt
34
+++ b/qapi/block-core.json
20
+++ b/docs/interop/qcow2.txt
35
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
36
##
22
is stored (NB: The string is not null terminated). 0 if the
37
{ 'command': 'blockdev-add', 'data': 'BlockdevOptions', 'boxed': true }
23
image doesn't have a backing file.
38
24
39
+##
25
+ Note: backing files are incompatible with raw external data
40
+# @x-blockdev-reopen:
26
+ files (auto-clear feature bit 1).
41
+#
42
+# Reopens a block device using the given set of options. Any option
43
+# not specified will be reset to its default value regardless of its
44
+# previous status. If an option cannot be changed or a particular
45
+# driver does not support reopening then the command will return an
46
+# error.
47
+#
48
+# The top-level @node-name option (from BlockdevOptions) must be
49
+# specified and is used to select the block device to be reopened.
50
+# Other @node-name options must be either omitted or set to the
51
+# current name of the appropriate node. This command won't change any
52
+# node name and any attempt to do it will result in an error.
53
+#
54
+# In the case of options that refer to child nodes, the behavior of
55
+# this command depends on the value:
56
+#
57
+# 1) A set of options (BlockdevOptions): the child is reopened with
58
+# the specified set of options.
59
+#
60
+# 2) A reference to the current child: the child is reopened using
61
+# its existing set of options.
62
+#
63
+# 3) A reference to a different node: the current child is replaced
64
+# with the specified one.
65
+#
66
+# 4) NULL: the current child (if any) is detached.
67
+#
68
+# Options (1) and (2) are supported in all cases, but at the moment
69
+# only @backing allows replacing or detaching an existing child.
70
+#
71
+# Unlike with blockdev-add, the @backing option must always be present
72
+# unless the node being reopened does not have a backing file and its
73
+# image does not have a default backing file name as part of its
74
+# metadata.
75
+#
76
+# Since: 4.0
77
+##
78
+{ 'command': 'x-blockdev-reopen',
79
+ 'data': 'BlockdevOptions', 'boxed': true }
80
+
27
+
81
##
28
16 - 19: backing_file_size
82
# @blockdev-del:
29
Length of the backing file name in bytes. Must not be
83
#
30
longer than 1023 bytes. Undefined if the image doesn't have
84
diff --git a/blockdev.c b/blockdev.c
85
index XXXXXXX..XXXXXXX 100644
86
--- a/blockdev.c
87
+++ b/blockdev.c
88
@@ -XXX,XX +XXX,XX @@ fail:
89
visit_free(v);
90
}
91
92
+void qmp_x_blockdev_reopen(BlockdevOptions *options, Error **errp)
93
+{
94
+ BlockDriverState *bs;
95
+ AioContext *ctx;
96
+ QObject *obj;
97
+ Visitor *v = qobject_output_visitor_new(&obj);
98
+ Error *local_err = NULL;
99
+ BlockReopenQueue *queue;
100
+ QDict *qdict;
101
+
102
+ /* Check for the selected node name */
103
+ if (!options->has_node_name) {
104
+ error_setg(errp, "Node name not specified");
105
+ goto fail;
106
+ }
107
+
108
+ bs = bdrv_find_node(options->node_name);
109
+ if (!bs) {
110
+ error_setg(errp, "Cannot find node named '%s'", options->node_name);
111
+ goto fail;
112
+ }
113
+
114
+ /* Put all options in a QDict and flatten it */
115
+ visit_type_BlockdevOptions(v, NULL, &options, &local_err);
116
+ if (local_err) {
117
+ error_propagate(errp, local_err);
118
+ goto fail;
119
+ }
120
+
121
+ visit_complete(v, &obj);
122
+ qdict = qobject_to(QDict, obj);
123
+
124
+ qdict_flatten(qdict);
125
+
126
+ /* Perform the reopen operation */
127
+ ctx = bdrv_get_aio_context(bs);
128
+ aio_context_acquire(ctx);
129
+ bdrv_subtree_drained_begin(bs);
130
+ queue = bdrv_reopen_queue(NULL, bs, qdict, false);
131
+ bdrv_reopen_multiple(queue, errp);
132
+ bdrv_subtree_drained_end(bs);
133
+ aio_context_release(ctx);
134
+
135
+fail:
136
+ visit_free(v);
137
+}
138
+
139
void qmp_blockdev_del(const char *node_name, Error **errp)
140
{
141
AioContext *aio_context;
142
--
31
--
143
2.20.1
32
2.25.3
144
33
145
34
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
This parameter has been unused since 1a63a907507fbbcfaee3f622907ec244b
3
Test 244 checks the expected behavior of qcow2 external data files
4
with respect to zero and discarded clusters. Filesystems however
5
are free to ignore discard requests, and this seems to be the
6
case for overlayfs. Relax the tests to skip checks on the
7
external data file for discarded areas, which implies not using
8
qemu-img compare in the data_file_raw=on case.
4
9
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
10
This fixes docker tests on RHEL8.
11
12
Cc: Kevin Wolf <kwolf@redhat.com>
13
Cc: qemu-block@nongnu.org
14
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
15
Message-Id: <20200409191006.24429-1-pbonzini@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
17
---
8
include/block/block.h | 2 +-
18
tests/qemu-iotests/244 | 10 ++++++++--
9
block.c | 4 ++--
19
tests/qemu-iotests/244.out | 9 ++++++---
10
block/replication.c | 3 +--
20
2 files changed, 14 insertions(+), 5 deletions(-)
11
qemu-io-cmds.c | 2 +-
12
4 files changed, 5 insertions(+), 6 deletions(-)
13
21
14
diff --git a/include/block/block.h b/include/block/block.h
22
diff --git a/tests/qemu-iotests/244 b/tests/qemu-iotests/244
23
index XXXXXXX..XXXXXXX 100755
24
--- a/tests/qemu-iotests/244
25
+++ b/tests/qemu-iotests/244
26
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
27
echo
28
$QEMU_IO -c 'read -P 0 0 1M' \
29
-c 'read -P 0x11 1M 1M' \
30
- -c 'read -P 0 2M 2M' \
31
-c 'read -P 0x11 4M 1M' \
32
-c 'read -P 0 5M 1M' \
33
-f raw "$TEST_IMG.data" |
34
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c 'read -P 0 0 1M' \
35
-f $IMGFMT "$TEST_IMG" |
36
_filter_qemu_io
37
38
+# Discarded clusters are only marked as such in the qcow2 metadata, but
39
+# they can contain stale data in the external data file. Instead, zero
40
+# clusters must be zeroed in the external data file too.
41
echo
42
-$QEMU_IMG compare "$TEST_IMG" "$TEST_IMG.data"
43
+$QEMU_IO -c 'read -P 0 0 1M' \
44
+ -c 'read -P 0x11 1M 1M' \
45
+ -c 'read -P 0 3M 3M' \
46
+ -f raw "$TEST_IMG".data |
47
+ _filter_qemu_io
48
49
echo -n "qcow2 file size after I/O: "
50
du -b $TEST_IMG | cut -f1
51
diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out
15
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
16
--- a/include/block/block.h
53
--- a/tests/qemu-iotests/244.out
17
+++ b/include/block/block.h
54
+++ b/tests/qemu-iotests/244.out
18
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
19
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
20
BlockDriverState *bs, QDict *options,
57
read 1048576/1048576 bytes at offset 1048576
21
bool keep_old_opts);
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
22
-int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp);
59
-read 2097152/2097152 bytes at offset 2097152
23
+int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp);
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
24
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
61
read 1048576/1048576 bytes at offset 4194304
25
Error **errp);
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
26
int bdrv_reopen_prepare(BDRVReopenState *reopen_state,
63
read 1048576/1048576 bytes at offset 5242880
27
diff --git a/block.c b/block.c
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
28
index XXXXXXX..XXXXXXX 100644
65
read 4194304/4194304 bytes at offset 2097152
29
--- a/block.c
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
30
+++ b/block.c
67
31
@@ -XXX,XX +XXX,XX @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
68
-Images are identical.
32
* All affected nodes must be drained between bdrv_reopen_queue() and
69
+read 1048576/1048576 bytes at offset 0
33
* bdrv_reopen_multiple().
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
34
*/
71
+read 1048576/1048576 bytes at offset 1048576
35
-int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp)
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
36
+int bdrv_reopen_multiple(BlockReopenQueue *bs_queue, Error **errp)
73
+read 3145728/3145728 bytes at offset 3145728
37
{
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
38
int ret = -1;
75
qcow2 file size after I/O: 327680
39
BlockReopenQueueEntry *bs_entry, *next;
76
40
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
77
=== bdrv_co_block_status test for file and offset=0 ===
41
42
bdrv_subtree_drained_begin(bs);
43
queue = bdrv_reopen_queue(NULL, bs, opts, true);
44
- ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, errp);
45
+ ret = bdrv_reopen_multiple(queue, errp);
46
bdrv_subtree_drained_end(bs);
47
48
return ret;
49
diff --git a/block/replication.c b/block/replication.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block/replication.c
52
+++ b/block/replication.c
53
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
54
}
55
56
if (reopen_queue) {
57
- bdrv_reopen_multiple(bdrv_get_aio_context(bs),
58
- reopen_queue, &local_err);
59
+ bdrv_reopen_multiple(reopen_queue, &local_err);
60
error_propagate(errp, local_err);
61
}
62
63
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/qemu-io-cmds.c
66
+++ b/qemu-io-cmds.c
67
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
68
69
bdrv_subtree_drained_begin(bs);
70
brq = bdrv_reopen_queue(NULL, bs, opts, true);
71
- bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
72
+ bdrv_reopen_multiple(brq, &local_err);
73
bdrv_subtree_drained_end(bs);
74
75
if (local_err) {
76
--
78
--
77
2.20.1
79
2.25.3
78
80
79
81
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
2
2
driver callbacks, and a supported_truncate_flags field in
3
If we reopen a BlockDriverState and there is an option that is present
3
BlockDriverState that allows drivers to advertise support for request
4
in bs->options but missing from the new set of options then we have to
4
flags in the context of truncate.
5
return an error unless the driver is able to reset it to its default
5
6
value.
6
For now, we always pass 0 and no drivers declare support for any flag.
7
7
8
This patch adds a new 'mutable_opts' field to BlockDriver. This is
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
a list of runtime options that can be modified during reopen. If an
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
option in this list is unspecified on reopen then it must be reset (or
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
return an error).
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
Signed-off-by: Alberto Garcia <berto@igalia.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
14
---
16
include/block/block_int.h | 8 ++++++++
15
include/block/block_int.h | 10 +++++++++-
17
block/file-posix.c | 6 ++++++
16
block/crypto.c | 3 ++-
18
block/qcow2.c | 25 +++++++++++++++++++++++++
17
block/file-posix.c | 2 +-
19
block/raw-format.c | 3 +++
18
block/file-win32.c | 2 +-
20
4 files changed, 42 insertions(+)
19
block/gluster.c | 1 +
20
block/io.c | 8 +++++++-
21
block/iscsi.c | 2 +-
22
block/nfs.c | 3 ++-
23
block/qcow2.c | 2 +-
24
block/qed.c | 1 +
25
block/raw-format.c | 2 +-
26
block/rbd.c | 1 +
27
block/sheepdog.c | 4 ++--
28
block/ssh.c | 2 +-
29
tests/test-block-iothread.c | 3 ++-
30
15 files changed, 33 insertions(+), 13 deletions(-)
21
31
22
diff --git a/include/block/block_int.h b/include/block/block_int.h
32
diff --git a/include/block/block_int.h b/include/block/block_int.h
23
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
24
--- a/include/block/block_int.h
34
--- a/include/block/block_int.h
25
+++ b/include/block/block_int.h
35
+++ b/include/block/block_int.h
26
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
27
37
*/
28
/* List of options for creating images, terminated by name == NULL */
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
29
QemuOptsList *create_opts;
39
bool exact, PreallocMode prealloc,
40
- Error **errp);
41
+ BdrvRequestFlags flags, Error **errp);
42
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
44
bool has_variable_length;
45
@@ -XXX,XX +XXX,XX @@ struct BlockDriverState {
46
/* Flags honored during pwrite_zeroes (so far: BDRV_REQ_FUA,
47
* BDRV_REQ_MAY_UNMAP, BDRV_REQ_WRITE_UNCHANGED) */
48
unsigned int supported_zero_flags;
30
+ /*
49
+ /*
31
+ * If this driver supports reopening images this contains a
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
32
+ * NULL-terminated list of the runtime options that can be
51
+ *
33
+ * modified. If an option in this list is unspecified during
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
34
+ * reopen then it _must_ be reset to its default value or return
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
35
+ * an error.
54
+ * the operation must fail.
36
+ */
55
+ */
37
+ const char *const *mutable_opts;
56
+ unsigned int supported_truncate_flags;
38
57
39
/*
58
/* the following member gives a name to every node on the bs graph. */
40
* Returns 0 for completed check, -errno for internal errors.
59
char node_name[32];
60
diff --git a/block/crypto.c b/block/crypto.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/crypto.c
63
+++ b/block/crypto.c
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
65
66
static int coroutine_fn
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
68
- PreallocMode prealloc, Error **errp)
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
70
+ Error **errp)
71
{
72
BlockCrypto *crypto = bs->opaque;
73
uint64_t payload_offset =
41
diff --git a/block/file-posix.c b/block/file-posix.c
74
diff --git a/block/file-posix.c b/block/file-posix.c
42
index XXXXXXX..XXXXXXX 100644
75
index XXXXXXX..XXXXXXX 100644
43
--- a/block/file-posix.c
76
--- a/block/file-posix.c
44
+++ b/block/file-posix.c
77
+++ b/block/file-posix.c
45
@@ -XXX,XX +XXX,XX @@ static QemuOptsList raw_runtime_opts = {
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
46
},
79
47
};
80
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
48
81
bool exact, PreallocMode prealloc,
49
+static const char *const mutable_opts[] = { "x-check-cache-dropped", NULL };
82
- Error **errp)
50
+
83
+ BdrvRequestFlags flags, Error **errp)
51
static int raw_open_common(BlockDriverState *bs, QDict *options,
84
{
52
int bdrv_flags, int open_flags,
85
BDRVRawState *s = bs->opaque;
53
bool device, Error **errp)
86
struct stat st;
54
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_file = {
87
diff --git a/block/file-win32.c b/block/file-win32.c
55
.bdrv_set_perm = raw_set_perm,
88
index XXXXXXX..XXXXXXX 100644
56
.bdrv_abort_perm_update = raw_abort_perm_update,
89
--- a/block/file-win32.c
57
.create_opts = &raw_create_opts,
90
+++ b/block/file-win32.c
58
+ .mutable_opts = mutable_opts,
91
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
59
};
92
60
93
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
61
/***********************************************/
94
bool exact, PreallocMode prealloc,
62
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_device = {
95
- Error **errp)
63
.bdrv_reopen_abort = raw_reopen_abort,
96
+ BdrvRequestFlags flags, Error **errp)
64
.bdrv_co_create_opts = hdev_co_create_opts,
97
{
65
.create_opts = &raw_create_opts,
98
BDRVRawState *s = bs->opaque;
66
+ .mutable_opts = mutable_opts,
99
LONG low, high;
67
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
100
diff --git a/block/gluster.c b/block/gluster.c
68
.bdrv_co_pwrite_zeroes = hdev_co_pwrite_zeroes,
101
index XXXXXXX..XXXXXXX 100644
69
102
--- a/block/gluster.c
70
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
103
+++ b/block/gluster.c
71
.bdrv_reopen_abort = raw_reopen_abort,
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
72
.bdrv_co_create_opts = hdev_co_create_opts,
105
int64_t offset,
73
.create_opts = &raw_create_opts,
106
bool exact,
74
+ .mutable_opts = mutable_opts,
107
PreallocMode prealloc,
75
.bdrv_co_invalidate_cache = raw_co_invalidate_cache,
108
+ BdrvRequestFlags flags,
76
109
Error **errp)
77
110
{
78
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_host_cdrom = {
111
BDRVGlusterState *s = bs->opaque;
79
.bdrv_reopen_abort = raw_reopen_abort,
112
diff --git a/block/io.c b/block/io.c
80
.bdrv_co_create_opts = hdev_co_create_opts,
113
index XXXXXXX..XXXXXXX 100644
81
.create_opts = &raw_create_opts,
114
--- a/block/io.c
82
+ .mutable_opts = mutable_opts,
115
+++ b/block/io.c
83
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
84
.bdrv_co_preadv = raw_co_preadv,
117
BlockDriverState *bs = child->bs;
85
.bdrv_co_pwritev = raw_co_pwritev,
118
BlockDriver *drv = bs->drv;
119
BdrvTrackedRequest req;
120
+ BdrvRequestFlags flags = 0;
121
int64_t old_size, new_bytes;
122
int ret;
123
124
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
125
}
126
127
if (drv->bdrv_co_truncate) {
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
129
+ if (flags & ~bs->supported_truncate_flags) {
130
+ error_setg(errp, "Block driver does not support requested flags");
131
+ ret = -ENOTSUP;
132
+ goto out;
133
+ }
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
135
} else if (bs->file && drv->is_filter) {
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
137
} else {
138
diff --git a/block/iscsi.c b/block/iscsi.c
139
index XXXXXXX..XXXXXXX 100644
140
--- a/block/iscsi.c
141
+++ b/block/iscsi.c
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
143
144
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
145
bool exact, PreallocMode prealloc,
146
- Error **errp)
147
+ BdrvRequestFlags flags, Error **errp)
148
{
149
IscsiLun *iscsilun = bs->opaque;
150
int64_t cur_length;
151
diff --git a/block/nfs.c b/block/nfs.c
152
index XXXXXXX..XXXXXXX 100644
153
--- a/block/nfs.c
154
+++ b/block/nfs.c
155
@@ -XXX,XX +XXX,XX @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
156
157
static int coroutine_fn
158
nfs_file_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
159
- PreallocMode prealloc, Error **errp)
160
+ PreallocMode prealloc, BdrvRequestFlags flags,
161
+ Error **errp)
162
{
163
NFSClient *client = bs->opaque;
164
int ret;
86
diff --git a/block/qcow2.c b/block/qcow2.c
165
diff --git a/block/qcow2.c b/block/qcow2.c
87
index XXXXXXX..XXXXXXX 100644
166
index XXXXXXX..XXXXXXX 100644
88
--- a/block/qcow2.c
167
--- a/block/qcow2.c
89
+++ b/block/qcow2.c
168
+++ b/block/qcow2.c
90
@@ -XXX,XX +XXX,XX @@ int qcow2_validate_table(BlockDriverState *bs, uint64_t offset,
169
@@ -XXX,XX +XXX,XX @@ fail:
170
171
static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
172
bool exact, PreallocMode prealloc,
173
- Error **errp)
174
+ BdrvRequestFlags flags, Error **errp)
175
{
176
BDRVQcow2State *s = bs->opaque;
177
uint64_t old_length;
178
diff --git a/block/qed.c b/block/qed.c
179
index XXXXXXX..XXXXXXX 100644
180
--- a/block/qed.c
181
+++ b/block/qed.c
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_truncate(BlockDriverState *bs,
183
int64_t offset,
184
bool exact,
185
PreallocMode prealloc,
186
+ BdrvRequestFlags flags,
187
Error **errp)
188
{
189
BDRVQEDState *s = bs->opaque;
190
diff --git a/block/raw-format.c b/block/raw-format.c
191
index XXXXXXX..XXXXXXX 100644
192
--- a/block/raw-format.c
193
+++ b/block/raw-format.c
194
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
195
196
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
197
bool exact, PreallocMode prealloc,
198
- Error **errp)
199
+ BdrvRequestFlags flags, Error **errp)
200
{
201
BDRVRawState *s = bs->opaque;
202
203
diff --git a/block/rbd.c b/block/rbd.c
204
index XXXXXXX..XXXXXXX 100644
205
--- a/block/rbd.c
206
+++ b/block/rbd.c
207
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qemu_rbd_co_truncate(BlockDriverState *bs,
208
int64_t offset,
209
bool exact,
210
PreallocMode prealloc,
211
+ BdrvRequestFlags flags,
212
Error **errp)
213
{
214
int r;
215
diff --git a/block/sheepdog.c b/block/sheepdog.c
216
index XXXXXXX..XXXXXXX 100644
217
--- a/block/sheepdog.c
218
+++ b/block/sheepdog.c
219
@@ -XXX,XX +XXX,XX @@ static int64_t sd_getlength(BlockDriverState *bs)
220
221
static int coroutine_fn sd_co_truncate(BlockDriverState *bs, int64_t offset,
222
bool exact, PreallocMode prealloc,
223
- Error **errp)
224
+ BdrvRequestFlags flags, Error **errp)
225
{
226
BDRVSheepdogState *s = bs->opaque;
227
int ret, fd;
228
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
229
230
assert(!flags);
231
if (offset > s->inode.vdi_size) {
232
- ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, NULL);
233
+ ret = sd_co_truncate(bs, offset, false, PREALLOC_MODE_OFF, 0, NULL);
234
if (ret < 0) {
235
return ret;
236
}
237
diff --git a/block/ssh.c b/block/ssh.c
238
index XXXXXXX..XXXXXXX 100644
239
--- a/block/ssh.c
240
+++ b/block/ssh.c
241
@@ -XXX,XX +XXX,XX @@ static int64_t ssh_getlength(BlockDriverState *bs)
242
243
static int coroutine_fn ssh_co_truncate(BlockDriverState *bs, int64_t offset,
244
bool exact, PreallocMode prealloc,
245
- Error **errp)
246
+ BdrvRequestFlags flags, Error **errp)
247
{
248
BDRVSSHState *s = bs->opaque;
249
250
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
251
index XXXXXXX..XXXXXXX 100644
252
--- a/tests/test-block-iothread.c
253
+++ b/tests/test-block-iothread.c
254
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_test_co_pdiscard(BlockDriverState *bs,
255
256
static int coroutine_fn
257
bdrv_test_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
258
- PreallocMode prealloc, Error **errp)
259
+ PreallocMode prealloc, BdrvRequestFlags flags,
260
+ Error **errp)
261
{
91
return 0;
262
return 0;
92
}
263
}
93
94
+static const char *const mutable_opts[] = {
95
+ QCOW2_OPT_LAZY_REFCOUNTS,
96
+ QCOW2_OPT_DISCARD_REQUEST,
97
+ QCOW2_OPT_DISCARD_SNAPSHOT,
98
+ QCOW2_OPT_DISCARD_OTHER,
99
+ QCOW2_OPT_OVERLAP,
100
+ QCOW2_OPT_OVERLAP_TEMPLATE,
101
+ QCOW2_OPT_OVERLAP_MAIN_HEADER,
102
+ QCOW2_OPT_OVERLAP_ACTIVE_L1,
103
+ QCOW2_OPT_OVERLAP_ACTIVE_L2,
104
+ QCOW2_OPT_OVERLAP_REFCOUNT_TABLE,
105
+ QCOW2_OPT_OVERLAP_REFCOUNT_BLOCK,
106
+ QCOW2_OPT_OVERLAP_SNAPSHOT_TABLE,
107
+ QCOW2_OPT_OVERLAP_INACTIVE_L1,
108
+ QCOW2_OPT_OVERLAP_INACTIVE_L2,
109
+ QCOW2_OPT_OVERLAP_BITMAP_DIRECTORY,
110
+ QCOW2_OPT_CACHE_SIZE,
111
+ QCOW2_OPT_L2_CACHE_SIZE,
112
+ QCOW2_OPT_L2_CACHE_ENTRY_SIZE,
113
+ QCOW2_OPT_REFCOUNT_CACHE_SIZE,
114
+ QCOW2_OPT_CACHE_CLEAN_INTERVAL,
115
+ NULL
116
+};
117
+
118
static QemuOptsList qcow2_runtime_opts = {
119
.name = "qcow2",
120
.head = QTAILQ_HEAD_INITIALIZER(qcow2_runtime_opts.head),
121
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_qcow2 = {
122
123
.create_opts = &qcow2_create_opts,
124
.strong_runtime_opts = qcow2_strong_runtime_opts,
125
+ .mutable_opts = mutable_opts,
126
.bdrv_co_check = qcow2_co_check,
127
.bdrv_amend_options = qcow2_amend_options,
128
129
diff --git a/block/raw-format.c b/block/raw-format.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/raw-format.c
132
+++ b/block/raw-format.c
133
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
134
bool has_size;
135
} BDRVRawState;
136
137
+static const char *const mutable_opts[] = { "offset", "size", NULL };
138
+
139
static QemuOptsList raw_runtime_opts = {
140
.name = "raw",
141
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
142
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
143
.create_opts = &raw_create_opts,
144
.bdrv_has_zero_init = &raw_has_zero_init,
145
.strong_runtime_opts = raw_strong_runtime_opts,
146
+ .mutable_opts = mutable_opts,
147
};
148
149
static void bdrv_raw_init(void)
150
--
264
--
151
2.20.1
265
2.25.3
152
266
153
267
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Now that block drivers can support flags for .bdrv_co_truncate, expose
2
the parameter in the node level interfaces bdrv_co_truncate() and
3
bdrv_truncate().
2
4
3
Children in QMP are specified with BlockdevRef / BlockdevRefOrNull,
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
which can contain a set of child options, a child reference, or
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
NULL. In optional attributes like "backing" it can also be missing.
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
Only the first case (set of child options) is being handled properly
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
8
by bdrv_reopen_queue(). This patch deals with all the others.
9
10
Here's how these cases should be handled when bdrv_reopen_queue() is
11
deciding what to do with each child of a BlockDriverState:
12
13
1) Set of child options: if the child was implicitly created (i.e
14
inherits_from points to the parent) then the options are removed
15
from the parent's options QDict and are passed to the child with
16
a recursive bdrv_reopen_queue() call. This case was already
17
working fine.
18
19
2) Child reference: there's two possibilites here.
20
21
2a) Reference to the current child: if the child was implicitly
22
created then it is put in the reopen queue, keeping its
23
current set of options (since this was a child reference
24
there was no way to specify a different set of options).
25
If the child is not implicit then it keeps its current set
26
of options but it is not reopened (and therefore does not
27
inherit any new option from the parent).
28
29
2b) Reference to a different BDS: the current child is not put
30
in the reopen queue at all. Passing a reference to a
31
different BDS can be used to replace a child, although at
32
the moment no driver implements this, so it results in an
33
error. In any case, the current child is not going to be
34
reopened (and might in fact disappear if it's replaced)
35
36
3) NULL: This is similar to (2b). Although no driver allows this
37
yet it can be used to detach the current child so it should not
38
be put in the reopen queue.
39
40
4) Missing option: at the moment "backing" is the only case where
41
this can happen. With "blockdev-add", leaving "backing" out
42
means that the default backing file is opened. We don't want to
43
open a new image during reopen, so we require that "backing" is
44
always present. We'll relax this requirement a bit in the next
45
patch. If keep_old_opts is true and "backing" is missing then
46
this behaves like 2a (the current child is reopened).
47
48
Signed-off-by: Alberto Garcia <berto@igalia.com>
49
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
50
---
11
---
51
include/block/block.h | 1 +
12
include/block/block.h | 5 +++--
52
block.c | 52 +++++++++++++++++++++++++++++++++++++------
13
block/block-backend.c | 2 +-
53
2 files changed, 46 insertions(+), 7 deletions(-)
14
block/crypto.c | 2 +-
15
block/io.c | 12 +++++++-----
16
block/parallels.c | 6 +++---
17
block/qcow.c | 4 ++--
18
block/qcow2-refcount.c | 2 +-
19
block/qcow2.c | 15 +++++++++------
20
block/raw-format.c | 2 +-
21
block/vhdx-log.c | 2 +-
22
block/vhdx.c | 2 +-
23
block/vmdk.c | 2 +-
24
tests/test-block-iothread.c | 6 +++---
25
13 files changed, 34 insertions(+), 28 deletions(-)
54
26
55
diff --git a/include/block/block.h b/include/block/block.h
27
diff --git a/include/block/block.h b/include/block/block.h
56
index XXXXXXX..XXXXXXX 100644
28
index XXXXXXX..XXXXXXX 100644
57
--- a/include/block/block.h
29
--- a/include/block/block.h
58
+++ b/include/block/block.h
30
+++ b/include/block/block.h
59
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVReopenState {
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
60
BlockDriverState *bs;
32
void bdrv_refresh_filename(BlockDriverState *bs);
61
int flags;
33
62
BlockdevDetectZeroesOptions detect_zeroes;
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
63
+ bool backing_missing;
35
- PreallocMode prealloc, Error **errp);
64
uint64_t perm, shared_perm;
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
65
QDict *options;
37
+ Error **errp);
66
QDict *explicit_options;
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
67
diff --git a/block.c b/block.c
39
- PreallocMode prealloc, Error **errp);
68
index XXXXXXX..XXXXXXX 100644
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
69
--- a/block.c
41
70
+++ b/block.c
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
71
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
43
int64_t bdrv_getlength(BlockDriverState *bs);
72
bs_entry->state.perm = UINT64_MAX;
44
diff --git a/block/block-backend.c b/block/block-backend.c
73
bs_entry->state.shared_perm = 0;
45
index XXXXXXX..XXXXXXX 100644
74
46
--- a/block/block-backend.c
75
+ /*
47
+++ b/block/block-backend.c
76
+ * If keep_old_opts is false then it means that unspecified
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
77
+ * options must be reset to their original value. We don't allow
49
return -ENOMEDIUM;
78
+ * resetting 'backing' but we need to know if the option is
50
}
79
+ * missing in order to decide if we have to return an error.
51
80
+ */
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
81
+ if (!keep_old_opts) {
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
82
+ bs_entry->state.backing_missing =
54
}
83
+ !qdict_haskey(options, "backing") &&
55
84
+ !qdict_haskey(options, "backing.driver");
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
85
+ }
57
diff --git a/block/crypto.c b/block/crypto.c
86
+
58
index XXXXXXX..XXXXXXX 100644
87
QLIST_FOREACH(child, &bs->children, next) {
59
--- a/block/crypto.c
88
- QDict *new_child_options;
60
+++ b/block/crypto.c
89
- char *child_key_dot;
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
90
+ QDict *new_child_options = NULL;
62
91
+ bool child_keep_old = keep_old_opts;
63
offset += payload_offset;
92
64
93
/* reopen can only change the options of block devices that were
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
94
* implicitly created and inherited options. For other (referenced)
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
95
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
67
}
96
continue;
68
97
}
69
static void block_crypto_close(BlockDriverState *bs)
98
70
diff --git a/block/io.c b/block/io.c
99
- child_key_dot = g_strdup_printf("%s.", child->name);
71
index XXXXXXX..XXXXXXX 100644
100
- qdict_extract_subqdict(explicit_options, NULL, child_key_dot);
72
--- a/block/io.c
101
- qdict_extract_subqdict(options, &new_child_options, child_key_dot);
73
+++ b/block/io.c
102
- g_free(child_key_dot);
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
103
+ /* Check if the options contain a child reference */
75
* 'offset' bytes in length.
104
+ if (qdict_haskey(options, child->name)) {
76
*/
105
+ const char *childref = qdict_get_try_str(options, child->name);
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
106
+ /*
78
- PreallocMode prealloc, Error **errp)
107
+ * The current child must not be reopened if the child
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
108
+ * reference is null or points to a different node.
80
+ Error **errp)
109
+ */
81
{
110
+ if (g_strcmp0(childref, child->bs->node_name)) {
82
BlockDriverState *bs = child->bs;
111
+ continue;
83
BlockDriver *drv = bs->drv;
112
+ }
84
BdrvTrackedRequest req;
113
+ /*
85
- BdrvRequestFlags flags = 0;
114
+ * If the child reference points to the current child then
86
int64_t old_size, new_bytes;
115
+ * reopen it with its existing set of options (note that
87
int ret;
116
+ * it can still inherit new options from the parent).
88
117
+ */
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
118
+ child_keep_old = true;
90
}
119
+ } else {
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
120
+ /* Extract child options ("child-name.*") */
92
} else if (bs->file && drv->is_filter) {
121
+ char *child_key_dot = g_strdup_printf("%s.", child->name);
93
- ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
122
+ qdict_extract_subqdict(explicit_options, NULL, child_key_dot);
94
+ ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
123
+ qdict_extract_subqdict(options, &new_child_options, child_key_dot);
95
} else {
124
+ g_free(child_key_dot);
96
error_setg(errp, "Image format driver does not support resize");
125
+ }
97
ret = -ENOTSUP;
126
98
@@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo {
127
bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options,
99
int64_t offset;
128
- child->role, options, flags, keep_old_opts);
100
bool exact;
129
+ child->role, options, flags, child_keep_old);
101
PreallocMode prealloc;
130
}
102
+ BdrvRequestFlags flags;
131
103
Error **errp;
132
return bs_queue;
104
int ret;
133
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
105
} TruncateCo;
134
106
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
135
drv_prepared = true;
107
{
136
108
TruncateCo *tco = opaque;
137
+ if (drv->supports_backing && reopen_state->backing_missing) {
109
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
138
+ error_setg(errp, "backing is missing for '%s'",
110
- tco->prealloc, tco->errp);
139
+ reopen_state->bs->node_name);
111
+ tco->prealloc, tco->flags, tco->errp);
140
+ ret = -EINVAL;
112
aio_wait_kick();
141
+ goto error;
113
}
142
+ }
114
143
+
115
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
144
/* Options that are not handled are only okay if they are unchanged
116
- PreallocMode prealloc, Error **errp)
145
* compared to the old state. It is expected that some options are only
117
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
146
* used for the initial open, but not reopen (e.g. filename) */
118
{
119
Coroutine *co;
120
TruncateCo tco = {
121
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
122
.offset = offset,
123
.exact = exact,
124
.prealloc = prealloc,
125
+ .flags = flags,
126
.errp = errp,
127
.ret = NOT_DONE,
128
};
129
diff --git a/block/parallels.c b/block/parallels.c
130
index XXXXXXX..XXXXXXX 100644
131
--- a/block/parallels.c
132
+++ b/block/parallels.c
133
@@ -XXX,XX +XXX,XX @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
134
} else {
135
ret = bdrv_truncate(bs->file,
136
(s->data_end + space) << BDRV_SECTOR_BITS,
137
- false, PREALLOC_MODE_OFF, NULL);
138
+ false, PREALLOC_MODE_OFF, 0, NULL);
139
}
140
if (ret < 0) {
141
return ret;
142
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn parallels_co_check(BlockDriverState *bs,
143
* That means we have to pass exact=true.
144
*/
145
ret = bdrv_truncate(bs->file, res->image_end_offset, true,
146
- PREALLOC_MODE_OFF, &local_err);
147
+ PREALLOC_MODE_OFF, 0, &local_err);
148
if (ret < 0) {
149
error_report_err(local_err);
150
res->check_errors++;
151
@@ -XXX,XX +XXX,XX @@ static void parallels_close(BlockDriverState *bs)
152
153
/* errors are ignored, so we might as well pass exact=true */
154
bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, true,
155
- PREALLOC_MODE_OFF, NULL);
156
+ PREALLOC_MODE_OFF, 0, NULL);
157
}
158
159
g_free(s->bat_dirty_bmap);
160
diff --git a/block/qcow.c b/block/qcow.c
161
index XXXXXXX..XXXXXXX 100644
162
--- a/block/qcow.c
163
+++ b/block/qcow.c
164
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
165
return -E2BIG;
166
}
167
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
168
- false, PREALLOC_MODE_OFF, NULL);
169
+ false, PREALLOC_MODE_OFF, 0, NULL);
170
if (ret < 0) {
171
return ret;
172
}
173
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
174
l1_length) < 0)
175
return -1;
176
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
177
- PREALLOC_MODE_OFF, NULL);
178
+ PREALLOC_MODE_OFF, 0, NULL);
179
if (ret < 0)
180
return ret;
181
182
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
183
index XXXXXXX..XXXXXXX 100644
184
--- a/block/qcow2-refcount.c
185
+++ b/block/qcow2-refcount.c
186
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
187
}
188
189
ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
190
- PREALLOC_MODE_OFF, &local_err);
191
+ PREALLOC_MODE_OFF, 0, &local_err);
192
if (ret < 0) {
193
error_report_err(local_err);
194
goto resize_fail;
195
diff --git a/block/qcow2.c b/block/qcow2.c
196
index XXXXXXX..XXXXXXX 100644
197
--- a/block/qcow2.c
198
+++ b/block/qcow2.c
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn preallocate_co(BlockDriverState *bs, uint64_t offset,
200
mode = PREALLOC_MODE_OFF;
201
}
202
ret = bdrv_co_truncate(s->data_file, host_offset + cur_bytes, false,
203
- mode, errp);
204
+ mode, 0, errp);
205
if (ret < 0) {
206
return ret;
207
}
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
209
* always fulfilled, so there is no need to pass it on.)
210
*/
211
bdrv_co_truncate(bs->file, (last_cluster + 1) * s->cluster_size,
212
- false, PREALLOC_MODE_OFF, &local_err);
213
+ false, PREALLOC_MODE_OFF, 0, &local_err);
214
if (local_err) {
215
warn_reportf_err(local_err,
216
"Failed to truncate the tail of the image: ");
217
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
218
* file should be resized to the exact target size, too,
219
* so we pass @exact here.
220
*/
221
- ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, errp);
222
+ ret = bdrv_co_truncate(s->data_file, offset, exact, prealloc, 0,
223
+ errp);
224
if (ret < 0) {
225
goto fail;
226
}
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
228
new_file_size = allocation_start +
229
nb_new_data_clusters * s->cluster_size;
230
/* Image file grows, so @exact does not matter */
231
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp);
232
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
233
+ errp);
234
if (ret < 0) {
235
error_prepend(errp, "Failed to resize underlying file: ");
236
qcow2_free_clusters(bs, allocation_start,
237
@@ -XXX,XX +XXX,XX @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs,
238
if (len < 0) {
239
return len;
240
}
241
- return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, NULL);
242
+ return bdrv_co_truncate(bs->file, len, false, PREALLOC_MODE_OFF, 0,
243
+ NULL);
244
}
245
246
if (offset_into_cluster(s, offset)) {
247
@@ -XXX,XX +XXX,XX @@ static int make_completely_empty(BlockDriverState *bs)
248
}
249
250
ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size, false,
251
- PREALLOC_MODE_OFF, &local_err);
252
+ PREALLOC_MODE_OFF, 0, &local_err);
253
if (ret < 0) {
254
error_report_err(local_err);
255
goto fail;
256
diff --git a/block/raw-format.c b/block/raw-format.c
257
index XXXXXXX..XXXXXXX 100644
258
--- a/block/raw-format.c
259
+++ b/block/raw-format.c
260
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
261
262
s->size = offset;
263
offset += s->offset;
264
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
265
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
266
}
267
268
static void raw_eject(BlockDriverState *bs, bool eject_flag)
269
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
270
index XXXXXXX..XXXXXXX 100644
271
--- a/block/vhdx-log.c
272
+++ b/block/vhdx-log.c
273
@@ -XXX,XX +XXX,XX @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
274
goto exit;
275
}
276
ret = bdrv_truncate(bs->file, new_file_size, false,
277
- PREALLOC_MODE_OFF, NULL);
278
+ PREALLOC_MODE_OFF, 0, NULL);
279
if (ret < 0) {
280
goto exit;
281
}
282
diff --git a/block/vhdx.c b/block/vhdx.c
283
index XXXXXXX..XXXXXXX 100644
284
--- a/block/vhdx.c
285
+++ b/block/vhdx.c
286
@@ -XXX,XX +XXX,XX @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
287
}
288
289
return bdrv_truncate(bs->file, *new_offset + s->block_size, false,
290
- PREALLOC_MODE_OFF, NULL);
291
+ PREALLOC_MODE_OFF, 0, NULL);
292
}
293
294
/*
295
diff --git a/block/vmdk.c b/block/vmdk.c
296
index XXXXXXX..XXXXXXX 100644
297
--- a/block/vmdk.c
298
+++ b/block/vmdk.c
299
@@ -XXX,XX +XXX,XX @@ vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
300
}
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
302
ret = bdrv_truncate(s->extents[i].file, length, false,
303
- PREALLOC_MODE_OFF, NULL);
304
+ PREALLOC_MODE_OFF, 0, NULL);
305
if (ret < 0) {
306
return ret;
307
}
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
309
index XXXXXXX..XXXXXXX 100644
310
--- a/tests/test-block-iothread.c
311
+++ b/tests/test-block-iothread.c
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
313
int ret;
314
315
/* Normal success path */
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
318
g_assert_cmpint(ret, ==, 0);
319
320
/* Early error: Negative offset */
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
323
g_assert_cmpint(ret, ==, -EINVAL);
324
325
/* Error: Read-only image */
326
c->bs->read_only = true;
327
c->bs->open_flags &= ~BDRV_O_RDWR;
328
329
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
330
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
331
g_assert_cmpint(ret, ==, -EACCES);
332
333
c->bs->read_only = false;
147
--
334
--
148
2.20.1
335
2.25.3
149
336
150
337
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Now that node level interface bdrv_truncate() supports passing request
2
2
flags to the block driver, expose this on the BlockBackend level, too.
3
The bdrv_reopen_queue() function is used to create a queue with
3
4
the BDSs that are going to be reopened and their new options. Once
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
the queue is ready bdrv_reopen_multiple() is called to perform the
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
operation.
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
The original options from each one of the BDSs are kept, with the new
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
9
options passed to bdrv_reopen_queue() applied on top of them.
10
11
For "x-blockdev-reopen" we want a function that behaves much like
12
"blockdev-add". We want to ignore the previous set of options so that
13
only the ones actually specified by the user are applied, with the
14
rest having their default values.
15
16
One of the things that we need is a way to tell bdrv_reopen_queue()
17
whether we want to keep the old set of options or not, and that's what
18
this patch does. All current callers are setting this new parameter to
19
true and x-blockdev-reopen will set it to false.
20
21
Signed-off-by: Alberto Garcia <berto@igalia.com>
22
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
23
---
10
---
24
include/block/block.h | 3 ++-
11
include/sysemu/block-backend.h | 2 +-
25
block.c | 34 +++++++++++++++++++---------------
12
block.c | 3 ++-
26
block/replication.c | 4 ++--
13
block/block-backend.c | 4 ++--
27
qemu-io-cmds.c | 2 +-
14
block/commit.c | 4 ++--
28
4 files changed, 24 insertions(+), 19 deletions(-)
15
block/crypto.c | 2 +-
29
16
block/mirror.c | 2 +-
30
diff --git a/include/block/block.h b/include/block/block.h
17
block/qcow2.c | 4 ++--
31
index XXXXXXX..XXXXXXX 100644
18
block/qed.c | 2 +-
32
--- a/include/block/block.h
19
block/vdi.c | 2 +-
33
+++ b/include/block/block.h
20
block/vhdx.c | 4 ++--
34
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
21
block/vmdk.c | 6 +++---
35
BlockDriverState *bdrv_new_open_driver(BlockDriver *drv, const char *node_name,
22
block/vpc.c | 2 +-
36
int flags, Error **errp);
23
blockdev.c | 2 +-
37
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
24
qemu-img.c | 2 +-
38
- BlockDriverState *bs, QDict *options);
25
qemu-io-cmds.c | 2 +-
39
+ BlockDriverState *bs, QDict *options,
26
15 files changed, 22 insertions(+), 21 deletions(-)
40
+ bool keep_old_opts);
27
41
int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **errp);
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
42
int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
29
index XXXXXXX..XXXXXXX 100644
43
Error **errp);
30
--- a/include/sysemu/block-backend.h
31
+++ b/include/sysemu/block-backend.h
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
34
int bytes);
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
36
- PreallocMode prealloc, Error **errp);
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
40
int64_t pos, int size);
44
diff --git a/block.c b/block.c
41
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
42
index XXXXXXX..XXXXXXX 100644
46
--- a/block.c
43
--- a/block.c
47
+++ b/block.c
44
+++ b/block.c
48
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
49
QDict *options,
46
int64_t size;
50
const BdrvChildRole *role,
47
int ret;
51
QDict *parent_options,
48
52
- int parent_flags)
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
53
+ int parent_flags,
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
54
+ bool keep_old_opts)
51
+ &local_err);
52
if (ret < 0 && ret != -ENOTSUP) {
53
error_propagate(errp, local_err);
54
return ret;
55
diff --git a/block/block-backend.c b/block/block-backend.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/block-backend.c
58
+++ b/block/block-backend.c
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
60
}
61
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
63
- PreallocMode prealloc, Error **errp)
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
55
{
65
{
56
assert(bs != NULL);
66
if (!blk_is_available(blk)) {
57
67
error_setg(errp, "No medium inserted");
58
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
68
return -ENOMEDIUM;
59
*/
69
}
60
70
61
/* Old explicitly set values (don't overwrite by inherited value) */
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
62
- if (bs_entry) {
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
63
- old_options = qdict_clone_shallow(bs_entry->state.explicit_options);
64
- } else {
65
- old_options = qdict_clone_shallow(bs->explicit_options);
66
+ if (bs_entry || keep_old_opts) {
67
+ old_options = qdict_clone_shallow(bs_entry ?
68
+ bs_entry->state.explicit_options :
69
+ bs->explicit_options);
70
+ bdrv_join_options(bs, options, old_options);
71
+ qobject_unref(old_options);
72
}
73
- bdrv_join_options(bs, options, old_options);
74
- qobject_unref(old_options);
75
76
explicit_options = qdict_clone_shallow(options);
77
78
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
79
flags = bdrv_get_flags(bs);
80
}
81
82
- /* Old values are used for options that aren't set yet */
83
- old_options = qdict_clone_shallow(bs->options);
84
- bdrv_join_options(bs, options, old_options);
85
- qobject_unref(old_options);
86
+ if (keep_old_opts) {
87
+ /* Old values are used for options that aren't set yet */
88
+ old_options = qdict_clone_shallow(bs->options);
89
+ bdrv_join_options(bs, options, old_options);
90
+ qobject_unref(old_options);
91
+ }
92
93
/* We have the final set of options so let's update the flags */
94
options_copy = qdict_clone_shallow(options);
95
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
96
g_free(child_key_dot);
97
98
bdrv_reopen_queue_child(bs_queue, child->bs, new_child_options,
99
- child->role, options, flags);
100
+ child->role, options, flags, keep_old_opts);
101
}
102
103
return bs_queue;
104
@@ -XXX,XX +XXX,XX @@ static BlockReopenQueue *bdrv_reopen_queue_child(BlockReopenQueue *bs_queue,
105
106
BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue,
107
BlockDriverState *bs,
108
- QDict *options)
109
+ QDict *options, bool keep_old_opts)
110
{
111
- return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0);
112
+ return bdrv_reopen_queue_child(bs_queue, bs, options, NULL, NULL, 0,
113
+ keep_old_opts);
114
}
73
}
115
74
116
/*
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
117
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_set_read_only(BlockDriverState *bs, bool read_only,
76
diff --git a/block/commit.c b/block/commit.c
118
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, read_only);
77
index XXXXXXX..XXXXXXX 100644
119
78
--- a/block/commit.c
120
bdrv_subtree_drained_begin(bs);
79
+++ b/block/commit.c
121
- queue = bdrv_reopen_queue(NULL, bs, opts);
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
122
+ queue = bdrv_reopen_queue(NULL, bs, opts, true);
81
}
123
ret = bdrv_reopen_multiple(bdrv_get_aio_context(bs), queue, errp);
82
124
bdrv_subtree_drained_end(bs);
83
if (base_len < len) {
125
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
126
diff --git a/block/replication.c b/block/replication.c
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
127
index XXXXXXX..XXXXXXX 100644
86
if (ret) {
128
--- a/block/replication.c
87
goto out;
129
+++ b/block/replication.c
88
}
130
@@ -XXX,XX +XXX,XX @@ static void reopen_backing_file(BlockDriverState *bs, bool writable,
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
131
QDict *opts = qdict_new();
90
* grow the backing file image if possible. If not possible,
132
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
91
* we must return an error */
133
reopen_queue = bdrv_reopen_queue(reopen_queue, s->hidden_disk->bs,
92
if (length > backing_length) {
134
- opts);
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
135
+ opts, true);
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
136
}
95
&local_err);
137
96
if (ret < 0) {
138
if (s->orig_secondary_read_only) {
97
error_report_err(local_err);
139
QDict *opts = qdict_new();
98
diff --git a/block/crypto.c b/block/crypto.c
140
qdict_put_bool(opts, BDRV_OPT_READ_ONLY, !writable);
99
index XXXXXXX..XXXXXXX 100644
141
reopen_queue = bdrv_reopen_queue(reopen_queue, s->secondary_disk->bs,
100
--- a/block/crypto.c
142
- opts);
101
+++ b/block/crypto.c
143
+ opts, true);
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
144
}
103
* which will be used by the crypto header
145
104
*/
146
if (reopen_queue) {
105
return blk_truncate(data->blk, data->size + headerlen, false,
106
- data->prealloc, errp);
107
+ data->prealloc, 0, errp);
108
}
109
110
111
diff --git a/block/mirror.c b/block/mirror.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/block/mirror.c
114
+++ b/block/mirror.c
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
116
117
if (s->bdev_length > base_length) {
118
ret = blk_truncate(s->target, s->bdev_length, false,
119
- PREALLOC_MODE_OFF, NULL);
120
+ PREALLOC_MODE_OFF, 0, NULL);
121
if (ret < 0) {
122
goto immediate_exit;
123
}
124
diff --git a/block/qcow2.c b/block/qcow2.c
125
index XXXXXXX..XXXXXXX 100644
126
--- a/block/qcow2.c
127
+++ b/block/qcow2.c
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
129
130
/* Okay, now that we have a valid image, let's give it the right size */
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
132
- errp);
133
+ 0, errp);
134
if (ret < 0) {
135
error_prepend(errp, "Could not resize image: ");
136
goto out;
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
138
* Amending image options should ensure that the image has
139
* exactly the given new values, so pass exact=true here.
140
*/
141
- ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, errp);
142
+ ret = blk_truncate(blk, new_size, true, PREALLOC_MODE_OFF, 0, errp);
143
blk_unref(blk);
144
if (ret < 0) {
145
return ret;
146
diff --git a/block/qed.c b/block/qed.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/block/qed.c
149
+++ b/block/qed.c
150
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_qed_co_create(BlockdevCreateOptions *opts,
151
* The QED format associates file length with allocation status,
152
* so a new file (which is empty) must have a length of 0.
153
*/
154
- ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, errp);
155
+ ret = blk_truncate(blk, 0, true, PREALLOC_MODE_OFF, 0, errp);
156
if (ret < 0) {
157
goto out;
158
}
159
diff --git a/block/vdi.c b/block/vdi.c
160
index XXXXXXX..XXXXXXX 100644
161
--- a/block/vdi.c
162
+++ b/block/vdi.c
163
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vdi_co_do_create(BlockdevCreateOptions *create_options,
164
165
if (image_type == VDI_TYPE_STATIC) {
166
ret = blk_truncate(blk, offset + blocks * block_size, false,
167
- PREALLOC_MODE_OFF, errp);
168
+ PREALLOC_MODE_OFF, 0, errp);
169
if (ret < 0) {
170
error_prepend(errp, "Failed to statically allocate file");
171
goto exit;
172
diff --git a/block/vhdx.c b/block/vhdx.c
173
index XXXXXXX..XXXXXXX 100644
174
--- a/block/vhdx.c
175
+++ b/block/vhdx.c
176
@@ -XXX,XX +XXX,XX @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
177
/* All zeroes, so we can just extend the file - the end of the BAT
178
* is the furthest thing we have written yet */
179
ret = blk_truncate(blk, data_file_offset, false, PREALLOC_MODE_OFF,
180
- errp);
181
+ 0, errp);
182
if (ret < 0) {
183
goto exit;
184
}
185
} else if (type == VHDX_TYPE_FIXED) {
186
ret = blk_truncate(blk, data_file_offset + image_size, false,
187
- PREALLOC_MODE_OFF, errp);
188
+ PREALLOC_MODE_OFF, 0, errp);
189
if (ret < 0) {
190
goto exit;
191
}
192
diff --git a/block/vmdk.c b/block/vmdk.c
193
index XXXXXXX..XXXXXXX 100644
194
--- a/block/vmdk.c
195
+++ b/block/vmdk.c
196
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
197
int gd_buf_size;
198
199
if (flat) {
200
- ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, errp);
201
+ ret = blk_truncate(blk, filesize, false, PREALLOC_MODE_OFF, 0, errp);
202
goto exit;
203
}
204
magic = cpu_to_be32(VMDK4_MAGIC);
205
@@ -XXX,XX +XXX,XX @@ static int vmdk_init_extent(BlockBackend *blk,
206
}
207
208
ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, false,
209
- PREALLOC_MODE_OFF, errp);
210
+ PREALLOC_MODE_OFF, 0, errp);
211
if (ret < 0) {
212
goto exit;
213
}
214
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn vmdk_co_do_create(int64_t size,
215
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
216
* for description file */
217
if (desc_offset == 0) {
218
- ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, errp);
219
+ ret = blk_truncate(blk, desc_len, false, PREALLOC_MODE_OFF, 0, errp);
220
if (ret < 0) {
221
goto exit;
222
}
223
diff --git a/block/vpc.c b/block/vpc.c
224
index XXXXXXX..XXXXXXX 100644
225
--- a/block/vpc.c
226
+++ b/block/vpc.c
227
@@ -XXX,XX +XXX,XX @@ static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
228
/* Add footer to total size */
229
total_size += HEADER_SIZE;
230
231
- ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, errp);
232
+ ret = blk_truncate(blk, total_size, false, PREALLOC_MODE_OFF, 0, errp);
233
if (ret < 0) {
234
return ret;
235
}
236
diff --git a/blockdev.c b/blockdev.c
237
index XXXXXXX..XXXXXXX 100644
238
--- a/blockdev.c
239
+++ b/blockdev.c
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
241
}
242
243
bdrv_drained_begin(bs);
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
246
bdrv_drained_end(bs);
247
248
out:
249
diff --git a/qemu-img.c b/qemu-img.c
250
index XXXXXXX..XXXXXXX 100644
251
--- a/qemu-img.c
252
+++ b/qemu-img.c
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
254
* resizing, so pass @exact=true. It is of no use to report
255
* success when the image has not actually been resized.
256
*/
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
259
if (!ret) {
260
qprintf(quiet, "Image resized.\n");
261
} else {
147
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
148
index XXXXXXX..XXXXXXX 100644
263
index XXXXXXX..XXXXXXX 100644
149
--- a/qemu-io-cmds.c
264
--- a/qemu-io-cmds.c
150
+++ b/qemu-io-cmds.c
265
+++ b/qemu-io-cmds.c
151
@@ -XXX,XX +XXX,XX @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
152
}
267
* exact=true. It is better to err on the "emit more errors" side
153
268
* than to be overly permissive.
154
bdrv_subtree_drained_begin(bs);
269
*/
155
- brq = bdrv_reopen_queue(NULL, bs, opts);
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
156
+ brq = bdrv_reopen_queue(NULL, bs, opts, true);
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
157
bdrv_reopen_multiple(bdrv_get_aio_context(bs), brq, &local_err);
272
if (ret < 0) {
158
bdrv_subtree_drained_end(bs);
273
error_report_err(local_err);
159
274
return ret;
160
--
275
--
161
2.20.1
276
2.25.3
162
277
163
278
diff view generated by jsdifflib
1
If BDRV_REQ_ZERO_WRITE is set and we're extending the image, calling
2
qcow2_cluster_zeroize() with flags=0 does the right thing: It doesn't
3
undo any previous preallocation, but just adds the zero flag to all
4
relevant L2 entries. If an external data file is in use, a write_zeroes
5
request to the data file is made instead.
6
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
9
Reviewed-by: Eric Blake <eblake@redhat.com>
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
---
12
---
3
block/file-posix.c | 107 ++++++++++++++++++++++++++-------------------
13
block/qcow2-cluster.c | 2 +-
4
1 file changed, 62 insertions(+), 45 deletions(-)
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
15
2 files changed, 35 insertions(+), 1 deletion(-)
5
16
6
diff --git a/block/file-posix.c b/block/file-posix.c
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
7
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
8
--- a/block/file-posix.c
19
--- a/block/qcow2-cluster.c
9
+++ b/block/file-posix.c
20
+++ b/block/qcow2-cluster.c
10
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
11
return ret;
22
/* Caller must pass aligned values, except at image end */
12
}
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
13
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
14
+static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
15
+ int *open_flags, Error **errp)
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
16
+{
27
17
+ BDRVRawState *s = bs->opaque;
28
/* The zero flag is only supported by version 3 and newer */
18
+ int fd = -1;
29
if (s->qcow_version < 3) {
19
+ int ret;
30
diff --git a/block/qcow2.c b/block/qcow2.c
20
+ int fcntl_flags = O_APPEND | O_NONBLOCK;
31
index XXXXXXX..XXXXXXX 100644
21
+#ifdef O_NOATIME
32
--- a/block/qcow2.c
22
+ fcntl_flags |= O_NOATIME;
33
+++ b/block/qcow2.c
23
+#endif
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
35
36
bs->supported_zero_flags = header.version >= 3 ?
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
39
40
/* Repair image if dirty */
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
43
g_assert_not_reached();
44
}
45
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
24
+
48
+
25
+ *open_flags = 0;
49
+ /*
26
+ if (s->type == FTYPE_CD) {
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
27
+ *open_flags |= O_NONBLOCK;
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
28
+ }
52
+ * at the end of the image (which it is here).
53
+ */
54
+ ret = qcow2_cluster_zeroize(bs, zero_start, offset - zero_start, 0);
55
+ if (ret < 0) {
56
+ error_setg_errno(errp, -ret, "Failed to zero out new clusters");
57
+ goto fail;
58
+ }
29
+
59
+
30
+ raw_parse_flags(flags, open_flags);
60
+ /* Write explicit zeros for the unaligned head */
61
+ if (zero_start > old_length) {
62
+ uint64_t len = zero_start - old_length;
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
64
+ QEMUIOVector qiov;
65
+ qemu_iovec_init_buf(&qiov, buf, len);
31
+
66
+
32
+#ifdef O_ASYNC
67
+ qemu_co_mutex_unlock(&s->lock);
33
+ /* Not all operating systems have O_ASYNC, and those that don't
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
34
+ * will not let us track the state into rs->open_flags (typically
69
+ qemu_co_mutex_lock(&s->lock);
35
+ * you achieve the same effect with an ioctl, for example I_SETSIG
36
+ * on Solaris). But we do not use O_ASYNC, so that's fine.
37
+ */
38
+ assert((s->open_flags & O_ASYNC) == 0);
39
+#endif
40
+
70
+
41
+ if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
71
+ qemu_vfree(buf);
42
+ /* dup the original fd */
72
+ if (ret < 0) {
43
+ fd = qemu_dup(s->fd);
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
44
+ if (fd >= 0) {
74
+ goto fail;
45
+ ret = fcntl_setfl(fd, *open_flags);
46
+ if (ret) {
47
+ qemu_close(fd);
48
+ fd = -1;
49
+ }
75
+ }
50
+ }
76
+ }
51
+ }
77
+ }
52
+
78
+
53
+ /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
79
if (prealloc != PREALLOC_MODE_OFF) {
54
+ if (fd == -1) {
80
/* Flush metadata before actually changing the image size */
55
+ const char *normalized_filename = bs->filename;
81
ret = qcow2_write_caches(bs);
56
+ ret = raw_normalize_devicepath(&normalized_filename, errp);
57
+ if (ret >= 0) {
58
+ assert(!(*open_flags & O_CREAT));
59
+ fd = qemu_open(normalized_filename, *open_flags);
60
+ if (fd == -1) {
61
+ error_setg_errno(errp, errno, "Could not reopen file");
62
+ return -1;
63
+ }
64
+ }
65
+ }
66
+
67
+ return fd;
68
+}
69
+
70
static int raw_reopen_prepare(BDRVReopenState *state,
71
BlockReopenQueue *queue, Error **errp)
72
{
73
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
74
75
state->opaque = g_new0(BDRVRawReopenState, 1);
76
rs = state->opaque;
77
- rs->fd = -1;
78
79
/* Handle options changes */
80
opts = qemu_opts_create(&raw_runtime_opts, NULL, 0, &error_abort);
81
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
82
* bdrv_reopen_prepare() will detect changes and complain. */
83
qemu_opts_to_qdict(opts, state->options);
84
85
- if (s->type == FTYPE_CD) {
86
- rs->open_flags |= O_NONBLOCK;
87
- }
88
-
89
- raw_parse_flags(state->flags, &rs->open_flags);
90
-
91
- int fcntl_flags = O_APPEND | O_NONBLOCK;
92
-#ifdef O_NOATIME
93
- fcntl_flags |= O_NOATIME;
94
-#endif
95
-
96
-#ifdef O_ASYNC
97
- /* Not all operating systems have O_ASYNC, and those that don't
98
- * will not let us track the state into rs->open_flags (typically
99
- * you achieve the same effect with an ioctl, for example I_SETSIG
100
- * on Solaris). But we do not use O_ASYNC, so that's fine.
101
- */
102
- assert((s->open_flags & O_ASYNC) == 0);
103
-#endif
104
-
105
- if ((rs->open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
106
- /* dup the original fd */
107
- rs->fd = qemu_dup(s->fd);
108
- if (rs->fd >= 0) {
109
- ret = fcntl_setfl(rs->fd, rs->open_flags);
110
- if (ret) {
111
- qemu_close(rs->fd);
112
- rs->fd = -1;
113
- }
114
- }
115
- }
116
-
117
- /* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
118
- if (rs->fd == -1) {
119
- const char *normalized_filename = state->bs->filename;
120
- ret = raw_normalize_devicepath(&normalized_filename, errp);
121
- if (ret >= 0) {
122
- assert(!(rs->open_flags & O_CREAT));
123
- rs->fd = qemu_open(normalized_filename, rs->open_flags);
124
- if (rs->fd == -1) {
125
- error_setg_errno(errp, errno, "Could not reopen file");
126
- ret = -1;
127
- }
128
- }
129
+ rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
130
+ &local_err);
131
+ if (local_err) {
132
+ error_propagate(errp, local_err);
133
+ ret = -1;
134
+ goto out;
135
}
136
137
/* Fail already reopen_prepare() if we can't get a working O_DIRECT
138
--
82
--
139
2.20.1
83
2.25.3
140
84
141
85
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The raw format driver can simply forward the flag and let its bs->file
2
child take care of actually providing the zeros.
2
3
3
bdrv_reopen_prepare() receives a BDRVReopenState with (among other
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
things) a new set of options to be applied to that BlockDriverState.
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
6
Reviewed-by: Eric Blake <eblake@redhat.com>
6
If an option is missing then it means that we want to reset it to its
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
7
default value rather than keep the previous one. This way the state
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
8
of the block device after being reopened is comparable to that of a
9
device added with "blockdev-add" using the same set of options.
10
11
Not all options from all drivers can be changed this way, however.
12
If the user attempts to reset an immutable option to its default value
13
using this method then we must forbid it.
14
15
This new function takes a BlockDriverState and a new set of options
16
and checks if there's any option that was previously set but is
17
missing from the new set of options.
18
19
If the option is present in both sets we don't need to check that they
20
have the same value. The loop at the end of bdrv_reopen_prepare()
21
already takes care of that.
22
23
Signed-off-by: Alberto Garcia <berto@igalia.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
10
---
26
block.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11
block/raw-format.c | 4 +++-
27
1 file changed, 58 insertions(+)
12
1 file changed, 3 insertions(+), 1 deletion(-)
28
13
29
diff --git a/block.c b/block.c
14
diff --git a/block/raw-format.c b/block/raw-format.c
30
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
16
--- a/block/raw-format.c
32
+++ b/block.c
17
+++ b/block/raw-format.c
33
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
34
NULL, errp);
19
20
s->size = offset;
21
offset += s->offset;
22
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
23
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
35
}
24
}
36
25
37
+/* Return true if the NULL-terminated @list contains @str */
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
38
+static bool is_str_in_list(const char *str, const char *const *list)
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
39
+{
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
40
+ if (str && list) {
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
41
+ int i;
30
bs->file->bs->supported_zero_flags);
42
+ for (i = 0; list[i] != NULL; i++) {
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
43
+ if (!strcmp(str, list[i])) {
32
+ BDRV_REQ_ZERO_WRITE;
44
+ return true;
33
45
+ }
34
if (bs->probed && !bdrv_is_read_only(bs)) {
46
+ }
35
bdrv_refresh_filename(bs->file->bs);
47
+ }
48
+ return false;
49
+}
50
+
51
+/*
52
+ * Check that every option set in @bs->options is also set in
53
+ * @new_opts.
54
+ *
55
+ * Options listed in the common_options list and in
56
+ * @bs->drv->mutable_opts are skipped.
57
+ *
58
+ * Return 0 on success, otherwise return -EINVAL and set @errp.
59
+ */
60
+static int bdrv_reset_options_allowed(BlockDriverState *bs,
61
+ const QDict *new_opts, Error **errp)
62
+{
63
+ const QDictEntry *e;
64
+ /* These options are common to all block drivers and are handled
65
+ * in bdrv_reopen_prepare() so they can be left out of @new_opts */
66
+ const char *const common_options[] = {
67
+ "node-name", "discard", "cache.direct", "cache.no-flush",
68
+ "read-only", "auto-read-only", "detect-zeroes", NULL
69
+ };
70
+
71
+ for (e = qdict_first(bs->options); e; e = qdict_next(bs->options, e)) {
72
+ if (!qdict_haskey(new_opts, e->key) &&
73
+ !is_str_in_list(e->key, common_options) &&
74
+ !is_str_in_list(e->key, bs->drv->mutable_opts)) {
75
+ error_setg(errp, "Option '%s' cannot be reset "
76
+ "to its default value", e->key);
77
+ return -EINVAL;
78
+ }
79
+ }
80
+
81
+ return 0;
82
+}
83
+
84
/*
85
* Returns true if @child can be reached recursively from @bs
86
*/
87
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
88
}
89
90
if (drv->bdrv_reopen_prepare) {
91
+ /*
92
+ * If a driver-specific option is missing, it means that we
93
+ * should reset it to its default value.
94
+ * But not all options allow that, so we need to check it first.
95
+ */
96
+ ret = bdrv_reset_options_allowed(reopen_state->bs,
97
+ reopen_state->options, errp);
98
+ if (ret) {
99
+ goto error;
100
+ }
101
+
102
ret = drv->bdrv_reopen_prepare(reopen_state, queue, &local_err);
103
if (ret) {
104
if (local_err != NULL) {
105
--
36
--
106
2.20.1
37
2.25.3
107
38
108
39
diff view generated by jsdifflib
1
Until now, with auto-read-only=on we tried to open the file read-write
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
first and if that failed, read-only was tried. This is actually not good
2
OS, so we can advertise the flag and just ignore it.
3
enough for libvirt, which gives QEMU SELinux permissions for read-write
4
only as soon as it actually intends to write to the image. So we need to
5
be able to switch between read-only and read-write at runtime.
6
7
This patch makes auto-read-only dynamic, i.e. the file is opened
8
read-only as long as no user of the node has requested write
9
permissions, but it is automatically reopened read-write as soon as the
10
first writer is attached. Conversely, if the last writer goes away, the
11
file is reopened read-only again.
12
13
bs->read_only is no longer set for auto-read-only=on files even if the
14
file descriptor is opened read-only because it will be transparently
15
upgraded as soon as a writer is attached. This changes the output of
16
qemu-iotests 232.
17
3
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
Message-Id: <20200424125448.63318-7-kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
19
---
10
---
20
block/file-posix.c | 36 +++++++++++++++++-------------------
11
block/file-posix.c | 4 ++++
21
tests/qemu-iotests/232.out | 12 ++++++------
12
1 file changed, 4 insertions(+)
22
2 files changed, 23 insertions(+), 25 deletions(-)
23
13
24
diff --git a/block/file-posix.c b/block/file-posix.c
14
diff --git a/block/file-posix.c b/block/file-posix.c
25
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
26
--- a/block/file-posix.c
16
--- a/block/file-posix.c
27
+++ b/block/file-posix.c
17
+++ b/block/file-posix.c
28
@@ -XXX,XX +XXX,XX @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
29
}
19
#endif
30
}
20
31
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
32
-static void raw_parse_flags(int bdrv_flags, int *open_flags)
22
+ if (S_ISREG(st.st_mode)) {
33
+static void raw_parse_flags(int bdrv_flags, int *open_flags, bool has_writers)
23
+ /* When extending regular files, we get zeros from the OS */
34
{
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
35
+ bool read_write = false;
36
assert(open_flags != NULL);
37
38
*open_flags |= O_BINARY;
39
*open_flags &= ~O_ACCMODE;
40
- if (bdrv_flags & BDRV_O_RDWR) {
41
+
42
+ if (bdrv_flags & BDRV_O_AUTO_RDONLY) {
43
+ read_write = has_writers;
44
+ } else if (bdrv_flags & BDRV_O_RDWR) {
45
+ read_write = true;
46
+ }
25
+ }
47
+
26
ret = 0;
48
+ if (read_write) {
27
fail:
49
*open_flags |= O_RDWR;
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
50
} else {
51
*open_flags |= O_RDONLY;
52
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
53
false);
54
55
s->open_flags = open_flags;
56
- raw_parse_flags(bdrv_flags, &s->open_flags);
57
+ raw_parse_flags(bdrv_flags, &s->open_flags, false);
58
59
s->fd = -1;
60
fd = qemu_open(filename, s->open_flags, 0644);
61
ret = fd < 0 ? -errno : 0;
62
63
- if (ret == -EACCES || ret == -EROFS) {
64
- /* Try to degrade to read-only, but if it doesn't work, still use the
65
- * normal error message. */
66
- if (bdrv_apply_auto_read_only(bs, NULL, NULL) == 0) {
67
- bdrv_flags &= ~BDRV_O_RDWR;
68
- raw_parse_flags(bdrv_flags, &s->open_flags);
69
- assert(!(s->open_flags & O_CREAT));
70
- fd = qemu_open(filename, s->open_flags);
71
- ret = fd < 0 ? -errno : 0;
72
- }
73
- }
74
-
75
if (ret < 0) {
76
error_setg_errno(errp, -ret, "Could not open '%s'", filename);
77
if (ret == -EROFS) {
78
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
79
}
80
81
static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
82
- int *open_flags, bool force_dup,
83
+ int *open_flags, uint64_t perm, bool force_dup,
84
Error **errp)
85
{
86
BDRVRawState *s = bs->opaque;
87
int fd = -1;
88
int ret;
89
+ bool has_writers = perm &
90
+ (BLK_PERM_WRITE | BLK_PERM_WRITE_UNCHANGED | BLK_PERM_RESIZE);
91
int fcntl_flags = O_APPEND | O_NONBLOCK;
92
#ifdef O_NOATIME
93
fcntl_flags |= O_NOATIME;
94
@@ -XXX,XX +XXX,XX @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
95
*open_flags |= O_NONBLOCK;
96
}
97
98
- raw_parse_flags(flags, open_flags);
99
+ raw_parse_flags(flags, open_flags, has_writers);
100
101
#ifdef O_ASYNC
102
/* Not all operating systems have O_ASYNC, and those that don't
103
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
104
qemu_opts_to_qdict(opts, state->options);
105
106
rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
107
- true, &local_err);
108
+ state->perm, true, &local_err);
109
if (local_err) {
110
error_propagate(errp, local_err);
111
ret = -1;
112
@@ -XXX,XX +XXX,XX @@ static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
113
s->perm_change_fd = rs->fd;
114
} else {
115
/* We may need a new fd if auto-read-only switches the mode */
116
- ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags,
117
+ ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags, perm,
118
false, errp);
119
if (ret < 0) {
120
return ret;
121
diff --git a/tests/qemu-iotests/232.out b/tests/qemu-iotests/232.out
122
index XXXXXXX..XXXXXXX 100644
123
--- a/tests/qemu-iotests/232.out
124
+++ b/tests/qemu-iotests/232.out
125
@@ -XXX,XX +XXX,XX @@ NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
126
NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
127
128
QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
129
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
130
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
131
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
132
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
133
134
QEMU_PROG: -drive driver=file,file=TEST_DIR/t.IMGFMT,if=none,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
135
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
136
-NODE_NAME: TEST_DIR/t.IMGFMT (file, read-only)
137
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
138
+NODE_NAME: TEST_DIR/t.IMGFMT (file)
139
140
=== -blockdev with read-write image: read-only/auto-read-only combinations ===
141
142
@@ -XXX,XX +XXX,XX @@ node0: TEST_DIR/t.IMGFMT (file, read-only)
143
node0: TEST_DIR/t.IMGFMT (file, read-only)
144
145
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
146
-node0: TEST_DIR/t.IMGFMT (file, read-only)
147
+node0: TEST_DIR/t.IMGFMT (file)
148
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
149
150
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0,auto-read-only=off: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
151
-node0: TEST_DIR/t.IMGFMT (file, read-only)
152
+node0: TEST_DIR/t.IMGFMT (file)
153
QEMU_PROG: -blockdev driver=file,filename=TEST_DIR/t.IMGFMT,node-name=node0: Could not open 'TEST_DIR/t.IMGFMT': Permission denied
154
155
=== Try commit to backing file with auto-read-only ===
156
--
29
--
157
2.20.1
30
2.25.3
158
31
159
32
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
When extending the size of an image that has a backing file larger than
2
its old size, make sure that the backing file data doesn't become
3
visible in the guest, but the added area is properly zeroed out.
2
4
3
Our permission system is useful to define what operations are allowed
5
Consider the following scenario where the overlay is shorter than its
4
on a certain block node and includes things like BLK_PERM_WRITE or
6
backing file:
5
BLK_PERM_RESIZE among others.
6
7
7
One of the permissions is BLK_PERM_GRAPH_MOD which allows "changing
8
base.qcow2: AAAAAAAA
8
the node that this BdrvChild points to". The exact meaning of this has
9
overlay.qcow2: BBBB
9
never been very clear, but it can be understood as "change any of the
10
links connected to the node". This can be used to prevent changing a
11
backing link, but it's too coarse.
12
10
13
This patch adds a new 'frozen' attribute to BdrvChild, which forbids
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
14
detaching the link from the node it points to, and new API to freeze
12
unallocated and make the additional As from base.qcow2 visible like
15
and unfreeze a backing chain.
13
before this patch, but zeros should be read.
16
14
17
After this change a few functions can fail, so they need additional
15
A similar case happens with the various variants of a commit job when an
18
checks.
16
intermediate file is short (- for unallocated):
19
17
20
Signed-off-by: Alberto Garcia <berto@igalia.com>
18
base.qcow2: A-A-AAAA
19
mid.qcow2: BB-B
20
top.qcow2: C--C--C-
21
22
After commit top.qcow2 to mid.qcow2, the following happens:
23
24
mid.qcow2: CB-C00C0 (correct result)
25
mid.qcow2: CB-C--C- (before this fix)
26
27
Without the fix, blocks that previously read as zeros on top.qcow2
28
suddenly turn into A.
29
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
32
Message-Id: <20200424125448.63318-8-kwolf@redhat.com>
33
Reviewed-by: Max Reitz <mreitz@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
35
---
23
include/block/block.h | 5 +++
36
block/io.c | 25 +++++++++++++++++++++++++
24
include/block/block_int.h | 6 ++++
37
1 file changed, 25 insertions(+)
25
block.c | 76 +++++++++++++++++++++++++++++++++++++++
26
3 files changed, 87 insertions(+)
27
38
28
diff --git a/include/block/block.h b/include/block/block.h
39
diff --git a/block/io.c b/block/io.c
29
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
30
--- a/include/block/block.h
41
--- a/block/io.c
31
+++ b/include/block/block.h
42
+++ b/block/io.c
32
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
33
BlockDriverState *bdrv_find_overlay(BlockDriverState *active,
44
goto out;
34
BlockDriverState *bs);
45
}
35
BlockDriverState *bdrv_find_base(BlockDriverState *bs);
36
+bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
37
+ Error **errp);
38
+int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
39
+ Error **errp);
40
+void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base);
41
42
43
typedef struct BdrvCheckResult {
44
diff --git a/include/block/block_int.h b/include/block/block_int.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/block_int.h
47
+++ b/include/block/block_int.h
48
@@ -XXX,XX +XXX,XX @@ struct BdrvChild {
49
uint64_t backup_perm;
50
uint64_t backup_shared_perm;
51
46
52
+ /*
47
+ /*
53
+ * This link is frozen: the child can neither be replaced nor
48
+ * If the image has a backing file that is large enough that it would
54
+ * detached from the parent.
49
+ * provide data for the new area, we cannot leave it unallocated because
50
+ * then the backing file content would become visible. Instead, zero-fill
51
+ * the new area.
52
+ *
53
+ * Note that if the image has a backing file, but was opened without the
54
+ * backing file, taking care of keeping things consistent with that backing
55
+ * file is the user's responsibility.
55
+ */
56
+ */
56
+ bool frozen;
57
+ if (new_bytes && bs->backing) {
58
+ int64_t backing_len;
57
+
59
+
58
QLIST_ENTRY(BdrvChild) next;
60
+ backing_len = bdrv_getlength(backing_bs(bs));
59
QLIST_ENTRY(BdrvChild) next_parent;
61
+ if (backing_len < 0) {
60
};
62
+ ret = backing_len;
61
diff --git a/block.c b/block.c
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
62
index XXXXXXX..XXXXXXX 100644
63
--- a/block.c
64
+++ b/block.c
65
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
66
BlockDriverState *old_bs = child->bs;
67
int i;
68
69
+ assert(!child->frozen);
70
+
71
if (old_bs && new_bs) {
72
assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
73
}
74
@@ -XXX,XX +XXX,XX @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
75
bool update_inherits_from = bdrv_chain_contains(bs, backing_hd) &&
76
bdrv_inherits_from_recursive(backing_hd, bs);
77
78
+ if (bdrv_is_backing_chain_frozen(bs, backing_bs(bs), errp)) {
79
+ return;
80
+ }
81
+
82
if (backing_hd) {
83
bdrv_ref(backing_hd);
84
}
85
@@ -XXX,XX +XXX,XX @@ void bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
86
if (!should_update_child(c, to)) {
87
continue;
88
}
89
+ if (c->frozen) {
90
+ error_setg(errp, "Cannot change '%s' link to '%s'",
91
+ c->name, from->node_name);
92
+ goto out;
64
+ goto out;
93
+ }
65
+ }
94
list = g_slist_prepend(list, c);
95
perm |= c->perm;
96
shared &= c->shared_perm;
97
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
98
return bdrv_find_overlay(bs, NULL);
99
}
100
101
+/*
102
+ * Return true if at least one of the backing links between @bs and
103
+ * @base is frozen. @errp is set if that's the case.
104
+ */
105
+bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
106
+ Error **errp)
107
+{
108
+ BlockDriverState *i;
109
+
66
+
110
+ for (i = bs; i != base && i->backing; i = backing_bs(i)) {
67
+ if (backing_len > old_size) {
111
+ if (i->backing->frozen) {
68
+ flags |= BDRV_REQ_ZERO_WRITE;
112
+ error_setg(errp, "Cannot change '%s' link from '%s' to '%s'",
113
+ i->backing->name, i->node_name,
114
+ backing_bs(i)->node_name);
115
+ return true;
116
+ }
69
+ }
117
+ }
70
+ }
118
+
71
+
119
+ return false;
72
if (drv->bdrv_co_truncate) {
120
+}
73
if (flags & ~bs->supported_truncate_flags) {
121
+
74
error_setg(errp, "Block driver does not support requested flags");
122
+/*
123
+ * Freeze all backing links between @bs and @base.
124
+ * If any of the links is already frozen the operation is aborted and
125
+ * none of the links are modified.
126
+ * Returns 0 on success. On failure returns < 0 and sets @errp.
127
+ */
128
+int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
129
+ Error **errp)
130
+{
131
+ BlockDriverState *i;
132
+
133
+ if (bdrv_is_backing_chain_frozen(bs, base, errp)) {
134
+ return -EPERM;
135
+ }
136
+
137
+ for (i = bs; i != base && i->backing; i = backing_bs(i)) {
138
+ i->backing->frozen = true;
139
+ }
140
+
141
+ return 0;
142
+}
143
+
144
+/*
145
+ * Unfreeze all backing links between @bs and @base. The caller must
146
+ * ensure that all links are frozen before using this function.
147
+ */
148
+void bdrv_unfreeze_backing_chain(BlockDriverState *bs, BlockDriverState *base)
149
+{
150
+ BlockDriverState *i;
151
+
152
+ for (i = bs; i != base && i->backing; i = backing_bs(i)) {
153
+ assert(i->backing->frozen);
154
+ i->backing->frozen = false;
155
+ }
156
+}
157
+
158
/*
159
* Drops images above 'base' up to and including 'top', and sets the image
160
* above 'top' to have base as its backing file.
161
@@ -XXX,XX +XXX,XX @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
162
goto exit;
163
}
164
165
+ /* This function changes all links that point to top and makes
166
+ * them point to base. Check that none of them is frozen. */
167
+ QLIST_FOREACH(c, &top->parents, next_parent) {
168
+ if (c->frozen) {
169
+ goto exit;
170
+ }
171
+ }
172
+
173
/* If 'base' recursively inherits from 'top' then we should set
174
* base->inherits_from to top->inherits_from after 'top' and all
175
* other intermediate nodes have been dropped.
176
--
75
--
177
2.20.1
76
2.25.3
178
77
179
78
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
We want to keep TEST_IMG for the full path of the main test image, but
2
filter_testfiles() must be called for other test images before replacing
3
other things like the image format because the test directory path could
4
contain the format as a substring.
2
5
3
Of all options of type BlockdevRef used to specify children in
6
Insert a filter_testfiles() call between both.
4
BlockdevOptions, 'backing' is the only one that is optional.
5
7
6
For "x-blockdev-reopen" we want that if an option is omitted then it
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
must be reset to its default value. The default value of 'backing'
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
8
means that QEMU opens the backing file specified in the image
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
9
metadata, but this is not something that we want to support for the
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
10
reopen operation.
11
12
Because of this the 'backing' option has to be specified during
13
reopen, pointing to the existing backing file if we want to keep it,
14
or pointing to a different one (or NULL) if we want to replace it (to
15
be implemented in a subsequent patch).
16
17
In order to simplify things a bit and not to require that the user
18
passes the 'backing' option to every single block device even when
19
it's clearly not necessary, this patch allows omitting this option if
20
the block device being reopened doesn't have a backing file attached
21
_and_ no default backing file is specified in the image metadata.
22
23
Signed-off-by: Alberto Garcia <berto@igalia.com>
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
13
---
26
block.c | 8 +++++++-
14
tests/qemu-iotests/iotests.py | 5 +++--
27
1 file changed, 7 insertions(+), 1 deletion(-)
15
1 file changed, 3 insertions(+), 2 deletions(-)
28
16
29
diff --git a/block.c b/block.c
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
30
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
19
--- a/tests/qemu-iotests/iotests.py
32
+++ b/block.c
20
+++ b/tests/qemu-iotests/iotests.py
33
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
34
22
for line in output.split('\n'):
35
drv_prepared = true;
23
if 'disk size' in line or 'actual-size' in line:
36
24
continue
37
- if (drv->supports_backing && reopen_state->backing_missing) {
25
- line = line.replace(filename, 'TEST_IMG') \
38
+ /*
26
- .replace(imgfmt, 'IMGFMT')
39
+ * We must provide the 'backing' option if the BDS has a backing
27
+ line = line.replace(filename, 'TEST_IMG')
40
+ * file or if the image file has a backing file name as part of
28
+ line = filter_testfiles(line)
41
+ * its metadata. Otherwise the 'backing' option can be omitted.
29
+ line = line.replace(imgfmt, 'IMGFMT')
42
+ */
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
43
+ if (drv->supports_backing && reopen_state->backing_missing &&
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
44
+ (backing_bs(reopen_state->bs) || reopen_state->bs->backing_file[0])) {
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
45
error_setg(errp, "backing is missing for '%s'",
46
reopen_state->bs->node_name);
47
ret = -EINVAL;
48
--
33
--
49
2.20.1
34
2.25.3
50
35
51
36
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
3
This patch adds several tests for the x-blockdev-reopen QMP command.
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Alberto Garcia <berto@igalia.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
6
---
8
tests/qemu-iotests/245 | 991 +++++++++++++++++++++++++++++++++++++
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
9
tests/qemu-iotests/245.out | 5 +
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/group | 1 +
9
tests/qemu-iotests/group | 1 +
11
3 files changed, 997 insertions(+)
10
3 files changed, 424 insertions(+)
12
create mode 100644 tests/qemu-iotests/245
11
create mode 100755 tests/qemu-iotests/274
13
create mode 100644 tests/qemu-iotests/245.out
12
create mode 100644 tests/qemu-iotests/274.out
14
13
15
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
16
new file mode 100644
15
new file mode 100755
17
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
18
--- /dev/null
17
--- /dev/null
19
+++ b/tests/qemu-iotests/245
18
+++ b/tests/qemu-iotests/274
20
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
21
+#!/usr/bin/env python
20
+#!/usr/bin/env python3
22
+#
21
+#
23
+# Test cases for the QMP 'x-blockdev-reopen' command
22
+# Copyright (C) 2019 Red Hat, Inc.
24
+#
25
+# Copyright (C) 2018-2019 Igalia, S.L.
26
+# Author: Alberto Garcia <berto@igalia.com>
27
+#
23
+#
28
+# This program is free software; you can redistribute it and/or modify
24
+# This program is free software; you can redistribute it and/or modify
29
+# it under the terms of the GNU General Public License as published by
25
+# it under the terms of the GNU General Public License as published by
30
+# the Free Software Foundation; either version 2 of the License, or
26
+# the Free Software Foundation; either version 2 of the License, or
31
+# (at your option) any later version.
27
+# (at your option) any later version.
...
...
36
+# GNU General Public License for more details.
32
+# GNU General Public License for more details.
37
+#
33
+#
38
+# You should have received a copy of the GNU General Public License
34
+# You should have received a copy of the GNU General Public License
39
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
35
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
40
+#
36
+#
41
+
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
42
+import os
38
+#
43
+import re
39
+# Some tests for short backing files and short overlays
40
+
44
+import iotests
41
+import iotests
45
+import copy
42
+
46
+import json
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
47
+from iotests import qemu_img, qemu_io
44
+iotests.verify_platform(['linux'])
48
+
45
+
49
+hd_path = [
46
+size_short = 1 * 1024 * 1024
50
+ os.path.join(iotests.test_dir, 'hd0.img'),
47
+size_long = 2 * 1024 * 1024
51
+ os.path.join(iotests.test_dir, 'hd1.img'),
48
+size_diff = size_long - size_short
52
+ os.path.join(iotests.test_dir, 'hd2.img')
49
+
53
+]
50
+def create_chain() -> None:
54
+
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
55
+def hd_opts(idx):
52
+ str(size_long))
56
+ return {'driver': iotests.imgfmt,
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
57
+ 'node-name': 'hd%d' % idx,
54
+ str(size_short))
58
+ 'file': {'driver': 'file',
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
59
+ 'node-name': 'hd%d-file' % idx,
56
+ str(size_long))
60
+ 'filename': hd_path[idx] } }
57
+
61
+
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
62
+class TestBlockdevReopen(iotests.QMPTestCase):
59
+
63
+ total_io_cmds = 0
60
+def create_vm() -> iotests.VM:
64
+
61
+ vm = iotests.VM()
65
+ def setUp(self):
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
66
+ qemu_img('create', '-f', iotests.imgfmt, hd_path[0], '3M')
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
67
+ qemu_img('create', '-f', iotests.imgfmt, '-b', hd_path[0], hd_path[1])
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
68
+ qemu_img('create', '-f', iotests.imgfmt, hd_path[2], '3M')
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
69
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xa0 0 1M', hd_path[0])
66
+ % iotests.imgfmt)
70
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xa1 1M 1M', hd_path[1])
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
71
+ qemu_io('-f', iotests.imgfmt, '-c', 'write -P 0xa2 2M 1M', hd_path[2])
68
+ return vm
72
+ self.vm = iotests.VM()
69
+
73
+ self.vm.launch()
70
+with iotests.FilePath('base') as base, \
74
+
71
+ iotests.FilePath('mid') as mid, \
75
+ def tearDown(self):
72
+ iotests.FilePath('top') as top:
76
+ self.vm.shutdown()
73
+
77
+ self.check_qemu_io_errors()
74
+ iotests.log('== Commit tests ==')
78
+ os.remove(hd_path[0])
75
+
79
+ os.remove(hd_path[1])
76
+ create_chain()
80
+ os.remove(hd_path[2])
77
+
81
+
78
+ iotests.log('=== Check visible data ===')
82
+ # The output of qemu-io is not returned by vm.hmp_qemu_io() but
79
+
83
+ # it's stored in the log and can only be read when the VM has been
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
84
+ # shut down. This function runs qemu-io and keeps track of the
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
85
+ # number of times it's been called.
82
+
86
+ def run_qemu_io(self, img, cmd):
83
+ iotests.log('=== Checking allocation status ===')
87
+ result = self.vm.hmp_qemu_io(img, cmd)
84
+
88
+ self.assert_qmp(result, 'return', '')
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
89
+ self.total_io_cmds += 1
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
90
+
87
+ base)
91
+ # Once the VM is shut down we can parse the log and see if qemu-io
88
+
92
+ # ran without errors.
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
93
+ def check_qemu_io_errors(self):
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
94
+ self.assertFalse(self.vm.is_running())
91
+ mid)
95
+ found = 0
92
+
96
+ log = self.vm.get_log()
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
97
+ for line in log.split("\n"):
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
98
+ if line.startswith("Pattern verification failed"):
95
+ top)
99
+ raise Exception("%s (command #%d)" % (line, found))
96
+
100
+ if re.match("read .*/.* bytes at offset", line):
97
+ iotests.log('=== Checking map ===')
101
+ found += 1
98
+
102
+ self.assertEqual(found, self.total_io_cmds,
99
+ iotests.qemu_img_log('map', '--output=json', base)
103
+ "Expected output of %d qemu-io commands, found %d" %
100
+ iotests.qemu_img_log('map', '--output=human', base)
104
+ (found, self.total_io_cmds))
101
+ iotests.qemu_img_log('map', '--output=json', mid)
105
+
102
+ iotests.qemu_img_log('map', '--output=human', mid)
106
+ # Run x-blockdev-reopen with 'opts' but applying 'newopts'
103
+ iotests.qemu_img_log('map', '--output=json', top)
107
+ # on top of it. The original 'opts' dict is unmodified
104
+ iotests.qemu_img_log('map', '--output=human', top)
108
+ def reopen(self, opts, newopts = {}, errmsg = None):
105
+
109
+ opts = copy.deepcopy(opts)
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
110
+
107
+
111
+ # Apply the changes from 'newopts' on top of 'opts'
108
+ iotests.qemu_img_log('commit', top)
112
+ for key in newopts:
109
+ iotests.img_info_log(mid)
113
+ value = newopts[key]
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
114
+ # If key has the form "foo.bar" then we need to do
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
115
+ # opts["foo"]["bar"] = value, not opts["foo.bar"] = value
112
+
116
+ subdict = opts
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
117
+ while key.find('.') != -1:
114
+
118
+ [prefix, key] = key.split('.', 1)
115
+ create_chain()
119
+ subdict = opts[prefix]
116
+ with create_vm() as vm:
120
+ subdict[key] = value
117
+ vm.launch()
121
+
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
122
+ result = self.vm.qmp('x-blockdev-reopen', conv_keys = False, **opts)
119
+
123
+ if errmsg:
120
+ iotests.img_info_log(mid)
124
+ self.assert_qmp(result, 'error/class', 'GenericError')
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
125
+ self.assert_qmp(result, 'error/desc', errmsg)
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
126
+ else:
123
+
127
+ self.assert_qmp(result, 'return', {})
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
128
+
125
+
129
+
126
+ create_chain()
130
+ # Run query-named-block-nodes and return the specified entry
127
+ with create_vm() as vm:
131
+ def get_node(self, node_name):
128
+ vm.launch()
132
+ result = self.vm.qmp('query-named-block-nodes')
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
133
+ for node in result['return']:
130
+ job_id='job0', auto_dismiss=False)
134
+ if node['node-name'] == node_name:
131
+ vm.run_job('job0', wait=5)
135
+ return node
132
+
136
+ return None
133
+ iotests.img_info_log(mid)
137
+
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
138
+ # Run 'query-named-block-nodes' and compare its output with the
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
139
+ # value passed by the user in 'graph'
136
+
140
+ def check_node_graph(self, graph):
137
+
141
+ result = self.vm.qmp('query-named-block-nodes')
138
+ iotests.log('== Resize tests ==')
142
+ self.assertEqual(json.dumps(graph, sort_keys=True),
139
+
143
+ json.dumps(result, sort_keys=True))
140
+ # Use different sizes for different allocation modes:
144
+
141
+ #
145
+ # This test opens one single disk image (without backing files)
142
+ # We want to have at least one test where 32 bit truncation in the size of
146
+ # and tries to reopen it with illegal / incorrect parameters.
143
+ # the overlapping area becomes visible. This is covered by the
147
+ def test_incorrect_parameters_single_file(self):
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
148
+ # Open 'hd0' only (no backing files)
145
+ #
149
+ opts = hd_opts(0)
146
+ # However, we can only do this for modes that don't preallocate data
150
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
147
+ # because otherwise we might run out of space on the test host.
151
+ self.assert_qmp(result, 'return', {})
148
+ #
152
+ original_graph = self.vm.qmp('query-named-block-nodes')
149
+ # We also want to test some unaligned combinations.
153
+
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
154
+ # We can reopen the image passing the same options
151
+ ('off', '6G', '1G', '8G', '5G'),
155
+ self.reopen(opts)
152
+ ('metadata', '32G', '30G', '33G', '31G'),
156
+
153
+ ('falloc', '10M', '5M', '15M', '9M'),
157
+ # We can also reopen passing a child reference in 'file'
154
+ ('full', '16M', '8M', '12M', '11M'),
158
+ self.reopen(opts, {'file': 'hd0-file'})
155
+ ('off', '384k', '253k', '512k', '253k'),
159
+
156
+ ('off', '400k', '256k', '512k', '336k'),
160
+ # We cannot change any of these
157
+ ('off', '512k', '256k', '500k', '436k')]:
161
+ self.reopen(opts, {'node-name': 'not-found'}, "Cannot find node named 'not-found'")
158
+
162
+ self.reopen(opts, {'node-name': ''}, "Cannot find node named ''")
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
163
+ self.reopen(opts, {'node-name': None}, "Invalid parameter type for 'node-name', expected: string")
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
164
+ self.reopen(opts, {'driver': 'raw'}, "Cannot change the option 'driver'")
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
165
+ self.reopen(opts, {'driver': ''}, "Invalid parameter ''")
162
+ top_size_old)
166
+ self.reopen(opts, {'driver': None}, "Invalid parameter type for 'driver', expected: string")
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
167
+ self.reopen(opts, {'file': 'not-found'}, "Cannot change the option 'file'")
164
+
168
+ self.reopen(opts, {'file': ''}, "Cannot change the option 'file'")
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
169
+ self.reopen(opts, {'file': None}, "Invalid parameter type for 'file', expected: BlockdevRef")
166
+ #
170
+ self.reopen(opts, {'file.node-name': 'newname'}, "Cannot change the option 'node-name'")
167
+ # In theory, leaving base_size to top_size_new unallocated would be
171
+ self.reopen(opts, {'file.driver': 'host_device'}, "Cannot change the option 'driver'")
168
+ # correct, but in practice, if we zero out anything, we zero out
172
+ self.reopen(opts, {'file.filename': hd_path[1]}, "Cannot change the option 'filename'")
169
+ # everything up to top_size_new.
173
+ self.reopen(opts, {'file.aio': 'native'}, "Cannot change the option 'aio'")
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
174
+ self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'")
171
+ '--preallocation', prealloc, top, top_size_new)
175
+ self.reopen(opts, {'file.filename': None}, "Invalid parameter type for 'file.filename', expected: string")
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
176
+
173
+ iotests.qemu_io_log('-c', 'map', top)
177
+ # node-name is optional in BlockdevOptions, but x-blockdev-reopen needs it
174
+ iotests.qemu_img_log('map', '--output=json', top)
178
+ del opts['node-name']
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
179
+ self.reopen(opts, {}, "Node name not specified")
180
+
181
+ # Check that nothing has changed
182
+ self.check_node_graph(original_graph)
183
+
184
+ # Remove the node
185
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
186
+ self.assert_qmp(result, 'return', {})
187
+
188
+ # This test opens an image with a backing file and tries to reopen
189
+ # it with illegal / incorrect parameters.
190
+ def test_incorrect_parameters_backing_file(self):
191
+ # Open hd1 omitting the backing options (hd0 will be opened
192
+ # with the default options)
193
+ opts = hd_opts(1)
194
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
195
+ self.assert_qmp(result, 'return', {})
196
+ original_graph = self.vm.qmp('query-named-block-nodes')
197
+
198
+ # We can't reopen the image passing the same options, 'backing' is mandatory
199
+ self.reopen(opts, {}, "backing is missing for 'hd1'")
200
+
201
+ # Everything works if we pass 'backing' using the existing node name
202
+ for node in original_graph['return']:
203
+ if node['drv'] == iotests.imgfmt and node['file'] == hd_path[0]:
204
+ backing_node_name = node['node-name']
205
+ self.reopen(opts, {'backing': backing_node_name})
206
+
207
+ # We can't use a non-existing or empty (non-NULL) node as the backing image
208
+ self.reopen(opts, {'backing': 'not-found'}, "Cannot find device= nor node_name=not-found")
209
+ self.reopen(opts, {'backing': ''}, "Cannot find device= nor node_name=")
210
+
211
+ # We can reopen the image just fine if we specify the backing options
212
+ opts['backing'] = {'driver': iotests.imgfmt,
213
+ 'file': {'driver': 'file',
214
+ 'filename': hd_path[0]}}
215
+ self.reopen(opts)
216
+
217
+ # We cannot change any of these options
218
+ self.reopen(opts, {'backing.node-name': 'newname'}, "Cannot change the option 'node-name'")
219
+ self.reopen(opts, {'backing.driver': 'raw'}, "Cannot change the option 'driver'")
220
+ self.reopen(opts, {'backing.file.node-name': 'newname'}, "Cannot change the option 'node-name'")
221
+ self.reopen(opts, {'backing.file.driver': 'host_device'}, "Cannot change the option 'driver'")
222
+
223
+ # Check that nothing has changed since the beginning
224
+ self.check_node_graph(original_graph)
225
+
226
+ # Remove the node
227
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1')
228
+ self.assert_qmp(result, 'return', {})
229
+
230
+ # Reopen an image several times changing some of its options
231
+ def test_reopen(self):
232
+ # Open the hd1 image passing all backing options
233
+ opts = hd_opts(1)
234
+ opts['backing'] = hd_opts(0)
235
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
236
+ self.assert_qmp(result, 'return', {})
237
+ original_graph = self.vm.qmp('query-named-block-nodes')
238
+
239
+ # We can reopen the image passing the same options
240
+ self.reopen(opts)
241
+
242
+ # Reopen in read-only mode
243
+ self.assert_qmp(self.get_node('hd1'), 'ro', False)
244
+
245
+ self.reopen(opts, {'read-only': True})
246
+ self.assert_qmp(self.get_node('hd1'), 'ro', True)
247
+ self.reopen(opts)
248
+ self.assert_qmp(self.get_node('hd1'), 'ro', False)
249
+
250
+ # Change the cache options
251
+ self.assert_qmp(self.get_node('hd1'), 'cache/writeback', True)
252
+ self.assert_qmp(self.get_node('hd1'), 'cache/direct', False)
253
+ self.assert_qmp(self.get_node('hd1'), 'cache/no-flush', False)
254
+ self.reopen(opts, {'cache': { 'direct': True, 'no-flush': True }})
255
+ self.assert_qmp(self.get_node('hd1'), 'cache/writeback', True)
256
+ self.assert_qmp(self.get_node('hd1'), 'cache/direct', True)
257
+ self.assert_qmp(self.get_node('hd1'), 'cache/no-flush', True)
258
+
259
+ # Reopen again with the original options
260
+ self.reopen(opts)
261
+ self.assert_qmp(self.get_node('hd1'), 'cache/writeback', True)
262
+ self.assert_qmp(self.get_node('hd1'), 'cache/direct', False)
263
+ self.assert_qmp(self.get_node('hd1'), 'cache/no-flush', False)
264
+
265
+ # Change 'detect-zeroes' and 'discard'
266
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'off')
267
+ self.reopen(opts, {'detect-zeroes': 'on'})
268
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'on')
269
+ self.reopen(opts, {'detect-zeroes': 'unmap'},
270
+ "setting detect-zeroes to unmap is not allowed " +
271
+ "without setting discard operation to unmap")
272
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'on')
273
+ self.reopen(opts, {'detect-zeroes': 'unmap', 'discard': 'unmap'})
274
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'unmap')
275
+ self.reopen(opts)
276
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'off')
277
+
278
+ # Changing 'force-share' is currently not supported
279
+ self.reopen(opts, {'force-share': True}, "Cannot change the option 'force-share'")
280
+
281
+ # Change some qcow2-specific options
282
+ # No way to test for success other than checking the return message
283
+ if iotests.imgfmt == 'qcow2':
284
+ self.reopen(opts, {'l2-cache-entry-size': 128 * 1024},
285
+ "L2 cache entry size must be a power of two "+
286
+ "between 512 and the cluster size (65536)")
287
+ self.reopen(opts, {'l2-cache-size': 1024 * 1024,
288
+ 'cache-size': 512 * 1024},
289
+ "l2-cache-size may not exceed cache-size")
290
+ self.reopen(opts, {'l2-cache-size': 4 * 1024 * 1024,
291
+ 'refcount-cache-size': 4 * 1024 * 1024,
292
+ 'l2-cache-entry-size': 32 * 1024})
293
+ self.reopen(opts, {'pass-discard-request': True})
294
+
295
+ # Check that nothing has changed since the beginning
296
+ # (from the parameters that we can check)
297
+ self.check_node_graph(original_graph)
298
+
299
+ # Check that the node names (other than the top-level one) are optional
300
+ del opts['file']['node-name']
301
+ del opts['backing']['node-name']
302
+ del opts['backing']['file']['node-name']
303
+ self.reopen(opts)
304
+ self.check_node_graph(original_graph)
305
+
306
+ # Reopen setting backing = null, this removes the backing image from the chain
307
+ self.reopen(opts, {'backing': None})
308
+ self.assert_qmp_absent(self.get_node('hd1'), 'image/backing-image')
309
+
310
+ # Open the 'hd0' image
311
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **hd_opts(0))
312
+ self.assert_qmp(result, 'return', {})
313
+
314
+ # Reopen the hd1 image setting 'hd0' as its backing image
315
+ self.reopen(opts, {'backing': 'hd0'})
316
+ self.assert_qmp(self.get_node('hd1'), 'image/backing-image/filename', hd_path[0])
317
+
318
+ # Check that nothing has changed since the beginning
319
+ self.reopen(hd_opts(0), {'read-only': True})
320
+ self.check_node_graph(original_graph)
321
+
322
+ # The backing file (hd0) is now a reference, we cannot change backing.* anymore
323
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
324
+
325
+ # We can't remove 'hd0' while it's a backing image of 'hd1'
326
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
327
+ self.assert_qmp(result, 'error/class', 'GenericError')
328
+ self.assert_qmp(result, 'error/desc', "Node 'hd0' is busy: node is used as backing hd of 'hd1'")
329
+
330
+ # But we can remove both nodes if done in the proper order
331
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1')
332
+ self.assert_qmp(result, 'return', {})
333
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
334
+ self.assert_qmp(result, 'return', {})
335
+
336
+ # Reopen a raw image and see the effect of changing the 'offset' option
337
+ def test_reopen_raw(self):
338
+ opts = {'driver': 'raw', 'node-name': 'hd0',
339
+ 'file': { 'driver': 'file',
340
+ 'filename': hd_path[0],
341
+ 'node-name': 'hd0-file' } }
342
+
343
+ # First we create a 2MB raw file, and fill each half with a
344
+ # different value
345
+ qemu_img('create', '-f', 'raw', hd_path[0], '2M')
346
+ qemu_io('-f', 'raw', '-c', 'write -P 0xa0 0 1M', hd_path[0])
347
+ qemu_io('-f', 'raw', '-c', 'write -P 0xa1 1M 1M', hd_path[0])
348
+
349
+ # Open the raw file with QEMU
350
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
351
+ self.assert_qmp(result, 'return', {})
352
+
353
+ # Read 1MB from offset 0
354
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
355
+
356
+ # Reopen the image with a 1MB offset.
357
+ # Now the results are different
358
+ self.reopen(opts, {'offset': 1024*1024})
359
+ self.run_qemu_io("hd0", "read -P 0xa1 0 1M")
360
+
361
+ # Reopen again with the original options.
362
+ # We get the original results again
363
+ self.reopen(opts)
364
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
365
+
366
+ # Remove the block device
367
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
368
+ self.assert_qmp(result, 'return', {})
369
+
370
+ # Omitting an option should reset it to the default value, but if
371
+ # an option cannot be changed it shouldn't be possible to reset it
372
+ # to its default value either
373
+ def test_reset_default_values(self):
374
+ opts = {'driver': 'qcow2', 'node-name': 'hd0',
375
+ 'file': { 'driver': 'file',
376
+ 'filename': hd_path[0],
377
+ 'x-check-cache-dropped': True, # This one can be changed
378
+ 'locking': 'off', # This one can NOT be changed
379
+ 'node-name': 'hd0-file' } }
380
+
381
+ # Open the file with QEMU
382
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
383
+ self.assert_qmp(result, 'return', {})
384
+
385
+ # file.x-check-cache-dropped can be changed...
386
+ self.reopen(opts, { 'file.x-check-cache-dropped': False })
387
+ # ...and dropped completely (resetting to the default value)
388
+ del opts['file']['x-check-cache-dropped']
389
+ self.reopen(opts)
390
+
391
+ # file.locking cannot be changed nor reset to the default value
392
+ self.reopen(opts, { 'file.locking': 'on' }, "Cannot change the option 'locking'")
393
+ del opts['file']['locking']
394
+ self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value")
395
+ # But we can reopen it if we maintain its previous value
396
+ self.reopen(opts, { 'file.locking': 'off' })
397
+
398
+ # Remove the block device
399
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
400
+ self.assert_qmp(result, 'return', {})
401
+
402
+ # This test modifies the node graph a few times by changing the
403
+ # 'backing' option on reopen and verifies that the guest data that
404
+ # is read afterwards is consistent with the graph changes.
405
+ def test_io_with_graph_changes(self):
406
+ opts = []
407
+
408
+ # Open hd0, hd1 and hd2 without any backing image
409
+ for i in range(3):
410
+ opts.append(hd_opts(i))
411
+ opts[i]['backing'] = None
412
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts[i])
413
+ self.assert_qmp(result, 'return', {})
414
+
415
+ # hd0
416
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
417
+ self.run_qemu_io("hd0", "read -P 0 1M 1M")
418
+ self.run_qemu_io("hd0", "read -P 0 2M 1M")
419
+
420
+ # hd1 <- hd0
421
+ self.reopen(opts[0], {'backing': 'hd1'})
422
+
423
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
424
+ self.run_qemu_io("hd0", "read -P 0xa1 1M 1M")
425
+ self.run_qemu_io("hd0", "read -P 0 2M 1M")
426
+
427
+ # hd1 <- hd0 , hd1 <- hd2
428
+ self.reopen(opts[2], {'backing': 'hd1'})
429
+
430
+ self.run_qemu_io("hd2", "read -P 0 0 1M")
431
+ self.run_qemu_io("hd2", "read -P 0xa1 1M 1M")
432
+ self.run_qemu_io("hd2", "read -P 0xa2 2M 1M")
433
+
434
+ # hd1 <- hd2 <- hd0
435
+ self.reopen(opts[0], {'backing': 'hd2'})
436
+
437
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
438
+ self.run_qemu_io("hd0", "read -P 0xa1 1M 1M")
439
+ self.run_qemu_io("hd0", "read -P 0xa2 2M 1M")
440
+
441
+ # hd2 <- hd0
442
+ self.reopen(opts[2], {'backing': None})
443
+
444
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
445
+ self.run_qemu_io("hd0", "read -P 0 1M 1M")
446
+ self.run_qemu_io("hd0", "read -P 0xa2 2M 1M")
447
+
448
+ # hd2 <- hd1 <- hd0
449
+ self.reopen(opts[1], {'backing': 'hd2'})
450
+ self.reopen(opts[0], {'backing': 'hd1'})
451
+
452
+ self.run_qemu_io("hd0", "read -P 0xa0 0 1M")
453
+ self.run_qemu_io("hd0", "read -P 0xa1 1M 1M")
454
+ self.run_qemu_io("hd0", "read -P 0xa2 2M 1M")
455
+
456
+ # Illegal operation: hd2 is a child of hd1
457
+ self.reopen(opts[2], {'backing': 'hd1'},
458
+ "Making 'hd1' a backing file of 'hd2' would create a cycle")
459
+
460
+ # hd2 <- hd0, hd2 <- hd1
461
+ self.reopen(opts[0], {'backing': 'hd2'})
462
+
463
+ self.run_qemu_io("hd1", "read -P 0 0 1M")
464
+ self.run_qemu_io("hd1", "read -P 0xa1 1M 1M")
465
+ self.run_qemu_io("hd1", "read -P 0xa2 2M 1M")
466
+
467
+ # More illegal operations
468
+ self.reopen(opts[2], {'backing': 'hd1'},
469
+ "Making 'hd1' a backing file of 'hd2' would create a cycle")
470
+ self.reopen(opts[2], {'file': 'hd0-file'}, "Cannot change the option 'file'")
471
+
472
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2')
473
+ self.assert_qmp(result, 'error/class', 'GenericError')
474
+ self.assert_qmp(result, 'error/desc', "Node 'hd2' is busy: node is used as backing hd of 'hd0'")
475
+
476
+ # hd1 doesn't have a backing file now
477
+ self.reopen(opts[1], {'backing': None})
478
+
479
+ self.run_qemu_io("hd1", "read -P 0 0 1M")
480
+ self.run_qemu_io("hd1", "read -P 0xa1 1M 1M")
481
+ self.run_qemu_io("hd1", "read -P 0 2M 1M")
482
+
483
+ # We can't remove the 'backing' option if the image has a
484
+ # default backing file
485
+ del opts[1]['backing']
486
+ self.reopen(opts[1], {}, "backing is missing for 'hd1'")
487
+
488
+ self.run_qemu_io("hd1", "read -P 0 0 1M")
489
+ self.run_qemu_io("hd1", "read -P 0xa1 1M 1M")
490
+ self.run_qemu_io("hd1", "read -P 0 2M 1M")
491
+
492
+ # This test verifies that we can't change the children of a block
493
+ # device during a reopen operation in a way that would create
494
+ # cycles in the node graph
495
+ def test_graph_cycles(self):
496
+ opts = []
497
+
498
+ # Open all three images without backing file
499
+ for i in range(3):
500
+ opts.append(hd_opts(i))
501
+ opts[i]['backing'] = None
502
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts[i])
503
+ self.assert_qmp(result, 'return', {})
504
+
505
+ # hd1 <- hd0, hd1 <- hd2
506
+ self.reopen(opts[0], {'backing': 'hd1'})
507
+ self.reopen(opts[2], {'backing': 'hd1'})
508
+
509
+ # Illegal: hd2 is backed by hd1
510
+ self.reopen(opts[1], {'backing': 'hd2'},
511
+ "Making 'hd2' a backing file of 'hd1' would create a cycle")
512
+
513
+ # hd1 <- hd0 <- hd2
514
+ self.reopen(opts[2], {'backing': 'hd0'})
515
+
516
+ # Illegal: hd2 is backed by hd0, which is backed by hd1
517
+ self.reopen(opts[1], {'backing': 'hd2'},
518
+ "Making 'hd2' a backing file of 'hd1' would create a cycle")
519
+
520
+ # Illegal: hd1 cannot point to itself
521
+ self.reopen(opts[1], {'backing': 'hd1'},
522
+ "Making 'hd1' a backing file of 'hd1' would create a cycle")
523
+
524
+ # Remove all backing files
525
+ self.reopen(opts[0])
526
+ self.reopen(opts[2])
527
+
528
+ ##########################################
529
+ # Add a blkverify node using hd0 and hd1 #
530
+ ##########################################
531
+ bvopts = {'driver': 'blkverify',
532
+ 'node-name': 'bv',
533
+ 'test': 'hd0',
534
+ 'raw': 'hd1'}
535
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **bvopts)
536
+ self.assert_qmp(result, 'return', {})
537
+
538
+ # blkverify doesn't currently allow reopening. TODO: implement this
539
+ self.reopen(bvopts, {}, "Block format 'blkverify' used by node 'bv'" +
540
+ " does not support reopening files")
541
+
542
+ # Illegal: hd0 is a child of the blkverify node
543
+ self.reopen(opts[0], {'backing': 'bv'},
544
+ "Making 'bv' a backing file of 'hd0' would create a cycle")
545
+
546
+ # Delete the blkverify node
547
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'bv')
548
+ self.assert_qmp(result, 'return', {})
549
+
550
+ # Misc reopen tests with different block drivers
551
+ def test_misc_drivers(self):
552
+ ####################
553
+ ###### quorum ######
554
+ ####################
555
+ for i in range(3):
556
+ opts = hd_opts(i)
557
+ # Open all three images without backing file
558
+ opts['backing'] = None
559
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
560
+ self.assert_qmp(result, 'return', {})
561
+
562
+ opts = {'driver': 'quorum',
563
+ 'node-name': 'quorum0',
564
+ 'children': ['hd0', 'hd1', 'hd2'],
565
+ 'vote-threshold': 2}
566
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
567
+ self.assert_qmp(result, 'return', {})
568
+
569
+ # Quorum doesn't currently allow reopening. TODO: implement this
570
+ self.reopen(opts, {}, "Block format 'quorum' used by node 'quorum0'" +
571
+ " does not support reopening files")
572
+
573
+ # You can't make quorum0 a backing file of hd0:
574
+ # hd0 is already a child of quorum0.
575
+ self.reopen(hd_opts(0), {'backing': 'quorum0'},
576
+ "Making 'quorum0' a backing file of 'hd0' would create a cycle")
577
+
578
+ # Delete quorum0
579
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'quorum0')
580
+ self.assert_qmp(result, 'return', {})
581
+
582
+ # Delete hd0, hd1 and hd2
583
+ for i in range(3):
584
+ result = self.vm.qmp('blockdev-del', conv_keys = True,
585
+ node_name = 'hd%d' % i)
586
+ self.assert_qmp(result, 'return', {})
587
+
588
+ ######################
589
+ ###### blkdebug ######
590
+ ######################
591
+ opts = {'driver': 'blkdebug',
592
+ 'node-name': 'bd',
593
+ 'config': '/dev/null',
594
+ 'image': hd_opts(0)}
595
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
596
+ self.assert_qmp(result, 'return', {})
597
+
598
+ # blkdebug allows reopening if we keep the same options
599
+ self.reopen(opts)
600
+
601
+ # but it currently does not allow changes
602
+ self.reopen(opts, {'image': 'hd1'}, "Cannot change the option 'image'")
603
+ self.reopen(opts, {'align': 33554432}, "Cannot change the option 'align'")
604
+ self.reopen(opts, {'config': '/non/existent'}, "Cannot change the option 'config'")
605
+ del opts['config']
606
+ self.reopen(opts, {}, "Option 'config' cannot be reset to its default value")
607
+
608
+ # Delete the blkdebug node
609
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'bd')
610
+ self.assert_qmp(result, 'return', {})
611
+
612
+ ##################
613
+ ###### null ######
614
+ ##################
615
+ opts = {'driver': 'null-aio', 'node-name': 'root', 'size': 1024}
616
+
617
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
618
+ self.assert_qmp(result, 'return', {})
619
+
620
+ # 1 << 30 is the default value, but we cannot change it explicitly
621
+ self.reopen(opts, {'size': (1 << 30)}, "Cannot change the option 'size'")
622
+
623
+ # We cannot change 'size' back to its default value either
624
+ del opts['size']
625
+ self.reopen(opts, {}, "Option 'size' cannot be reset to its default value")
626
+
627
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'root')
628
+ self.assert_qmp(result, 'return', {})
629
+
630
+ ##################
631
+ ###### file ######
632
+ ##################
633
+ opts = hd_opts(0)
634
+ opts['file']['locking'] = 'on'
635
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
636
+ self.assert_qmp(result, 'return', {})
637
+
638
+ # 'locking' cannot be changed
639
+ del opts['file']['locking']
640
+ self.reopen(opts, {'file.locking': 'on'})
641
+ self.reopen(opts, {'file.locking': 'off'}, "Cannot change the option 'locking'")
642
+ self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value")
643
+
644
+ # Trying to reopen the 'file' node directly does not make a difference
645
+ opts = opts['file']
646
+ self.reopen(opts, {'locking': 'on'})
647
+ self.reopen(opts, {'locking': 'off'}, "Cannot change the option 'locking'")
648
+ self.reopen(opts, {}, "Option 'locking' cannot be reset to its default value")
649
+
650
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
651
+ self.assert_qmp(result, 'return', {})
652
+
653
+ ######################
654
+ ###### throttle ######
655
+ ######################
656
+ opts = { 'qom-type': 'throttle-group', 'id': 'group0',
657
+ 'props': { 'limits': { 'iops-total': 1000 } } }
658
+ result = self.vm.qmp('object-add', conv_keys = False, **opts)
659
+ self.assert_qmp(result, 'return', {})
660
+
661
+ opts = { 'qom-type': 'throttle-group', 'id': 'group1',
662
+ 'props': { 'limits': { 'iops-total': 2000 } } }
663
+ result = self.vm.qmp('object-add', conv_keys = False, **opts)
664
+ self.assert_qmp(result, 'return', {})
665
+
666
+ # Add a throttle filter with group = group0
667
+ opts = { 'driver': 'throttle', 'node-name': 'throttle0',
668
+ 'throttle-group': 'group0', 'file': hd_opts(0) }
669
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
670
+ self.assert_qmp(result, 'return', {})
671
+
672
+ # We can reopen it if we keep the same options
673
+ self.reopen(opts)
674
+
675
+ # We can also reopen if 'file' is a reference to the child
676
+ self.reopen(opts, {'file': 'hd0'})
677
+
678
+ # This is illegal
679
+ self.reopen(opts, {'throttle-group': 'notfound'}, "Throttle group 'notfound' does not exist")
680
+
681
+ # But it's possible to change the group to group1
682
+ self.reopen(opts, {'throttle-group': 'group1'})
683
+
684
+ # Now group1 is in use, it cannot be deleted
685
+ result = self.vm.qmp('object-del', id = 'group1')
686
+ self.assert_qmp(result, 'error/class', 'GenericError')
687
+ self.assert_qmp(result, 'error/desc', "object 'group1' is in use, can not be deleted")
688
+
689
+ # Default options, this switches the group back to group0
690
+ self.reopen(opts)
691
+
692
+ # So now we cannot delete group0
693
+ result = self.vm.qmp('object-del', id = 'group0')
694
+ self.assert_qmp(result, 'error/class', 'GenericError')
695
+ self.assert_qmp(result, 'error/desc', "object 'group0' is in use, can not be deleted")
696
+
697
+ # But group1 is free this time, and it can be deleted
698
+ result = self.vm.qmp('object-del', id = 'group1')
699
+ self.assert_qmp(result, 'return', {})
700
+
701
+ # Let's delete the filter node
702
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'throttle0')
703
+ self.assert_qmp(result, 'return', {})
704
+
705
+ # And we can finally get rid of group0
706
+ result = self.vm.qmp('object-del', id = 'group0')
707
+ self.assert_qmp(result, 'return', {})
708
+
709
+ # If an image has a backing file then the 'backing' option must be
710
+ # passed on reopen. We don't allow leaving the option out in this
711
+ # case because it's unclear what the correct semantics would be.
712
+ def test_missing_backing_options_1(self):
713
+ # hd2
714
+ opts = hd_opts(2)
715
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
716
+ self.assert_qmp(result, 'return', {})
717
+
718
+ # hd0
719
+ opts = hd_opts(0)
720
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
721
+ self.assert_qmp(result, 'return', {})
722
+
723
+ # hd0 has no backing file: we can omit the 'backing' option
724
+ self.reopen(opts)
725
+
726
+ # hd2 <- hd0
727
+ self.reopen(opts, {'backing': 'hd2'})
728
+
729
+ # hd0 has a backing file: we must set the 'backing' option
730
+ self.reopen(opts, {}, "backing is missing for 'hd0'")
731
+
732
+ # hd2 can't be removed because it's the backing file of hd0
733
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2')
734
+ self.assert_qmp(result, 'error/class', 'GenericError')
735
+ self.assert_qmp(result, 'error/desc', "Node 'hd2' is busy: node is used as backing hd of 'hd0'")
736
+
737
+ # Detach hd2 from hd0.
738
+ self.reopen(opts, {'backing': None})
739
+ self.reopen(opts, {}, "backing is missing for 'hd0'")
740
+
741
+ # Remove both hd0 and hd2
742
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
743
+ self.assert_qmp(result, 'return', {})
744
+
745
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd2')
746
+ self.assert_qmp(result, 'return', {})
747
+
748
+ # If an image has default backing file (as part of its metadata)
749
+ # then the 'backing' option must be passed on reopen. We don't
750
+ # allow leaving the option out in this case because it's unclear
751
+ # what the correct semantics would be.
752
+ def test_missing_backing_options_2(self):
753
+ # hd0 <- hd1
754
+ # (hd0 is hd1's default backing file)
755
+ opts = hd_opts(1)
756
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
757
+ self.assert_qmp(result, 'return', {})
758
+
759
+ # hd1 has a backing file: we can't omit the 'backing' option
760
+ self.reopen(opts, {}, "backing is missing for 'hd1'")
761
+
762
+ # Let's detach the backing file
763
+ self.reopen(opts, {'backing': None})
764
+
765
+ # No backing file attached to hd1 now, but we still can't omit the 'backing' option
766
+ self.reopen(opts, {}, "backing is missing for 'hd1'")
767
+
768
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd1')
769
+ self.assert_qmp(result, 'return', {})
770
+
771
+ # Test that making 'backing' a reference to an existing child
772
+ # keeps its current options
773
+ def test_backing_reference(self):
774
+ # hd2 <- hd1 <- hd0
775
+ opts = hd_opts(0)
776
+ opts['backing'] = hd_opts(1)
777
+ opts['backing']['backing'] = hd_opts(2)
778
+ # Enable 'detect-zeroes' on all three nodes
779
+ opts['detect-zeroes'] = 'on'
780
+ opts['backing']['detect-zeroes'] = 'on'
781
+ opts['backing']['backing']['detect-zeroes'] = 'on'
782
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
783
+ self.assert_qmp(result, 'return', {})
784
+
785
+ # Reopen the chain passing the minimum amount of required options.
786
+ # By making 'backing' a reference to hd1 (instead of a sub-dict)
787
+ # we tell QEMU to keep its current set of options.
788
+ opts = {'driver': iotests.imgfmt,
789
+ 'node-name': 'hd0',
790
+ 'file': 'hd0-file',
791
+ 'backing': 'hd1' }
792
+ self.reopen(opts)
793
+
794
+ # This has reset 'detect-zeroes' on hd0, but not on hd1 and hd2.
795
+ self.assert_qmp(self.get_node('hd0'), 'detect_zeroes', 'off')
796
+ self.assert_qmp(self.get_node('hd1'), 'detect_zeroes', 'on')
797
+ self.assert_qmp(self.get_node('hd2'), 'detect_zeroes', 'on')
798
+
799
+ # Test what happens if the graph changes due to other operations
800
+ # such as block-stream
801
+ def test_block_stream_1(self):
802
+ # hd1 <- hd0
803
+ opts = hd_opts(0)
804
+ opts['backing'] = hd_opts(1)
805
+ opts['backing']['backing'] = None
806
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
807
+ self.assert_qmp(result, 'return', {})
808
+
809
+ # Stream hd1 into hd0 and wait until it's done
810
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0', device = 'hd0')
811
+ self.assert_qmp(result, 'return', {})
812
+ self.wait_until_completed(drive = 'stream0')
813
+
814
+ # Now we have only hd0
815
+ self.assertEqual(self.get_node('hd1'), None)
816
+
817
+ # We have backing.* options but there's no backing file anymore
818
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
819
+
820
+ # If we remove the 'backing' option then we can reopen hd0 just fine
821
+ del opts['backing']
822
+ self.reopen(opts)
823
+
824
+ # We can also reopen hd0 if we set 'backing' to null
825
+ self.reopen(opts, {'backing': None})
826
+
827
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
828
+ self.assert_qmp(result, 'return', {})
829
+
830
+ # Another block_stream test
831
+ def test_block_stream_2(self):
832
+ # hd2 <- hd1 <- hd0
833
+ opts = hd_opts(0)
834
+ opts['backing'] = hd_opts(1)
835
+ opts['backing']['backing'] = hd_opts(2)
836
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
837
+ self.assert_qmp(result, 'return', {})
838
+
839
+ # Stream hd1 into hd0 and wait until it's done
840
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
841
+ device = 'hd0', base_node = 'hd2')
842
+ self.assert_qmp(result, 'return', {})
843
+ self.wait_until_completed(drive = 'stream0')
844
+
845
+ # The chain is hd2 <- hd0 now. hd1 is missing
846
+ self.assertEqual(self.get_node('hd1'), None)
847
+
848
+ # The backing options in the dict were meant for hd1, but we cannot
849
+ # use them with hd2 because hd1 had a backing file while hd2 does not.
850
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
851
+
852
+ # If we remove hd1's options from the dict then things work fine
853
+ opts['backing'] = opts['backing']['backing']
854
+ self.reopen(opts)
855
+
856
+ # We can also reopen hd0 if we use a reference to the backing file
857
+ self.reopen(opts, {'backing': 'hd2'})
858
+
859
+ # But we cannot leave the option out
860
+ del opts['backing']
861
+ self.reopen(opts, {}, "backing is missing for 'hd0'")
862
+
863
+ # Now we can delete hd0 (and hd2)
864
+ result = self.vm.qmp('blockdev-del', conv_keys = True, node_name = 'hd0')
865
+ self.assert_qmp(result, 'return', {})
866
+ self.assertEqual(self.get_node('hd2'), None)
867
+
868
+ # Reopen the chain during a block-stream job (from hd1 to hd0)
869
+ def test_block_stream_3(self):
870
+ # hd2 <- hd1 <- hd0
871
+ opts = hd_opts(0)
872
+ opts['backing'] = hd_opts(1)
873
+ opts['backing']['backing'] = hd_opts(2)
874
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
875
+ self.assert_qmp(result, 'return', {})
876
+
877
+ # hd2 <- hd0
878
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
879
+ device = 'hd0', base_node = 'hd2', speed = 512 * 1024)
880
+ self.assert_qmp(result, 'return', {})
881
+
882
+ # We can't remove hd2 while the stream job is ongoing
883
+ opts['backing']['backing'] = None
884
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
885
+
886
+ # We can't remove hd1 while the stream job is ongoing
887
+ opts['backing'] = None
888
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
889
+
890
+ self.wait_until_completed(drive = 'stream0')
891
+
892
+ # Reopen the chain during a block-stream job (from hd2 to hd1)
893
+ def test_block_stream_4(self):
894
+ # hd2 <- hd1 <- hd0
895
+ opts = hd_opts(0)
896
+ opts['backing'] = hd_opts(1)
897
+ opts['backing']['backing'] = hd_opts(2)
898
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
899
+ self.assert_qmp(result, 'return', {})
900
+
901
+ # hd1 <- hd0
902
+ result = self.vm.qmp('block-stream', conv_keys = True, job_id = 'stream0',
903
+ device = 'hd1', speed = 512 * 1024)
904
+ self.assert_qmp(result, 'return', {})
905
+
906
+ # We can't reopen with the original options because that would
907
+ # make hd1 read-only and block-stream requires it to be read-write
908
+ self.reopen(opts, {}, "Can't set node 'hd1' to r/o with copy-on-read enabled")
909
+
910
+ # We can't remove hd2 while the stream job is ongoing
911
+ opts['backing']['backing'] = None
912
+ self.reopen(opts, {'backing.read-only': False}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
913
+
914
+ # We can detach hd1 from hd0 because it doesn't affect the stream job
915
+ opts['backing'] = None
916
+ self.reopen(opts)
917
+
918
+ self.wait_until_completed(drive = 'stream0')
919
+
920
+ # Reopen the chain during a block-commit job (from hd0 to hd2)
921
+ def test_block_commit_1(self):
922
+ # hd2 <- hd1 <- hd0
923
+ opts = hd_opts(0)
924
+ opts['backing'] = hd_opts(1)
925
+ opts['backing']['backing'] = hd_opts(2)
926
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
927
+ self.assert_qmp(result, 'return', {})
928
+
929
+ result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
930
+ device = 'hd0', speed = 1024 * 1024)
931
+ self.assert_qmp(result, 'return', {})
932
+
933
+ # We can't remove hd2 while the commit job is ongoing
934
+ opts['backing']['backing'] = None
935
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd1' to 'hd2'")
936
+
937
+ # We can't remove hd1 while the commit job is ongoing
938
+ opts['backing'] = None
939
+ self.reopen(opts, {}, "Cannot change 'backing' link from 'hd0' to 'hd1'")
940
+
941
+ event = self.vm.event_wait(name='BLOCK_JOB_READY')
942
+ self.assert_qmp(event, 'data/device', 'commit0')
943
+ self.assert_qmp(event, 'data/type', 'commit')
944
+ self.assert_qmp_absent(event, 'data/error')
945
+
946
+ result = self.vm.qmp('block-job-complete', device='commit0')
947
+ self.assert_qmp(result, 'return', {})
948
+
949
+ self.wait_until_completed(drive = 'commit0')
950
+
951
+ # Reopen the chain during a block-commit job (from hd1 to hd2)
952
+ def test_block_commit_2(self):
953
+ # hd2 <- hd1 <- hd0
954
+ opts = hd_opts(0)
955
+ opts['backing'] = hd_opts(1)
956
+ opts['backing']['backing'] = hd_opts(2)
957
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
958
+ self.assert_qmp(result, 'return', {})
959
+
960
+ result = self.vm.qmp('block-commit', conv_keys = True, job_id = 'commit0',
961
+ device = 'hd0', top_node = 'hd1', speed = 1024 * 1024)
962
+ self.assert_qmp(result, 'return', {})
963
+
964
+ # We can't remove hd2 while the commit job is ongoing
965
+ opts['backing']['backing'] = None
966
+ self.reopen(opts, {}, "Cannot change the option 'backing.driver'")
967
+
968
+ # We can't remove hd1 while the commit job is ongoing
969
+ opts['backing'] = None
970
+ self.reopen(opts, {}, "Cannot change backing link if 'hd0' has an implicit backing file")
971
+
972
+ # hd2 <- hd0
973
+ self.wait_until_completed(drive = 'commit0')
974
+
975
+ self.assert_qmp(self.get_node('hd0'), 'ro', False)
976
+ self.assertEqual(self.get_node('hd1'), None)
977
+ self.assert_qmp(self.get_node('hd2'), 'ro', True)
978
+
979
+ # We don't allow setting a backing file that uses a different AioContext
980
+ def test_iothreads(self):
981
+ opts = hd_opts(0)
982
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
983
+ self.assert_qmp(result, 'return', {})
984
+
985
+ opts2 = hd_opts(2)
986
+ result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2)
987
+ self.assert_qmp(result, 'return', {})
988
+
989
+ result = self.vm.qmp('object-add', qom_type='iothread', id='iothread0')
990
+ self.assert_qmp(result, 'return', {})
991
+
992
+ result = self.vm.qmp('object-add', qom_type='iothread', id='iothread1')
993
+ self.assert_qmp(result, 'return', {})
994
+
995
+ result = self.vm.qmp('x-blockdev-set-iothread', node_name='hd0', iothread='iothread0')
996
+ self.assert_qmp(result, 'return', {})
997
+
998
+ self.reopen(opts, {'backing': 'hd2'}, "Cannot use a new backing file with a different AioContext")
999
+
1000
+ result = self.vm.qmp('x-blockdev-set-iothread', node_name='hd2', iothread='iothread1')
1001
+ self.assert_qmp(result, 'return', {})
1002
+
1003
+ self.reopen(opts, {'backing': 'hd2'}, "Cannot use a new backing file with a different AioContext")
1004
+
1005
+ result = self.vm.qmp('x-blockdev-set-iothread', node_name='hd2', iothread='iothread0')
1006
+ self.assert_qmp(result, 'return', {})
1007
+
1008
+ self.reopen(opts, {'backing': 'hd2'})
1009
+
1010
+if __name__ == '__main__':
1011
+ iotests.main(supported_fmts=["qcow2"])
1012
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
1013
new file mode 100644
176
new file mode 100644
1014
index XXXXXXX..XXXXXXX
177
index XXXXXXX..XXXXXXX
1015
--- /dev/null
178
--- /dev/null
1016
+++ b/tests/qemu-iotests/245.out
179
+++ b/tests/qemu-iotests/274.out
1017
@@ -XXX,XX +XXX,XX @@
180
@@ -XXX,XX +XXX,XX @@
1018
+..................
181
+== Commit tests ==
1019
+----------------------------------------------------------------------
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
1020
+Ran 18 tests
183
+
1021
+
184
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
1022
+OK
185
+
186
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
187
+
188
+wrote 2097152/2097152 bytes at offset 0
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
190
+
191
+=== Check visible data ===
192
+read 1048576/1048576 bytes at offset 0
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
194
+
195
+read 1048576/1048576 bytes at offset 1048576
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
197
+
198
+=== Checking allocation status ===
199
+1048576/1048576 bytes allocated at offset 0 bytes
200
+1048576/1048576 bytes allocated at offset 1 MiB
201
+
202
+0/1048576 bytes allocated at offset 0 bytes
203
+0/0 bytes allocated at offset 1 MiB
204
+
205
+0/1048576 bytes allocated at offset 0 bytes
206
+0/1048576 bytes allocated at offset 1 MiB
207
+
208
+=== Checking map ===
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
210
+
211
+Offset Length Mapped to File
212
+0 0x200000 0x50000 TEST_DIR/PID-base
213
+
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
215
+
216
+Offset Length Mapped to File
217
+0 0x100000 0x50000 TEST_DIR/PID-base
218
+
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
221
+
222
+Offset Length Mapped to File
223
+0 0x100000 0x50000 TEST_DIR/PID-base
224
+
225
+=== Testing qemu-img commit (top -> mid) ===
226
+Image committed.
227
+
228
+image: TEST_IMG
229
+file format: IMGFMT
230
+virtual size: 2 MiB (2097152 bytes)
231
+cluster_size: 65536
232
+backing file: TEST_DIR/PID-base
233
+Format specific information:
234
+ compat: 1.1
235
+ lazy refcounts: false
236
+ refcount bits: 16
237
+ corrupt: false
238
+
239
+read 1048576/1048576 bytes at offset 0
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+
242
+read 1048576/1048576 bytes at offset 1048576
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
244
+
245
+=== Testing HMP commit (top -> mid) ===
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
247
+
248
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
249
+
250
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
251
+
252
+wrote 2097152/2097152 bytes at offset 0
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
254
+
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
256
+{"return": ""}
257
+image: TEST_IMG
258
+file format: IMGFMT
259
+virtual size: 2 MiB (2097152 bytes)
260
+cluster_size: 65536
261
+backing file: TEST_DIR/PID-base
262
+Format specific information:
263
+ compat: 1.1
264
+ lazy refcounts: false
265
+ refcount bits: 16
266
+ corrupt: false
267
+
268
+read 1048576/1048576 bytes at offset 0
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
270
+
271
+read 1048576/1048576 bytes at offset 1048576
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
273
+
274
+=== Testing QMP active commit (top -> mid) ===
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
276
+
277
+Formatting 'TEST_DIR/PID-mid', fmt=qcow2 size=1048576 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
278
+
279
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=2097152 backing_file=TEST_DIR/PID-mid cluster_size=65536 lazy_refcounts=off refcount_bits=16
280
+
281
+wrote 2097152/2097152 bytes at offset 0
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
283
+
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
285
+{"return": {}}
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
287
+{"return": {}}
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
291
+{"return": {}}
292
+image: TEST_IMG
293
+file format: IMGFMT
294
+virtual size: 2 MiB (2097152 bytes)
295
+cluster_size: 65536
296
+backing file: TEST_DIR/PID-base
297
+Format specific information:
298
+ compat: 1.1
299
+ lazy refcounts: false
300
+ refcount bits: 16
301
+ corrupt: false
302
+
303
+read 1048576/1048576 bytes at offset 0
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+
306
+read 1048576/1048576 bytes at offset 1048576
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
308
+
309
+== Resize tests ==
310
+=== preallocation=off ===
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
312
+
313
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=1073741824 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
314
+
315
+wrote 65536/65536 bytes at offset 5368709120
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
317
+
318
+Image resized.
319
+
320
+read 65536/65536 bytes at offset 5368709120
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
322
+
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
325
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
328
+
329
+=== preallocation=metadata ===
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
331
+
332
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=32212254720 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
333
+
334
+wrote 65536/65536 bytes at offset 33285996544
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
336
+
337
+Image resized.
338
+
339
+read 65536/65536 bytes at offset 33285996544
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
341
+
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
344
+
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
352
+
353
+=== preallocation=falloc ===
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
355
+
356
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=5242880 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
357
+
358
+wrote 65536/65536 bytes at offset 9437184
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
360
+
361
+Image resized.
362
+
363
+read 65536/65536 bytes at offset 9437184
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
365
+
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
368
+
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
371
+
372
+=== preallocation=full ===
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
374
+
375
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=8388608 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
376
+
377
+wrote 65536/65536 bytes at offset 11534336
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
379
+
380
+Image resized.
381
+
382
+read 65536/65536 bytes at offset 11534336
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
384
+
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
387
+
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
390
+
391
+=== preallocation=off ===
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
393
+
394
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=259072 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
395
+
396
+wrote 65536/65536 bytes at offset 259072
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
398
+
399
+Image resized.
400
+
401
+read 65536/65536 bytes at offset 259072
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
403
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
406
+
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
410
+
411
+=== preallocation=off ===
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
413
+
414
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
415
+
416
+wrote 65536/65536 bytes at offset 344064
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
418
+
419
+Image resized.
420
+
421
+read 65536/65536 bytes at offset 344064
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
423
+
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
426
+
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
429
+
430
+=== preallocation=off ===
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
432
+
433
+Formatting 'TEST_DIR/PID-top', fmt=qcow2 size=262144 backing_file=TEST_DIR/PID-base cluster_size=65536 lazy_refcounts=off refcount_bits=16
434
+
435
+wrote 65536/65536 bytes at offset 446464
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
437
+
438
+Image resized.
439
+
440
+read 65536/65536 bytes at offset 446464
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
442
+
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
445
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
448
+
1023
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
449
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
1024
index XXXXXXX..XXXXXXX 100644
450
index XXXXXXX..XXXXXXX 100644
1025
--- a/tests/qemu-iotests/group
451
--- a/tests/qemu-iotests/group
1026
+++ b/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
1027
@@ -XXX,XX +XXX,XX @@
453
@@ -XXX,XX +XXX,XX @@
1028
242 rw auto quick
454
270 rw backing quick
1029
243 rw auto quick
455
272 rw
1030
244 rw auto quick
456
273 backing quick
1031
+245 rw auto
457
+274 rw backing
458
277 rw quick
459
279 rw backing quick
460
280 rw migration quick
1032
--
461
--
1033
2.20.1
462
2.25.3
1034
463
1035
464
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
The BDRV_REQ_ZERO_WRITE is currently implemented in a way that first the
2
image is possibly preallocated and then the zero flag is added to all
3
clusters. This means that a copy-on-write operation may be needed when
4
writing to these clusters, despite having used preallocation, negating
5
one of the major benefits of preallocation.
2
6
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
8
and if the protocol driver can ensure that the new area reads as zeros,
9
we can skip setting the zero flag in the qcow2 layer.
10
11
Unfortunately, the same approach doesn't work for metadata
12
preallocation, so we'll still set the zero flag there.
13
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Reviewed-by: Max Reitz <mreitz@redhat.com>
16
Message-Id: <20200424142701.67053-1-kwolf@redhat.com>
17
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
19
---
6
block/stream.c | 21 +++++++++++++++++++++
20
block/qcow2.c | 22 +++++++++++++++++++---
7
1 file changed, 21 insertions(+)
21
tests/qemu-iotests/274.out | 4 ++--
22
2 files changed, 21 insertions(+), 5 deletions(-)
8
23
9
diff --git a/block/stream.c b/block/stream.c
24
diff --git a/block/qcow2.c b/block/qcow2.c
10
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
11
--- a/block/stream.c
26
--- a/block/qcow2.c
12
+++ b/block/stream.c
27
+++ b/block/qcow2.c
13
@@ -XXX,XX +XXX,XX @@ typedef struct StreamBlockJob {
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
14
BlockdevOnError on_error;
29
/* Allocate the data area */
15
char *backing_file_str;
30
new_file_size = allocation_start +
16
bool bs_read_only;
31
nb_new_data_clusters * s->cluster_size;
17
+ bool chain_frozen;
32
- /* Image file grows, so @exact does not matter */
18
} StreamBlockJob;
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
19
34
- errp);
20
static int coroutine_fn stream_populate(BlockBackend *blk,
35
+ /*
21
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn stream_populate(BlockBackend *blk,
36
+ * Image file grows, so @exact does not matter.
22
return blk_co_preadv(blk, offset, qiov.size, &qiov, BDRV_REQ_COPY_ON_READ);
37
+ *
23
}
38
+ * If we need to zero out the new area, try first whether the protocol
24
39
+ * driver can already take care of this.
25
+static void stream_abort(Job *job)
40
+ */
26
+{
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
27
+ StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
28
+
43
+ BDRV_REQ_ZERO_WRITE, NULL);
29
+ if (s->chain_frozen) {
44
+ if (ret >= 0) {
30
+ BlockJob *bjob = &s->common;
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
31
+ bdrv_unfreeze_backing_chain(blk_bs(bjob->blk), s->base);
46
+ }
32
+ }
47
+ } else {
33
+}
48
+ ret = -1;
34
+
49
+ }
35
static int stream_prepare(Job *job)
50
+ if (ret < 0) {
36
{
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
37
StreamBlockJob *s = container_of(job, StreamBlockJob, common.job);
52
+ errp);
38
@@ -XXX,XX +XXX,XX @@ static int stream_prepare(Job *job)
53
+ }
39
Error *local_err = NULL;
54
if (ret < 0) {
40
int ret = 0;
55
error_prepend(errp, "Failed to resize underlying file: ");
41
56
qcow2_free_clusters(bs, allocation_start,
42
+ bdrv_unfreeze_backing_chain(bs, base);
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
43
+ s->chain_frozen = false;
58
index XXXXXXX..XXXXXXX 100644
44
+
59
--- a/tests/qemu-iotests/274.out
45
if (bs->backing) {
60
+++ b/tests/qemu-iotests/274.out
46
const char *base_id = NULL, *base_fmt = NULL;
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
47
if (base) {
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
48
@@ -XXX,XX +XXX,XX @@ static const BlockJobDriver stream_job_driver = {
63
49
.free = block_job_free,
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
50
.run = stream_run,
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
51
.prepare = stream_prepare,
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
52
+ .abort = stream_abort,
67
53
.clean = stream_clean,
68
=== preallocation=full ===
54
.user_resume = block_job_user_resume,
69
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
55
.drain = block_job_drain,
70
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
56
@@ -XXX,XX +XXX,XX @@ void stream_start(const char *job_id, BlockDriverState *bs,
71
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
57
&error_abort);
72
58
}
73
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
59
74
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
60
+ if (bdrv_freeze_backing_chain(bs, base, errp) < 0) {
75
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
61
+ job_early_fail(&s->common.job);
76
62
+ goto fail;
77
=== preallocation=off ===
63
+ }
78
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
64
+
65
s->base = base;
66
s->backing_file_str = g_strdup(backing_file_str);
67
s->bs_read_only = bs_read_only;
68
+ s->chain_frozen = true;
69
70
s->on_error = on_error;
71
trace_stream_start(bs, base, s);
72
--
79
--
73
2.20.1
80
2.25.3
74
81
75
82
diff view generated by jsdifflib
1
The way that reopen interacts with permission changes has one big
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
2
problem: Both operations are recursive, and the permissions are changes
3
for each node in the reopen queue.
4
2
5
For a simple graph that consists just of parent and child,
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
6
.bdrv_check_perm will be called twice for the child, once recursively
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
7
when adjusting the permissions of parent, and once again when the child
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
8
itself is reopened.
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
7
persistent across system reboot.
9
8
10
Even worse, the first .bdrv_check_perm call happens before
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
11
.bdrv_reopen_prepare was called for the child and the second one is
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
12
called afterwards.
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
14
Making sure that .bdrv_check_perm (and the other permission callbacks)
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
15
are called only once is hard. We can cope with multiple calls right now,
16
but as soon as file-posix gets a dynamic auto-read-only that may need to
17
open a new file descriptor, we get the additional requirement that all
18
of them are after the .bdrv_reopen_prepare call.
19
20
So reorder things in bdrv_reopen_multiple() to first call
21
.bdrv_reopen_prepare for all involved nodes and only then adjust
22
permissions.
23
24
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
25
---
15
---
26
block.c | 35 ++++++++++++++++++++++++-----------
16
hw/block/nvme.h | 2 +
27
1 file changed, 24 insertions(+), 11 deletions(-)
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
18
hw/block/nvme.c | 109 ++++++++++++++++++++++++++
19
hw/block/Makefile.objs | 2 +-
20
hw/block/trace-events | 4 +
21
5 files changed, 288 insertions(+), 1 deletion(-)
28
22
29
diff --git a/block.c b/block.c
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
30
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
31
--- a/block.c
25
--- a/hw/block/nvme.h
32
+++ b/block.c
26
+++ b/hw/block/nvme.h
33
@@ -XXX,XX +XXX,XX @@ static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
34
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
35
typedef struct BlockReopenQueueEntry {
29
36
bool prepared;
30
char *serial;
37
+ bool perms_checked;
31
+ HostMemoryBackend *pmrdev;
38
BDRVReopenState state;
32
+
39
QSIMPLEQ_ENTRY(BlockReopenQueueEntry) entry;
33
NvmeNamespace *namespaces;
40
} BlockReopenQueueEntry;
34
NvmeSQueue **sq;
41
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
35
NvmeCQueue **cq;
42
bs_entry->prepared = true;
36
diff --git a/include/block/nvme.h b/include/block/nvme.h
37
index XXXXXXX..XXXXXXX 100644
38
--- a/include/block/nvme.h
39
+++ b/include/block/nvme.h
40
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeBar {
41
uint64_t acq;
42
uint32_t cmbloc;
43
uint32_t cmbsz;
44
+ uint8_t padding[3520]; /* not used by QEMU */
45
+ uint32_t pmrcap;
46
+ uint32_t pmrctl;
47
+ uint32_t pmrsts;
48
+ uint32_t pmrebs;
49
+ uint32_t pmrswtp;
50
+ uint32_t pmrmsc;
51
} NvmeBar;
52
53
enum NvmeCapShift {
54
@@ -XXX,XX +XXX,XX @@ enum NvmeCapShift {
55
CAP_CSS_SHIFT = 37,
56
CAP_MPSMIN_SHIFT = 48,
57
CAP_MPSMAX_SHIFT = 52,
58
+ CAP_PMR_SHIFT = 56,
59
};
60
61
enum NvmeCapMask {
62
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
63
CAP_CSS_MASK = 0xff,
64
CAP_MPSMIN_MASK = 0xf,
65
CAP_MPSMAX_MASK = 0xf,
66
+ CAP_PMR_MASK = 0x1,
67
};
68
69
#define NVME_CAP_MQES(cap) (((cap) >> CAP_MQES_SHIFT) & CAP_MQES_MASK)
70
@@ -XXX,XX +XXX,XX @@ enum NvmeCapMask {
71
<< CAP_MPSMIN_SHIFT)
72
#define NVME_CAP_SET_MPSMAX(cap, val) (cap |= (uint64_t)(val & CAP_MPSMAX_MASK)\
73
<< CAP_MPSMAX_SHIFT)
74
+#define NVME_CAP_SET_PMRS(cap, val) (cap |= (uint64_t)(val & CAP_PMR_MASK)\
75
+ << CAP_PMR_SHIFT)
76
77
enum NvmeCcShift {
78
CC_EN_SHIFT = 0,
79
@@ -XXX,XX +XXX,XX @@ enum NvmeCmbszMask {
80
#define NVME_CMBSZ_GETSIZE(cmbsz) \
81
(NVME_CMBSZ_SZ(cmbsz) * (1 << (12 + 4 * NVME_CMBSZ_SZU(cmbsz))))
82
83
+enum NvmePmrcapShift {
84
+ PMRCAP_RDS_SHIFT = 3,
85
+ PMRCAP_WDS_SHIFT = 4,
86
+ PMRCAP_BIR_SHIFT = 5,
87
+ PMRCAP_PMRTU_SHIFT = 8,
88
+ PMRCAP_PMRWBM_SHIFT = 10,
89
+ PMRCAP_PMRTO_SHIFT = 16,
90
+ PMRCAP_CMSS_SHIFT = 24,
91
+};
92
+
93
+enum NvmePmrcapMask {
94
+ PMRCAP_RDS_MASK = 0x1,
95
+ PMRCAP_WDS_MASK = 0x1,
96
+ PMRCAP_BIR_MASK = 0x7,
97
+ PMRCAP_PMRTU_MASK = 0x3,
98
+ PMRCAP_PMRWBM_MASK = 0xf,
99
+ PMRCAP_PMRTO_MASK = 0xff,
100
+ PMRCAP_CMSS_MASK = 0x1,
101
+};
102
+
103
+#define NVME_PMRCAP_RDS(pmrcap) \
104
+ ((pmrcap >> PMRCAP_RDS_SHIFT) & PMRCAP_RDS_MASK)
105
+#define NVME_PMRCAP_WDS(pmrcap) \
106
+ ((pmrcap >> PMRCAP_WDS_SHIFT) & PMRCAP_WDS_MASK)
107
+#define NVME_PMRCAP_BIR(pmrcap) \
108
+ ((pmrcap >> PMRCAP_BIR_SHIFT) & PMRCAP_BIR_MASK)
109
+#define NVME_PMRCAP_PMRTU(pmrcap) \
110
+ ((pmrcap >> PMRCAP_PMRTU_SHIFT) & PMRCAP_PMRTU_MASK)
111
+#define NVME_PMRCAP_PMRWBM(pmrcap) \
112
+ ((pmrcap >> PMRCAP_PMRWBM_SHIFT) & PMRCAP_PMRWBM_MASK)
113
+#define NVME_PMRCAP_PMRTO(pmrcap) \
114
+ ((pmrcap >> PMRCAP_PMRTO_SHIFT) & PMRCAP_PMRTO_MASK)
115
+#define NVME_PMRCAP_CMSS(pmrcap) \
116
+ ((pmrcap >> PMRCAP_CMSS_SHIFT) & PMRCAP_CMSS_MASK)
117
+
118
+#define NVME_PMRCAP_SET_RDS(pmrcap, val) \
119
+ (pmrcap |= (uint64_t)(val & PMRCAP_RDS_MASK) << PMRCAP_RDS_SHIFT)
120
+#define NVME_PMRCAP_SET_WDS(pmrcap, val) \
121
+ (pmrcap |= (uint64_t)(val & PMRCAP_WDS_MASK) << PMRCAP_WDS_SHIFT)
122
+#define NVME_PMRCAP_SET_BIR(pmrcap, val) \
123
+ (pmrcap |= (uint64_t)(val & PMRCAP_BIR_MASK) << PMRCAP_BIR_SHIFT)
124
+#define NVME_PMRCAP_SET_PMRTU(pmrcap, val) \
125
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTU_MASK) << PMRCAP_PMRTU_SHIFT)
126
+#define NVME_PMRCAP_SET_PMRWBM(pmrcap, val) \
127
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRWBM_MASK) << PMRCAP_PMRWBM_SHIFT)
128
+#define NVME_PMRCAP_SET_PMRTO(pmrcap, val) \
129
+ (pmrcap |= (uint64_t)(val & PMRCAP_PMRTO_MASK) << PMRCAP_PMRTO_SHIFT)
130
+#define NVME_PMRCAP_SET_CMSS(pmrcap, val) \
131
+ (pmrcap |= (uint64_t)(val & PMRCAP_CMSS_MASK) << PMRCAP_CMSS_SHIFT)
132
+
133
+enum NvmePmrctlShift {
134
+ PMRCTL_EN_SHIFT = 0,
135
+};
136
+
137
+enum NvmePmrctlMask {
138
+ PMRCTL_EN_MASK = 0x1,
139
+};
140
+
141
+#define NVME_PMRCTL_EN(pmrctl) ((pmrctl >> PMRCTL_EN_SHIFT) & PMRCTL_EN_MASK)
142
+
143
+#define NVME_PMRCTL_SET_EN(pmrctl, val) \
144
+ (pmrctl |= (uint64_t)(val & PMRCTL_EN_MASK) << PMRCTL_EN_SHIFT)
145
+
146
+enum NvmePmrstsShift {
147
+ PMRSTS_ERR_SHIFT = 0,
148
+ PMRSTS_NRDY_SHIFT = 8,
149
+ PMRSTS_HSTS_SHIFT = 9,
150
+ PMRSTS_CBAI_SHIFT = 12,
151
+};
152
+
153
+enum NvmePmrstsMask {
154
+ PMRSTS_ERR_MASK = 0xff,
155
+ PMRSTS_NRDY_MASK = 0x1,
156
+ PMRSTS_HSTS_MASK = 0x7,
157
+ PMRSTS_CBAI_MASK = 0x1,
158
+};
159
+
160
+#define NVME_PMRSTS_ERR(pmrsts) \
161
+ ((pmrsts >> PMRSTS_ERR_SHIFT) & PMRSTS_ERR_MASK)
162
+#define NVME_PMRSTS_NRDY(pmrsts) \
163
+ ((pmrsts >> PMRSTS_NRDY_SHIFT) & PMRSTS_NRDY_MASK)
164
+#define NVME_PMRSTS_HSTS(pmrsts) \
165
+ ((pmrsts >> PMRSTS_HSTS_SHIFT) & PMRSTS_HSTS_MASK)
166
+#define NVME_PMRSTS_CBAI(pmrsts) \
167
+ ((pmrsts >> PMRSTS_CBAI_SHIFT) & PMRSTS_CBAI_MASK)
168
+
169
+#define NVME_PMRSTS_SET_ERR(pmrsts, val) \
170
+ (pmrsts |= (uint64_t)(val & PMRSTS_ERR_MASK) << PMRSTS_ERR_SHIFT)
171
+#define NVME_PMRSTS_SET_NRDY(pmrsts, val) \
172
+ (pmrsts |= (uint64_t)(val & PMRSTS_NRDY_MASK) << PMRSTS_NRDY_SHIFT)
173
+#define NVME_PMRSTS_SET_HSTS(pmrsts, val) \
174
+ (pmrsts |= (uint64_t)(val & PMRSTS_HSTS_MASK) << PMRSTS_HSTS_SHIFT)
175
+#define NVME_PMRSTS_SET_CBAI(pmrsts, val) \
176
+ (pmrsts |= (uint64_t)(val & PMRSTS_CBAI_MASK) << PMRSTS_CBAI_SHIFT)
177
+
178
+enum NvmePmrebsShift {
179
+ PMREBS_PMRSZU_SHIFT = 0,
180
+ PMREBS_RBB_SHIFT = 4,
181
+ PMREBS_PMRWBZ_SHIFT = 8,
182
+};
183
+
184
+enum NvmePmrebsMask {
185
+ PMREBS_PMRSZU_MASK = 0xf,
186
+ PMREBS_RBB_MASK = 0x1,
187
+ PMREBS_PMRWBZ_MASK = 0xffffff,
188
+};
189
+
190
+#define NVME_PMREBS_PMRSZU(pmrebs) \
191
+ ((pmrebs >> PMREBS_PMRSZU_SHIFT) & PMREBS_PMRSZU_MASK)
192
+#define NVME_PMREBS_RBB(pmrebs) \
193
+ ((pmrebs >> PMREBS_RBB_SHIFT) & PMREBS_RBB_MASK)
194
+#define NVME_PMREBS_PMRWBZ(pmrebs) \
195
+ ((pmrebs >> PMREBS_PMRWBZ_SHIFT) & PMREBS_PMRWBZ_MASK)
196
+
197
+#define NVME_PMREBS_SET_PMRSZU(pmrebs, val) \
198
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRSZU_MASK) << PMREBS_PMRSZU_SHIFT)
199
+#define NVME_PMREBS_SET_RBB(pmrebs, val) \
200
+ (pmrebs |= (uint64_t)(val & PMREBS_RBB_MASK) << PMREBS_RBB_SHIFT)
201
+#define NVME_PMREBS_SET_PMRWBZ(pmrebs, val) \
202
+ (pmrebs |= (uint64_t)(val & PMREBS_PMRWBZ_MASK) << PMREBS_PMRWBZ_SHIFT)
203
+
204
+enum NvmePmrswtpShift {
205
+ PMRSWTP_PMRSWTU_SHIFT = 0,
206
+ PMRSWTP_PMRSWTV_SHIFT = 8,
207
+};
208
+
209
+enum NvmePmrswtpMask {
210
+ PMRSWTP_PMRSWTU_MASK = 0xf,
211
+ PMRSWTP_PMRSWTV_MASK = 0xffffff,
212
+};
213
+
214
+#define NVME_PMRSWTP_PMRSWTU(pmrswtp) \
215
+ ((pmrswtp >> PMRSWTP_PMRSWTU_SHIFT) & PMRSWTP_PMRSWTU_MASK)
216
+#define NVME_PMRSWTP_PMRSWTV(pmrswtp) \
217
+ ((pmrswtp >> PMRSWTP_PMRSWTV_SHIFT) & PMRSWTP_PMRSWTV_MASK)
218
+
219
+#define NVME_PMRSWTP_SET_PMRSWTU(pmrswtp, val) \
220
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTU_MASK) << PMRSWTP_PMRSWTU_SHIFT)
221
+#define NVME_PMRSWTP_SET_PMRSWTV(pmrswtp, val) \
222
+ (pmrswtp |= (uint64_t)(val & PMRSWTP_PMRSWTV_MASK) << PMRSWTP_PMRSWTV_SHIFT)
223
+
224
+enum NvmePmrmscShift {
225
+ PMRMSC_CMSE_SHIFT = 1,
226
+ PMRMSC_CBA_SHIFT = 12,
227
+};
228
+
229
+enum NvmePmrmscMask {
230
+ PMRMSC_CMSE_MASK = 0x1,
231
+ PMRMSC_CBA_MASK = 0xfffffffffffff,
232
+};
233
+
234
+#define NVME_PMRMSC_CMSE(pmrmsc) \
235
+ ((pmrmsc >> PMRMSC_CMSE_SHIFT) & PMRMSC_CMSE_MASK)
236
+#define NVME_PMRMSC_CBA(pmrmsc) \
237
+ ((pmrmsc >> PMRMSC_CBA_SHIFT) & PMRMSC_CBA_MASK)
238
+
239
+#define NVME_PMRMSC_SET_CMSE(pmrmsc, val) \
240
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CMSE_MASK) << PMRMSC_CMSE_SHIFT)
241
+#define NVME_PMRMSC_SET_CBA(pmrmsc, val) \
242
+ (pmrmsc |= (uint64_t)(val & PMRMSC_CBA_MASK) << PMRMSC_CBA_SHIFT)
243
+
244
typedef struct NvmeCmd {
245
uint8_t opcode;
246
uint8_t fuse;
247
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
248
index XXXXXXX..XXXXXXX 100644
249
--- a/hw/block/nvme.c
250
+++ b/hw/block/nvme.c
251
@@ -XXX,XX +XXX,XX @@
252
* -drive file=<file>,if=none,id=<drive_id>
253
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
254
* cmb_size_mb=<cmb_size_mb[optional]>, \
255
+ * [pmrdev=<mem_backend_file_id>,] \
256
* num_queues=<N[optional]>
257
*
258
* Note cmb_size_mb denotes size of CMB in MB. CMB is assumed to be at
259
* offset 0 in BAR2 and supports only WDS, RDS and SQS for now.
260
+ *
261
+ * cmb_size_mb= and pmrdev= options are mutually exclusive due to limitation
262
+ * in available BAR's. cmb_size_mb= will take precedence over pmrdev= when
263
+ * both provided.
264
+ * Enabling pmr emulation can be achieved by pointing to memory-backend-file.
265
+ * For example:
266
+ * -object memory-backend-file,id=<mem_id>,share=on,mem-path=<file_path>, \
267
+ * size=<size> .... -device nvme,...,pmrdev=<mem_id>
268
*/
269
270
#include "qemu/osdep.h"
271
@@ -XXX,XX +XXX,XX @@
272
#include "sysemu/sysemu.h"
273
#include "qapi/error.h"
274
#include "qapi/visitor.h"
275
+#include "sysemu/hostmem.h"
276
#include "sysemu/block-backend.h"
277
+#include "exec/ram_addr.h"
278
279
#include "qemu/log.h"
280
#include "qemu/module.h"
281
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
282
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
283
"invalid write to read only CMBSZ, ignored");
284
return;
285
+ case 0xE00: /* PMRCAP */
286
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
287
+ "invalid write to PMRCAP register, ignored");
288
+ return;
289
+ case 0xE04: /* TODO PMRCTL */
290
+ break;
291
+ case 0xE08: /* PMRSTS */
292
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
293
+ "invalid write to PMRSTS register, ignored");
294
+ return;
295
+ case 0xE0C: /* PMREBS */
296
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
297
+ "invalid write to PMREBS register, ignored");
298
+ return;
299
+ case 0xE10: /* PMRSWTP */
300
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrswtp_readonly,
301
+ "invalid write to PMRSWTP register, ignored");
302
+ return;
303
+ case 0xE14: /* TODO PMRMSC */
304
+ break;
305
default:
306
NVME_GUEST_ERR(nvme_ub_mmiowr_invalid,
307
"invalid MMIO write,"
308
@@ -XXX,XX +XXX,XX @@ static uint64_t nvme_mmio_read(void *opaque, hwaddr addr, unsigned size)
43
}
309
}
44
310
45
+ QSIMPLEQ_FOREACH(bs_entry, bs_queue, entry) {
311
if (addr < sizeof(n->bar)) {
46
+ BDRVReopenState *state = &bs_entry->state;
312
+ /*
47
+ ret = bdrv_check_perm(state->bs, bs_queue, state->perm,
313
+ * When PMRWBM bit 1 is set then read from
48
+ state->shared_perm, NULL, errp);
314
+ * from PMRSTS should ensure prior writes
49
+ if (ret < 0) {
315
+ * made it to persistent media
50
+ goto cleanup_perm;
316
+ */
317
+ if (addr == 0xE08 &&
318
+ (NVME_PMRCAP_PMRWBM(n->bar.pmrcap) & 0x02)) {
319
+ qemu_ram_writeback(n->pmrdev->mr.ram_block,
320
+ 0, n->pmrdev->size);
51
+ }
321
+ }
52
+ bs_entry->perms_checked = true;
322
memcpy(&val, ptr + addr, size);
323
} else {
324
NVME_GUEST_ERR(nvme_ub_mmiord_invalid_ofs,
325
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
326
error_setg(errp, "serial property not set");
327
return;
328
}
329
+
330
+ if (!n->cmb_size_mb && n->pmrdev) {
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
334
+ g_free(path);
335
+ return;
336
+ }
337
+
338
+ if (!is_power_of_2(n->pmrdev->size)) {
339
+ error_setg(errp, "pmr backend size needs to be power of 2 in size");
340
+ return;
341
+ }
342
+
343
+ host_memory_backend_set_mapped(n->pmrdev, true);
53
+ }
344
+ }
54
+
345
+
55
/* If we reach this point, we have success and just need to apply the
346
blkconf_blocksizes(&n->conf);
56
* changes
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
57
*/
348
false, errp)) {
58
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
352
353
+ } else if (n->pmrdev) {
354
+ /* Controller Capabilities register */
355
+ NVME_CAP_SET_PMRS(n->bar.cap, 1);
356
+
357
+ /* PMR Capabities register */
358
+ n->bar.pmrcap = 0;
359
+ NVME_PMRCAP_SET_RDS(n->bar.pmrcap, 0);
360
+ NVME_PMRCAP_SET_WDS(n->bar.pmrcap, 0);
361
+ NVME_PMRCAP_SET_BIR(n->bar.pmrcap, 2);
362
+ NVME_PMRCAP_SET_PMRTU(n->bar.pmrcap, 0);
363
+ /* Turn on bit 1 support */
364
+ NVME_PMRCAP_SET_PMRWBM(n->bar.pmrcap, 0x02);
365
+ NVME_PMRCAP_SET_PMRTO(n->bar.pmrcap, 0);
366
+ NVME_PMRCAP_SET_CMSS(n->bar.pmrcap, 0);
367
+
368
+ /* PMR Control register */
369
+ n->bar.pmrctl = 0;
370
+ NVME_PMRCTL_SET_EN(n->bar.pmrctl, 0);
371
+
372
+ /* PMR Status register */
373
+ n->bar.pmrsts = 0;
374
+ NVME_PMRSTS_SET_ERR(n->bar.pmrsts, 0);
375
+ NVME_PMRSTS_SET_NRDY(n->bar.pmrsts, 0);
376
+ NVME_PMRSTS_SET_HSTS(n->bar.pmrsts, 0);
377
+ NVME_PMRSTS_SET_CBAI(n->bar.pmrsts, 0);
378
+
379
+ /* PMR Elasticity Buffer Size register */
380
+ n->bar.pmrebs = 0;
381
+ NVME_PMREBS_SET_PMRSZU(n->bar.pmrebs, 0);
382
+ NVME_PMREBS_SET_RBB(n->bar.pmrebs, 0);
383
+ NVME_PMREBS_SET_PMRWBZ(n->bar.pmrebs, 0);
384
+
385
+ /* PMR Sustained Write Throughput register */
386
+ n->bar.pmrswtp = 0;
387
+ NVME_PMRSWTP_SET_PMRSWTU(n->bar.pmrswtp, 0);
388
+ NVME_PMRSWTP_SET_PMRSWTV(n->bar.pmrswtp, 0);
389
+
390
+ /* PMR Memory Space Control register */
391
+ n->bar.pmrmsc = 0;
392
+ NVME_PMRMSC_SET_CMSE(n->bar.pmrmsc, 0);
393
+ NVME_PMRMSC_SET_CBA(n->bar.pmrmsc, 0);
394
+
395
+ pci_register_bar(pci_dev, NVME_PMRCAP_BIR(n->bar.pmrcap),
396
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
397
+ PCI_BASE_ADDRESS_MEM_PREFETCH, &n->pmrdev->mr);
59
}
398
}
60
399
61
ret = 0;
400
for (i = 0; i < n->num_namespaces; i++) {
62
+cleanup_perm:
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
63
+ QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
402
if (n->cmb_size_mb) {
64
+ BDRVReopenState *state = &bs_entry->state;
403
g_free(n->cmbuf);
65
+
404
}
66
+ if (!bs_entry->perms_checked) {
405
+
67
+ continue;
406
+ if (n->pmrdev) {
68
+ }
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
69
70
+ if (ret == 0) {
71
+ bdrv_set_perm(state->bs, state->perm, state->shared_perm);
72
+ } else {
73
+ bdrv_abort_perm_update(state->bs);
74
+ }
75
+ }
408
+ }
76
cleanup:
409
msix_uninit_exclusive_bar(pci_dev);
77
QSIMPLEQ_FOREACH_SAFE(bs_entry, bs_queue, entry, next) {
78
if (ret) {
79
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
80
} while ((entry = qdict_next(reopen_state->options, entry)));
81
}
82
83
- ret = bdrv_check_perm(reopen_state->bs, queue, reopen_state->perm,
84
- reopen_state->shared_perm, NULL, errp);
85
- if (ret < 0) {
86
- goto error;
87
- }
88
-
89
ret = 0;
90
91
/* Restore the original reopen_state->options QDict */
92
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
93
94
bdrv_refresh_limits(bs, NULL);
95
96
- bdrv_set_perm(reopen_state->bs, reopen_state->perm,
97
- reopen_state->shared_perm);
98
-
99
new_can_write =
100
!bdrv_is_read_only(bs) && !(bdrv_get_flags(bs) & BDRV_O_INACTIVE);
101
if (!old_can_write && new_can_write && drv->bdrv_reopen_bitmaps_rw) {
102
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_abort(BDRVReopenState *reopen_state)
103
if (drv->bdrv_reopen_abort) {
104
drv->bdrv_reopen_abort(reopen_state);
105
}
106
-
107
- bdrv_abort_perm_update(reopen_state->bs);
108
}
410
}
109
411
110
412
static Property nvme_props[] = {
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
415
+ HostMemoryBackend *),
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
420
index XXXXXXX..XXXXXXX 100644
421
--- a/hw/block/Makefile.objs
422
+++ b/hw/block/Makefile.objs
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
424
common-obj-$(CONFIG_XEN) += xen-block.o
425
common-obj-$(CONFIG_ECC) += ecc.o
426
common-obj-$(CONFIG_ONENAND) += onenand.o
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
428
common-obj-$(CONFIG_SWIM) += swim.o
429
430
common-obj-$(CONFIG_SH4) += tc58128.o
431
432
obj-$(CONFIG_VIRTIO_BLK) += virtio-blk.o
433
obj-$(CONFIG_VHOST_USER_BLK) += vhost-user-blk.o
434
+obj-$(CONFIG_NVME_PCI) += nvme.o
435
436
obj-y += dataplane/
437
diff --git a/hw/block/trace-events b/hw/block/trace-events
438
index XXXXXXX..XXXXXXX 100644
439
--- a/hw/block/trace-events
440
+++ b/hw/block/trace-events
441
@@ -XXX,XX +XXX,XX @@ nvme_ub_mmiowr_ssreset_w1c_unsupported(void) "attempted to W1C CSTS.NSSRO but CA
442
nvme_ub_mmiowr_ssreset_unsupported(void) "attempted NVM subsystem reset but CAP.NSSRS is zero (not supported)"
443
nvme_ub_mmiowr_cmbloc_reserved(void) "invalid write to reserved CMBLOC when CMBSZ is zero, ignored"
444
nvme_ub_mmiowr_cmbsz_readonly(void) "invalid write to read only CMBSZ, ignored"
445
+nvme_ub_mmiowr_pmrcap_readonly(void) "invalid write to read only PMRCAP, ignored"
446
+nvme_ub_mmiowr_pmrsts_readonly(void) "invalid write to read only PMRSTS, ignored"
447
+nvme_ub_mmiowr_pmrebs_readonly(void) "invalid write to read only PMREBS, ignored"
448
+nvme_ub_mmiowr_pmrswtp_readonly(void) "invalid write to read only PMRSWTP, ignored"
449
nvme_ub_mmiowr_invalid(uint64_t offset, uint64_t data) "invalid MMIO write, offset=0x%"PRIx64", data=0x%"PRIx64""
450
nvme_ub_mmiord_misaligned32(uint64_t offset) "MMIO read not 32-bit aligned, offset=0x%"PRIx64""
451
nvme_ub_mmiord_toosmall(uint64_t offset) "MMIO read smaller than 32-bits, offset=0x%"PRIx64""
111
--
452
--
112
2.20.1
453
2.25.3
113
454
114
455
diff view generated by jsdifflib
Deleted patch
1
Using a different read-only setting for bs->open_flags than for the
2
flags to the driver's open function is just inconsistent and a bad idea.
3
After this patch, the temporary snapshot keeps being opened read-only if
4
read-only=on,snapshot=on is passed.
5
1
6
If we wanted to change this behaviour to make only the orginal image
7
file read-only, but the temporary overlay read-write (as the comment in
8
the removed code suggests), that change would have to be made in
9
bdrv_temp_snapshot_options() (where the comment suggests otherwise).
10
11
Addressing this inconsistency before introducing dynamic auto-read-only
12
is important because otherwise we would immediately try to reopen the
13
temporary overlay even though the file is already unlinked.
14
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
block.c | 7 -------
18
tests/qemu-iotests/051 | 7 +++++++
19
tests/qemu-iotests/051.out | 9 +++++++++
20
tests/qemu-iotests/051.pc.out | 9 +++++++++
21
4 files changed, 25 insertions(+), 7 deletions(-)
22
23
diff --git a/block.c b/block.c
24
index XXXXXXX..XXXXXXX 100644
25
--- a/block.c
26
+++ b/block.c
27
@@ -XXX,XX +XXX,XX @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
28
*/
29
open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_PROTOCOL);
30
31
- /*
32
- * Snapshots should be writable.
33
- */
34
- if (flags & BDRV_O_TEMPORARY) {
35
- open_flags |= BDRV_O_RDWR;
36
- }
37
-
38
return open_flags;
39
}
40
41
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
42
index XXXXXXX..XXXXXXX 100755
43
--- a/tests/qemu-iotests/051
44
+++ b/tests/qemu-iotests/051
45
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -c "read -P 0x33 0 4k" "$TEST_IMG" | _filter_qemu_io
46
# Using snapshot=on with a non-existent TMPDIR
47
TMPDIR=/nonexistent run_qemu -drive driver=null-co,snapshot=on
48
49
+# Using snapshot=on together with read-only=on
50
+echo "info block" |
51
+ run_qemu -drive file="$TEST_IMG",snapshot=on,read-only=on,if=none,id=$device_id |
52
+ _filter_qemu_io |
53
+ sed -e 's#"/[^"]*/vl\.[A-Za-z]\{6\}"#SNAPSHOT_PATH#g'
54
+
55
+
56
# success, all done
57
echo "*** done"
58
rm -f $seq.full
59
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
60
index XXXXXXX..XXXXXXX 100644
61
--- a/tests/qemu-iotests/051.out
62
+++ b/tests/qemu-iotests/051.out
63
@@ -XXX,XX +XXX,XX @@ read 4096/4096 bytes at offset 0
64
Testing: -drive driver=null-co,snapshot=on
65
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
66
67
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
68
+QEMU X.Y.Z monitor - type 'help' for more information
69
+(qemu) info block
70
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2", "file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2, read-only)
71
+ Removable device: not locked, tray closed
72
+ Cache mode: writeback, ignore flushes
73
+ Backing file: TEST_DIR/t.qcow2 (chain depth: 1)
74
+(qemu) quit
75
+
76
*** done
77
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
78
index XXXXXXX..XXXXXXX 100644
79
--- a/tests/qemu-iotests/051.pc.out
80
+++ b/tests/qemu-iotests/051.pc.out
81
@@ -XXX,XX +XXX,XX @@ read 4096/4096 bytes at offset 0
82
Testing: -drive driver=null-co,snapshot=on
83
QEMU_PROG: -drive driver=null-co,snapshot=on: Could not get temporary filename: No such file or directory
84
85
+Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,read-only=on,if=none,id=drive0
86
+QEMU X.Y.Z monitor - type 'help' for more information
87
+(qemu) info block
88
+drive0 (NODE_NAME): json:{"backing": {"driver": "qcow2", "file": {"driver": "file", "filename": "TEST_DIR/t.qcow2"}}, "driver": "qcow2", "file": {"driver": "file", "filename": SNAPSHOT_PATH}} (qcow2, read-only)
89
+ Removable device: not locked, tray closed
90
+ Cache mode: writeback, ignore flushes
91
+ Backing file: TEST_DIR/t.qcow2 (chain depth: 1)
92
+(qemu) quit
93
+
94
*** done
95
--
96
2.20.1
97
98
diff view generated by jsdifflib
Deleted patch
1
We'll want to access the file descriptor in the reopen_state while
2
processing permission changes in the context of the repoen.
3
1
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
block/file-posix.c | 10 ++++++++++
7
1 file changed, 10 insertions(+)
8
9
diff --git a/block/file-posix.c b/block/file-posix.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/file-posix.c
12
+++ b/block/file-posix.c
13
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
14
uint64_t locked_perm;
15
uint64_t locked_shared_perm;
16
17
+ BDRVReopenState *reopen_state;
18
+
19
#ifdef CONFIG_XFS
20
bool is_xfs:1;
21
#endif
22
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
23
}
24
}
25
26
+ s->reopen_state = state;
27
out:
28
qemu_opts_del(opts);
29
return ret;
30
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_commit(BDRVReopenState *state)
31
32
g_free(state->opaque);
33
state->opaque = NULL;
34
+
35
+ assert(s->reopen_state == state);
36
+ s->reopen_state = NULL;
37
}
38
39
40
static void raw_reopen_abort(BDRVReopenState *state)
41
{
42
BDRVRawReopenState *rs = state->opaque;
43
+ BDRVRawState *s = state->bs->opaque;
44
45
/* nothing to do if NULL, we didn't get far enough */
46
if (rs == NULL) {
47
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_abort(BDRVReopenState *state)
48
}
49
g_free(state->opaque);
50
state->opaque = NULL;
51
+
52
+ assert(s->reopen_state == state);
53
+ s->reopen_state = NULL;
54
}
55
56
static int hdev_get_max_transfer_length(BlockDriverState *bs, int fd)
57
--
58
2.20.1
59
60
diff view generated by jsdifflib
Deleted patch
1
There is no reason why we can take locks on the new file descriptor only
2
in raw_reopen_commit() where error handling isn't possible any more.
3
Instead, we can already do this in raw_reopen_prepare().
4
1
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
6
---
7
block/file-posix.c | 27 ++++++++++++++++-----------
8
1 file changed, 16 insertions(+), 11 deletions(-)
9
10
diff --git a/block/file-posix.c b/block/file-posix.c
11
index XXXXXXX..XXXXXXX 100644
12
--- a/block/file-posix.c
13
+++ b/block/file-posix.c
14
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
15
BDRVRawState *s;
16
BDRVRawReopenState *rs;
17
QemuOpts *opts;
18
- int ret = 0;
19
+ int ret;
20
Error *local_err = NULL;
21
22
assert(state != NULL);
23
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
24
if (rs->fd != -1) {
25
raw_probe_alignment(state->bs, rs->fd, &local_err);
26
if (local_err) {
27
- qemu_close(rs->fd);
28
- rs->fd = -1;
29
error_propagate(errp, local_err);
30
ret = -EINVAL;
31
+ goto out_fd;
32
+ }
33
+
34
+ /* Copy locks to the new fd */
35
+ ret = raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
36
+ s->locked_shared_perm, false, errp);
37
+ if (ret < 0) {
38
+ ret = -EINVAL;
39
+ goto out_fd;
40
}
41
}
42
43
s->reopen_state = state;
44
+ ret = 0;
45
+out_fd:
46
+ if (ret < 0) {
47
+ qemu_close(rs->fd);
48
+ rs->fd = -1;
49
+ }
50
out:
51
qemu_opts_del(opts);
52
return ret;
53
@@ -XXX,XX +XXX,XX @@ static void raw_reopen_commit(BDRVReopenState *state)
54
{
55
BDRVRawReopenState *rs = state->opaque;
56
BDRVRawState *s = state->bs->opaque;
57
- Error *local_err = NULL;
58
59
s->check_cache_dropped = rs->check_cache_dropped;
60
s->open_flags = rs->open_flags;
61
62
- /* Copy locks to the new fd before closing the old one. */
63
- raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
64
- s->locked_shared_perm, false, &local_err);
65
- if (local_err) {
66
- /* shouldn't fail in a sane host, but report it just in case. */
67
- error_report_err(local_err);
68
- }
69
qemu_close(s->fd);
70
s->fd = rs->fd;
71
72
--
73
2.20.1
74
75
diff view generated by jsdifflib
1
In order to be able to dynamically reopen the file read-only or
1
The QMP handler qmp_object_add() and the implementation of --object in
2
read-write, depending on the users that are attached, we need to be able
2
qemu-storage-daemon can share most of the code. Currently,
3
to switch to a different file descriptor during the permission change.
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
because different visitors need to be used.
4
5
5
This interacts with reopen, which also creates a new file descriptor and
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
6
performs permission changes internally. In this case, the permission
7
new function user_creatable_add_dict() that can get an additional
7
change code must reuse the reopen file descriptor instead of creating a
8
parameter. The handling of "props" is only required for compatibility
8
third one.
9
and not required for the qemu-storage-daemon command line, so it stays
9
10
in qmp_object_add().
10
In turn, reopen can drop its code to copy file locks to the new file
11
descriptor because that is now done when applying the new permissions.
12
11
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
---
13
---
15
block/file-posix.c | 96 ++++++++++++++++++++++++++++++++++++++++------
14
include/qom/object_interfaces.h | 12 ++++++++++++
16
1 file changed, 85 insertions(+), 11 deletions(-)
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
16
qom/qom-qmp-cmds.c | 24 +-----------------------
17
3 files changed, 40 insertions(+), 23 deletions(-)
17
18
18
diff --git a/block/file-posix.c b/block/file-posix.c
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
19
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
20
--- a/block/file-posix.c
21
--- a/include/qom/object_interfaces.h
21
+++ b/block/file-posix.c
22
+++ b/include/qom/object_interfaces.h
22
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRawState {
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
23
uint64_t locked_perm;
24
const QDict *qdict,
24
uint64_t locked_shared_perm;
25
Visitor *v, Error **errp);
25
26
26
+ int perm_change_fd;
27
+/**
27
BDRVReopenState *reopen_state;
28
+ * user_creatable_add_dict:
28
29
+ * @qdict: the object definition
29
#ifdef CONFIG_XFS
30
+ * @errp: if an error occurs, a pointer to an area to store the error
30
@@ -XXX,XX +XXX,XX @@ static int raw_handle_perm_lock(BlockDriverState *bs,
31
+ *
32
+ * Create an instance of the user creatable object that is defined by
33
+ * @qdict. The object type is taken from the QDict key 'qom-type', its
34
+ * ID from the key 'id'. The remaining entries in @qdict are used to
35
+ * initialize the object properties.
36
+ */
37
+void user_creatable_add_dict(QDict *qdict, Error **errp);
38
+
39
/**
40
* user_creatable_add_opts:
41
* @opts: the object definition
42
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
43
index XXXXXXX..XXXXXXX 100644
44
--- a/qom/object_interfaces.c
45
+++ b/qom/object_interfaces.c
46
@@ -XXX,XX +XXX,XX @@
47
#include "qapi/qmp/qerror.h"
48
#include "qapi/qmp/qjson.h"
49
#include "qapi/qmp/qstring.h"
50
+#include "qapi/qobject-input-visitor.h"
51
#include "qom/object_interfaces.h"
52
#include "qemu/help_option.h"
53
#include "qemu/module.h"
54
@@ -XXX,XX +XXX,XX @@ out:
55
return obj;
31
}
56
}
32
57
33
static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
34
- int *open_flags, Error **errp)
59
+{
35
+ int *open_flags, bool force_dup,
60
+ Visitor *v;
36
+ Error **errp)
61
+ Object *obj;
62
+ g_autofree char *type = NULL;
63
+ g_autofree char *id = NULL;
64
+
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
66
+ if (!type) {
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
68
+ return;
69
+ }
70
+ qdict_del(qdict, "qom-type");
71
+
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
73
+ if (!id) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
75
+ return;
76
+ }
77
+ qdict_del(qdict, "id");
78
+
79
+ v = qobject_input_visitor_new(QOBJECT(qdict));
80
+ obj = user_creatable_add_type(type, id, qdict, v, errp);
81
+ visit_free(v);
82
+ object_unref(obj);
83
+}
84
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
37
{
86
{
38
BDRVRawState *s = bs->opaque;
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
39
int fd = -1;
88
index XXXXXXX..XXXXXXX 100644
40
@@ -XXX,XX +XXX,XX @@ static int raw_reconfigure_getfd(BlockDriverState *bs, int flags,
89
--- a/qom/qom-qmp-cmds.c
41
assert((s->open_flags & O_ASYNC) == 0);
90
+++ b/qom/qom-qmp-cmds.c
42
#endif
91
@@ -XXX,XX +XXX,XX @@
43
92
#include "qapi/qapi-commands-qom.h"
44
+ if (!force_dup && *open_flags == s->open_flags) {
93
#include "qapi/qmp/qdict.h"
45
+ /* We're lucky, the existing fd is fine */
94
#include "qapi/qmp/qerror.h"
46
+ return s->fd;
95
-#include "qapi/qobject-input-visitor.h"
47
+ }
96
#include "qemu/cutils.h"
48
+
97
#include "qom/object_interfaces.h"
49
if ((*open_flags & ~fcntl_flags) == (s->open_flags & ~fcntl_flags)) {
98
#include "qom/qom-qobject.h"
50
/* dup the original fd */
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
51
fd = qemu_dup(s->fd);
100
{
52
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
101
QObject *props;
53
qemu_opts_to_qdict(opts, state->options);
102
QDict *pdict;
54
103
- Visitor *v;
55
rs->fd = raw_reconfigure_getfd(state->bs, state->flags, &rs->open_flags,
104
- Object *obj;
56
- &local_err);
105
- g_autofree char *type = NULL;
57
+ true, &local_err);
106
- g_autofree char *id = NULL;
58
if (local_err) {
59
error_propagate(errp, local_err);
60
ret = -1;
61
@@ -XXX,XX +XXX,XX @@ static int raw_reopen_prepare(BDRVReopenState *state,
62
ret = -EINVAL;
63
goto out_fd;
64
}
65
-
107
-
66
- /* Copy locks to the new fd */
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
67
- ret = raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
109
- if (!type) {
68
- s->locked_shared_perm, false, errp);
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
69
- if (ret < 0) {
111
- return;
70
- ret = -EINVAL;
112
- }
71
- goto out_fd;
113
- qdict_del(qdict, "qom-type");
72
- }
114
-
115
- id = g_strdup(qdict_get_try_str(qdict, "id"));
116
- if (!id) {
117
- error_setg(errp, QERR_MISSING_PARAMETER, "id");
118
- return;
119
- }
120
- qdict_del(qdict, "id");
121
122
props = qdict_get(qdict, "props");
123
if (props) {
124
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
125
qobject_unref(pdict);
73
}
126
}
74
127
75
s->reopen_state = state;
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
76
@@ -XXX,XX +XXX,XX @@ static QemuOptsList raw_create_opts = {
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
77
static int raw_check_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared,
130
- visit_free(v);
78
Error **errp)
131
- object_unref(obj);
79
{
132
+ user_creatable_add_dict(qdict, errp);
80
- return raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
81
+ BDRVRawState *s = bs->opaque;
82
+ BDRVRawReopenState *rs = NULL;
83
+ int open_flags;
84
+ int ret;
85
+
86
+ if (s->perm_change_fd) {
87
+ /*
88
+ * In the context of reopen, this function may be called several times
89
+ * (directly and recursively while change permissions of the parent).
90
+ * This is even true for children that don't inherit from the original
91
+ * reopen node, so s->reopen_state is not set.
92
+ *
93
+ * Ignore all but the first call.
94
+ */
95
+ return 0;
96
+ }
97
+
98
+ if (s->reopen_state) {
99
+ /* We already have a new file descriptor to set permissions for */
100
+ assert(s->reopen_state->perm == perm);
101
+ assert(s->reopen_state->shared_perm == shared);
102
+ rs = s->reopen_state->opaque;
103
+ s->perm_change_fd = rs->fd;
104
+ } else {
105
+ /* We may need a new fd if auto-read-only switches the mode */
106
+ ret = raw_reconfigure_getfd(bs, bs->open_flags, &open_flags,
107
+ false, errp);
108
+ if (ret < 0) {
109
+ return ret;
110
+ } else if (ret != s->fd) {
111
+ s->perm_change_fd = ret;
112
+ }
113
+ }
114
+
115
+ /* Prepare permissions on old fd to avoid conflicts between old and new,
116
+ * but keep everything locked that new will need. */
117
+ ret = raw_handle_perm_lock(bs, RAW_PL_PREPARE, perm, shared, errp);
118
+ if (ret < 0) {
119
+ goto fail;
120
+ }
121
+
122
+ /* Copy locks to the new fd */
123
+ if (s->perm_change_fd) {
124
+ ret = raw_apply_lock_bytes(NULL, s->perm_change_fd, perm, ~shared,
125
+ false, errp);
126
+ if (ret < 0) {
127
+ raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
128
+ goto fail;
129
+ }
130
+ }
131
+ return 0;
132
+
133
+fail:
134
+ if (s->perm_change_fd && !s->reopen_state) {
135
+ qemu_close(s->perm_change_fd);
136
+ }
137
+ s->perm_change_fd = 0;
138
+ return ret;
139
}
133
}
140
134
141
static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
135
void qmp_object_del(const char *id, Error **errp)
142
{
143
BDRVRawState *s = bs->opaque;
144
+
145
+ /* For reopen, we have already switched to the new fd (.bdrv_set_perm is
146
+ * called after .bdrv_reopen_commit) */
147
+ if (s->perm_change_fd && s->fd != s->perm_change_fd) {
148
+ qemu_close(s->fd);
149
+ s->fd = s->perm_change_fd;
150
+ }
151
+ s->perm_change_fd = 0;
152
+
153
raw_handle_perm_lock(bs, RAW_PL_COMMIT, perm, shared, NULL);
154
s->perm = perm;
155
s->shared_perm = shared;
156
@@ -XXX,XX +XXX,XX @@ static void raw_set_perm(BlockDriverState *bs, uint64_t perm, uint64_t shared)
157
158
static void raw_abort_perm_update(BlockDriverState *bs)
159
{
160
+ BDRVRawState *s = bs->opaque;
161
+
162
+ /* For reopen, .bdrv_reopen_abort is called afterwards and will close
163
+ * the file descriptor. */
164
+ if (s->perm_change_fd && !s->reopen_state) {
165
+ qemu_close(s->perm_change_fd);
166
+ }
167
+ s->perm_change_fd = 0;
168
+
169
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
170
}
171
172
--
136
--
173
2.20.1
137
2.25.3
174
138
175
139
diff view generated by jsdifflib
Deleted patch
1
From: Keith Busch <keith.busch@intel.com>
2
1
3
The implementation used blocks units rather than the expected bytes.
4
5
Fixes: c03e7ef12a9 ("nvme: Implement Write Zeroes")
6
Reported-by: Ming Lei <ming.lei@redhat.com>
7
Signed-off-by: Keith Busch <keith.busch@intel.com>
8
Reviewed-by: Christoph Hellwig <hch@lst.de>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
hw/block/nvme.c | 6 +++---
12
1 file changed, 3 insertions(+), 3 deletions(-)
13
14
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/hw/block/nvme.c
17
+++ b/hw/block/nvme.c
18
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
19
const uint8_t data_shift = ns->id_ns.lbaf[lba_index].ds;
20
uint64_t slba = le64_to_cpu(rw->slba);
21
uint32_t nlb = le16_to_cpu(rw->nlb) + 1;
22
- uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
23
- uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
24
+ uint64_t offset = slba << data_shift;
25
+ uint32_t count = nlb << data_shift;
26
27
if (unlikely(slba + nlb > ns->id_ns.nsze)) {
28
trace_nvme_err_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
29
@@ -XXX,XX +XXX,XX @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace *ns, NvmeCmd *cmd,
30
req->has_sg = false;
31
block_acct_start(blk_get_stats(n->conf.blk), &req->acct, 0,
32
BLOCK_ACCT_WRITE);
33
- req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, aio_slba, aio_nlb,
34
+ req->aiocb = blk_aio_pwrite_zeroes(n->conf.blk, offset, count,
35
BDRV_REQ_MAY_UNMAP, nvme_rw_cb, req);
36
return NVME_NO_COMPLETE;
37
}
38
--
39
2.20.1
40
41
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
block/commit.c | 16 ++++++++++++++++
7
1 file changed, 16 insertions(+)
8
9
diff --git a/block/commit.c b/block/commit.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/commit.c
12
+++ b/block/commit.c
13
@@ -XXX,XX +XXX,XX @@ typedef struct CommitBlockJob {
14
BlockDriverState *base_bs;
15
BlockdevOnError on_error;
16
bool base_read_only;
17
+ bool chain_frozen;
18
char *backing_file_str;
19
} CommitBlockJob;
20
21
@@ -XXX,XX +XXX,XX @@ static int commit_prepare(Job *job)
22
{
23
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
24
25
+ bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
26
+ s->chain_frozen = false;
27
+
28
/* Remove base node parent that still uses BLK_PERM_WRITE/RESIZE before
29
* the normal backing chain can be restored. */
30
blk_unref(s->base);
31
@@ -XXX,XX +XXX,XX @@ static void commit_abort(Job *job)
32
CommitBlockJob *s = container_of(job, CommitBlockJob, common.job);
33
BlockDriverState *top_bs = blk_bs(s->top);
34
35
+ if (s->chain_frozen) {
36
+ bdrv_unfreeze_backing_chain(s->commit_top_bs, s->base_bs);
37
+ }
38
+
39
/* Make sure commit_top_bs and top stay around until bdrv_replace_node() */
40
bdrv_ref(top_bs);
41
bdrv_ref(s->commit_top_bs);
42
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
43
}
44
}
45
46
+ if (bdrv_freeze_backing_chain(commit_top_bs, base, errp) < 0) {
47
+ goto fail;
48
+ }
49
+ s->chain_frozen = true;
50
+
51
ret = block_job_add_bdrv(&s->common, "base", base, 0, BLK_PERM_ALL, errp);
52
if (ret < 0) {
53
goto fail;
54
@@ -XXX,XX +XXX,XX @@ void commit_start(const char *job_id, BlockDriverState *bs,
55
return;
56
57
fail:
58
+ if (s->chain_frozen) {
59
+ bdrv_unfreeze_backing_chain(commit_top_bs, base);
60
+ }
61
if (s->base) {
62
blk_unref(s->base);
63
}
64
--
65
2.20.1
66
67
diff view generated by jsdifflib
Deleted patch
1
From: Alberto Garcia <berto@igalia.com>
2
1
3
Signed-off-by: Alberto Garcia <berto@igalia.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
---
6
block/mirror.c | 8 ++++++++
7
1 file changed, 8 insertions(+)
8
9
diff --git a/block/mirror.c b/block/mirror.c
10
index XXXXXXX..XXXXXXX 100644
11
--- a/block/mirror.c
12
+++ b/block/mirror.c
13
@@ -XXX,XX +XXX,XX @@ static int mirror_exit_common(Job *job)
14
}
15
s->prepared = true;
16
17
+ if (bdrv_chain_contains(src, target_bs)) {
18
+ bdrv_unfreeze_backing_chain(mirror_top_bs, target_bs);
19
+ }
20
+
21
bdrv_release_dirty_bitmap(src, s->dirty_bitmap);
22
23
/* Make sure that the source BDS doesn't go away during bdrv_replace_node,
24
@@ -XXX,XX +XXX,XX @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
25
goto fail;
26
}
27
}
28
+
29
+ if (bdrv_freeze_backing_chain(mirror_top_bs, target, errp) < 0) {
30
+ goto fail;
31
+ }
32
}
33
34
QTAILQ_INIT(&s->ops_in_flight);
35
--
36
2.20.1
37
38
diff view generated by jsdifflib
1
From: Alberto Garcia <berto@igalia.com>
1
After processing the option string with the keyval parser, we get a
2
QDict that contains only strings. This QDict must be fed to a keyval
3
visitor which converts the strings into the right data types.
2
4
3
This patch allows the user to change the backing file of an image that
5
qmp_object_add(), however, uses the normal QObject input visitor, which
4
is being reopened. Here's what it does:
6
expects a QDict where all properties already have the QType that matches
7
the data type required by the QOM object type.
5
8
6
- In bdrv_reopen_prepare(): check that the value of 'backing' points
9
Change the --object implementation in qemu-storage-daemon so that it
7
to an existing node or is null. If it points to an existing node it
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
8
also needs to make sure that replacing the backing file will not
11
directly instead and pass it a new keyval boolean that decides which
9
create a cycle in the node graph (i.e. you cannot reach the parent
12
visitor must be used.
10
from the new backing file).
11
13
12
- In bdrv_reopen_commit(): perform the actual node replacement by
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
13
calling bdrv_set_backing_hd().
14
15
There may be temporary implicit nodes between a BDS and its backing
16
file (e.g. a commit filter node). In these cases bdrv_reopen_prepare()
17
looks for the real (non-implicit) backing file and requires that the
18
'backing' option points to it. Replacing or detaching a backing file
19
is forbidden if there are implicit nodes in the middle.
20
21
Although x-blockdev-reopen is meant to be used like blockdev-add,
22
there's an important thing that must be taken into account: the only
23
way to set a new backing file is by using a reference to an existing
24
node (previously added with e.g. blockdev-add). If 'backing' contains
25
a dictionary with a new set of options ({"driver": "qcow2", "file": {
26
... }}) then it is interpreted that the _existing_ backing file must
27
be reopened with those options.
28
29
Signed-off-by: Alberto Garcia <berto@igalia.com>
30
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
31
---
16
---
32
include/block/block.h | 2 +
17
include/qom/object_interfaces.h | 6 +++++-
33
block.c | 166 ++++++++++++++++++++++++++++++++++++++++++
18
qemu-storage-daemon.c | 4 +---
34
2 files changed, 168 insertions(+)
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
35
22
36
diff --git a/include/block/block.h b/include/block/block.h
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
37
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
38
--- a/include/block/block.h
25
--- a/include/qom/object_interfaces.h
39
+++ b/include/block/block.h
26
+++ b/include/qom/object_interfaces.h
40
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVReopenState {
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
41
int flags;
28
/**
42
BlockdevDetectZeroesOptions detect_zeroes;
29
* user_creatable_add_dict:
43
bool backing_missing;
30
* @qdict: the object definition
44
+ bool replace_backing_bs; /* new_backing_bs is ignored if this is false */
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
45
+ BlockDriverState *new_backing_bs; /* If NULL then detach the current bs */
32
+ * assume that all @qdict values are strings); otherwise, use
46
uint64_t perm, shared_perm;
33
+ * the normal QObject visitor (i.e. assume all @qdict values
47
QDict *options;
34
+ * have the QType expected by the QOM object type)
48
QDict *explicit_options;
35
* @errp: if an error occurs, a pointer to an area to store the error
49
diff --git a/block.c b/block.c
36
*
37
* Create an instance of the user creatable object that is defined by
38
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
39
* ID from the key 'id'. The remaining entries in @qdict are used to
40
* initialize the object properties.
41
*/
42
-void user_creatable_add_dict(QDict *qdict, Error **errp);
43
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp);
44
45
/**
46
* user_creatable_add_opts:
47
diff --git a/qemu-storage-daemon.c b/qemu-storage-daemon.c
50
index XXXXXXX..XXXXXXX 100644
48
index XXXXXXX..XXXXXXX 100644
51
--- a/block.c
49
--- a/qemu-storage-daemon.c
52
+++ b/block.c
50
+++ b/qemu-storage-daemon.c
53
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_open(const char *filename, const char *reference,
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
54
NULL, errp);
52
QemuOpts *opts;
53
const char *type;
54
QDict *args;
55
- QObject *ret_data = NULL;
56
57
/* FIXME The keyval parser rejects 'help' arguments, so we must
58
* unconditionall try QemuOpts first. */
59
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
60
qemu_opts_del(opts);
61
62
args = keyval_parse(optarg, "qom-type", &error_fatal);
63
- qmp_object_add(args, &ret_data, &error_fatal);
64
+ user_creatable_add_dict(args, true, &error_fatal);
65
qobject_unref(args);
66
- qobject_unref(ret_data);
67
break;
68
}
69
default:
70
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/qom/object_interfaces.c
73
+++ b/qom/object_interfaces.c
74
@@ -XXX,XX +XXX,XX @@ out:
75
return obj;
55
}
76
}
56
77
57
+/*
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
58
+ * Returns true if @child can be reached recursively from @bs
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
59
+ */
80
{
60
+static bool bdrv_recurse_has_child(BlockDriverState *bs,
81
Visitor *v;
61
+ BlockDriverState *child)
82
Object *obj;
62
+{
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
63
+ BdrvChild *c;
84
}
64
+
85
qdict_del(qdict, "id");
65
+ if (bs == child) {
86
66
+ return true;
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
88
+ if (keyval) {
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
90
+ } else {
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
67
+ }
92
+ }
68
+
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
69
+ QLIST_FOREACH(c, &bs->children, next) {
94
visit_free(v);
70
+ if (bdrv_recurse_has_child(c->bs, child)) {
95
object_unref(obj);
71
+ return true;
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
72
+ }
97
index XXXXXXX..XXXXXXX 100644
73
+ }
98
--- a/qom/qom-qmp-cmds.c
74
+
99
+++ b/qom/qom-qmp-cmds.c
75
+ return false;
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
76
+}
101
qobject_unref(pdict);
77
+
78
/*
79
* Adds a BlockDriverState to a simple queue for an atomic, transactional
80
* reopen of multiple devices.
81
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_multiple(AioContext *ctx, BlockReopenQueue *bs_queue, Error **er
82
if (ret < 0) {
83
goto cleanup_perm;
84
}
85
+ /* Check if new_backing_bs would accept the new permissions */
86
+ if (state->replace_backing_bs && state->new_backing_bs) {
87
+ uint64_t nperm, nshared;
88
+ bdrv_child_perm(state->bs, state->new_backing_bs,
89
+ NULL, &child_backing, bs_queue,
90
+ state->perm, state->shared_perm,
91
+ &nperm, &nshared);
92
+ ret = bdrv_check_update_perm(state->new_backing_bs, NULL,
93
+ nperm, nshared, NULL, errp);
94
+ if (ret < 0) {
95
+ goto cleanup_perm;
96
+ }
97
+ }
98
bs_entry->perms_checked = true;
99
}
102
}
100
103
101
@@ -XXX,XX +XXX,XX @@ cleanup_perm:
104
- user_creatable_add_dict(qdict, errp);
102
bdrv_set_perm(state->bs, state->perm, state->shared_perm);
105
+ user_creatable_add_dict(qdict, false, errp);
103
} else {
104
bdrv_abort_perm_update(state->bs);
105
+ if (state->replace_backing_bs && state->new_backing_bs) {
106
+ bdrv_abort_perm_update(state->new_backing_bs);
107
+ }
108
}
109
}
110
cleanup:
111
@@ -XXX,XX +XXX,XX @@ cleanup:
112
qobject_unref(bs_entry->state.explicit_options);
113
qobject_unref(bs_entry->state.options);
114
}
115
+ if (bs_entry->state.new_backing_bs) {
116
+ bdrv_unref(bs_entry->state.new_backing_bs);
117
+ }
118
g_free(bs_entry);
119
}
120
g_free(bs_queue);
121
@@ -XXX,XX +XXX,XX @@ static void bdrv_reopen_perm(BlockReopenQueue *q, BlockDriverState *bs,
122
*shared = cumulative_shared_perms;
123
}
106
}
124
107
125
+/*
108
void qmp_object_del(const char *id, Error **errp)
126
+ * Take a BDRVReopenState and check if the value of 'backing' in the
127
+ * reopen_state->options QDict is valid or not.
128
+ *
129
+ * If 'backing' is missing from the QDict then return 0.
130
+ *
131
+ * If 'backing' contains the node name of the backing file of
132
+ * reopen_state->bs then return 0.
133
+ *
134
+ * If 'backing' contains a different node name (or is null) then check
135
+ * whether the current backing file can be replaced with the new one.
136
+ * If that's the case then reopen_state->replace_backing_bs is set to
137
+ * true and reopen_state->new_backing_bs contains a pointer to the new
138
+ * backing BlockDriverState (or NULL).
139
+ *
140
+ * Return 0 on success, otherwise return < 0 and set @errp.
141
+ */
142
+static int bdrv_reopen_parse_backing(BDRVReopenState *reopen_state,
143
+ Error **errp)
144
+{
145
+ BlockDriverState *bs = reopen_state->bs;
146
+ BlockDriverState *overlay_bs, *new_backing_bs;
147
+ QObject *value;
148
+ const char *str;
149
+
150
+ value = qdict_get(reopen_state->options, "backing");
151
+ if (value == NULL) {
152
+ return 0;
153
+ }
154
+
155
+ switch (qobject_type(value)) {
156
+ case QTYPE_QNULL:
157
+ new_backing_bs = NULL;
158
+ break;
159
+ case QTYPE_QSTRING:
160
+ str = qobject_get_try_str(value);
161
+ new_backing_bs = bdrv_lookup_bs(NULL, str, errp);
162
+ if (new_backing_bs == NULL) {
163
+ return -EINVAL;
164
+ } else if (bdrv_recurse_has_child(new_backing_bs, bs)) {
165
+ error_setg(errp, "Making '%s' a backing file of '%s' "
166
+ "would create a cycle", str, bs->node_name);
167
+ return -EINVAL;
168
+ }
169
+ break;
170
+ default:
171
+ /* 'backing' does not allow any other data type */
172
+ g_assert_not_reached();
173
+ }
174
+
175
+ /*
176
+ * TODO: before removing the x- prefix from x-blockdev-reopen we
177
+ * should move the new backing file into the right AioContext
178
+ * instead of returning an error.
179
+ */
180
+ if (new_backing_bs) {
181
+ if (bdrv_get_aio_context(new_backing_bs) != bdrv_get_aio_context(bs)) {
182
+ error_setg(errp, "Cannot use a new backing file "
183
+ "with a different AioContext");
184
+ return -EINVAL;
185
+ }
186
+ }
187
+
188
+ /*
189
+ * Find the "actual" backing file by skipping all links that point
190
+ * to an implicit node, if any (e.g. a commit filter node).
191
+ */
192
+ overlay_bs = bs;
193
+ while (backing_bs(overlay_bs) && backing_bs(overlay_bs)->implicit) {
194
+ overlay_bs = backing_bs(overlay_bs);
195
+ }
196
+
197
+ /* If we want to replace the backing file we need some extra checks */
198
+ if (new_backing_bs != backing_bs(overlay_bs)) {
199
+ /* Check for implicit nodes between bs and its backing file */
200
+ if (bs != overlay_bs) {
201
+ error_setg(errp, "Cannot change backing link if '%s' has "
202
+ "an implicit backing file", bs->node_name);
203
+ return -EPERM;
204
+ }
205
+ /* Check if the backing link that we want to replace is frozen */
206
+ if (bdrv_is_backing_chain_frozen(overlay_bs, backing_bs(overlay_bs),
207
+ errp)) {
208
+ return -EPERM;
209
+ }
210
+ reopen_state->replace_backing_bs = true;
211
+ if (new_backing_bs) {
212
+ bdrv_ref(new_backing_bs);
213
+ reopen_state->new_backing_bs = new_backing_bs;
214
+ }
215
+ }
216
+
217
+ return 0;
218
+}
219
+
220
/*
221
* Prepares a BlockDriverState for reopen. All changes are staged in the
222
* 'opaque' field of the BDRVReopenState, which is used and allocated by
223
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
224
goto error;
225
}
226
227
+ /*
228
+ * Allow changing the 'backing' option. The new value can be
229
+ * either a reference to an existing node (using its node name)
230
+ * or NULL to simply detach the current backing file.
231
+ */
232
+ ret = bdrv_reopen_parse_backing(reopen_state, errp);
233
+ if (ret < 0) {
234
+ goto error;
235
+ }
236
+ qdict_del(reopen_state->options, "backing");
237
+
238
/* Options that are not handled are only okay if they are unchanged
239
* compared to the old state. It is expected that some options are only
240
* used for the initial open, but not reopen (e.g. filename) */
241
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
242
bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
243
bs->detect_zeroes = reopen_state->detect_zeroes;
244
245
+ if (reopen_state->replace_backing_bs) {
246
+ qdict_del(bs->explicit_options, "backing");
247
+ qdict_del(bs->options, "backing");
248
+ }
249
+
250
/* Remove child references from bs->options and bs->explicit_options.
251
* Child options were already removed in bdrv_reopen_queue_child() */
252
QLIST_FOREACH(child, &bs->children, next) {
253
@@ -XXX,XX +XXX,XX @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
254
qdict_del(bs->options, child->name);
255
}
256
257
+ /*
258
+ * Change the backing file if a new one was specified. We do this
259
+ * after updating bs->options, so bdrv_refresh_filename() (called
260
+ * from bdrv_set_backing_hd()) has the new values.
261
+ */
262
+ if (reopen_state->replace_backing_bs) {
263
+ BlockDriverState *old_backing_bs = backing_bs(bs);
264
+ assert(!old_backing_bs || !old_backing_bs->implicit);
265
+ /* Abort the permission update on the backing bs we're detaching */
266
+ if (old_backing_bs) {
267
+ bdrv_abort_perm_update(old_backing_bs);
268
+ }
269
+ bdrv_set_backing_hd(bs, reopen_state->new_backing_bs, &error_abort);
270
+ }
271
+
272
bdrv_refresh_limits(bs, NULL);
273
274
new_can_write =
275
--
109
--
276
2.20.1
110
2.25.3
277
111
278
112
diff view generated by jsdifflib