1
The following changes since commit 98bfaac788be0ca63d7d010c8d4ba100ff1d8278:
1
The following changes since commit 16aaacb307ed607b9780c12702c44f0fe52edc7e:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2017-09-01-v3' into staging (2017-09-04 13:28:09 +0100)
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 83a8c775a8bf134eb18a719322939b74a818d750:
9
for you to fetch changes up to eaae29ef89d498d0eac553c77b554f310a47f809:
10
10
11
qcow2: move qcow2_store_persistent_dirty_bitmaps() before cache flushing (2017-09-06 14:40:18 +0200)
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
16
- Fix resize (extending) of short overlays
17
- nvme: introduce PMR support from NVMe 1.4 spec
18
- qemu-storage-daemon: Fix non-string --object properties
15
19
16
----------------------------------------------------------------
20
----------------------------------------------------------------
17
Daniel P. Berrange (1):
21
Alberto Garcia (1):
18
block: document semantics of bdrv_co_preadv|pwritev
22
qcow2: Add incompatibility note between backing files and raw external data files
19
23
20
Eric Blake (2):
24
Andrzej Jakowski (1):
21
qcow: Change signature of get_cluster_offset()
25
nvme: introduce PMR support from NVMe 1.4 spec
22
qcow: Check failure of bdrv_getlength() and bdrv_truncate()
23
26
24
Manos Pitsidianakis (10):
27
Kevin Wolf (12):
25
block: pass bdrv_* methods to bs->file by default in block filters
28
block: Add flags to BlockDriver.bdrv_co_truncate()
26
block: remove unused bdrv_media_changed
29
block: Add flags to bdrv(_co)_truncate()
27
block: remove bdrv_truncate callback in blkdebug
30
block-backend: Add flags to blk_truncate()
28
block: add default implementations for bdrv_co_get_block_status()
31
qcow2: Support BDRV_REQ_ZERO_WRITE for truncate
29
block: move ThrottleGroup membership to ThrottleGroupMember
32
raw-format: Support BDRV_REQ_ZERO_WRITE for truncate
30
block: add aio_context field in ThrottleGroupMember
33
file-posix: Support BDRV_REQ_ZERO_WRITE for truncate
31
block: tidy ThrottleGroupMember initializations
34
block: truncate: Don't make backing file data visible
32
block: convert ThrottleGroup to object with QOM
35
iotests: Filter testfiles out in filter_img_info()
33
block: add throttle block filter driver
36
iotests: Test committing to short backing file
34
qemu-iotests: add 184 for throttle filter driver
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
35
40
36
Pavel Butsykin (1):
41
Paolo Bonzini (1):
37
qcow2: move qcow2_store_persistent_dirty_bitmaps() before cache flushing
42
qemu-iotests: allow qcow2 external discarded clusters to contain stale data
38
43
39
qapi/block-core.json | 66 +++-
44
docs/interop/qcow2.txt | 3 +
40
include/block/block.h | 1 -
45
hw/block/nvme.h | 2 +
41
include/block/block_int.h | 56 ++-
46
include/block/block.h | 5 +-
42
include/block/throttle-groups.h | 52 ++-
47
include/block/block_int.h | 10 +-
43
include/qemu/throttle-options.h | 60 +++-
48
include/block/nvme.h | 172 ++++++++++++++++++++++++++
44
include/qemu/throttle.h | 3 +
49
include/qom/object_interfaces.h | 16 +++
45
include/sysemu/block-backend.h | 20 +-
50
include/sysemu/block-backend.h | 2 +-
46
block.c | 35 +-
51
block.c | 3 +-
47
block/blkdebug.c | 20 +-
52
block/block-backend.c | 4 +-
48
block/block-backend.c | 62 ++--
53
block/commit.c | 4 +-
49
block/commit.c | 12 +-
54
block/crypto.c | 7 +-
50
block/io.c | 26 ++
55
block/file-posix.c | 6 +-
51
block/mirror.c | 12 +-
56
block/file-win32.c | 2 +-
52
block/qapi.c | 8 +-
57
block/gluster.c | 1 +
53
block/qcow.c | 153 ++++----
58
block/io.c | 43 ++++++-
54
block/qcow2.c | 16 +-
59
block/iscsi.c | 2 +-
55
block/raw-format.c | 6 -
60
block/mirror.c | 2 +-
56
block/throttle-groups.c | 750 ++++++++++++++++++++++++++++++----------
61
block/nfs.c | 3 +-
57
block/throttle.c | 237 +++++++++++++
62
block/parallels.c | 6 +-
58
blockdev.c | 4 +-
63
block/qcow.c | 4 +-
59
tests/test-throttle.c | 111 +++---
64
block/qcow2-cluster.c | 2 +-
60
util/throttle.c | 151 ++++++++
65
block/qcow2-refcount.c | 2 +-
61
block/Makefile.objs | 1 +
66
block/qcow2.c | 73 +++++++++--
62
tests/qemu-iotests/184 | 205 +++++++++++
67
block/qed.c | 3 +-
63
tests/qemu-iotests/184.out | 302 ++++++++++++++++
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 ++++++++++++++++++++++++++++++++++++++++
64
tests/qemu-iotests/group | 1 +
92
tests/qemu-iotests/group | 1 +
65
26 files changed, 1917 insertions(+), 453 deletions(-)
93
49 files changed, 951 insertions(+), 96 deletions(-)
66
create mode 100644 block/throttle.c
94
create mode 100755 tests/qemu-iotests/274
67
create mode 100755 tests/qemu-iotests/184
95
create mode 100644 tests/qemu-iotests/274.out
68
create mode 100644 tests/qemu-iotests/184.out
69
96
97
diff view generated by jsdifflib
New patch
1
From: Alberto Garcia <berto@igalia.com>
1
2
3
Backing files and raw external data files are mutually exclusive.
4
The documentation of the raw external data bit (in autoclear_features)
5
already indicates that, but we should also mention it on the other
6
side.
7
8
Suggested-by: Eric Blake <eblake@redhat.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>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
docs/interop/qcow2.txt | 3 +++
15
1 file changed, 3 insertions(+)
16
17
diff --git a/docs/interop/qcow2.txt b/docs/interop/qcow2.txt
18
index XXXXXXX..XXXXXXX 100644
19
--- a/docs/interop/qcow2.txt
20
+++ b/docs/interop/qcow2.txt
21
@@ -XXX,XX +XXX,XX @@ The first cluster of a qcow2 image contains the file header:
22
is stored (NB: The string is not null terminated). 0 if the
23
image doesn't have a backing file.
24
25
+ Note: backing files are incompatible with raw external data
26
+ files (auto-clear feature bit 1).
27
+
28
16 - 19: backing_file_size
29
Length of the backing file name in bytes. Must not be
30
longer than 1023 bytes. Undefined if the image doesn't have
31
--
32
2.25.3
33
34
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Paolo Bonzini <pbonzini@redhat.com>
2
2
3
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
3
Test 244 checks the expected behavior of qcow2 external data files
4
which is called whenever a ThrottleGroupMember is initialized. There's
4
with respect to zero and discarded clusters. Filesystems however
5
no need for them to be separate.
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.
6
9
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
10
This fixes docker tests on RHEL8.
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
9
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
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>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
17
---
12
block/block-backend.c | 3 ---
18
tests/qemu-iotests/244 | 10 ++++++++--
13
block/throttle-groups.c | 3 +++
19
tests/qemu-iotests/244.out | 9 ++++++---
14
2 files changed, 3 insertions(+), 3 deletions(-)
20
2 files changed, 14 insertions(+), 5 deletions(-)
15
21
16
diff --git a/block/block-backend.c b/block/block-backend.c
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
17
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
18
--- a/block/block-backend.c
53
--- a/tests/qemu-iotests/244.out
19
+++ b/block/block-backend.c
54
+++ b/tests/qemu-iotests/244.out
20
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
55
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 0
21
blk->shared_perm = shared_perm;
56
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
22
blk_set_enable_write_cache(blk, true);
57
read 1048576/1048576 bytes at offset 1048576
23
58
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
24
- qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock);
59
-read 2097152/2097152 bytes at offset 2097152
25
- qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]);
60
-2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
26
- qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]);
61
read 1048576/1048576 bytes at offset 4194304
27
block_acct_init(&blk->stats);
62
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
28
63
read 1048576/1048576 bytes at offset 5242880
29
notifier_list_init(&blk->remove_bs_notifiers);
64
@@ -XXX,XX +XXX,XX @@ read 1048576/1048576 bytes at offset 1048576
30
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
65
read 4194304/4194304 bytes at offset 2097152
31
index XXXXXXX..XXXXXXX 100644
66
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
32
--- a/block/throttle-groups.c
67
33
+++ b/block/throttle-groups.c
68
-Images are identical.
34
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
69
+read 1048576/1048576 bytes at offset 0
35
read_timer_cb,
70
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
36
write_timer_cb,
71
+read 1048576/1048576 bytes at offset 1048576
37
tgm);
72
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
38
+ qemu_co_mutex_init(&tgm->throttled_reqs_lock);
73
+read 3145728/3145728 bytes at offset 3145728
39
+ qemu_co_queue_init(&tgm->throttled_reqs[0]);
74
+3 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
40
+ qemu_co_queue_init(&tgm->throttled_reqs[1]);
75
qcow2 file size after I/O: 327680
41
76
42
qemu_mutex_unlock(&tg->lock);
77
=== bdrv_co_block_status test for file and offset=0 ===
43
}
44
--
78
--
45
2.13.5
79
2.25.3
46
80
47
81
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
This adds a new BdrvRequestFlags parameter to the .bdrv_co_truncate()
2
2
driver callbacks, and a supported_truncate_flags field in
3
The following functions fail if bs->drv is a filter and does not
3
BlockDriverState that allows drivers to advertise support for request
4
implement them:
4
flags in the context of truncate.
5
5
6
bdrv_probe_blocksizes
6
For now, we always pass 0 and no drivers declare support for any flag.
7
bdrv_probe_geometry
7
8
bdrv_truncate
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
bdrv_has_zero_init
9
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
10
bdrv_get_info
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
11
Reviewed-by: Max Reitz <mreitz@redhat.com>
12
Instead, the call should be passed to bs->file if it exists, to allow
12
Message-Id: <20200424125448.63318-2-kwolf@redhat.com>
13
filter drivers to support those methods without implementing them. This
14
commit makes `drv->is_filter = true` imply that these callbacks will be
15
forwarded to bs->file by default, so disabling support for these
16
functions must be done explicitly.
17
18
Reviewed-by: Eric Blake <eblake@redhat.com>
19
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
20
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
14
---
23
include/block/block_int.h | 6 +++++-
15
include/block/block_int.h | 10 +++++++++-
24
block.c | 21 +++++++++++++++++++--
16
block/crypto.c | 3 ++-
25
2 files changed, 24 insertions(+), 3 deletions(-)
17
block/file-posix.c | 2 +-
18
block/file-win32.c | 2 +-
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(-)
26
31
27
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
28
index XXXXXXX..XXXXXXX 100644
33
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block_int.h
34
--- a/include/block/block_int.h
30
+++ b/include/block/block_int.h
35
+++ b/include/block/block_int.h
31
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
36
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
32
const char *format_name;
37
*/
33
int instance_size;
38
int coroutine_fn (*bdrv_co_truncate)(BlockDriverState *bs, int64_t offset,
34
39
bool exact, PreallocMode prealloc,
35
- /* set to true if the BlockDriver is a block filter */
40
- Error **errp);
36
+ /* set to true if the BlockDriver is a block filter. Block filters pass
41
+ BdrvRequestFlags flags, Error **errp);
37
+ * certain callbacks that refer to data (see block.c) to their bs->file if
42
38
+ * the driver doesn't implement them. Drivers that do not wish to forward
43
int64_t (*bdrv_getlength)(BlockDriverState *bs);
39
+ * must implement them and return -ENOTSUP.
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;
49
+ /*
50
+ * Flags honoured during truncate (so far: BDRV_REQ_ZERO_WRITE).
51
+ *
52
+ * If BDRV_REQ_ZERO_WRITE is given, the truncate operation must make sure
53
+ * that any added space reads as all zeros. If this can't be guaranteed,
54
+ * the operation must fail.
40
+ */
55
+ */
41
bool is_filter;
56
+ unsigned int supported_truncate_flags;
42
/* for snapshots block filter like Quorum can implement the
57
43
* following recursive callback.
58
/* the following member gives a name to every node on the bs graph. */
44
diff --git a/block.c b/block.c
59
char node_name[32];
45
index XXXXXXX..XXXXXXX 100644
60
diff --git a/block/crypto.c b/block/crypto.c
46
--- a/block.c
61
index XXXXXXX..XXXXXXX 100644
47
+++ b/block.c
62
--- a/block/crypto.c
48
@@ -XXX,XX +XXX,XX @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
63
+++ b/block/crypto.c
49
64
@@ -XXX,XX +XXX,XX @@ static int block_crypto_co_create_generic(BlockDriverState *bs,
50
if (drv && drv->bdrv_probe_blocksizes) {
65
51
return drv->bdrv_probe_blocksizes(bs, bsz);
66
static int coroutine_fn
52
+ } else if (drv && drv->is_filter && bs->file) {
67
block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
53
+ return bdrv_probe_blocksizes(bs->file->bs, bsz);
68
- PreallocMode prealloc, Error **errp)
69
+ PreallocMode prealloc, BdrvRequestFlags flags,
70
+ Error **errp)
71
{
72
BlockCrypto *crypto = bs->opaque;
73
uint64_t payload_offset =
74
diff --git a/block/file-posix.c b/block/file-posix.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/file-posix.c
77
+++ b/block/file-posix.c
78
@@ -XXX,XX +XXX,XX @@ raw_regular_truncate(BlockDriverState *bs, int fd, int64_t offset,
79
80
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
81
bool exact, PreallocMode prealloc,
82
- Error **errp)
83
+ BdrvRequestFlags flags, Error **errp)
84
{
85
BDRVRawState *s = bs->opaque;
86
struct stat st;
87
diff --git a/block/file-win32.c b/block/file-win32.c
88
index XXXXXXX..XXXXXXX 100644
89
--- a/block/file-win32.c
90
+++ b/block/file-win32.c
91
@@ -XXX,XX +XXX,XX @@ static void raw_close(BlockDriverState *bs)
92
93
static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
94
bool exact, PreallocMode prealloc,
95
- Error **errp)
96
+ BdrvRequestFlags flags, Error **errp)
97
{
98
BDRVRawState *s = bs->opaque;
99
LONG low, high;
100
diff --git a/block/gluster.c b/block/gluster.c
101
index XXXXXXX..XXXXXXX 100644
102
--- a/block/gluster.c
103
+++ b/block/gluster.c
104
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qemu_gluster_co_truncate(BlockDriverState *bs,
105
int64_t offset,
106
bool exact,
107
PreallocMode prealloc,
108
+ BdrvRequestFlags flags,
109
Error **errp)
110
{
111
BDRVGlusterState *s = bs->opaque;
112
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
115
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
117
BlockDriverState *bs = child->bs;
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,
54
}
125
}
55
126
56
return -ENOTSUP;
127
if (drv->bdrv_co_truncate) {
57
@@ -XXX,XX +XXX,XX @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
128
- ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, errp);
58
129
+ if (flags & ~bs->supported_truncate_flags) {
59
if (drv && drv->bdrv_probe_geometry) {
130
+ error_setg(errp, "Block driver does not support requested flags");
60
return drv->bdrv_probe_geometry(bs, geo);
131
+ ret = -ENOTSUP;
61
+ } else if (drv && drv->is_filter && bs->file) {
132
+ goto out;
62
+ return bdrv_probe_geometry(bs->file->bs, geo);
63
}
64
65
return -ENOTSUP;
66
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
67
68
assert(child->perm & BLK_PERM_RESIZE);
69
70
+ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
71
if (!drv) {
72
error_setg(errp, "No medium inserted");
73
return -ENOMEDIUM;
74
}
75
if (!drv->bdrv_truncate) {
76
+ if (bs->file && drv->is_filter) {
77
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
78
+ }
133
+ }
79
error_setg(errp, "Image format driver does not support resize");
134
+ ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
80
return -ENOTSUP;
135
} else if (bs->file && drv->is_filter) {
81
}
136
ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
82
@@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init(BlockDriverState *bs)
137
} else {
83
if (bs->drv->bdrv_has_zero_init) {
138
diff --git a/block/iscsi.c b/block/iscsi.c
84
return bs->drv->bdrv_has_zero_init(bs);
139
index XXXXXXX..XXXXXXX 100644
85
}
140
--- a/block/iscsi.c
86
+ if (bs->file && bs->drv->is_filter) {
141
+++ b/block/iscsi.c
87
+ return bdrv_has_zero_init(bs->file->bs);
142
@@ -XXX,XX +XXX,XX @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
88
+ }
143
89
144
static int coroutine_fn iscsi_co_truncate(BlockDriverState *bs, int64_t offset,
90
/* safe default */
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;
165
diff --git a/block/qcow2.c b/block/qcow2.c
166
index XXXXXXX..XXXXXXX 100644
167
--- a/block/qcow2.c
168
+++ b/block/qcow2.c
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
@@ -XXX,XX +XXX,XX @@ void bdrv_get_backing_filename(BlockDriverState *bs,
93
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
94
{
95
BlockDriver *drv = bs->drv;
96
- if (!drv)
97
+ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
98
+ if (!drv) {
99
return -ENOMEDIUM;
100
- if (!drv->bdrv_get_info)
101
+ }
102
+ if (!drv->bdrv_get_info) {
103
+ if (bs->file && drv->is_filter) {
104
+ return bdrv_get_info(bs->file->bs, bdi);
105
+ }
106
return -ENOTSUP;
107
+ }
108
memset(bdi, 0, sizeof(*bdi));
109
return drv->bdrv_get_info(bs, bdi);
110
}
263
}
111
--
264
--
112
2.13.5
265
2.25.3
113
266
114
267
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.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
Omitting the check for whether bdrv_getlength() and bdrv_truncate()
5
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
failed meant that it was theoretically possible to return an
6
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
incorrect offset to the caller. More likely, conditions for either
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
of these functions to fail would also cause one of our other calls
8
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
(such as bdrv_pread() or bdrv_pwrite_sync()) to also fail, but
9
Message-Id: <20200424125448.63318-3-kwolf@redhat.com>
8
auditing that we are safe is difficult compared to just patching
9
things to always forward on the error rather than ignoring it.
10
11
Use osdep.h macros instead of open-coded rounding while in the
12
area.
13
14
Reported-by: Markus Armbruster <armbru@redhat.com>
15
Signed-off-by: Eric Blake <eblake@redhat.com>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
11
---
18
block/qcow.c | 30 ++++++++++++++++++++++--------
12
include/block/block.h | 5 +++--
19
1 file changed, 22 insertions(+), 8 deletions(-)
13
block/block-backend.c | 2 +-
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(-)
20
26
27
diff --git a/include/block/block.h b/include/block/block.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block.h
30
+++ b/include/block/block.h
31
@@ -XXX,XX +XXX,XX @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
32
void bdrv_refresh_filename(BlockDriverState *bs);
33
34
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
35
- PreallocMode prealloc, Error **errp);
36
+ PreallocMode prealloc, BdrvRequestFlags flags,
37
+ Error **errp);
38
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
39
- PreallocMode prealloc, Error **errp);
40
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
41
42
int64_t bdrv_nb_sectors(BlockDriverState *bs);
43
int64_t bdrv_getlength(BlockDriverState *bs);
44
diff --git a/block/block-backend.c b/block/block-backend.c
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/block-backend.c
47
+++ b/block/block-backend.c
48
@@ -XXX,XX +XXX,XX @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
49
return -ENOMEDIUM;
50
}
51
52
- return bdrv_truncate(blk->root, offset, exact, prealloc, errp);
53
+ return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
54
}
55
56
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
57
diff --git a/block/crypto.c b/block/crypto.c
58
index XXXXXXX..XXXXXXX 100644
59
--- a/block/crypto.c
60
+++ b/block/crypto.c
61
@@ -XXX,XX +XXX,XX @@ block_crypto_co_truncate(BlockDriverState *bs, int64_t offset, bool exact,
62
63
offset += payload_offset;
64
65
- return bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
66
+ return bdrv_co_truncate(bs->file, offset, exact, prealloc, 0, errp);
67
}
68
69
static void block_crypto_close(BlockDriverState *bs)
70
diff --git a/block/io.c b/block/io.c
71
index XXXXXXX..XXXXXXX 100644
72
--- a/block/io.c
73
+++ b/block/io.c
74
@@ -XXX,XX +XXX,XX @@ static void bdrv_parent_cb_resize(BlockDriverState *bs)
75
* 'offset' bytes in length.
76
*/
77
int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
78
- PreallocMode prealloc, Error **errp)
79
+ PreallocMode prealloc, BdrvRequestFlags flags,
80
+ Error **errp)
81
{
82
BlockDriverState *bs = child->bs;
83
BlockDriver *drv = bs->drv;
84
BdrvTrackedRequest req;
85
- BdrvRequestFlags flags = 0;
86
int64_t old_size, new_bytes;
87
int ret;
88
89
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
90
}
91
ret = drv->bdrv_co_truncate(bs, offset, exact, prealloc, flags, errp);
92
} else if (bs->file && drv->is_filter) {
93
- ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, errp);
94
+ ret = bdrv_co_truncate(bs->file, offset, exact, prealloc, flags, errp);
95
} else {
96
error_setg(errp, "Image format driver does not support resize");
97
ret = -ENOTSUP;
98
@@ -XXX,XX +XXX,XX @@ typedef struct TruncateCo {
99
int64_t offset;
100
bool exact;
101
PreallocMode prealloc;
102
+ BdrvRequestFlags flags;
103
Error **errp;
104
int ret;
105
} TruncateCo;
106
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_truncate_co_entry(void *opaque)
107
{
108
TruncateCo *tco = opaque;
109
tco->ret = bdrv_co_truncate(tco->child, tco->offset, tco->exact,
110
- tco->prealloc, tco->errp);
111
+ tco->prealloc, tco->flags, tco->errp);
112
aio_wait_kick();
113
}
114
115
int bdrv_truncate(BdrvChild *child, int64_t offset, bool exact,
116
- PreallocMode prealloc, Error **errp)
117
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
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);
21
diff --git a/block/qcow.c b/block/qcow.c
160
diff --git a/block/qcow.c b/block/qcow.c
22
index XXXXXXX..XXXXXXX 100644
161
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow.c
162
--- a/block/qcow.c
24
+++ b/block/qcow.c
163
+++ b/block/qcow.c
25
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
164
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
26
{
165
return -E2BIG;
27
BDRVQcowState *s = bs->opaque;
166
}
28
int min_index, i, j, l1_index, l2_index, ret;
167
ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
29
- uint64_t l2_offset, *l2_table, cluster_offset, tmp;
168
- false, PREALLOC_MODE_OFF, NULL);
30
+ int64_t l2_offset;
169
+ false, PREALLOC_MODE_OFF, 0, NULL);
31
+ uint64_t *l2_table, cluster_offset, tmp;
170
if (ret < 0) {
32
uint32_t min_count;
171
return ret;
33
int new_l2_table;
172
}
34
173
@@ -XXX,XX +XXX,XX @@ static int qcow_make_empty(BlockDriverState *bs)
35
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
174
l1_length) < 0)
36
return 0;
175
return -1;
37
/* allocate a new l2 entry */
176
ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, false,
38
l2_offset = bdrv_getlength(bs->file->bs);
177
- PREALLOC_MODE_OFF, NULL);
39
+ if (l2_offset < 0) {
178
+ PREALLOC_MODE_OFF, 0, NULL);
40
+ return l2_offset;
179
if (ret < 0)
41
+ }
180
return ret;
42
/* round to cluster size */
181
43
- l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
182
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
44
+ l2_offset = QEMU_ALIGN_UP(l2_offset, s->cluster_size);
183
index XXXXXXX..XXXXXXX 100644
45
/* update the L1 entry */
184
--- a/block/qcow2-refcount.c
46
s->l1_table[l1_index] = l2_offset;
185
+++ b/block/qcow2-refcount.c
47
tmp = cpu_to_be64(l2_offset);
186
@@ -XXX,XX +XXX,XX @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
48
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
187
}
49
return -EIO;
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;
50
}
226
}
51
cluster_offset = bdrv_getlength(bs->file->bs);
227
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
52
- cluster_offset = (cluster_offset + s->cluster_size - 1) &
228
new_file_size = allocation_start +
53
- ~(s->cluster_size - 1);
229
nb_new_data_clusters * s->cluster_size;
54
+ if ((int64_t) cluster_offset < 0) {
230
/* Image file grows, so @exact does not matter */
55
+ return cluster_offset;
231
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, errp);
56
+ }
232
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
57
+ cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
233
+ errp);
58
/* write the cluster content */
234
if (ret < 0) {
59
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
235
error_prepend(errp, "Failed to resize underlying file: ");
60
s->cluster_size);
236
qcow2_free_clusters(bs, allocation_start,
61
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
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,
62
}
300
}
63
} else {
301
length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE);
64
cluster_offset = bdrv_getlength(bs->file->bs);
302
ret = bdrv_truncate(s->extents[i].file, length, false,
65
+ if ((int64_t) cluster_offset < 0) {
303
- PREALLOC_MODE_OFF, NULL);
66
+ return cluster_offset;
304
+ PREALLOC_MODE_OFF, 0, NULL);
67
+ }
305
if (ret < 0) {
68
if (allocate == 1) {
306
return ret;
69
/* round to cluster size */
307
}
70
- cluster_offset = (cluster_offset + s->cluster_size - 1) &
308
diff --git a/tests/test-block-iothread.c b/tests/test-block-iothread.c
71
- ~(s->cluster_size - 1);
309
index XXXXXXX..XXXXXXX 100644
72
- bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
310
--- a/tests/test-block-iothread.c
73
- PREALLOC_MODE_OFF, NULL);
311
+++ b/tests/test-block-iothread.c
74
+ cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
312
@@ -XXX,XX +XXX,XX @@ static void test_sync_op_truncate(BdrvChild *c)
75
+ if (cluster_offset + s->cluster_size > INT64_MAX) {
313
int ret;
76
+ return -E2BIG;
314
77
+ }
315
/* Normal success path */
78
+ ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
316
- ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, NULL);
79
+ PREALLOC_MODE_OFF, NULL);
317
+ ret = bdrv_truncate(c, 65536, false, PREALLOC_MODE_OFF, 0, NULL);
80
+ if (ret < 0) {
318
g_assert_cmpint(ret, ==, 0);
81
+ return ret;
319
82
+ }
320
/* Early error: Negative offset */
83
/* if encrypted, we must initialize the cluster
321
- ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, NULL);
84
content which won't be written */
322
+ ret = bdrv_truncate(c, -2, false, PREALLOC_MODE_OFF, 0, NULL);
85
if (bs->encrypted &&
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;
86
--
334
--
87
2.13.5
335
2.25.3
88
336
89
337
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
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
This commit eliminates the 1:1 relationship between BlockBackend and
3
4
throttle group state. Users will be able to create multiple throttle
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
5
nodes, each with its own throttle group state, in the future. The
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
6
throttle group state cannot be per-BlockBackend anymore, it must be
7
per-throttle node. This is done by gathering ThrottleGroup membership
8
details from BlockBackendPublic into ThrottleGroupMember and refactoring
9
existing code to use the structure.
10
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Reviewed-by: Alberto Garcia <berto@igalia.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Max Reitz <mreitz@redhat.com>
13
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
8
Message-Id: <20200424125448.63318-4-kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
10
---
16
include/block/throttle-groups.h | 39 +++++-
11
include/sysemu/block-backend.h | 2 +-
17
include/sysemu/block-backend.h | 20 +--
12
block.c | 3 ++-
18
block/block-backend.c | 66 +++++----
13
block/block-backend.c | 4 ++--
19
block/qapi.c | 8 +-
14
block/commit.c | 4 ++--
20
block/throttle-groups.c | 288 ++++++++++++++++++++--------------------
15
block/crypto.c | 2 +-
21
blockdev.c | 4 +-
16
block/mirror.c | 2 +-
22
tests/test-throttle.c | 53 ++++----
17
block/qcow2.c | 4 ++--
23
7 files changed, 252 insertions(+), 226 deletions(-)
18
block/qed.c | 2 +-
24
19
block/vdi.c | 2 +-
25
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
20
block/vhdx.c | 4 ++--
26
index XXXXXXX..XXXXXXX 100644
21
block/vmdk.c | 6 +++---
27
--- a/include/block/throttle-groups.h
22
block/vpc.c | 2 +-
28
+++ b/include/block/throttle-groups.h
23
blockdev.c | 2 +-
29
@@ -XXX,XX +XXX,XX @@
24
qemu-img.c | 2 +-
30
#include "qemu/throttle.h"
25
qemu-io-cmds.c | 2 +-
31
#include "block/block_int.h"
26
15 files changed, 22 insertions(+), 21 deletions(-)
32
27
33
-const char *throttle_group_get_name(BlockBackend *blk);
34
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
35
+ * and holds related data.
36
+ */
37
+
38
+typedef struct ThrottleGroupMember {
39
+ /* throttled_reqs_lock protects the CoQueues for throttled requests. */
40
+ CoMutex throttled_reqs_lock;
41
+ CoQueue throttled_reqs[2];
42
+
43
+ /* Nonzero if the I/O limits are currently being ignored; generally
44
+ * it is zero. Accessed with atomic operations.
45
+ */
46
+ unsigned int io_limits_disabled;
47
+
48
+ /* The following fields are protected by the ThrottleGroup lock.
49
+ * See the ThrottleGroup documentation for details.
50
+ * throttle_state tells us if I/O limits are configured. */
51
+ ThrottleState *throttle_state;
52
+ ThrottleTimers throttle_timers;
53
+ unsigned pending_reqs[2];
54
+ QLIST_ENTRY(ThrottleGroupMember) round_robin;
55
+
56
+} ThrottleGroupMember;
57
+
58
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
59
60
ThrottleState *throttle_group_incref(const char *name);
61
void throttle_group_unref(ThrottleState *ts);
62
63
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
64
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
65
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
66
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
67
68
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
69
-void throttle_group_unregister_blk(BlockBackend *blk);
70
-void throttle_group_restart_blk(BlockBackend *blk);
71
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
72
+ const char *groupname);
73
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
74
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
75
76
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
77
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
78
unsigned int bytes,
79
bool is_write);
80
81
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
28
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
82
index XXXXXXX..XXXXXXX 100644
29
index XXXXXXX..XXXXXXX 100644
83
--- a/include/sysemu/block-backend.h
30
--- a/include/sysemu/block-backend.h
84
+++ b/include/sysemu/block-backend.h
31
+++ b/include/sysemu/block-backend.h
85
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
86
33
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
87
/* This struct is embedded in (the private) BlockBackend struct and contains
34
int bytes);
88
* fields that must be public. This is in particular for QLIST_ENTRY() and
35
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
89
- * friends so that BlockBackends can be kept in lists outside block-backend.c */
36
- PreallocMode prealloc, Error **errp);
90
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
37
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp);
91
+ * */
38
int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes);
92
typedef struct BlockBackendPublic {
39
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
93
- /* throttled_reqs_lock protects the CoQueues for throttled requests. */
40
int64_t pos, int size);
94
- CoMutex throttled_reqs_lock;
41
diff --git a/block.c b/block.c
95
- CoQueue throttled_reqs[2];
42
index XXXXXXX..XXXXXXX 100644
96
-
43
--- a/block.c
97
- /* Nonzero if the I/O limits are currently being ignored; generally
44
+++ b/block.c
98
- * it is zero. Accessed with atomic operations.
45
@@ -XXX,XX +XXX,XX @@ static int64_t create_file_fallback_truncate(BlockBackend *blk,
99
- */
46
int64_t size;
100
- unsigned int io_limits_disabled;
47
int ret;
101
-
48
102
- /* The following fields are protected by the ThrottleGroup lock.
49
- ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, &local_err);
103
- * See the ThrottleGroup documentation for details.
50
+ ret = blk_truncate(blk, minimum_size, false, PREALLOC_MODE_OFF, 0,
104
- * throttle_state tells us if I/O limits are configured. */
51
+ &local_err);
105
- ThrottleState *throttle_state;
52
if (ret < 0 && ret != -ENOTSUP) {
106
- ThrottleTimers throttle_timers;
53
error_propagate(errp, local_err);
107
- unsigned pending_reqs[2];
54
return ret;
108
- QLIST_ENTRY(BlockBackendPublic) round_robin;
109
+ ThrottleGroupMember throttle_group_member;
110
} BlockBackendPublic;
111
112
BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm);
113
diff --git a/block/block-backend.c b/block/block-backend.c
55
diff --git a/block/block-backend.c b/block/block-backend.c
114
index XXXXXXX..XXXXXXX 100644
56
index XXXXXXX..XXXXXXX 100644
115
--- a/block/block-backend.c
57
--- a/block/block-backend.c
116
+++ b/block/block-backend.c
58
+++ b/block/block-backend.c
117
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
59
@@ -XXX,XX +XXX,XX @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
118
blk->shared_perm = shared_perm;
60
}
119
blk_set_enable_write_cache(blk, true);
61
120
62
int blk_truncate(BlockBackend *blk, int64_t offset, bool exact,
121
- qemu_co_mutex_init(&blk->public.throttled_reqs_lock);
63
- PreallocMode prealloc, Error **errp)
122
- qemu_co_queue_init(&blk->public.throttled_reqs[0]);
64
+ PreallocMode prealloc, BdrvRequestFlags flags, Error **errp)
123
- qemu_co_queue_init(&blk->public.throttled_reqs[1]);
124
+ qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock);
125
+ qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]);
126
+ qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]);
127
block_acct_init(&blk->stats);
128
129
notifier_list_init(&blk->remove_bs_notifiers);
130
@@ -XXX,XX +XXX,XX @@ static void blk_delete(BlockBackend *blk)
131
assert(!blk->refcnt);
132
assert(!blk->name);
133
assert(!blk->dev);
134
- if (blk->public.throttle_state) {
135
+ if (blk->public.throttle_group_member.throttle_state) {
136
blk_io_limits_disable(blk);
137
}
138
if (blk->root) {
139
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
140
*/
141
void blk_remove_bs(BlockBackend *blk)
142
{
65
{
143
+ ThrottleTimers *tt;
66
if (!blk_is_available(blk)) {
144
+
67
error_setg(errp, "No medium inserted");
145
notifier_list_notify(&blk->remove_bs_notifiers, blk);
68
return -ENOMEDIUM;
146
- if (blk->public.throttle_state) {
69
}
147
- throttle_timers_detach_aio_context(&blk->public.throttle_timers);
70
148
+ if (blk->public.throttle_group_member.throttle_state) {
71
- return bdrv_truncate(blk->root, offset, exact, prealloc, 0, errp);
149
+ tt = &blk->public.throttle_group_member.throttle_timers;
72
+ return bdrv_truncate(blk->root, offset, exact, prealloc, flags, errp);
150
+ throttle_timers_detach_aio_context(tt);
151
}
152
153
blk_update_root_state(blk);
154
@@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
155
bdrv_ref(bs);
156
157
notifier_list_notify(&blk->insert_bs_notifiers, blk);
158
- if (blk->public.throttle_state) {
159
+ if (blk->public.throttle_group_member.throttle_state) {
160
throttle_timers_attach_aio_context(
161
- &blk->public.throttle_timers, bdrv_get_aio_context(bs));
162
+ &blk->public.throttle_group_member.throttle_timers,
163
+ bdrv_get_aio_context(bs));
164
}
165
166
return 0;
167
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
168
bdrv_inc_in_flight(bs);
169
170
/* throttling disk I/O */
171
- if (blk->public.throttle_state) {
172
- throttle_group_co_io_limits_intercept(blk, bytes, false);
173
+ if (blk->public.throttle_group_member.throttle_state) {
174
+ throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
175
+ bytes, false);
176
}
177
178
ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
179
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
180
}
181
182
bdrv_inc_in_flight(bs);
183
-
184
/* throttling disk I/O */
185
- if (blk->public.throttle_state) {
186
- throttle_group_co_io_limits_intercept(blk, bytes, true);
187
+ if (blk->public.throttle_group_member.throttle_state) {
188
+ throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
189
+ bytes, true);
190
}
191
192
if (!blk->enable_write_cache) {
193
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
194
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
195
{
196
BlockDriverState *bs = blk_bs(blk);
197
+ ThrottleTimers *tt;
198
199
if (bs) {
200
- if (blk->public.throttle_state) {
201
- throttle_timers_detach_aio_context(&blk->public.throttle_timers);
202
+ if (blk->public.throttle_group_member.throttle_state) {
203
+ tt = &blk->public.throttle_group_member.throttle_timers;
204
+ throttle_timers_detach_aio_context(tt);
205
}
206
bdrv_set_aio_context(bs, new_context);
207
- if (blk->public.throttle_state) {
208
- throttle_timers_attach_aio_context(&blk->public.throttle_timers,
209
- new_context);
210
+ if (blk->public.throttle_group_member.throttle_state) {
211
+ tt = &blk->public.throttle_group_member.throttle_timers;
212
+ throttle_timers_attach_aio_context(tt, new_context);
213
}
214
}
215
}
73
}
216
@@ -XXX,XX +XXX,XX @@ int blk_commit_all(void)
74
217
/* throttling disk I/O limits */
75
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
218
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
76
diff --git a/block/commit.c b/block/commit.c
219
{
77
index XXXXXXX..XXXXXXX 100644
220
- throttle_group_config(blk, cfg);
78
--- a/block/commit.c
221
+ throttle_group_config(&blk->public.throttle_group_member, cfg);
79
+++ b/block/commit.c
80
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn commit_run(Job *job, Error **errp)
81
}
82
83
if (base_len < len) {
84
- ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, NULL);
85
+ ret = blk_truncate(s->base, len, false, PREALLOC_MODE_OFF, 0, NULL);
86
if (ret) {
87
goto out;
88
}
89
@@ -XXX,XX +XXX,XX @@ int bdrv_commit(BlockDriverState *bs)
90
* grow the backing file image if possible. If not possible,
91
* we must return an error */
92
if (length > backing_length) {
93
- ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF,
94
+ ret = blk_truncate(backing, length, false, PREALLOC_MODE_OFF, 0,
95
&local_err);
96
if (ret < 0) {
97
error_report_err(local_err);
98
diff --git a/block/crypto.c b/block/crypto.c
99
index XXXXXXX..XXXXXXX 100644
100
--- a/block/crypto.c
101
+++ b/block/crypto.c
102
@@ -XXX,XX +XXX,XX @@ static ssize_t block_crypto_init_func(QCryptoBlock *block,
103
* which will be used by the crypto header
104
*/
105
return blk_truncate(data->blk, data->size + headerlen, false,
106
- data->prealloc, errp);
107
+ data->prealloc, 0, errp);
222
}
108
}
223
109
224
void blk_io_limits_disable(BlockBackend *blk)
110
225
{
111
diff --git a/block/mirror.c b/block/mirror.c
226
- assert(blk->public.throttle_state);
112
index XXXXXXX..XXXXXXX 100644
227
+ assert(blk->public.throttle_group_member.throttle_state);
113
--- a/block/mirror.c
228
bdrv_drained_begin(blk_bs(blk));
114
+++ b/block/mirror.c
229
- throttle_group_unregister_blk(blk);
115
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn mirror_run(Job *job, Error **errp)
230
+ throttle_group_unregister_tgm(&blk->public.throttle_group_member);
116
231
bdrv_drained_end(blk_bs(blk));
117
if (s->bdev_length > base_length) {
232
}
118
ret = blk_truncate(s->target, s->bdev_length, false,
233
119
- PREALLOC_MODE_OFF, NULL);
234
/* should be called before blk_set_io_limits if a limit is set */
120
+ PREALLOC_MODE_OFF, 0, NULL);
235
void blk_io_limits_enable(BlockBackend *blk, const char *group)
121
if (ret < 0) {
236
{
122
goto immediate_exit;
237
- assert(!blk->public.throttle_state);
238
- throttle_group_register_blk(blk, group);
239
+ assert(!blk->public.throttle_group_member.throttle_state);
240
+ throttle_group_register_tgm(&blk->public.throttle_group_member, group);
241
}
242
243
void blk_io_limits_update_group(BlockBackend *blk, const char *group)
244
{
245
/* this BB is not part of any group */
246
- if (!blk->public.throttle_state) {
247
+ if (!blk->public.throttle_group_member.throttle_state) {
248
return;
249
}
250
251
/* this BB is a part of the same group than the one we want */
252
- if (!g_strcmp0(throttle_group_get_name(blk), group)) {
253
+ if (!g_strcmp0(throttle_group_get_name(&blk->public.throttle_group_member),
254
+ group)) {
255
return;
256
}
257
258
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_begin(BdrvChild *child)
259
/* Note that blk->root may not be accessible here yet if we are just
260
* attaching to a BlockDriverState that is drained. Use child instead. */
261
262
- if (atomic_fetch_inc(&blk->public.io_limits_disabled) == 0) {
263
- throttle_group_restart_blk(blk);
264
+ if (atomic_fetch_inc(&blk->public.throttle_group_member.io_limits_disabled) == 0) {
265
+ throttle_group_restart_tgm(&blk->public.throttle_group_member);
266
}
267
}
268
269
@@ -XXX,XX +XXX,XX @@ static void blk_root_drained_end(BdrvChild *child)
270
BlockBackend *blk = child->opaque;
271
assert(blk->quiesce_counter);
272
273
- assert(blk->public.io_limits_disabled);
274
- atomic_dec(&blk->public.io_limits_disabled);
275
+ assert(blk->public.throttle_group_member.io_limits_disabled);
276
+ atomic_dec(&blk->public.throttle_group_member.io_limits_disabled);
277
278
if (--blk->quiesce_counter == 0) {
279
if (blk->dev_ops && blk->dev_ops->drained_end) {
280
diff --git a/block/qapi.c b/block/qapi.c
281
index XXXXXXX..XXXXXXX 100644
282
--- a/block/qapi.c
283
+++ b/block/qapi.c
284
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
285
286
info->detect_zeroes = bs->detect_zeroes;
287
288
- if (blk && blk_get_public(blk)->throttle_state) {
289
+ if (blk && blk_get_public(blk)->throttle_group_member.throttle_state) {
290
ThrottleConfig cfg;
291
+ BlockBackendPublic *blkp = blk_get_public(blk);
292
293
- throttle_group_get_config(blk, &cfg);
294
+ throttle_group_get_config(&blkp->throttle_group_member, &cfg);
295
296
info->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg;
297
info->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg;
298
@@ -XXX,XX +XXX,XX @@ BlockDeviceInfo *bdrv_block_device_info(BlockBackend *blk,
299
info->iops_size = cfg.op_size;
300
301
info->has_group = true;
302
- info->group = g_strdup(throttle_group_get_name(blk));
303
+ info->group =
304
+ g_strdup(throttle_group_get_name(&blkp->throttle_group_member));
305
}
306
307
info->write_threshold = bdrv_write_threshold_get(bs);
308
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
309
index XXXXXXX..XXXXXXX 100644
310
--- a/block/throttle-groups.c
311
+++ b/block/throttle-groups.c
312
@@ -XXX,XX +XXX,XX @@
313
#include "sysemu/qtest.h"
314
315
/* The ThrottleGroup structure (with its ThrottleState) is shared
316
- * among different BlockBackends and it's independent from
317
+ * among different ThrottleGroupMembers and it's independent from
318
* AioContext, so in order to use it from different threads it needs
319
* its own locking.
320
*
321
@@ -XXX,XX +XXX,XX @@
322
* The whole ThrottleGroup structure is private and invisible to
323
* outside users, that only use it through its ThrottleState.
324
*
325
- * In addition to the ThrottleGroup structure, BlockBackendPublic has
326
+ * In addition to the ThrottleGroup structure, ThrottleGroupMember has
327
* fields that need to be accessed by other members of the group and
328
* therefore also need to be protected by this lock. Once a
329
- * BlockBackend is registered in a group those fields can be accessed
330
+ * ThrottleGroupMember is registered in a group those fields can be accessed
331
* by other threads any time.
332
*
333
* Again, all this is handled internally and is mostly transparent to
334
* the outside. The 'throttle_timers' field however has an additional
335
* constraint because it may be temporarily invalid (see for example
336
* blk_set_aio_context()). Therefore in this file a thread will
337
- * access some other BlockBackend's timers only after verifying that
338
- * that BlockBackend has throttled requests in the queue.
339
+ * access some other ThrottleGroupMember's timers only after verifying that
340
+ * that ThrottleGroupMember has throttled requests in the queue.
341
*/
342
typedef struct ThrottleGroup {
343
char *name; /* This is constant during the lifetime of the group */
344
345
QemuMutex lock; /* This lock protects the following four fields */
346
ThrottleState ts;
347
- QLIST_HEAD(, BlockBackendPublic) head;
348
- BlockBackend *tokens[2];
349
+ QLIST_HEAD(, ThrottleGroupMember) head;
350
+ ThrottleGroupMember *tokens[2];
351
bool any_timer_armed[2];
352
QEMUClockType clock_type;
353
354
@@ -XXX,XX +XXX,XX @@ void throttle_group_unref(ThrottleState *ts)
355
qemu_mutex_unlock(&throttle_groups_lock);
356
}
357
358
-/* Get the name from a BlockBackend's ThrottleGroup. The name (and the pointer)
359
+/* Get the name from a ThrottleGroupMember's group. The name (and the pointer)
360
* is guaranteed to remain constant during the lifetime of the group.
361
*
362
- * @blk: a BlockBackend that is member of a throttling group
363
+ * @tgm: a ThrottleGroupMember
364
* @ret: the name of the group.
365
*/
366
-const char *throttle_group_get_name(BlockBackend *blk)
367
+const char *throttle_group_get_name(ThrottleGroupMember *tgm)
368
{
369
- BlockBackendPublic *blkp = blk_get_public(blk);
370
- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
371
+ ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
372
return tg->name;
373
}
374
375
-/* Return the next BlockBackend in the round-robin sequence, simulating a
376
- * circular list.
377
+/* Return the next ThrottleGroupMember in the round-robin sequence, simulating
378
+ * a circular list.
379
*
380
* This assumes that tg->lock is held.
381
*
382
- * @blk: the current BlockBackend
383
- * @ret: the next BlockBackend in the sequence
384
+ * @tgm: the current ThrottleGroupMember
385
+ * @ret: the next ThrottleGroupMember in the sequence
386
*/
387
-static BlockBackend *throttle_group_next_blk(BlockBackend *blk)
388
+static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *tgm)
389
{
390
- BlockBackendPublic *blkp = blk_get_public(blk);
391
- ThrottleState *ts = blkp->throttle_state;
392
+ ThrottleState *ts = tgm->throttle_state;
393
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
394
- BlockBackendPublic *next = QLIST_NEXT(blkp, round_robin);
395
+ ThrottleGroupMember *next = QLIST_NEXT(tgm, round_robin);
396
397
if (!next) {
398
next = QLIST_FIRST(&tg->head);
399
}
400
401
- return blk_by_public(next);
402
+ return next;
403
}
404
405
/*
406
- * Return whether a BlockBackend has pending requests.
407
+ * Return whether a ThrottleGroupMember has pending requests.
408
*
409
* This assumes that tg->lock is held.
410
*
411
- * @blk: the BlockBackend
412
- * @is_write: the type of operation (read/write)
413
- * @ret: whether the BlockBackend has pending requests.
414
+ * @tgm: the ThrottleGroupMember
415
+ * @is_write: the type of operation (read/write)
416
+ * @ret: whether the ThrottleGroupMember has pending requests.
417
*/
418
-static inline bool blk_has_pending_reqs(BlockBackend *blk,
419
+static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm,
420
bool is_write)
421
{
422
- const BlockBackendPublic *blkp = blk_get_public(blk);
423
- return blkp->pending_reqs[is_write];
424
+ return tgm->pending_reqs[is_write];
425
}
426
427
-/* Return the next BlockBackend in the round-robin sequence with pending I/O
428
- * requests.
429
+/* Return the next ThrottleGroupMember in the round-robin sequence with pending
430
+ * I/O requests.
431
*
432
* This assumes that tg->lock is held.
433
*
434
- * @blk: the current BlockBackend
435
+ * @tgm: the current ThrottleGroupMember
436
* @is_write: the type of operation (read/write)
437
- * @ret: the next BlockBackend with pending requests, or blk if there is
438
- * none.
439
+ * @ret: the next ThrottleGroupMember with pending requests, or tgm if
440
+ * there is none.
441
*/
442
-static BlockBackend *next_throttle_token(BlockBackend *blk, bool is_write)
443
+static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
444
+ bool is_write)
445
{
446
- BlockBackendPublic *blkp = blk_get_public(blk);
447
- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
448
- BlockBackend *token, *start;
449
+ ThrottleState *ts = tgm->throttle_state;
450
+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
451
+ ThrottleGroupMember *token, *start;
452
453
start = token = tg->tokens[is_write];
454
455
/* get next bs round in round robin style */
456
- token = throttle_group_next_blk(token);
457
- while (token != start && !blk_has_pending_reqs(token, is_write)) {
458
- token = throttle_group_next_blk(token);
459
+ token = throttle_group_next_tgm(token);
460
+ while (token != start && !tgm_has_pending_reqs(token, is_write)) {
461
+ token = throttle_group_next_tgm(token);
462
}
463
464
/* If no IO are queued for scheduling on the next round robin token
465
- * then decide the token is the current bs because chances are
466
- * the current bs get the current request queued.
467
+ * then decide the token is the current tgm because chances are
468
+ * the current tgm got the current request queued.
469
*/
470
- if (token == start && !blk_has_pending_reqs(token, is_write)) {
471
- token = blk;
472
+ if (token == start && !tgm_has_pending_reqs(token, is_write)) {
473
+ token = tgm;
474
}
475
476
- /* Either we return the original BB, or one with pending requests */
477
- assert(token == blk || blk_has_pending_reqs(token, is_write));
478
+ /* Either we return the original TGM, or one with pending requests */
479
+ assert(token == tgm || tgm_has_pending_reqs(token, is_write));
480
481
return token;
482
}
483
484
-/* Check if the next I/O request for a BlockBackend needs to be throttled or
485
- * not. If there's no timer set in this group, set one and update the token
486
- * accordingly.
487
+/* Check if the next I/O request for a ThrottleGroupMember needs to be
488
+ * throttled or not. If there's no timer set in this group, set one and update
489
+ * the token accordingly.
490
*
491
* This assumes that tg->lock is held.
492
*
493
- * @blk: the current BlockBackend
494
+ * @tgm: the current ThrottleGroupMember
495
* @is_write: the type of operation (read/write)
496
* @ret: whether the I/O request needs to be throttled or not
497
*/
498
-static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write)
499
+static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
500
+ bool is_write)
501
{
502
- BlockBackendPublic *blkp = blk_get_public(blk);
503
- ThrottleState *ts = blkp->throttle_state;
504
- ThrottleTimers *tt = &blkp->throttle_timers;
505
+ ThrottleState *ts = tgm->throttle_state;
506
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
507
+ ThrottleTimers *tt = &tgm->throttle_timers;
508
bool must_wait;
509
510
- if (atomic_read(&blkp->io_limits_disabled)) {
511
+ if (atomic_read(&tgm->io_limits_disabled)) {
512
return false;
513
}
514
515
@@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(BlockBackend *blk, bool is_write)
516
517
must_wait = throttle_schedule_timer(ts, tt, is_write);
518
519
- /* If a timer just got armed, set blk as the current token */
520
+ /* If a timer just got armed, set tgm as the current token */
521
if (must_wait) {
522
- tg->tokens[is_write] = blk;
523
+ tg->tokens[is_write] = tgm;
524
tg->any_timer_armed[is_write] = true;
525
}
526
527
return must_wait;
528
}
529
530
-/* Start the next pending I/O request for a BlockBackend. Return whether
531
+/* Start the next pending I/O request for a ThrottleGroupMember. Return whether
532
* any request was actually pending.
533
*
534
- * @blk: the current BlockBackend
535
+ * @tgm: the current ThrottleGroupMember
536
* @is_write: the type of operation (read/write)
537
*/
538
-static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
539
+static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm,
540
bool is_write)
541
{
542
- BlockBackendPublic *blkp = blk_get_public(blk);
543
bool ret;
544
545
- qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
546
- ret = qemu_co_queue_next(&blkp->throttled_reqs[is_write]);
547
- qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
548
+ qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
549
+ ret = qemu_co_queue_next(&tgm->throttled_reqs[is_write]);
550
+ qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
551
552
return ret;
553
}
554
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn throttle_group_co_restart_queue(BlockBackend *blk,
555
*
556
* This assumes that tg->lock is held.
557
*
558
- * @blk: the current BlockBackend
559
+ * @tgm: the current ThrottleGroupMember
560
* @is_write: the type of operation (read/write)
561
*/
562
-static void schedule_next_request(BlockBackend *blk, bool is_write)
563
+static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
564
{
565
- BlockBackendPublic *blkp = blk_get_public(blk);
566
- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
567
+ ThrottleState *ts = tgm->throttle_state;
568
+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
569
bool must_wait;
570
- BlockBackend *token;
571
+ ThrottleGroupMember *token;
572
573
/* Check if there's any pending request to schedule next */
574
- token = next_throttle_token(blk, is_write);
575
- if (!blk_has_pending_reqs(token, is_write)) {
576
+ token = next_throttle_token(tgm, is_write);
577
+ if (!tgm_has_pending_reqs(token, is_write)) {
578
return;
579
}
580
581
@@ -XXX,XX +XXX,XX @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
582
583
/* If it doesn't have to wait, queue it for immediate execution */
584
if (!must_wait) {
585
- /* Give preference to requests from the current blk */
586
+ /* Give preference to requests from the current tgm */
587
if (qemu_in_coroutine() &&
588
- throttle_group_co_restart_queue(blk, is_write)) {
589
- token = blk;
590
+ throttle_group_co_restart_queue(tgm, is_write)) {
591
+ token = tgm;
592
} else {
593
- ThrottleTimers *tt = &blk_get_public(token)->throttle_timers;
594
+ ThrottleTimers *tt = &token->throttle_timers;
595
int64_t now = qemu_clock_get_ns(tg->clock_type);
596
timer_mod(tt->timers[is_write], now);
597
tg->any_timer_armed[is_write] = true;
598
@@ -XXX,XX +XXX,XX @@ static void schedule_next_request(BlockBackend *blk, bool is_write)
599
* if necessary, and schedule the next request using a round robin
600
* algorithm.
601
*
602
- * @blk: the current BlockBackend
603
+ * @tgm: the current ThrottleGroupMember
604
* @bytes: the number of bytes for this I/O
605
* @is_write: the type of operation (read/write)
606
*/
607
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
608
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
609
unsigned int bytes,
610
bool is_write)
611
{
612
bool must_wait;
613
- BlockBackend *token;
614
-
615
- BlockBackendPublic *blkp = blk_get_public(blk);
616
- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
617
+ ThrottleGroupMember *token;
618
+ ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
619
qemu_mutex_lock(&tg->lock);
620
621
/* First we check if this I/O has to be throttled. */
622
- token = next_throttle_token(blk, is_write);
623
+ token = next_throttle_token(tgm, is_write);
624
must_wait = throttle_group_schedule_timer(token, is_write);
625
626
/* Wait if there's a timer set or queued requests of this type */
627
- if (must_wait || blkp->pending_reqs[is_write]) {
628
- blkp->pending_reqs[is_write]++;
629
+ if (must_wait || tgm->pending_reqs[is_write]) {
630
+ tgm->pending_reqs[is_write]++;
631
qemu_mutex_unlock(&tg->lock);
632
- qemu_co_mutex_lock(&blkp->throttled_reqs_lock);
633
- qemu_co_queue_wait(&blkp->throttled_reqs[is_write],
634
- &blkp->throttled_reqs_lock);
635
- qemu_co_mutex_unlock(&blkp->throttled_reqs_lock);
636
+ qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
637
+ qemu_co_queue_wait(&tgm->throttled_reqs[is_write],
638
+ &tgm->throttled_reqs_lock);
639
+ qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
640
qemu_mutex_lock(&tg->lock);
641
- blkp->pending_reqs[is_write]--;
642
+ tgm->pending_reqs[is_write]--;
643
}
644
645
/* The I/O will be executed, so do the accounting */
646
- throttle_account(blkp->throttle_state, is_write, bytes);
647
+ throttle_account(tgm->throttle_state, is_write, bytes);
648
649
/* Schedule the next request */
650
- schedule_next_request(blk, is_write);
651
+ schedule_next_request(tgm, is_write);
652
653
qemu_mutex_unlock(&tg->lock);
654
}
655
656
typedef struct {
657
- BlockBackend *blk;
658
+ ThrottleGroupMember *tgm;
659
bool is_write;
660
} RestartData;
661
662
static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
663
{
664
RestartData *data = opaque;
665
- BlockBackend *blk = data->blk;
666
+ ThrottleGroupMember *tgm = data->tgm;
667
+ ThrottleState *ts = tgm->throttle_state;
668
+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
669
bool is_write = data->is_write;
670
- BlockBackendPublic *blkp = blk_get_public(blk);
671
- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
672
bool empty_queue;
673
674
- empty_queue = !throttle_group_co_restart_queue(blk, is_write);
675
+ empty_queue = !throttle_group_co_restart_queue(tgm, is_write);
676
677
/* If the request queue was empty then we have to take care of
678
* scheduling the next one */
679
if (empty_queue) {
680
qemu_mutex_lock(&tg->lock);
681
- schedule_next_request(blk, is_write);
682
+ schedule_next_request(tgm, is_write);
683
qemu_mutex_unlock(&tg->lock);
684
}
685
}
686
687
-static void throttle_group_restart_queue(BlockBackend *blk, bool is_write)
688
+static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write)
689
{
690
+ BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
691
+ throttle_group_member);
692
+ BlockBackend *blk = blk_by_public(blkp);
693
Coroutine *co;
694
RestartData rd = {
695
- .blk = blk,
696
+ .tgm = tgm,
697
.is_write = is_write
698
};
699
700
@@ -XXX,XX +XXX,XX @@ static void throttle_group_restart_queue(BlockBackend *blk, bool is_write)
701
aio_co_enter(blk_get_aio_context(blk), co);
702
}
703
704
-void throttle_group_restart_blk(BlockBackend *blk)
705
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
706
{
707
- BlockBackendPublic *blkp = blk_get_public(blk);
708
-
709
- if (blkp->throttle_state) {
710
- throttle_group_restart_queue(blk, 0);
711
- throttle_group_restart_queue(blk, 1);
712
+ if (tgm->throttle_state) {
713
+ throttle_group_restart_queue(tgm, 0);
714
+ throttle_group_restart_queue(tgm, 1);
715
}
716
}
717
718
@@ -XXX,XX +XXX,XX @@ void throttle_group_restart_blk(BlockBackend *blk)
719
* to throttle_config(), but guarantees atomicity within the
720
* throttling group.
721
*
722
- * @blk: a BlockBackend that is a member of the group
723
+ * @tgm: a ThrottleGroupMember that is a member of the group
724
* @cfg: the configuration to set
725
*/
726
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg)
727
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
728
{
729
- BlockBackendPublic *blkp = blk_get_public(blk);
730
- ThrottleState *ts = blkp->throttle_state;
731
+ ThrottleState *ts = tgm->throttle_state;
732
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
733
qemu_mutex_lock(&tg->lock);
734
throttle_config(ts, tg->clock_type, cfg);
735
qemu_mutex_unlock(&tg->lock);
736
737
- throttle_group_restart_blk(blk);
738
+ throttle_group_restart_tgm(tgm);
739
}
740
741
/* Get the throttle configuration from a particular group. Similar to
742
* throttle_get_config(), but guarantees atomicity within the
743
* throttling group.
744
*
745
- * @blk: a BlockBackend that is a member of the group
746
+ * @tgm: a ThrottleGroupMember that is a member of the group
747
* @cfg: the configuration will be written here
748
*/
749
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg)
750
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
751
{
752
- BlockBackendPublic *blkp = blk_get_public(blk);
753
- ThrottleState *ts = blkp->throttle_state;
754
+ ThrottleState *ts = tgm->throttle_state;
755
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
756
qemu_mutex_lock(&tg->lock);
757
throttle_get_config(ts, cfg);
758
@@ -XXX,XX +XXX,XX @@ void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg)
759
static void timer_cb(BlockBackend *blk, bool is_write)
760
{
761
BlockBackendPublic *blkp = blk_get_public(blk);
762
- ThrottleState *ts = blkp->throttle_state;
763
+ ThrottleGroupMember *tgm = &blkp->throttle_group_member;
764
+ ThrottleState *ts = tgm->throttle_state;
765
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
766
767
/* The timer has just been fired, so we can update the flag */
768
@@ -XXX,XX +XXX,XX @@ static void timer_cb(BlockBackend *blk, bool is_write)
769
qemu_mutex_unlock(&tg->lock);
770
771
/* Run the request that was waiting for this timer */
772
- throttle_group_restart_queue(blk, is_write);
773
+ throttle_group_restart_queue(tgm, is_write);
774
}
775
776
static void read_timer_cb(void *opaque)
777
@@ -XXX,XX +XXX,XX @@ static void write_timer_cb(void *opaque)
778
timer_cb(opaque, true);
779
}
780
781
-/* Register a BlockBackend in the throttling group, also initializing its
782
- * timers and updating its throttle_state pointer to point to it. If a
783
+/* Register a ThrottleGroupMember from the throttling group, also initializing
784
+ * its timers and updating its throttle_state pointer to point to it. If a
785
* throttling group with that name does not exist yet, it will be created.
786
*
787
- * @blk: the BlockBackend to insert
788
+ * @tgm: the ThrottleGroupMember to insert
789
* @groupname: the name of the group
790
*/
791
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname)
792
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
793
+ const char *groupname)
794
{
795
int i;
796
- BlockBackendPublic *blkp = blk_get_public(blk);
797
+ BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
798
+ throttle_group_member);
799
+ BlockBackend *blk = blk_by_public(blkp);
800
ThrottleState *ts = throttle_group_incref(groupname);
801
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
802
- blkp->throttle_state = ts;
803
+
804
+ tgm->throttle_state = ts;
805
806
qemu_mutex_lock(&tg->lock);
807
- /* If the ThrottleGroup is new set this BlockBackend as the token */
808
+ /* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
809
for (i = 0; i < 2; i++) {
810
if (!tg->tokens[i]) {
811
- tg->tokens[i] = blk;
812
+ tg->tokens[i] = tgm;
813
}
814
}
815
816
- QLIST_INSERT_HEAD(&tg->head, blkp, round_robin);
817
+ QLIST_INSERT_HEAD(&tg->head, tgm, round_robin);
818
819
- throttle_timers_init(&blkp->throttle_timers,
820
+ throttle_timers_init(&tgm->throttle_timers,
821
blk_get_aio_context(blk),
822
tg->clock_type,
823
read_timer_cb,
824
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_blk(BlockBackend *blk, const char *groupname)
825
qemu_mutex_unlock(&tg->lock);
826
}
827
828
-/* Unregister a BlockBackend from its group, removing it from the list,
829
+/* Unregister a ThrottleGroupMember from its group, removing it from the list,
830
* destroying the timers and setting the throttle_state pointer to NULL.
831
*
832
- * The BlockBackend must not have pending throttled requests, so the caller has
833
- * to drain them first.
834
+ * The ThrottleGroupMember must not have pending throttled requests, so the
835
+ * caller has to drain them first.
836
*
837
* The group will be destroyed if it's empty after this operation.
838
*
839
- * @blk: the BlockBackend to remove
840
+ * @tgm the ThrottleGroupMember to remove
841
*/
842
-void throttle_group_unregister_blk(BlockBackend *blk)
843
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
844
{
845
- BlockBackendPublic *blkp = blk_get_public(blk);
846
- ThrottleGroup *tg = container_of(blkp->throttle_state, ThrottleGroup, ts);
847
+ ThrottleState *ts = tgm->throttle_state;
848
+ ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
849
+ ThrottleGroupMember *token;
850
int i;
851
852
- assert(blkp->pending_reqs[0] == 0 && blkp->pending_reqs[1] == 0);
853
- assert(qemu_co_queue_empty(&blkp->throttled_reqs[0]));
854
- assert(qemu_co_queue_empty(&blkp->throttled_reqs[1]));
855
+ assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
856
+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
857
+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
858
859
qemu_mutex_lock(&tg->lock);
860
for (i = 0; i < 2; i++) {
861
- if (tg->tokens[i] == blk) {
862
- BlockBackend *token = throttle_group_next_blk(blk);
863
- /* Take care of the case where this is the last blk in the group */
864
- if (token == blk) {
865
+ if (tg->tokens[i] == tgm) {
866
+ token = throttle_group_next_tgm(tgm);
867
+ /* Take care of the case where this is the last tgm in the group */
868
+ if (token == tgm) {
869
token = NULL;
870
}
123
}
871
tg->tokens[i] = token;
124
diff --git a/block/qcow2.c b/block/qcow2.c
872
}
125
index XXXXXXX..XXXXXXX 100644
873
}
126
--- a/block/qcow2.c
874
127
+++ b/block/qcow2.c
875
- /* remove the current blk from the list */
128
@@ -XXX,XX +XXX,XX @@ qcow2_co_create(BlockdevCreateOptions *create_options, Error **errp)
876
- QLIST_REMOVE(blkp, round_robin);
129
877
- throttle_timers_destroy(&blkp->throttle_timers);
130
/* Okay, now that we have a valid image, let's give it the right size */
878
+ /* remove the current tgm from the list */
131
ret = blk_truncate(blk, qcow2_opts->size, false, qcow2_opts->preallocation,
879
+ QLIST_REMOVE(tgm, round_robin);
132
- errp);
880
+ throttle_timers_destroy(&tgm->throttle_timers);
133
+ 0, errp);
881
qemu_mutex_unlock(&tg->lock);
134
if (ret < 0) {
882
135
error_prepend(errp, "Could not resize image: ");
883
throttle_group_unref(&tg->ts);
136
goto out;
884
- blkp->throttle_state = NULL;
137
@@ -XXX,XX +XXX,XX @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
885
+ tgm->throttle_state = NULL;
138
* Amending image options should ensure that the image has
886
}
139
* exactly the given new values, so pass exact=true here.
887
140
*/
888
static void throttle_groups_init(void)
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
}
889
diff --git a/blockdev.c b/blockdev.c
236
diff --git a/blockdev.c b/blockdev.c
890
index XXXXXXX..XXXXXXX 100644
237
index XXXXXXX..XXXXXXX 100644
891
--- a/blockdev.c
238
--- a/blockdev.c
892
+++ b/blockdev.c
239
+++ b/blockdev.c
893
@@ -XXX,XX +XXX,XX @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
240
@@ -XXX,XX +XXX,XX @@ void qmp_block_resize(bool has_device, const char *device,
894
if (throttle_enabled(&cfg)) {
241
}
895
/* Enable I/O limits if they're not enabled yet, otherwise
242
896
* just update the throttling group. */
243
bdrv_drained_begin(bs);
897
- if (!blk_get_public(blk)->throttle_state) {
244
- ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, errp);
898
+ if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
245
+ ret = blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
899
blk_io_limits_enable(blk,
246
bdrv_drained_end(bs);
900
arg->has_group ? arg->group :
247
901
arg->has_device ? arg->device :
248
out:
902
@@ -XXX,XX +XXX,XX @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
249
diff --git a/qemu-img.c b/qemu-img.c
903
}
250
index XXXXXXX..XXXXXXX 100644
904
/* Set the new throttling configuration */
251
--- a/qemu-img.c
905
blk_set_io_limits(blk, &cfg);
252
+++ b/qemu-img.c
906
- } else if (blk_get_public(blk)->throttle_state) {
253
@@ -XXX,XX +XXX,XX @@ static int img_resize(int argc, char **argv)
907
+ } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
254
* resizing, so pass @exact=true. It is of no use to report
908
/* If all throttling settings are set to 0, disable I/O limits */
255
* success when the image has not actually been resized.
909
blk_io_limits_disable(blk);
256
*/
910
}
257
- ret = blk_truncate(blk, total_size, true, prealloc, &err);
911
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
258
+ ret = blk_truncate(blk, total_size, true, prealloc, 0, &err);
912
index XXXXXXX..XXXXXXX 100644
259
if (!ret) {
913
--- a/tests/test-throttle.c
260
qprintf(quiet, "Image resized.\n");
914
+++ b/tests/test-throttle.c
261
} else {
915
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
262
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
916
ThrottleConfig cfg1, cfg2;
263
index XXXXXXX..XXXXXXX 100644
917
BlockBackend *blk1, *blk2, *blk3;
264
--- a/qemu-io-cmds.c
918
BlockBackendPublic *blkp1, *blkp2, *blkp3;
265
+++ b/qemu-io-cmds.c
919
+ ThrottleGroupMember *tgm1, *tgm2, *tgm3;
266
@@ -XXX,XX +XXX,XX @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
920
267
* exact=true. It is better to err on the "emit more errors" side
921
/* No actual I/O is performed on these devices */
268
* than to be overly permissive.
922
blk1 = blk_new(0, BLK_PERM_ALL);
269
*/
923
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
270
- ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, &local_err);
924
blkp2 = blk_get_public(blk2);
271
+ ret = blk_truncate(blk, offset, true, PREALLOC_MODE_OFF, 0, &local_err);
925
blkp3 = blk_get_public(blk3);
272
if (ret < 0) {
926
273
error_report_err(local_err);
927
- g_assert(blkp1->throttle_state == NULL);
274
return ret;
928
- g_assert(blkp2->throttle_state == NULL);
929
- g_assert(blkp3->throttle_state == NULL);
930
+ tgm1 = &blkp1->throttle_group_member;
931
+ tgm2 = &blkp2->throttle_group_member;
932
+ tgm3 = &blkp3->throttle_group_member;
933
934
- throttle_group_register_blk(blk1, "bar");
935
- throttle_group_register_blk(blk2, "foo");
936
- throttle_group_register_blk(blk3, "bar");
937
+ g_assert(tgm1->throttle_state == NULL);
938
+ g_assert(tgm2->throttle_state == NULL);
939
+ g_assert(tgm3->throttle_state == NULL);
940
941
- g_assert(blkp1->throttle_state != NULL);
942
- g_assert(blkp2->throttle_state != NULL);
943
- g_assert(blkp3->throttle_state != NULL);
944
+ throttle_group_register_tgm(tgm1, "bar");
945
+ throttle_group_register_tgm(tgm2, "foo");
946
+ throttle_group_register_tgm(tgm3, "bar");
947
948
- g_assert(!strcmp(throttle_group_get_name(blk1), "bar"));
949
- g_assert(!strcmp(throttle_group_get_name(blk2), "foo"));
950
- g_assert(blkp1->throttle_state == blkp3->throttle_state);
951
+ g_assert(tgm1->throttle_state != NULL);
952
+ g_assert(tgm2->throttle_state != NULL);
953
+ g_assert(tgm3->throttle_state != NULL);
954
+
955
+ g_assert(!strcmp(throttle_group_get_name(tgm1), "bar"));
956
+ g_assert(!strcmp(throttle_group_get_name(tgm2), "foo"));
957
+ g_assert(tgm1->throttle_state == tgm3->throttle_state);
958
959
/* Setting the config of a group member affects the whole group */
960
throttle_config_init(&cfg1);
961
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
962
cfg1.buckets[THROTTLE_BPS_WRITE].avg = 285000;
963
cfg1.buckets[THROTTLE_OPS_READ].avg = 20000;
964
cfg1.buckets[THROTTLE_OPS_WRITE].avg = 12000;
965
- throttle_group_config(blk1, &cfg1);
966
+ throttle_group_config(tgm1, &cfg1);
967
968
- throttle_group_get_config(blk1, &cfg1);
969
- throttle_group_get_config(blk3, &cfg2);
970
+ throttle_group_get_config(tgm1, &cfg1);
971
+ throttle_group_get_config(tgm3, &cfg2);
972
g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
973
974
cfg2.buckets[THROTTLE_BPS_READ].avg = 4547;
975
cfg2.buckets[THROTTLE_BPS_WRITE].avg = 1349;
976
cfg2.buckets[THROTTLE_OPS_READ].avg = 123;
977
cfg2.buckets[THROTTLE_OPS_WRITE].avg = 86;
978
- throttle_group_config(blk3, &cfg1);
979
+ throttle_group_config(tgm3, &cfg1);
980
981
- throttle_group_get_config(blk1, &cfg1);
982
- throttle_group_get_config(blk3, &cfg2);
983
+ throttle_group_get_config(tgm1, &cfg1);
984
+ throttle_group_get_config(tgm3, &cfg2);
985
g_assert(!memcmp(&cfg1, &cfg2, sizeof(cfg1)));
986
987
- throttle_group_unregister_blk(blk1);
988
- throttle_group_unregister_blk(blk2);
989
- throttle_group_unregister_blk(blk3);
990
+ throttle_group_unregister_tgm(tgm1);
991
+ throttle_group_unregister_tgm(tgm2);
992
+ throttle_group_unregister_tgm(tgm3);
993
994
- g_assert(blkp1->throttle_state == NULL);
995
- g_assert(blkp2->throttle_state == NULL);
996
- g_assert(blkp3->throttle_state == NULL);
997
+ g_assert(tgm1->throttle_state == NULL);
998
+ g_assert(tgm2->throttle_state == NULL);
999
+ g_assert(tgm3->throttle_state == NULL);
1000
}
1001
1002
int main(int argc, char **argv)
1003
--
275
--
1004
2.13.5
276
2.25.3
1005
277
1006
278
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
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.
2
6
3
timer_cb() needs to know about the current Aio context of the throttle
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
request that is woken up. In order to make ThrottleGroupMember backend
8
Message-Id: <20200424125448.63318-5-kwolf@redhat.com>
5
agnostic, this information is stored in an aio_context field instead of
9
Reviewed-by: Eric Blake <eblake@redhat.com>
6
accessing it from BlockBackend.
10
Reviewed-by: Max Reitz <mreitz@redhat.com>
7
8
Reviewed-by: Alberto Garcia <berto@igalia.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
12
---
13
include/block/throttle-groups.h | 7 ++++-
13
block/qcow2-cluster.c | 2 +-
14
block/block-backend.c | 15 ++++------
14
block/qcow2.c | 34 ++++++++++++++++++++++++++++++++++
15
block/throttle-groups.c | 38 ++++++++++++++++---------
15
2 files changed, 35 insertions(+), 1 deletion(-)
16
tests/test-throttle.c | 63 +++++++++++++++++++++--------------------
17
4 files changed, 69 insertions(+), 54 deletions(-)
18
16
19
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
17
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/throttle-groups.h
19
--- a/block/qcow2-cluster.c
22
+++ b/include/block/throttle-groups.h
20
+++ b/block/qcow2-cluster.c
23
@@ -XXX,XX +XXX,XX @@
21
@@ -XXX,XX +XXX,XX @@ int qcow2_cluster_zeroize(BlockDriverState *bs, uint64_t offset,
24
*/
22
/* Caller must pass aligned values, except at image end */
25
23
assert(QEMU_IS_ALIGNED(offset, s->cluster_size));
26
typedef struct ThrottleGroupMember {
24
assert(QEMU_IS_ALIGNED(end_offset, s->cluster_size) ||
27
+ AioContext *aio_context;
25
- end_offset == bs->total_sectors << BDRV_SECTOR_BITS);
28
/* throttled_reqs_lock protects the CoQueues for throttled requests. */
26
+ end_offset >= bs->total_sectors << BDRV_SECTOR_BITS);
29
CoMutex throttled_reqs_lock;
27
30
CoQueue throttled_reqs[2];
28
/* The zero flag is only supported by version 3 and newer */
31
@@ -XXX,XX +XXX,XX @@ void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
29
if (s->qcow_version < 3) {
32
void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
30
diff --git a/block/qcow2.c b/block/qcow2.c
33
34
void throttle_group_register_tgm(ThrottleGroupMember *tgm,
35
- const char *groupname);
36
+ const char *groupname,
37
+ AioContext *ctx);
38
void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
39
void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
40
41
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
42
unsigned int bytes,
43
bool is_write);
44
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
45
+ AioContext *new_context);
46
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
47
48
#endif
49
diff --git a/block/block-backend.c b/block/block-backend.c
50
index XXXXXXX..XXXXXXX 100644
31
index XXXXXXX..XXXXXXX 100644
51
--- a/block/block-backend.c
32
--- a/block/qcow2.c
52
+++ b/block/block-backend.c
33
+++ b/block/qcow2.c
53
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
34
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_do_open(BlockDriverState *bs, QDict *options,
54
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
35
55
{
36
bs->supported_zero_flags = header.version >= 3 ?
56
BlockDriverState *bs = blk_bs(blk);
37
BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK : 0;
57
- ThrottleTimers *tt;
38
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
58
+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
39
59
40
/* Repair image if dirty */
60
if (bs) {
41
if (!(flags & (BDRV_O_CHECK | BDRV_O_INACTIVE)) && !bs->read_only &&
61
- if (blk->public.throttle_group_member.throttle_state) {
42
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
62
- tt = &blk->public.throttle_group_member.throttle_timers;
43
g_assert_not_reached();
63
- throttle_timers_detach_aio_context(tt);
64
+ if (tgm->throttle_state) {
65
+ throttle_group_detach_aio_context(tgm);
66
+ throttle_group_attach_aio_context(tgm, new_context);
67
}
68
bdrv_set_aio_context(bs, new_context);
69
- if (blk->public.throttle_group_member.throttle_state) {
70
- tt = &blk->public.throttle_group_member.throttle_timers;
71
- throttle_timers_attach_aio_context(tt, new_context);
72
- }
73
}
44
}
74
}
45
75
46
+ if ((flags & BDRV_REQ_ZERO_WRITE) && offset > old_length) {
76
@@ -XXX,XX +XXX,XX @@ void blk_io_limits_disable(BlockBackend *blk)
47
+ uint64_t zero_start = QEMU_ALIGN_UP(old_length, s->cluster_size);
77
void blk_io_limits_enable(BlockBackend *blk, const char *group)
78
{
79
assert(!blk->public.throttle_group_member.throttle_state);
80
- throttle_group_register_tgm(&blk->public.throttle_group_member, group);
81
+ throttle_group_register_tgm(&blk->public.throttle_group_member,
82
+ group, blk_get_aio_context(blk));
83
}
84
85
void blk_io_limits_update_group(BlockBackend *blk, const char *group)
86
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/throttle-groups.c
89
+++ b/block/throttle-groups.c
90
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
91
92
static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write)
93
{
94
- BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
95
- throttle_group_member);
96
- BlockBackend *blk = blk_by_public(blkp);
97
Coroutine *co;
98
RestartData rd = {
99
.tgm = tgm,
100
@@ -XXX,XX +XXX,XX @@ static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
101
};
102
103
co = qemu_coroutine_create(throttle_group_restart_queue_entry, &rd);
104
- aio_co_enter(blk_get_aio_context(blk), co);
105
+ aio_co_enter(tgm->aio_context, co);
106
}
107
108
void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
109
@@ -XXX,XX +XXX,XX @@ void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
110
/* ThrottleTimers callback. This wakes up a request that was waiting
111
* because it had been throttled.
112
*
113
- * @blk: the BlockBackend whose request had been throttled
114
+ * @tgm: the ThrottleGroupMember whose request had been throttled
115
* @is_write: the type of operation (read/write)
116
*/
117
-static void timer_cb(BlockBackend *blk, bool is_write)
118
+static void timer_cb(ThrottleGroupMember *tgm, bool is_write)
119
{
120
- BlockBackendPublic *blkp = blk_get_public(blk);
121
- ThrottleGroupMember *tgm = &blkp->throttle_group_member;
122
ThrottleState *ts = tgm->throttle_state;
123
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
124
125
@@ -XXX,XX +XXX,XX @@ static void write_timer_cb(void *opaque)
126
*
127
* @tgm: the ThrottleGroupMember to insert
128
* @groupname: the name of the group
129
+ * @ctx: the AioContext to use
130
*/
131
void throttle_group_register_tgm(ThrottleGroupMember *tgm,
132
- const char *groupname)
133
+ const char *groupname,
134
+ AioContext *ctx)
135
{
136
int i;
137
- BlockBackendPublic *blkp = container_of(tgm, BlockBackendPublic,
138
- throttle_group_member);
139
- BlockBackend *blk = blk_by_public(blkp);
140
ThrottleState *ts = throttle_group_incref(groupname);
141
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
142
143
tgm->throttle_state = ts;
144
+ tgm->aio_context = ctx;
145
146
qemu_mutex_lock(&tg->lock);
147
/* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
148
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
149
QLIST_INSERT_HEAD(&tg->head, tgm, round_robin);
150
151
throttle_timers_init(&tgm->throttle_timers,
152
- blk_get_aio_context(blk),
153
+ tgm->aio_context,
154
tg->clock_type,
155
read_timer_cb,
156
write_timer_cb,
157
- blk);
158
+ tgm);
159
160
qemu_mutex_unlock(&tg->lock);
161
}
162
@@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
163
tgm->throttle_state = NULL;
164
}
165
166
+void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
167
+ AioContext *new_context)
168
+{
169
+ ThrottleTimers *tt = &tgm->throttle_timers;
170
+ throttle_timers_attach_aio_context(tt, new_context);
171
+ tgm->aio_context = new_context;
172
+}
173
+
48
+
174
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
49
+ /*
175
+{
50
+ * Use zero clusters as much as we can. qcow2_cluster_zeroize()
176
+ ThrottleTimers *tt = &tgm->throttle_timers;
51
+ * requires a cluster-aligned start. The end may be unaligned if it is
177
+ throttle_timers_detach_aio_context(tt);
52
+ * at the end of the image (which it is here).
178
+ tgm->aio_context = NULL;
53
+ */
179
+}
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
+ }
180
+
59
+
181
static void throttle_groups_init(void)
60
+ /* Write explicit zeros for the unaligned head */
182
{
61
+ if (zero_start > old_length) {
183
qemu_mutex_init(&throttle_groups_lock);
62
+ uint64_t len = zero_start - old_length;
184
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
63
+ uint8_t *buf = qemu_blockalign0(bs, len);
185
index XXXXXXX..XXXXXXX 100644
64
+ QEMUIOVector qiov;
186
--- a/tests/test-throttle.c
65
+ qemu_iovec_init_buf(&qiov, buf, len);
187
+++ b/tests/test-throttle.c
188
@@ -XXX,XX +XXX,XX @@
189
static AioContext *ctx;
190
static LeakyBucket bkt;
191
static ThrottleConfig cfg;
192
+static ThrottleGroupMember tgm;
193
static ThrottleState ts;
194
-static ThrottleTimers tt;
195
+static ThrottleTimers *tt;
196
197
/* useful function */
198
static bool double_cmp(double x, double y)
199
@@ -XXX,XX +XXX,XX @@ static void test_init(void)
200
{
201
int i;
202
203
+ tt = &tgm.throttle_timers;
204
+
66
+
205
/* fill the structures with crap */
67
+ qemu_co_mutex_unlock(&s->lock);
206
memset(&ts, 1, sizeof(ts));
68
+ ret = qcow2_co_pwritev_part(bs, old_length, len, &qiov, 0, 0);
207
- memset(&tt, 1, sizeof(tt));
69
+ qemu_co_mutex_lock(&s->lock);
208
+ memset(tt, 1, sizeof(*tt));
70
+
209
71
+ qemu_vfree(buf);
210
/* init structures */
72
+ if (ret < 0) {
211
throttle_init(&ts);
73
+ error_setg_errno(errp, -ret, "Failed to zero out the new area");
212
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
74
+ goto fail;
213
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
75
+ }
214
read_timer_cb, write_timer_cb, &ts);
76
+ }
215
77
+ }
216
/* check initialized fields */
78
+
217
- g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
79
if (prealloc != PREALLOC_MODE_OFF) {
218
- g_assert(tt.timers[0]);
80
/* Flush metadata before actually changing the image size */
219
- g_assert(tt.timers[1]);
81
ret = qcow2_write_caches(bs);
220
+ g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
221
+ g_assert(tt->timers[0]);
222
+ g_assert(tt->timers[1]);
223
224
/* check other fields where cleared */
225
g_assert(!ts.previous_leak);
226
@@ -XXX,XX +XXX,XX @@ static void test_init(void)
227
g_assert(!ts.cfg.buckets[i].level);
228
}
229
230
- throttle_timers_destroy(&tt);
231
+ throttle_timers_destroy(tt);
232
}
233
234
static void test_destroy(void)
235
{
236
int i;
237
throttle_init(&ts);
238
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
239
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
240
read_timer_cb, write_timer_cb, &ts);
241
- throttle_timers_destroy(&tt);
242
+ throttle_timers_destroy(tt);
243
for (i = 0; i < 2; i++) {
244
- g_assert(!tt.timers[i]);
245
+ g_assert(!tt->timers[i]);
246
}
247
}
248
249
@@ -XXX,XX +XXX,XX @@ static void test_config_functions(void)
250
orig_cfg.op_size = 1;
251
252
throttle_init(&ts);
253
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
254
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
255
read_timer_cb, write_timer_cb, &ts);
256
/* structure reset by throttle_init previous_leak should be null */
257
g_assert(!ts.previous_leak);
258
@@ -XXX,XX +XXX,XX @@ static void test_config_functions(void)
259
/* get back the fixed configuration */
260
throttle_get_config(&ts, &final_cfg);
261
262
- throttle_timers_destroy(&tt);
263
+ throttle_timers_destroy(tt);
264
265
g_assert(final_cfg.buckets[THROTTLE_BPS_TOTAL].avg == 153);
266
g_assert(final_cfg.buckets[THROTTLE_BPS_READ].avg == 56);
267
@@ -XXX,XX +XXX,XX @@ static void test_have_timer(void)
268
{
269
/* zero structures */
270
memset(&ts, 0, sizeof(ts));
271
- memset(&tt, 0, sizeof(tt));
272
+ memset(tt, 0, sizeof(*tt));
273
274
/* no timer set should return false */
275
- g_assert(!throttle_timers_are_initialized(&tt));
276
+ g_assert(!throttle_timers_are_initialized(tt));
277
278
/* init structures */
279
throttle_init(&ts);
280
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
281
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
282
read_timer_cb, write_timer_cb, &ts);
283
284
/* timer set by init should return true */
285
- g_assert(throttle_timers_are_initialized(&tt));
286
+ g_assert(throttle_timers_are_initialized(tt));
287
288
- throttle_timers_destroy(&tt);
289
+ throttle_timers_destroy(tt);
290
}
291
292
static void test_detach_attach(void)
293
{
294
/* zero structures */
295
memset(&ts, 0, sizeof(ts));
296
- memset(&tt, 0, sizeof(tt));
297
+ memset(tt, 0, sizeof(*tt));
298
299
/* init the structure */
300
throttle_init(&ts);
301
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
302
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
303
read_timer_cb, write_timer_cb, &ts);
304
305
/* timer set by init should return true */
306
- g_assert(throttle_timers_are_initialized(&tt));
307
+ g_assert(throttle_timers_are_initialized(tt));
308
309
/* timer should no longer exist after detaching */
310
- throttle_timers_detach_aio_context(&tt);
311
- g_assert(!throttle_timers_are_initialized(&tt));
312
+ throttle_timers_detach_aio_context(tt);
313
+ g_assert(!throttle_timers_are_initialized(tt));
314
315
/* timer should exist again after attaching */
316
- throttle_timers_attach_aio_context(&tt, ctx);
317
- g_assert(throttle_timers_are_initialized(&tt));
318
+ throttle_timers_attach_aio_context(tt, ctx);
319
+ g_assert(throttle_timers_are_initialized(tt));
320
321
- throttle_timers_destroy(&tt);
322
+ throttle_timers_destroy(tt);
323
}
324
325
static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
326
@@ -XXX,XX +XXX,XX @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
327
cfg.op_size = op_size;
328
329
throttle_init(&ts);
330
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
331
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
332
read_timer_cb, write_timer_cb, &ts);
333
throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg);
334
335
@@ -XXX,XX +XXX,XX @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
336
return false;
337
}
338
339
- throttle_timers_destroy(&tt);
340
+ throttle_timers_destroy(tt);
341
342
return true;
343
}
344
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
345
g_assert(tgm2->throttle_state == NULL);
346
g_assert(tgm3->throttle_state == NULL);
347
348
- throttle_group_register_tgm(tgm1, "bar");
349
- throttle_group_register_tgm(tgm2, "foo");
350
- throttle_group_register_tgm(tgm3, "bar");
351
+ throttle_group_register_tgm(tgm1, "bar", blk_get_aio_context(blk1));
352
+ throttle_group_register_tgm(tgm2, "foo", blk_get_aio_context(blk2));
353
+ throttle_group_register_tgm(tgm3, "bar", blk_get_aio_context(blk3));
354
355
g_assert(tgm1->throttle_state != NULL);
356
g_assert(tgm2->throttle_state != NULL);
357
--
82
--
358
2.13.5
83
2.25.3
359
84
360
85
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
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
This function is not used anywhere, so remove it.
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
5
Reviewed-by: Max Reitz <mreitz@redhat.com>
5
Markus Armbruster adds:
6
The i82078 floppy device model used to call bdrv_media_changed() to
7
implement its media change bit when backed by a host floppy. This
8
went away in 21fcf36 "fdc: simplify media change handling".
9
Probably broke host floppy media change. Host floppy pass-through
10
was dropped in commit f709623. bdrv_media_changed() has never been
11
used for anything else. Remove it.
12
(Source is Message-ID: <87y3ruaypm.fsf@dusky.pond.sub.org>)
13
14
Reviewed-by: Eric Blake <eblake@redhat.com>
6
Reviewed-by: Eric Blake <eblake@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
8
Message-Id: <20200424125448.63318-6-kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
10
---
19
include/block/block.h | 1 -
11
block/raw-format.c | 4 +++-
20
include/block/block_int.h | 1 -
12
1 file changed, 3 insertions(+), 1 deletion(-)
21
block.c | 14 --------------
22
block/raw-format.c | 6 ------
23
4 files changed, 22 deletions(-)
24
13
25
diff --git a/include/block/block.h b/include/block/block.h
26
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/block.h
28
+++ b/include/block/block.h
29
@@ -XXX,XX +XXX,XX @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
30
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
31
bool bdrv_is_sg(BlockDriverState *bs);
32
bool bdrv_is_inserted(BlockDriverState *bs);
33
-int bdrv_media_changed(BlockDriverState *bs);
34
void bdrv_lock_medium(BlockDriverState *bs, bool locked);
35
void bdrv_eject(BlockDriverState *bs, bool eject_flag);
36
const char *bdrv_get_format_name(BlockDriverState *bs);
37
diff --git a/include/block/block_int.h b/include/block/block_int.h
38
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block_int.h
40
+++ b/include/block/block_int.h
41
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
42
43
/* removable device specific */
44
bool (*bdrv_is_inserted)(BlockDriverState *bs);
45
- int (*bdrv_media_changed)(BlockDriverState *bs);
46
void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag);
47
void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked);
48
49
diff --git a/block.c b/block.c
50
index XXXXXXX..XXXXXXX 100644
51
--- a/block.c
52
+++ b/block.c
53
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_inserted(BlockDriverState *bs)
54
}
55
56
/**
57
- * Return whether the media changed since the last call to this
58
- * function, or -ENOTSUP if we don't know. Most drivers don't know.
59
- */
60
-int bdrv_media_changed(BlockDriverState *bs)
61
-{
62
- BlockDriver *drv = bs->drv;
63
-
64
- if (drv && drv->bdrv_media_changed) {
65
- return drv->bdrv_media_changed(bs);
66
- }
67
- return -ENOTSUP;
68
-}
69
-
70
-/**
71
* If eject_flag is TRUE, eject the media. Otherwise, close the tray
72
*/
73
void bdrv_eject(BlockDriverState *bs, bool eject_flag)
74
diff --git a/block/raw-format.c b/block/raw-format.c
14
diff --git a/block/raw-format.c b/block/raw-format.c
75
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
76
--- a/block/raw-format.c
16
--- a/block/raw-format.c
77
+++ b/block/raw-format.c
17
+++ b/block/raw-format.c
78
@@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset,
18
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_truncate(BlockDriverState *bs, int64_t offset,
79
return bdrv_truncate(bs->file, offset, prealloc, 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);
80
}
24
}
81
25
82
-static int raw_media_changed(BlockDriverState *bs)
83
-{
84
- return bdrv_media_changed(bs->file->bs);
85
-}
86
-
87
static void raw_eject(BlockDriverState *bs, bool eject_flag)
26
static void raw_eject(BlockDriverState *bs, bool eject_flag)
88
{
27
@@ -XXX,XX +XXX,XX @@ static int raw_open(BlockDriverState *bs, QDict *options, int flags,
89
bdrv_eject(bs->file->bs, eject_flag);
28
bs->supported_zero_flags = BDRV_REQ_WRITE_UNCHANGED |
90
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
29
((BDRV_REQ_FUA | BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK) &
91
.bdrv_refresh_limits = &raw_refresh_limits,
30
bs->file->bs->supported_zero_flags);
92
.bdrv_probe_blocksizes = &raw_probe_blocksizes,
31
+ bs->supported_truncate_flags = bs->file->bs->supported_truncate_flags &
93
.bdrv_probe_geometry = &raw_probe_geometry,
32
+ BDRV_REQ_ZERO_WRITE;
94
- .bdrv_media_changed = &raw_media_changed,
33
95
.bdrv_eject = &raw_eject,
34
if (bs->probed && !bdrv_is_read_only(bs)) {
96
.bdrv_lock_medium = &raw_lock_medium,
35
bdrv_refresh_filename(bs->file->bs);
97
.bdrv_co_ioctl = &raw_co_ioctl,
98
--
36
--
99
2.13.5
37
2.25.3
100
38
101
39
diff view generated by jsdifflib
1
From: "Daniel P. Berrange" <berrange@redhat.com>
1
For regular files, we always get BDRV_REQ_ZERO_WRITE behaviour from the
2
OS, so we can advertise the flag and just ignore it.
2
3
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
4
Reviewed-by: Eric Blake <eblake@redhat.com>
5
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Signed-off-by: Daniel P. Berrange <berrange@redhat.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>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
10
---
8
include/block/block_int.h | 31 +++++++++++++++++++++++++++++++
11
block/file-posix.c | 4 ++++
9
1 file changed, 31 insertions(+)
12
1 file changed, 4 insertions(+)
10
13
11
diff --git a/include/block/block_int.h b/include/block/block_int.h
14
diff --git a/block/file-posix.c b/block/file-posix.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/include/block/block_int.h
16
--- a/block/file-posix.c
14
+++ b/include/block/block_int.h
17
+++ b/block/file-posix.c
15
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
18
@@ -XXX,XX +XXX,XX @@ static int raw_open_common(BlockDriverState *bs, QDict *options,
16
19
#endif
17
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
20
18
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
21
bs->supported_zero_flags = BDRV_REQ_MAY_UNMAP | BDRV_REQ_NO_FALLBACK;
19
+
22
+ if (S_ISREG(st.st_mode)) {
20
+ /**
23
+ /* When extending regular files, we get zeros from the OS */
21
+ * @offset: position in bytes to read at
24
+ bs->supported_truncate_flags = BDRV_REQ_ZERO_WRITE;
22
+ * @bytes: number of bytes to read
25
+ }
23
+ * @qiov: the buffers to fill with read data
26
ret = 0;
24
+ * @flags: currently unused, always 0
27
fail:
25
+ *
28
if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
26
+ * @offset and @bytes will be a multiple of 'request_alignment',
27
+ * but the length of individual @qiov elements does not have to
28
+ * be a multiple.
29
+ *
30
+ * @bytes will always equal the total size of @qiov, and will be
31
+ * no larger than 'max_transfer'.
32
+ *
33
+ * The buffer in @qiov may point directly to guest memory.
34
+ */
35
int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs,
36
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
37
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
38
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
39
int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs,
40
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags);
41
+ /**
42
+ * @offset: position in bytes to write at
43
+ * @bytes: number of bytes to write
44
+ * @qiov: the buffers containing data to write
45
+ * @flags: zero or more bits allowed by 'supported_write_flags'
46
+ *
47
+ * @offset and @bytes will be a multiple of 'request_alignment',
48
+ * but the length of individual @qiov elements does not have to
49
+ * be a multiple.
50
+ *
51
+ * @bytes will always equal the total size of @qiov, and will be
52
+ * no larger than 'max_transfer'.
53
+ *
54
+ * The buffer in @qiov may point directly to guest memory.
55
+ */
56
int coroutine_fn (*bdrv_co_pwritev)(BlockDriverState *bs,
57
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
58
59
--
29
--
60
2.13.5
30
2.25.3
61
31
62
32
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
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
bdrv_co_get_block_status_from_file() and
5
Consider the following scenario where the overlay is shorter than its
4
bdrv_co_get_block_status_from_backing() set *file to bs->file and
6
backing file:
5
bs->backing respectively, so that bdrv_co_get_block_status() can recurse
6
to them. Future block drivers won't have to duplicate code to implement
7
this.
8
7
9
Reviewed-by: Fam Zheng <famz@redhat.com>
8
base.qcow2: AAAAAAAA
10
Reviewed-by: Eric Blake <eblake@redhat.com>
9
overlay.qcow2: BBBB
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
11
When resizing (extending) overlay.qcow2, the new blocks should not stay
13
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
12
unallocated and make the additional As from base.qcow2 visible like
13
before this patch, but zeros should be read.
14
15
A similar case happens with the various variants of a commit job when an
16
intermediate file is short (- for unallocated):
17
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>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
34
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
35
---
16
include/block/block_int.h | 18 ++++++++++++++++++
36
block/io.c | 25 +++++++++++++++++++++++++
17
block/blkdebug.c | 12 +-----------
37
1 file changed, 25 insertions(+)
18
block/commit.c | 12 +-----------
19
block/io.c | 26 ++++++++++++++++++++++++++
20
block/mirror.c | 12 +-----------
21
5 files changed, 47 insertions(+), 33 deletions(-)
22
38
23
diff --git a/include/block/block_int.h b/include/block/block_int.h
24
index XXXXXXX..XXXXXXX 100644
25
--- a/include/block/block_int.h
26
+++ b/include/block/block_int.h
27
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
28
uint64_t perm, uint64_t shared,
29
uint64_t *nperm, uint64_t *nshared);
30
31
+/*
32
+ * Default implementation for drivers to pass bdrv_co_get_block_status() to
33
+ * their file.
34
+ */
35
+int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
36
+ int64_t sector_num,
37
+ int nb_sectors,
38
+ int *pnum,
39
+ BlockDriverState **file);
40
+/*
41
+ * Default implementation for drivers to pass bdrv_co_get_block_status() to
42
+ * their backing file.
43
+ */
44
+int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
45
+ int64_t sector_num,
46
+ int nb_sectors,
47
+ int *pnum,
48
+ BlockDriverState **file);
49
const char *bdrv_get_parent_name(const BlockDriverState *bs);
50
void blk_dev_change_media_cb(BlockBackend *blk, bool load, Error **errp);
51
bool blk_dev_has_removable_media(BlockBackend *blk);
52
diff --git a/block/blkdebug.c b/block/blkdebug.c
53
index XXXXXXX..XXXXXXX 100644
54
--- a/block/blkdebug.c
55
+++ b/block/blkdebug.c
56
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
57
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
58
}
59
60
-static int64_t coroutine_fn blkdebug_co_get_block_status(
61
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
62
- BlockDriverState **file)
63
-{
64
- *pnum = nb_sectors;
65
- *file = bs->file->bs;
66
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
67
- (sector_num << BDRV_SECTOR_BITS);
68
-}
69
-
70
static void blkdebug_close(BlockDriverState *bs)
71
{
72
BDRVBlkdebugState *s = bs->opaque;
73
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
74
.bdrv_co_flush_to_disk = blkdebug_co_flush,
75
.bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes,
76
.bdrv_co_pdiscard = blkdebug_co_pdiscard,
77
- .bdrv_co_get_block_status = blkdebug_co_get_block_status,
78
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
79
80
.bdrv_debug_event = blkdebug_debug_event,
81
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
82
diff --git a/block/commit.c b/block/commit.c
83
index XXXXXXX..XXXXXXX 100644
84
--- a/block/commit.c
85
+++ b/block/commit.c
86
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
87
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
88
}
89
90
-static int64_t coroutine_fn bdrv_commit_top_get_block_status(
91
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
92
- BlockDriverState **file)
93
-{
94
- *pnum = nb_sectors;
95
- *file = bs->backing->bs;
96
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
97
- (sector_num << BDRV_SECTOR_BITS);
98
-}
99
-
100
static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts)
101
{
102
bdrv_refresh_filename(bs->backing->bs);
103
@@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
104
static BlockDriver bdrv_commit_top = {
105
.format_name = "commit_top",
106
.bdrv_co_preadv = bdrv_commit_top_preadv,
107
- .bdrv_co_get_block_status = bdrv_commit_top_get_block_status,
108
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,
109
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
110
.bdrv_close = bdrv_commit_top_close,
111
.bdrv_child_perm = bdrv_commit_top_child_perm,
112
diff --git a/block/io.c b/block/io.c
39
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
40
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
41
--- a/block/io.c
115
+++ b/block/io.c
42
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvCoGetBlockStatusData {
43
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset, bool exact,
117
bool done;
44
goto out;
118
} BdrvCoGetBlockStatusData;
45
}
119
46
120
+int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
47
+ /*
121
+ int64_t sector_num,
48
+ * If the image has a backing file that is large enough that it would
122
+ int nb_sectors,
49
+ * provide data for the new area, we cannot leave it unallocated because
123
+ int *pnum,
50
+ * then the backing file content would become visible. Instead, zero-fill
124
+ BlockDriverState **file)
51
+ * the new area.
125
+{
52
+ *
126
+ assert(bs->file && bs->file->bs);
53
+ * Note that if the image has a backing file, but was opened without the
127
+ *pnum = nb_sectors;
54
+ * backing file, taking care of keeping things consistent with that backing
128
+ *file = bs->file->bs;
55
+ * file is the user's responsibility.
129
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
56
+ */
130
+ (sector_num << BDRV_SECTOR_BITS);
57
+ if (new_bytes && bs->backing) {
131
+}
58
+ int64_t backing_len;
132
+
59
+
133
+int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
60
+ backing_len = bdrv_getlength(backing_bs(bs));
134
+ int64_t sector_num,
61
+ if (backing_len < 0) {
135
+ int nb_sectors,
62
+ ret = backing_len;
136
+ int *pnum,
63
+ error_setg_errno(errp, -ret, "Could not get backing file size");
137
+ BlockDriverState **file)
64
+ goto out;
138
+{
65
+ }
139
+ assert(bs->backing && bs->backing->bs);
140
+ *pnum = nb_sectors;
141
+ *file = bs->backing->bs;
142
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
143
+ (sector_num << BDRV_SECTOR_BITS);
144
+}
145
+
66
+
146
/*
67
+ if (backing_len > old_size) {
147
* Returns the allocation status of the specified sectors.
68
+ flags |= BDRV_REQ_ZERO_WRITE;
148
* Drivers not implementing the functionality are assumed to not support
69
+ }
149
diff --git a/block/mirror.c b/block/mirror.c
70
+ }
150
index XXXXXXX..XXXXXXX 100644
71
+
151
--- a/block/mirror.c
72
if (drv->bdrv_co_truncate) {
152
+++ b/block/mirror.c
73
if (flags & ~bs->supported_truncate_flags) {
153
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
74
error_setg(errp, "Block driver does not support requested flags");
154
return bdrv_co_flush(bs->backing->bs);
155
}
156
157
-static int64_t coroutine_fn bdrv_mirror_top_get_block_status(
158
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
159
- BlockDriverState **file)
160
-{
161
- *pnum = nb_sectors;
162
- *file = bs->backing->bs;
163
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
164
- (sector_num << BDRV_SECTOR_BITS);
165
-}
166
-
167
static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
168
int64_t offset, int bytes, BdrvRequestFlags flags)
169
{
170
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_mirror_top = {
171
.bdrv_co_pwrite_zeroes = bdrv_mirror_top_pwrite_zeroes,
172
.bdrv_co_pdiscard = bdrv_mirror_top_pdiscard,
173
.bdrv_co_flush = bdrv_mirror_top_flush,
174
- .bdrv_co_get_block_status = bdrv_mirror_top_get_block_status,
175
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,
176
.bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
177
.bdrv_close = bdrv_mirror_top_close,
178
.bdrv_child_perm = bdrv_mirror_top_child_perm,
179
--
75
--
180
2.13.5
76
2.25.3
181
77
182
78
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.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
The old signature has an ambiguous meaning for a return of 0:
6
Insert a filter_testfiles() call between both.
4
either no allocation was requested or necessary, or an error
5
occurred (but any errno associated with the error is lost to
6
the caller, which then has to assume EIO).
7
7
8
Better is to follow the example of qcow2, by changing the
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
signature to have a separate return value that cleanly
9
Reviewed-by: Max Reitz <mreitz@redhat.com>
10
distinguishes between failure and success, along with a
10
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
parameter that cleanly holds a 64-bit value. Then update all
11
Message-Id: <20200424125448.63318-9-kwolf@redhat.com>
12
callers.
13
14
While auditing that all return paths return a negative errno
15
(rather than -1), I also simplified places where we can pass
16
NULL rather than a local Error that just gets thrown away.
17
18
Suggested-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Eric Blake <eblake@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
13
---
22
block/qcow.c | 123 +++++++++++++++++++++++++++++++++++------------------------
14
tests/qemu-iotests/iotests.py | 5 +++--
23
1 file changed, 73 insertions(+), 50 deletions(-)
15
1 file changed, 3 insertions(+), 2 deletions(-)
24
16
25
diff --git a/block/qcow.c b/block/qcow.c
17
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
26
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
27
--- a/block/qcow.c
19
--- a/tests/qemu-iotests/iotests.py
28
+++ b/block/qcow.c
20
+++ b/tests/qemu-iotests/iotests.py
29
@@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state,
21
@@ -XXX,XX +XXX,XX @@ def filter_img_info(output, filename):
30
* 'compressed_size'. 'compressed_size' must be > 0 and <
22
for line in output.split('\n'):
31
* cluster_size
23
if 'disk size' in line or 'actual-size' in line:
32
*
24
continue
33
- * return 0 if not allocated.
25
- line = line.replace(filename, 'TEST_IMG') \
34
+ * return 0 if not allocated, 1 if *result is assigned, and negative
26
- .replace(imgfmt, 'IMGFMT')
35
+ * errno on failure.
27
+ line = line.replace(filename, 'TEST_IMG')
36
*/
28
+ line = filter_testfiles(line)
37
-static uint64_t get_cluster_offset(BlockDriverState *bs,
29
+ line = line.replace(imgfmt, 'IMGFMT')
38
- uint64_t offset, int allocate,
30
line = re.sub('iters: [0-9]+', 'iters: XXX', line)
39
- int compressed_size,
31
line = re.sub('uuid: [-a-f0-9]+', 'uuid: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', line)
40
- int n_start, int n_end)
32
line = re.sub('cid: [0-9]+', 'cid: XXXXXXXXXX', line)
41
+static int get_cluster_offset(BlockDriverState *bs,
42
+ uint64_t offset, int allocate,
43
+ int compressed_size,
44
+ int n_start, int n_end, uint64_t *result)
45
{
46
BDRVQcowState *s = bs->opaque;
47
- int min_index, i, j, l1_index, l2_index;
48
+ int min_index, i, j, l1_index, l2_index, ret;
49
uint64_t l2_offset, *l2_table, cluster_offset, tmp;
50
uint32_t min_count;
51
int new_l2_table;
52
53
+ *result = 0;
54
l1_index = offset >> (s->l2_bits + s->cluster_bits);
55
l2_offset = s->l1_table[l1_index];
56
new_l2_table = 0;
57
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
58
/* update the L1 entry */
59
s->l1_table[l1_index] = l2_offset;
60
tmp = cpu_to_be64(l2_offset);
61
- if (bdrv_pwrite_sync(bs->file,
62
- s->l1_table_offset + l1_index * sizeof(tmp),
63
- &tmp, sizeof(tmp)) < 0)
64
- return 0;
65
+ ret = bdrv_pwrite_sync(bs->file,
66
+ s->l1_table_offset + l1_index * sizeof(tmp),
67
+ &tmp, sizeof(tmp));
68
+ if (ret < 0) {
69
+ return ret;
70
+ }
71
new_l2_table = 1;
72
}
73
for(i = 0; i < L2_CACHE_SIZE; i++) {
74
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
75
l2_table = s->l2_cache + (min_index << s->l2_bits);
76
if (new_l2_table) {
77
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
78
- if (bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
79
- s->l2_size * sizeof(uint64_t)) < 0)
80
- return 0;
81
+ ret = bdrv_pwrite_sync(bs->file, l2_offset, l2_table,
82
+ s->l2_size * sizeof(uint64_t));
83
+ if (ret < 0) {
84
+ return ret;
85
+ }
86
} else {
87
- if (bdrv_pread(bs->file, l2_offset, l2_table,
88
- s->l2_size * sizeof(uint64_t)) !=
89
- s->l2_size * sizeof(uint64_t))
90
- return 0;
91
+ ret = bdrv_pread(bs->file, l2_offset, l2_table,
92
+ s->l2_size * sizeof(uint64_t));
93
+ if (ret < 0) {
94
+ return ret;
95
+ }
96
}
97
s->l2_cache_offsets[min_index] = l2_offset;
98
s->l2_cache_counts[min_index] = 1;
99
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
100
/* if the cluster is already compressed, we must
101
decompress it in the case it is not completely
102
overwritten */
103
- if (decompress_cluster(bs, cluster_offset) < 0)
104
- return 0;
105
+ if (decompress_cluster(bs, cluster_offset) < 0) {
106
+ return -EIO;
107
+ }
108
cluster_offset = bdrv_getlength(bs->file->bs);
109
cluster_offset = (cluster_offset + s->cluster_size - 1) &
110
~(s->cluster_size - 1);
111
/* write the cluster content */
112
- if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
113
- s->cluster_size) !=
114
- s->cluster_size)
115
- return -1;
116
+ ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
117
+ s->cluster_size);
118
+ if (ret < 0) {
119
+ return ret;
120
+ }
121
} else {
122
cluster_offset = bdrv_getlength(bs->file->bs);
123
if (allocate == 1) {
124
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
125
s->cluster_data,
126
BDRV_SECTOR_SIZE,
127
NULL) < 0) {
128
- errno = EIO;
129
- return -1;
130
+ return -EIO;
131
+ }
132
+ ret = bdrv_pwrite(bs->file,
133
+ cluster_offset + i * 512,
134
+ s->cluster_data, 512);
135
+ if (ret < 0) {
136
+ return ret;
137
}
138
- if (bdrv_pwrite(bs->file,
139
- cluster_offset + i * 512,
140
- s->cluster_data, 512) != 512)
141
- return -1;
142
}
143
}
144
}
145
@@ -XXX,XX +XXX,XX @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
146
/* update L2 table */
147
tmp = cpu_to_be64(cluster_offset);
148
l2_table[l2_index] = tmp;
149
- if (bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
150
- &tmp, sizeof(tmp)) < 0)
151
- return 0;
152
+ ret = bdrv_pwrite_sync(bs->file, l2_offset + l2_index * sizeof(tmp),
153
+ &tmp, sizeof(tmp));
154
+ if (ret < 0) {
155
+ return ret;
156
+ }
157
}
158
- return cluster_offset;
159
+ *result = cluster_offset;
160
+ return 1;
161
}
162
163
static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
164
int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
165
{
166
BDRVQcowState *s = bs->opaque;
167
- int index_in_cluster, n;
168
+ int index_in_cluster, n, ret;
169
uint64_t cluster_offset;
170
171
qemu_co_mutex_lock(&s->lock);
172
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
173
+ ret = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0, &cluster_offset);
174
qemu_co_mutex_unlock(&s->lock);
175
+ if (ret < 0) {
176
+ return ret;
177
+ }
178
index_in_cluster = sector_num & (s->cluster_sectors - 1);
179
n = s->cluster_sectors - index_in_cluster;
180
if (n > nb_sectors)
181
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
182
183
while (nb_sectors != 0) {
184
/* prepare next request */
185
- cluster_offset = get_cluster_offset(bs, sector_num << 9,
186
- 0, 0, 0, 0);
187
+ ret = get_cluster_offset(bs, sector_num << 9,
188
+ 0, 0, 0, 0, &cluster_offset);
189
+ if (ret < 0) {
190
+ break;
191
+ }
192
index_in_cluster = sector_num & (s->cluster_sectors - 1);
193
n = s->cluster_sectors - index_in_cluster;
194
if (n > nb_sectors) {
195
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
196
ret = bdrv_co_readv(bs->backing, sector_num, n, &hd_qiov);
197
qemu_co_mutex_lock(&s->lock);
198
if (ret < 0) {
199
- goto fail;
200
+ break;
201
}
202
} else {
203
/* Note: in this case, no need to wait */
204
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
205
} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
206
/* add AIO support for compressed blocks ? */
207
if (decompress_cluster(bs, cluster_offset) < 0) {
208
- goto fail;
209
+ ret = -EIO;
210
+ break;
211
}
212
memcpy(buf,
213
s->cluster_cache + index_in_cluster * 512, 512 * n);
214
} else {
215
if ((cluster_offset & 511) != 0) {
216
- goto fail;
217
+ ret = -EIO;
218
+ break;
219
}
220
hd_iov.iov_base = (void *)buf;
221
hd_iov.iov_len = n * 512;
222
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
223
assert(s->crypto);
224
if (qcrypto_block_decrypt(s->crypto, sector_num, buf,
225
n * BDRV_SECTOR_SIZE, NULL) < 0) {
226
- goto fail;
227
+ ret = -EIO;
228
+ break;
229
}
230
}
231
}
232
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
233
buf += n * 512;
234
}
235
236
-done:
237
qemu_co_mutex_unlock(&s->lock);
238
239
if (qiov->niov > 1) {
240
@@ -XXX,XX +XXX,XX @@ done:
241
}
242
243
return ret;
244
-
245
-fail:
246
- ret = -EIO;
247
- goto done;
248
}
249
250
static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
251
@@ -XXX,XX +XXX,XX @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
252
if (n > nb_sectors) {
253
n = nb_sectors;
254
}
255
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
256
- index_in_cluster,
257
- index_in_cluster + n);
258
+ ret = get_cluster_offset(bs, sector_num << 9, 1, 0,
259
+ index_in_cluster,
260
+ index_in_cluster + n, &cluster_offset);
261
+ if (ret < 0) {
262
+ break;
263
+ }
264
if (!cluster_offset || (cluster_offset & 511) != 0) {
265
ret = -EIO;
266
break;
267
@@ -XXX,XX +XXX,XX @@ qcow_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
268
goto success;
269
}
270
qemu_co_mutex_lock(&s->lock);
271
- cluster_offset = get_cluster_offset(bs, offset, 2, out_len, 0, 0);
272
+ ret = get_cluster_offset(bs, offset, 2, out_len, 0, 0, &cluster_offset);
273
qemu_co_mutex_unlock(&s->lock);
274
+ if (ret < 0) {
275
+ goto fail;
276
+ }
277
if (cluster_offset == 0) {
278
ret = -EIO;
279
goto fail;
280
--
33
--
281
2.13.5
34
2.25.3
282
35
283
36
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2
2
Message-Id: <20200424125448.63318-10-kwolf@redhat.com>
3
Reviewed-by: Alberto Garcia <berto@igalia.com>
3
Reviewed-by: Max Reitz <mreitz@redhat.com>
4
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
4
Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.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/184 | 205 ++++++++++++++++++++++++++++++
7
tests/qemu-iotests/274 | 155 +++++++++++++++++++++
9
tests/qemu-iotests/184.out | 302 +++++++++++++++++++++++++++++++++++++++++++++
8
tests/qemu-iotests/274.out | 268 +++++++++++++++++++++++++++++++++++++
10
tests/qemu-iotests/group | 1 +
9
tests/qemu-iotests/group | 1 +
11
3 files changed, 508 insertions(+)
10
3 files changed, 424 insertions(+)
12
create mode 100755 tests/qemu-iotests/184
11
create mode 100755 tests/qemu-iotests/274
13
create mode 100644 tests/qemu-iotests/184.out
12
create mode 100644 tests/qemu-iotests/274.out
14
13
15
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
14
diff --git a/tests/qemu-iotests/274 b/tests/qemu-iotests/274
16
new file mode 100755
15
new file mode 100755
17
index XXXXXXX..XXXXXXX
16
index XXXXXXX..XXXXXXX
18
--- /dev/null
17
--- /dev/null
19
+++ b/tests/qemu-iotests/184
18
+++ b/tests/qemu-iotests/274
20
@@ -XXX,XX +XXX,XX @@
19
@@ -XXX,XX +XXX,XX @@
21
+#!/bin/bash
20
+#!/usr/bin/env python3
22
+#
21
+#
23
+# Test I/O throttle block filter driver interface
22
+# Copyright (C) 2019 Red Hat, Inc.
24
+#
25
+# Copyright (C) 2017 Manos Pitsidianakis
26
+#
23
+#
27
+# 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
28
+# 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
29
+# the Free Software Foundation; either version 2 of the License, or
26
+# the Free Software Foundation; either version 2 of the License, or
30
+# (at your option) any later version.
27
+# (at your option) any later version.
...
...
35
+# GNU General Public License for more details.
32
+# GNU General Public License for more details.
36
+#
33
+#
37
+# 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
38
+# 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/>.
39
+#
36
+#
40
+
37
+# Creator/Owner: Kevin Wolf <kwolf@redhat.com>
41
+# creator
38
+#
42
+owner="Manos Pitsidianakis"
39
+# Some tests for short backing files and short overlays
43
+
40
+
44
+seq=`basename $0`
41
+import iotests
45
+echo "QA output created by $seq"
42
+
46
+
43
+iotests.verify_image_format(supported_fmts=['qcow2'])
47
+here=`pwd`
44
+iotests.verify_platform(['linux'])
48
+status=1    # failure is the default!
45
+
49
+
46
+size_short = 1 * 1024 * 1024
50
+_cleanup()
47
+size_long = 2 * 1024 * 1024
51
+{
48
+size_diff = size_long - size_short
52
+ _cleanup_test_img
49
+
53
+}
50
+def create_chain() -> None:
54
+trap "_cleanup; exit \$status" 0 1 2 3 15
51
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base,
55
+
52
+ str(size_long))
56
+# get standard environment, filters and checks
53
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, mid,
57
+. ./common.rc
54
+ str(size_short))
58
+. ./common.filter
55
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', mid, top,
59
+
56
+ str(size_long))
60
+_supported_fmt qcow2
57
+
61
+_supported_proto file
58
+ iotests.qemu_io_log('-c', 'write -P 1 0 %d' % size_long, base)
62
+_supported_os Linux
59
+
63
+
60
+def create_vm() -> iotests.VM:
64
+function do_run_qemu()
61
+ vm = iotests.VM()
65
+{
62
+ vm.add_blockdev('file,filename=%s,node-name=base-file' % base)
66
+ echo Testing: "$@" | _filter_imgfmt
63
+ vm.add_blockdev('%s,file=base-file,node-name=base' % iotests.imgfmt)
67
+ $QEMU -nographic -qmp-pretty stdio -serial none "$@"
64
+ vm.add_blockdev('file,filename=%s,node-name=mid-file' % mid)
68
+ echo
65
+ vm.add_blockdev('%s,file=mid-file,node-name=mid,backing=base'
69
+}
66
+ % iotests.imgfmt)
70
+
67
+ vm.add_drive(top, 'backing=mid,node-name=top')
71
+function run_qemu()
68
+ return vm
72
+{
69
+
73
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
70
+with iotests.FilePath('base') as base, \
74
+ | _filter_qemu_io | _filter_generated_node_ids
71
+ iotests.FilePath('mid') as mid, \
75
+}
72
+ iotests.FilePath('top') as top:
76
+
73
+
77
+_make_test_img 64M
74
+ iotests.log('== Commit tests ==')
78
+test_throttle=$($QEMU_IMG --help|grep throttle)
75
+
79
+[ "$test_throttle" = "" ] && _supported_fmt throttle
76
+ create_chain()
80
+
77
+
81
+echo
78
+ iotests.log('=== Check visible data ===')
82
+echo "== checking interface =="
79
+
83
+
80
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, top)
84
+run_qemu <<EOF
81
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), top)
85
+{ "execute": "qmp_capabilities" }
82
+
86
+{ "execute": "blockdev-add",
83
+ iotests.log('=== Checking allocation status ===')
87
+ "arguments": {
84
+
88
+ "driver": "$IMGFMT",
85
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
89
+ "node-name": "disk0",
86
+ '-c', 'alloc %d %d' % (size_short, size_diff),
90
+ "file": {
87
+ base)
91
+ "driver": "file",
88
+
92
+ "filename": "$TEST_IMG"
89
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
93
+ }
90
+ '-c', 'alloc %d %d' % (size_short, size_diff),
94
+ }
91
+ mid)
95
+}
92
+
96
+{ "execute": "object-add",
93
+ iotests.qemu_io_log('-c', 'alloc 0 %d' % size_short,
97
+ "arguments": {
94
+ '-c', 'alloc %d %d' % (size_short, size_diff),
98
+ "qom-type": "throttle-group",
95
+ top)
99
+ "id": "group0",
96
+
100
+ "props": {
97
+ iotests.log('=== Checking map ===')
101
+ "limits" : {
98
+
102
+ "iops-total": 1000
99
+ iotests.qemu_img_log('map', '--output=json', base)
103
+ }
100
+ iotests.qemu_img_log('map', '--output=human', base)
104
+ }
101
+ iotests.qemu_img_log('map', '--output=json', mid)
105
+ }
102
+ iotests.qemu_img_log('map', '--output=human', mid)
106
+}
103
+ iotests.qemu_img_log('map', '--output=json', top)
107
+{ "execute": "blockdev-add",
104
+ iotests.qemu_img_log('map', '--output=human', top)
108
+ "arguments": {
105
+
109
+ "driver": "throttle",
106
+ iotests.log('=== Testing qemu-img commit (top -> mid) ===')
110
+ "node-name": "throttle0",
107
+
111
+ "throttle-group": "group0",
108
+ iotests.qemu_img_log('commit', top)
112
+ "file": "disk0"
109
+ iotests.img_info_log(mid)
113
+ }
110
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
114
+}
111
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
115
+{ "execute": "query-named-block-nodes" }
112
+
116
+{ "execute": "query-block" }
113
+ iotests.log('=== Testing HMP commit (top -> mid) ===')
117
+{ "execute": "quit" }
114
+
118
+EOF
115
+ create_chain()
119
+
116
+ with create_vm() as vm:
120
+echo
117
+ vm.launch()
121
+echo "== property changes in ThrottleGroup =="
118
+ vm.qmp_log('human-monitor-command', command_line='commit drive0')
122
+
119
+
123
+run_qemu <<EOF
120
+ iotests.img_info_log(mid)
124
+{ "execute": "qmp_capabilities" }
121
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
125
+{ "execute": "object-add",
122
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
126
+ "arguments": {
123
+
127
+ "qom-type": "throttle-group",
124
+ iotests.log('=== Testing QMP active commit (top -> mid) ===')
128
+ "id": "group0",
125
+
129
+ "props" : {
126
+ create_chain()
130
+ "limits": {
127
+ with create_vm() as vm:
131
+ "iops-total": 1000
128
+ vm.launch()
132
+ }
129
+ vm.qmp_log('block-commit', device='top', base_node='mid',
133
+ }
130
+ job_id='job0', auto_dismiss=False)
134
+ }
131
+ vm.run_job('job0', wait=5)
135
+}
132
+
136
+{ "execute" : "qom-get",
133
+ iotests.img_info_log(mid)
137
+ "arguments" : {
134
+ iotests.qemu_io_log('-c', 'read -P 1 0 %d' % size_short, mid)
138
+ "path" : "group0",
135
+ iotests.qemu_io_log('-c', 'read -P 0 %d %d' % (size_short, size_diff), mid)
139
+ "property" : "limits"
136
+
140
+ }
137
+
141
+}
138
+ iotests.log('== Resize tests ==')
142
+{ "execute" : "qom-set",
139
+
143
+ "arguments" : {
140
+ # Use different sizes for different allocation modes:
144
+ "path" : "group0",
141
+ #
145
+ "property" : "limits",
142
+ # We want to have at least one test where 32 bit truncation in the size of
146
+ "value" : {
143
+ # the overlapping area becomes visible. This is covered by the
147
+ "iops-total" : 0
144
+ # prealloc='off' case (1G to 6G is an overlap of 5G).
148
+ }
145
+ #
149
+ }
146
+ # However, we can only do this for modes that don't preallocate data
150
+}
147
+ # because otherwise we might run out of space on the test host.
151
+{ "execute" : "qom-get",
148
+ #
152
+ "arguments" : {
149
+ # We also want to test some unaligned combinations.
153
+ "path" : "group0",
150
+ for (prealloc, base_size, top_size_old, top_size_new, off) in [
154
+ "property" : "limits"
151
+ ('off', '6G', '1G', '8G', '5G'),
155
+ }
152
+ ('metadata', '32G', '30G', '33G', '31G'),
156
+}
153
+ ('falloc', '10M', '5M', '15M', '9M'),
157
+{ "execute": "quit" }
154
+ ('full', '16M', '8M', '12M', '11M'),
158
+EOF
155
+ ('off', '384k', '253k', '512k', '253k'),
159
+
156
+ ('off', '400k', '256k', '512k', '336k'),
160
+echo
157
+ ('off', '512k', '256k', '500k', '436k')]:
161
+echo "== object creation/set errors =="
158
+
162
+
159
+ iotests.log('=== preallocation=%s ===' % prealloc)
163
+run_qemu <<EOF
160
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, base, base_size)
164
+{ "execute": "qmp_capabilities" }
161
+ iotests.qemu_img_log('create', '-f', iotests.imgfmt, '-b', base, top,
165
+{ "execute": "object-add",
162
+ top_size_old)
166
+ "arguments": {
163
+ iotests.qemu_io_log('-c', 'write -P 1 %s 64k' % off, base)
167
+ "qom-type": "throttle-group",
164
+
168
+ "id": "group0",
165
+ # After this, top_size_old to base_size should be allocated/zeroed.
169
+ "props" : {
166
+ #
170
+ "limits": {
167
+ # In theory, leaving base_size to top_size_new unallocated would be
171
+ "iops-total": 1000
168
+ # correct, but in practice, if we zero out anything, we zero out
172
+ }
169
+ # everything up to top_size_new.
173
+ }
170
+ iotests.qemu_img_log('resize', '-f', iotests.imgfmt,
174
+ }
171
+ '--preallocation', prealloc, top, top_size_new)
175
+}
172
+ iotests.qemu_io_log('-c', 'read -P 0 %s 64k' % off, top)
176
+{ "execute" : "qom-set",
173
+ iotests.qemu_io_log('-c', 'map', top)
177
+ "arguments" : {
174
+ iotests.qemu_img_log('map', '--output=json', top)
178
+ "path" : "group0",
175
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
179
+ "property" : "x-iops-total",
180
+ "value" : 0
181
+ }
182
+}
183
+{ "execute" : "qom-set",
184
+ "arguments" : {
185
+ "path" : "group0",
186
+ "property" : "limits",
187
+ "value" : {
188
+ "iops-total" : 10,
189
+ "iops-read" : 10
190
+ }
191
+ }
192
+}
193
+{ "execute": "quit" }
194
+EOF
195
+
196
+echo
197
+echo "== don't specify group =="
198
+
199
+run_qemu <<EOF
200
+{ "execute": "qmp_capabilities" }
201
+{ "execute": "blockdev-add",
202
+ "arguments": {
203
+ "driver": "$IMGFMT",
204
+ "node-name": "disk0",
205
+ "file": {
206
+ "driver": "file",
207
+ "filename": "$TEST_IMG"
208
+ }
209
+ }
210
+}
211
+{ "execute": "blockdev-add",
212
+ "arguments": {
213
+ "driver": "throttle",
214
+ "node-name": "throttle0",
215
+ "file": "disk0"
216
+ }
217
+}
218
+{ "execute": "quit" }
219
+EOF
220
+
221
+echo
222
+# success, all done
223
+echo "*** done"
224
+rm -f $seq.full
225
+status=0
226
diff --git a/tests/qemu-iotests/184.out b/tests/qemu-iotests/184.out
227
new file mode 100644
176
new file mode 100644
228
index XXXXXXX..XXXXXXX
177
index XXXXXXX..XXXXXXX
229
--- /dev/null
178
--- /dev/null
230
+++ b/tests/qemu-iotests/184.out
179
+++ b/tests/qemu-iotests/274.out
231
@@ -XXX,XX +XXX,XX @@
180
@@ -XXX,XX +XXX,XX @@
232
+QA output created by 184
181
+== Commit tests ==
233
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
182
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
234
+
183
+
235
+== checking interface ==
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
236
+Testing:
185
+
237
+{
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
238
+ QMP_VERSION
187
+
239
+}
188
+wrote 2097152/2097152 bytes at offset 0
240
+{
189
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
241
+ "return": {
190
+
242
+ }
191
+=== Check visible data ===
243
+}
192
+read 1048576/1048576 bytes at offset 0
244
+{
193
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
245
+ "return": {
194
+
246
+ }
195
+read 1048576/1048576 bytes at offset 1048576
247
+}
196
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
248
+{
197
+
249
+ "return": {
198
+=== Checking allocation status ===
250
+ }
199
+1048576/1048576 bytes allocated at offset 0 bytes
251
+}
200
+1048576/1048576 bytes allocated at offset 1 MiB
252
+{
201
+
253
+ "return": {
202
+0/1048576 bytes allocated at offset 0 bytes
254
+ }
203
+0/0 bytes allocated at offset 1 MiB
255
+}
204
+
256
+{
205
+0/1048576 bytes allocated at offset 0 bytes
257
+ "return": [
206
+0/1048576 bytes allocated at offset 1 MiB
258
+ {
207
+
259
+ "iops_rd": 0,
208
+=== Checking map ===
260
+ "detect_zeroes": "off",
209
+[{ "start": 0, "length": 2097152, "depth": 0, "zero": false, "data": true, "offset": 327680}]
261
+ "image": {
210
+
262
+ "virtual-size": 67108864,
211
+Offset Length Mapped to File
263
+ "filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
212
+0 0x200000 0x50000 TEST_DIR/PID-base
264
+ "cluster-size": 65536,
213
+
265
+ "format": "throttle",
214
+[{ "start": 0, "length": 1048576, "depth": 1, "zero": false, "data": true, "offset": 327680}]
266
+ "actual-size": 200704,
215
+
267
+ "dirty-flag": false
216
+Offset Length Mapped to File
268
+ },
217
+0 0x100000 0x50000 TEST_DIR/PID-base
269
+ "iops_wr": 0,
218
+
270
+ "ro": false,
219
+[{ "start": 0, "length": 1048576, "depth": 2, "zero": false, "data": true, "offset": 327680},
271
+ "node-name": "throttle0",
220
+{ "start": 1048576, "length": 1048576, "depth": 0, "zero": true, "data": false}]
272
+ "backing_file_depth": 0,
221
+
273
+ "drv": "throttle",
222
+Offset Length Mapped to File
274
+ "iops": 0,
223
+0 0x100000 0x50000 TEST_DIR/PID-base
275
+ "bps_wr": 0,
224
+
276
+ "write_threshold": 0,
225
+=== Testing qemu-img commit (top -> mid) ===
277
+ "encrypted": false,
226
+Image committed.
278
+ "bps": 0,
227
+
279
+ "bps_rd": 0,
228
+image: TEST_IMG
280
+ "cache": {
229
+file format: IMGFMT
281
+ "no-flush": false,
230
+virtual size: 2 MiB (2097152 bytes)
282
+ "direct": false,
231
+cluster_size: 65536
283
+ "writeback": true
232
+backing file: TEST_DIR/PID-base
284
+ },
233
+Format specific information:
285
+ "file": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
234
+ compat: 1.1
286
+ "encryption_key_missing": false
235
+ lazy refcounts: false
287
+ },
236
+ refcount bits: 16
288
+ {
237
+ corrupt: false
289
+ "iops_rd": 0,
238
+
290
+ "detect_zeroes": "off",
239
+read 1048576/1048576 bytes at offset 0
291
+ "image": {
240
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
292
+ "virtual-size": 67108864,
241
+
293
+ "filename": "TEST_DIR/t.qcow2",
242
+read 1048576/1048576 bytes at offset 1048576
294
+ "cluster-size": 65536,
243
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
295
+ "format": "qcow2",
244
+
296
+ "actual-size": 200704,
245
+=== Testing HMP commit (top -> mid) ===
297
+ "format-specific": {
246
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
298
+ "type": "qcow2",
247
+
299
+ "data": {
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
300
+ "compat": "1.1",
249
+
301
+ "lazy-refcounts": false,
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
302
+ "refcount-bits": 16,
251
+
303
+ "corrupt": false
252
+wrote 2097152/2097152 bytes at offset 0
304
+ }
253
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
305
+ },
254
+
306
+ "dirty-flag": false
255
+{"execute": "human-monitor-command", "arguments": {"command-line": "commit drive0"}}
307
+ },
256
+{"return": ""}
308
+ "iops_wr": 0,
257
+image: TEST_IMG
309
+ "ro": false,
258
+file format: IMGFMT
310
+ "node-name": "disk0",
259
+virtual size: 2 MiB (2097152 bytes)
311
+ "backing_file_depth": 0,
260
+cluster_size: 65536
312
+ "drv": "qcow2",
261
+backing file: TEST_DIR/PID-base
313
+ "iops": 0,
262
+Format specific information:
314
+ "bps_wr": 0,
263
+ compat: 1.1
315
+ "write_threshold": 0,
264
+ lazy refcounts: false
316
+ "encrypted": false,
265
+ refcount bits: 16
317
+ "bps": 0,
266
+ corrupt: false
318
+ "bps_rd": 0,
267
+
319
+ "cache": {
268
+read 1048576/1048576 bytes at offset 0
320
+ "no-flush": false,
269
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
321
+ "direct": false,
270
+
322
+ "writeback": true
271
+read 1048576/1048576 bytes at offset 1048576
323
+ },
272
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
324
+ "file": "TEST_DIR/t.qcow2",
273
+
325
+ "encryption_key_missing": false
274
+=== Testing QMP active commit (top -> mid) ===
326
+ },
275
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=2097152 cluster_size=65536 lazy_refcounts=off refcount_bits=16
327
+ {
276
+
328
+ "iops_rd": 0,
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
329
+ "detect_zeroes": "off",
278
+
330
+ "image": {
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
331
+ "virtual-size": 197120,
280
+
332
+ "filename": "TEST_DIR/t.qcow2",
281
+wrote 2097152/2097152 bytes at offset 0
333
+ "format": "file",
282
+2 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
334
+ "actual-size": 200704,
283
+
335
+ "dirty-flag": false
284
+{"execute": "block-commit", "arguments": {"auto-dismiss": false, "base-node": "mid", "device": "top", "job-id": "job0"}}
336
+ },
285
+{"return": {}}
337
+ "iops_wr": 0,
286
+{"execute": "job-complete", "arguments": {"id": "job0"}}
338
+ "ro": false,
287
+{"return": {}}
339
+ "node-name": "NODE_NAME",
288
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_READY", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
340
+ "backing_file_depth": 0,
289
+{"data": {"device": "job0", "len": 0, "offset": 0, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
341
+ "drv": "file",
290
+{"execute": "job-dismiss", "arguments": {"id": "job0"}}
342
+ "iops": 0,
291
+{"return": {}}
343
+ "bps_wr": 0,
292
+image: TEST_IMG
344
+ "write_threshold": 0,
293
+file format: IMGFMT
345
+ "encrypted": false,
294
+virtual size: 2 MiB (2097152 bytes)
346
+ "bps": 0,
295
+cluster_size: 65536
347
+ "bps_rd": 0,
296
+backing file: TEST_DIR/PID-base
348
+ "cache": {
297
+Format specific information:
349
+ "no-flush": false,
298
+ compat: 1.1
350
+ "direct": false,
299
+ lazy refcounts: false
351
+ "writeback": true
300
+ refcount bits: 16
352
+ },
301
+ corrupt: false
353
+ "file": "TEST_DIR/t.qcow2",
302
+
354
+ "encryption_key_missing": false
303
+read 1048576/1048576 bytes at offset 0
355
+ }
304
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
356
+ ]
305
+
357
+}
306
+read 1048576/1048576 bytes at offset 1048576
358
+{
307
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
359
+ "return": [
308
+
360
+ ]
309
+== Resize tests ==
361
+}
310
+=== preallocation=off ===
362
+{
311
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=6442450944 cluster_size=65536 lazy_refcounts=off refcount_bits=16
363
+ "return": {
312
+
364
+ }
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
365
+}
314
+
366
+{
315
+wrote 65536/65536 bytes at offset 5368709120
367
+ "timestamp": {
316
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
368
+ "seconds": TIMESTAMP,
317
+
369
+ "microseconds": TIMESTAMP
318
+Image resized.
370
+ },
319
+
371
+ "event": "SHUTDOWN",
320
+read 65536/65536 bytes at offset 5368709120
372
+ "data": {
321
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
373
+ "guest": false
322
+
374
+ }
323
+1 GiB (0x40000000) bytes not allocated at offset 0 bytes (0x0)
375
+}
324
+7 GiB (0x1c0000000) bytes allocated at offset 1 GiB (0x40000000)
376
+
325
+
377
+
326
+[{ "start": 0, "length": 1073741824, "depth": 1, "zero": true, "data": false},
378
+== property changes in ThrottleGroup ==
327
+{ "start": 1073741824, "length": 7516192768, "depth": 0, "zero": true, "data": false}]
379
+Testing:
328
+
380
+{
329
+=== preallocation=metadata ===
381
+ QMP_VERSION
330
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=34359738368 cluster_size=65536 lazy_refcounts=off refcount_bits=16
382
+}
331
+
383
+{
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
384
+ "return": {
333
+
385
+ }
334
+wrote 65536/65536 bytes at offset 33285996544
386
+}
335
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
387
+{
336
+
388
+ "return": {
337
+Image resized.
389
+ }
338
+
390
+}
339
+read 65536/65536 bytes at offset 33285996544
391
+{
340
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
392
+ "return": {
341
+
393
+ "bps-read-max-length": 1,
342
+30 GiB (0x780000000) bytes not allocated at offset 0 bytes (0x0)
394
+ "iops-read-max-length": 1,
343
+3 GiB (0xc0000000) bytes allocated at offset 30 GiB (0x780000000)
395
+ "bps-read-max": 0,
344
+
396
+ "bps-total": 0,
345
+[{ "start": 0, "length": 32212254720, "depth": 1, "zero": true, "data": false},
397
+ "iops-total-max-length": 1,
346
+{ "start": 32212254720, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 327680},
398
+ "iops-total": 1000,
347
+{ "start": 32749125632, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 537264128},
399
+ "iops-write-max": 0,
348
+{ "start": 33285996544, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1074200576},
400
+ "bps-write": 0,
349
+{ "start": 33822867456, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 1611137024},
401
+ "bps-total-max": 0,
350
+{ "start": 34359738368, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2148139008},
402
+ "bps-write-max": 0,
351
+{ "start": 34896609280, "length": 536870912, "depth": 0, "zero": true, "data": false, "offset": 2685075456}]
403
+ "iops-size": 0,
352
+
404
+ "iops-read": 0,
353
+=== preallocation=falloc ===
405
+ "iops-write-max-length": 1,
354
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=10485760 cluster_size=65536 lazy_refcounts=off refcount_bits=16
406
+ "iops-write": 0,
355
+
407
+ "bps-total-max-length": 1,
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
408
+ "iops-read-max": 0,
357
+
409
+ "bps-read": 0,
358
+wrote 65536/65536 bytes at offset 9437184
410
+ "bps-write-max-length": 1,
359
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
411
+ "iops-total-max": 0
360
+
412
+ }
361
+Image resized.
413
+}
362
+
414
+{
363
+read 65536/65536 bytes at offset 9437184
415
+ "return": {
364
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
416
+ }
365
+
417
+}
366
+5 MiB (0x500000) bytes not allocated at offset 0 bytes (0x0)
418
+{
367
+10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
419
+ "return": {
368
+
420
+ "bps-read-max-length": 1,
369
+[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
421
+ "iops-read-max-length": 1,
370
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
422
+ "bps-read-max": 0,
371
+
423
+ "bps-total": 0,
372
+=== preallocation=full ===
424
+ "iops-total-max-length": 1,
373
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
425
+ "iops-total": 0,
374
+
426
+ "iops-write-max": 0,
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
427
+ "bps-write": 0,
376
+
428
+ "bps-total-max": 0,
377
+wrote 65536/65536 bytes at offset 11534336
429
+ "bps-write-max": 0,
378
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
430
+ "iops-size": 0,
379
+
431
+ "iops-read": 0,
380
+Image resized.
432
+ "iops-write-max-length": 1,
381
+
433
+ "iops-write": 0,
382
+read 65536/65536 bytes at offset 11534336
434
+ "bps-total-max-length": 1,
383
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
435
+ "iops-read-max": 0,
384
+
436
+ "bps-read": 0,
385
+8 MiB (0x800000) bytes not allocated at offset 0 bytes (0x0)
437
+ "bps-write-max-length": 1,
386
+4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
438
+ "iops-total-max": 0
387
+
439
+ }
388
+[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
440
+}
389
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
441
+{
390
+
442
+ "return": {
391
+=== preallocation=off ===
443
+ }
392
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
444
+}
393
+
445
+{
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
446
+ "timestamp": {
395
+
447
+ "seconds": TIMESTAMP,
396
+wrote 65536/65536 bytes at offset 259072
448
+ "microseconds": TIMESTAMP
397
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
449
+ },
398
+
450
+ "event": "SHUTDOWN",
399
+Image resized.
451
+ "data": {
400
+
452
+ "guest": false
401
+read 65536/65536 bytes at offset 259072
453
+ }
402
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
454
+}
403
+
455
+
404
+192 KiB (0x30000) bytes not allocated at offset 0 bytes (0x0)
456
+
405
+320 KiB (0x50000) bytes allocated at offset 192 KiB (0x30000)
457
+== object creation/set errors ==
406
+
458
+Testing:
407
+[{ "start": 0, "length": 196608, "depth": 1, "zero": true, "data": false},
459
+{
408
+{ "start": 196608, "length": 65536, "depth": 0, "zero": false, "data": true, "offset": 327680},
460
+ QMP_VERSION
409
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
461
+}
410
+
462
+{
411
+=== preallocation=off ===
463
+ "return": {
412
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=409600 cluster_size=65536 lazy_refcounts=off refcount_bits=16
464
+ }
413
+
465
+}
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
466
+{
415
+
467
+ "return": {
416
+wrote 65536/65536 bytes at offset 344064
468
+ }
417
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
469
+}
418
+
470
+{
419
+Image resized.
471
+ "error": {
420
+
472
+ "class": "GenericError",
421
+read 65536/65536 bytes at offset 344064
473
+ "desc": "Property cannot be set after initialization"
422
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
474
+ }
423
+
475
+}
424
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
476
+{
425
+256 KiB (0x40000) bytes allocated at offset 256 KiB (0x40000)
477
+ "error": {
426
+
478
+ "class": "GenericError",
427
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
479
+ "desc": "bps/iops/max total values and read/write values cannot be used at the same time"
428
+{ "start": 262144, "length": 262144, "depth": 0, "zero": true, "data": false}]
480
+ }
429
+
481
+}
430
+=== preallocation=off ===
482
+{
431
+Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=524288 cluster_size=65536 lazy_refcounts=off refcount_bits=16
483
+ "return": {
432
+
484
+ }
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
485
+}
434
+
486
+{
435
+wrote 65536/65536 bytes at offset 446464
487
+ "timestamp": {
436
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
488
+ "seconds": TIMESTAMP,
437
+
489
+ "microseconds": TIMESTAMP
438
+Image resized.
490
+ },
439
+
491
+ "event": "SHUTDOWN",
440
+read 65536/65536 bytes at offset 446464
492
+ "data": {
441
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
493
+ "guest": false
442
+
494
+ }
443
+256 KiB (0x40000) bytes not allocated at offset 0 bytes (0x0)
495
+}
444
+244 KiB (0x3d000) bytes allocated at offset 256 KiB (0x40000)
496
+
445
+
497
+
446
+[{ "start": 0, "length": 262144, "depth": 1, "zero": true, "data": false},
498
+== don't specify group ==
447
+{ "start": 262144, "length": 249856, "depth": 0, "zero": true, "data": false}]
499
+Testing:
448
+
500
+{
501
+ QMP_VERSION
502
+}
503
+{
504
+ "return": {
505
+ }
506
+}
507
+{
508
+ "return": {
509
+ }
510
+}
511
+{
512
+ "error": {
513
+ "class": "GenericError",
514
+ "desc": "Parameter 'throttle-group' is missing"
515
+ }
516
+}
517
+{
518
+ "return": {
519
+ }
520
+}
521
+{
522
+ "timestamp": {
523
+ "seconds": TIMESTAMP,
524
+ "microseconds": TIMESTAMP
525
+ },
526
+ "event": "SHUTDOWN",
527
+ "data": {
528
+ "guest": false
529
+ }
530
+}
531
+
532
+
533
+*** done
534
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
535
index XXXXXXX..XXXXXXX 100644
450
index XXXXXXX..XXXXXXX 100644
536
--- a/tests/qemu-iotests/group
451
--- a/tests/qemu-iotests/group
537
+++ b/tests/qemu-iotests/group
452
+++ b/tests/qemu-iotests/group
538
@@ -XXX,XX +XXX,XX @@
453
@@ -XXX,XX +XXX,XX @@
539
181 rw auto migration
454
270 rw backing quick
540
182 rw auto quick
455
272 rw
541
183 rw auto migration
456
273 backing quick
542
+184 rw auto quick
457
+274 rw backing
543
185 rw auto
458
277 rw quick
544
186 rw auto
459
279 rw backing quick
545
187 rw auto
460
280 rw migration quick
546
--
461
--
547
2.13.5
462
2.25.3
548
463
549
464
diff view generated by jsdifflib
1
From: Pavel Butsykin <pbutsykin@virtuozzo.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
After calling qcow2_inactivate(), all qcow2 caches must be flushed, but this
7
Instead, try to forward the BDRV_REQ_ZERO_WRITE to the protocol driver,
4
may not happen, because the last call qcow2_store_persistent_dirty_bitmaps()
8
and if the protocol driver can ensure that the new area reads as zeros,
5
can lead to marking l2/refcont cache as dirty.
9
we can skip setting the zero flag in the qcow2 layer.
6
10
7
Let's move qcow2_store_persistent_dirty_bitmaps() before the caсhe flushing
11
Unfortunately, the same approach doesn't work for metadata
8
to fix it.
12
preallocation, so we'll still set the zero flag there.
9
13
10
Cc: qemu-stable@nongnu.org
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.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>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
19
---
14
block/qcow2.c | 16 ++++++++--------
20
block/qcow2.c | 22 +++++++++++++++++++---
15
1 file changed, 8 insertions(+), 8 deletions(-)
21
tests/qemu-iotests/274.out | 4 ++--
22
2 files changed, 21 insertions(+), 5 deletions(-)
16
23
17
diff --git a/block/qcow2.c b/block/qcow2.c
24
diff --git a/block/qcow2.c b/block/qcow2.c
18
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2.c
26
--- a/block/qcow2.c
20
+++ b/block/qcow2.c
27
+++ b/block/qcow2.c
21
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
28
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn qcow2_co_truncate(BlockDriverState *bs, int64_t offset,
22
int ret, result = 0;
29
/* Allocate the data area */
23
Error *local_err = NULL;
30
new_file_size = allocation_start +
24
31
nb_new_data_clusters * s->cluster_size;
25
+ qcow2_store_persistent_dirty_bitmaps(bs, &local_err);
32
- /* Image file grows, so @exact does not matter */
26
+ if (local_err != NULL) {
33
- ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
27
+ result = -EINVAL;
34
- errp);
28
+ error_report_err(local_err);
35
+ /*
29
+ error_report("Persistent bitmaps are lost for node '%s'",
36
+ * Image file grows, so @exact does not matter.
30
+ bdrv_get_device_or_node_name(bs));
37
+ *
31
+ }
38
+ * If we need to zero out the new area, try first whether the protocol
32
+
39
+ * driver can already take care of this.
33
ret = qcow2_cache_flush(bs, s->l2_table_cache);
40
+ */
34
if (ret) {
41
+ if (flags & BDRV_REQ_ZERO_WRITE) {
35
result = ret;
42
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc,
36
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
43
+ BDRV_REQ_ZERO_WRITE, NULL);
37
strerror(-ret));
44
+ if (ret >= 0) {
38
}
45
+ flags &= ~BDRV_REQ_ZERO_WRITE;
39
46
+ }
40
- qcow2_store_persistent_dirty_bitmaps(bs, &local_err);
47
+ } else {
41
- if (local_err != NULL) {
48
+ ret = -1;
42
- result = -EINVAL;
49
+ }
43
- error_report_err(local_err);
50
+ if (ret < 0) {
44
- error_report("Persistent bitmaps are lost for node '%s'",
51
+ ret = bdrv_co_truncate(bs->file, new_file_size, false, prealloc, 0,
45
- bdrv_get_device_or_node_name(bs));
52
+ errp);
46
- }
53
+ }
47
-
54
if (ret < 0) {
48
if (result == 0) {
55
error_prepend(errp, "Failed to resize underlying file: ");
49
qcow2_mark_clean(bs);
56
qcow2_free_clusters(bs, allocation_start,
50
}
57
diff --git a/tests/qemu-iotests/274.out b/tests/qemu-iotests/274.out
58
index XXXXXXX..XXXXXXX 100644
59
--- a/tests/qemu-iotests/274.out
60
+++ b/tests/qemu-iotests/274.out
61
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 9437184
62
10 MiB (0xa00000) bytes allocated at offset 5 MiB (0x500000)
63
64
[{ "start": 0, "length": 5242880, "depth": 1, "zero": true, "data": false},
65
-{ "start": 5242880, "length": 10485760, "depth": 0, "zero": true, "data": false, "offset": 327680}]
66
+{ "start": 5242880, "length": 10485760, "depth": 0, "zero": false, "data": true, "offset": 327680}]
67
68
=== preallocation=full ===
69
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=16777216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
70
@@ -XXX,XX +XXX,XX @@ read 65536/65536 bytes at offset 11534336
71
4 MiB (0x400000) bytes allocated at offset 8 MiB (0x800000)
72
73
[{ "start": 0, "length": 8388608, "depth": 1, "zero": true, "data": false},
74
-{ "start": 8388608, "length": 4194304, "depth": 0, "zero": true, "data": false, "offset": 327680}]
75
+{ "start": 8388608, "length": 4194304, "depth": 0, "zero": false, "data": true, "offset": 327680}]
76
77
=== preallocation=off ===
78
Formatting 'TEST_DIR/PID-base', fmt=qcow2 size=393216 cluster_size=65536 lazy_refcounts=off refcount_bits=16
51
--
79
--
52
2.13.5
80
2.25.3
53
81
54
82
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
2
2
3
block/throttle.c uses existing I/O throttle infrastructure inside a
3
This patch introduces support for PMR that has been defined as part of NVMe 1.4
4
block filter driver. I/O operations are intercepted in the filter's
4
spec. User can now specify a pmrdev option that should point to HostMemoryBackend.
5
read/write coroutines, and referred to block/throttle-groups.c
5
pmrdev memory region will subsequently be exposed as PCI BAR 2 in emulated NVMe
6
device. Guest OS can perform mmio read and writes to the PMR region that will stay
7
persistent across system reboot.
6
8
7
The driver can be used with the syntax
9
Signed-off-by: Andrzej Jakowski <andrzej.jakowski@linux.intel.com>
8
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar
10
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
9
10
which registers the throttle filter node with the ThrottleGroup 'bar'. The
11
given group must be created beforehand with object-add or -object.
12
13
Reviewed-by: Alberto Garcia <berto@igalia.com>
14
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Message-Id: <20200330164656.9348-1-andrzej.jakowski@linux.intel.com>
13
Reviewed-by: Keith Busch <kbusch@kernel.org>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
15
---
18
qapi/block-core.json | 18 ++-
16
hw/block/nvme.h | 2 +
19
include/block/throttle-groups.h | 5 +
17
include/block/nvme.h | 172 +++++++++++++++++++++++++++++++++++++++++
20
include/qemu/throttle-options.h | 1 +
18
hw/block/nvme.c | 109 ++++++++++++++++++++++++++
21
block/throttle-groups.c | 15 ++-
19
hw/block/Makefile.objs | 2 +-
22
block/throttle.c | 237 ++++++++++++++++++++++++++++++++++++++++
20
hw/block/trace-events | 4 +
23
block/Makefile.objs | 1 +
21
5 files changed, 288 insertions(+), 1 deletion(-)
24
6 files changed, 275 insertions(+), 2 deletions(-)
25
create mode 100644 block/throttle.c
26
22
27
diff --git a/qapi/block-core.json b/qapi/block-core.json
23
diff --git a/hw/block/nvme.h b/hw/block/nvme.h
28
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
29
--- a/qapi/block-core.json
25
--- a/hw/block/nvme.h
30
+++ b/qapi/block-core.json
26
+++ b/hw/block/nvme.h
27
@@ -XXX,XX +XXX,XX @@ typedef struct NvmeCtrl {
28
uint64_t timestamp_set_qemu_clock_ms; /* QEMU clock time */
29
30
char *serial;
31
+ HostMemoryBackend *pmrdev;
32
+
33
NvmeNamespace *namespaces;
34
NvmeSQueue **sq;
35
NvmeCQueue **cq;
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
31
@@ -XXX,XX +XXX,XX @@
251
@@ -XXX,XX +XXX,XX @@
32
# Drivers that are supported in block device operations.
252
* -drive file=<file>,if=none,id=<drive_id>
33
#
253
* -device nvme,drive=<drive_id>,serial=<serial>,id=<id[optional]>, \
34
# @vxhs: Since 2.10
254
* cmb_size_mb=<cmb_size_mb[optional]>, \
35
+# @throttle: Since 2.11
255
+ * [pmrdev=<mem_backend_file_id>,] \
36
#
256
* num_queues=<N[optional]>
37
# Since: 2.9
257
*
38
##
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"
39
@@ -XXX,XX +XXX,XX @@
271
@@ -XXX,XX +XXX,XX @@
40
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
272
#include "sysemu/sysemu.h"
41
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
273
#include "qapi/error.h"
42
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
274
#include "qapi/visitor.h"
43
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
275
+#include "sysemu/hostmem.h"
44
+ 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
276
#include "sysemu/block-backend.h"
45
277
+#include "exec/ram_addr.h"
46
##
278
47
# @BlockdevOptionsFile:
279
#include "qemu/log.h"
48
@@ -XXX,XX +XXX,XX @@
280
#include "qemu/module.h"
49
'*tls-creds': 'str' } }
281
@@ -XXX,XX +XXX,XX @@ static void nvme_write_bar(NvmeCtrl *n, hwaddr offset, uint64_t data,
50
282
NVME_GUEST_ERR(nvme_ub_mmiowr_cmbsz_readonly,
51
##
283
"invalid write to read only CMBSZ, ignored");
52
+# @BlockdevOptionsThrottle:
284
return;
53
+#
285
+ case 0xE00: /* PMRCAP */
54
+# Driver specific block device options for the throttle driver
286
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrcap_readonly,
55
+#
287
+ "invalid write to PMRCAP register, ignored");
56
+# @throttle-group: the name of the throttle-group object to use. It
57
+# must already exist.
58
+# @file: reference to or definition of the data source block device
59
+# Since: 2.11
60
+##
61
+{ 'struct': 'BlockdevOptionsThrottle',
62
+ 'data': { 'throttle-group': 'str',
63
+ 'file' : 'BlockdevRef'
64
+ } }
65
+##
66
# @BlockdevOptions:
67
#
68
# Options for creating a block device. Many options are available for all
69
@@ -XXX,XX +XXX,XX @@
70
'replication':'BlockdevOptionsReplication',
71
'sheepdog': 'BlockdevOptionsSheepdog',
72
'ssh': 'BlockdevOptionsSsh',
73
+ 'throttle': 'BlockdevOptionsThrottle',
74
'vdi': 'BlockdevOptionsGenericFormat',
75
'vhdx': 'BlockdevOptionsGenericFormat',
76
'vmdk': 'BlockdevOptionsGenericCOWFormat',
77
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
78
index XXXXXXX..XXXXXXX 100644
79
--- a/include/block/throttle-groups.h
80
+++ b/include/block/throttle-groups.h
81
@@ -XXX,XX +XXX,XX @@ void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
82
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
83
AioContext *new_context);
84
void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
85
+/*
86
+ * throttle_group_exists() must be called under the global
87
+ * mutex.
88
+ */
89
+bool throttle_group_exists(const char *name);
90
91
#endif
92
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
93
index XXXXXXX..XXXXXXX 100644
94
--- a/include/qemu/throttle-options.h
95
+++ b/include/qemu/throttle-options.h
96
@@ -XXX,XX +XXX,XX @@
97
#define QEMU_OPT_BPS_WRITE_MAX "bps-write-max"
98
#define QEMU_OPT_BPS_WRITE_MAX_LENGTH "bps-write-max-length"
99
#define QEMU_OPT_IOPS_SIZE "iops-size"
100
+#define QEMU_OPT_THROTTLE_GROUP_NAME "throttle-group"
101
102
#define THROTTLE_OPT_PREFIX "throttling."
103
#define THROTTLE_OPTS \
104
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
105
index XXXXXXX..XXXXXXX 100644
106
--- a/block/throttle-groups.c
107
+++ b/block/throttle-groups.c
108
@@ -XXX,XX +XXX,XX @@ static ThrottleGroup *throttle_group_by_name(const char *name)
109
return NULL;
110
}
111
112
+/* This function reads throttle_groups and must be called under the global
113
+ * mutex.
114
+ */
115
+bool throttle_group_exists(const char *name)
116
+{
117
+ return throttle_group_by_name(name) != NULL;
118
+}
119
+
120
/* Increments the reference count of a ThrottleGroup given its name.
121
*
122
* If no ThrottleGroup is found with the given name a new one is
123
@@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
124
ThrottleGroupMember *token;
125
int i;
126
127
+ if (!ts) {
128
+ /* Discard already unregistered tgm */
129
+ return;
288
+ return;
130
+ }
289
+ case 0xE04: /* TODO PMRCTL */
131
+
290
+ break;
132
assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
291
+ case 0xE08: /* PMRSTS */
133
assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
292
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrsts_readonly,
134
assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
293
+ "invalid write to PMRSTS register, ignored");
135
@@ -XXX,XX +XXX,XX @@ static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
294
+ return;
136
assert(tg->name);
295
+ case 0xE0C: /* PMREBS */
137
296
+ NVME_GUEST_ERR(nvme_ub_mmiowr_pmrebs_readonly,
138
/* error if name is duplicate */
297
+ "invalid write to PMREBS register, ignored");
139
- if (throttle_group_by_name(tg->name) != NULL) {
298
+ return;
140
+ if (throttle_group_exists(tg->name)) {
299
+ case 0xE10: /* PMRSWTP */
141
error_setg(errp, "A group with this name already exists");
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)
309
}
310
311
if (addr < sizeof(n->bar)) {
312
+ /*
313
+ * When PMRWBM bit 1 is set then read from
314
+ * from PMRSTS should ensure prior writes
315
+ * made it to persistent media
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);
321
+ }
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");
142
return;
327
return;
143
}
328
}
144
diff --git a/block/throttle.c b/block/throttle.c
329
+
145
new file mode 100644
330
+ if (!n->cmb_size_mb && n->pmrdev) {
146
index XXXXXXX..XXXXXXX
331
+ if (host_memory_backend_is_mapped(n->pmrdev)) {
147
--- /dev/null
332
+ char *path = object_get_canonical_path_component(OBJECT(n->pmrdev));
148
+++ b/block/throttle.c
333
+ error_setg(errp, "can't use already busy memdev: %s", path);
149
@@ -XXX,XX +XXX,XX @@
334
+ g_free(path);
150
+/*
335
+ return;
151
+ * QEMU block throttling filter driver infrastructure
336
+ }
152
+ *
337
+
153
+ * Copyright (c) 2017 Manos Pitsidianakis
338
+ if (!is_power_of_2(n->pmrdev->size)) {
154
+ *
339
+ error_setg(errp, "pmr backend size needs to be power of 2 in size");
155
+ * This program is free software; you can redistribute it and/or
340
+ return;
156
+ * modify it under the terms of the GNU General Public License as
341
+ }
157
+ * published by the Free Software Foundation; either version 2 or
342
+
158
+ * (at your option) version 3 of the License.
343
+ host_memory_backend_set_mapped(n->pmrdev, true);
159
+ *
160
+ * This program is distributed in the hope that it will be useful,
161
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
162
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
163
+ * GNU General Public License for more details.
164
+ *
165
+ * You should have received a copy of the GNU General Public License
166
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
167
+ */
168
+
169
+#include "qemu/osdep.h"
170
+#include "block/throttle-groups.h"
171
+#include "qemu/throttle-options.h"
172
+#include "qapi/error.h"
173
+
174
+static QemuOptsList throttle_opts = {
175
+ .name = "throttle",
176
+ .head = QTAILQ_HEAD_INITIALIZER(throttle_opts.head),
177
+ .desc = {
178
+ {
179
+ .name = QEMU_OPT_THROTTLE_GROUP_NAME,
180
+ .type = QEMU_OPT_STRING,
181
+ .help = "Name of the throttle group",
182
+ },
183
+ { /* end of list */ }
184
+ },
185
+};
186
+
187
+static int throttle_configure_tgm(BlockDriverState *bs,
188
+ ThrottleGroupMember *tgm,
189
+ QDict *options, Error **errp)
190
+{
191
+ int ret;
192
+ const char *group_name;
193
+ Error *local_err = NULL;
194
+ QemuOpts *opts = qemu_opts_create(&throttle_opts, NULL, 0, &error_abort);
195
+
196
+ qemu_opts_absorb_qdict(opts, options, &local_err);
197
+ if (local_err) {
198
+ error_propagate(errp, local_err);
199
+ ret = -EINVAL;
200
+ goto fin;
201
+ }
344
+ }
202
+
345
+
203
+ group_name = qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME);
346
blkconf_blocksizes(&n->conf);
204
+ if (!group_name) {
347
if (!blkconf_apply_backend_options(&n->conf, blk_is_read_only(n->conf.blk),
205
+ error_setg(errp, "Please specify a throttle group");
348
false, errp)) {
206
+ ret = -EINVAL;
349
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
207
+ goto fin;
350
PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64 |
208
+ } else if (!throttle_group_exists(group_name)) {
351
PCI_BASE_ADDRESS_MEM_PREFETCH, &n->ctrl_mem);
209
+ error_setg(errp, "Throttle group '%s' does not exist", group_name);
352
210
+ ret = -EINVAL;
353
+ } else if (n->pmrdev) {
211
+ goto fin;
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);
398
}
399
400
for (i = 0; i < n->num_namespaces; i++) {
401
@@ -XXX,XX +XXX,XX @@ static void nvme_exit(PCIDevice *pci_dev)
402
if (n->cmb_size_mb) {
403
g_free(n->cmbuf);
404
}
405
+
406
+ if (n->pmrdev) {
407
+ host_memory_backend_set_mapped(n->pmrdev, false);
212
+ }
408
+ }
213
+
409
msix_uninit_exclusive_bar(pci_dev);
214
+ /* Register membership to group with name group_name */
410
}
215
+ throttle_group_register_tgm(tgm, group_name, bdrv_get_aio_context(bs));
411
216
+ ret = 0;
412
static Property nvme_props[] = {
217
+fin:
413
DEFINE_BLOCK_PROPERTIES(NvmeCtrl, conf),
218
+ qemu_opts_del(opts);
414
+ DEFINE_PROP_LINK("pmrdev", NvmeCtrl, pmrdev, TYPE_MEMORY_BACKEND,
219
+ return ret;
415
+ HostMemoryBackend *),
220
+}
416
DEFINE_PROP_STRING("serial", NvmeCtrl, serial),
221
+
417
DEFINE_PROP_UINT32("cmb_size_mb", NvmeCtrl, cmb_size_mb, 0),
222
+static int throttle_open(BlockDriverState *bs, QDict *options,
418
DEFINE_PROP_UINT32("num_queues", NvmeCtrl, num_queues, 64),
223
+ int flags, Error **errp)
419
diff --git a/hw/block/Makefile.objs b/hw/block/Makefile.objs
224
+{
225
+ ThrottleGroupMember *tgm = bs->opaque;
226
+
227
+ bs->file = bdrv_open_child(NULL, options, "file", bs,
228
+ &child_file, false, errp);
229
+ if (!bs->file) {
230
+ return -EINVAL;
231
+ }
232
+ bs->supported_write_flags = bs->file->bs->supported_write_flags;
233
+ bs->supported_zero_flags = bs->file->bs->supported_zero_flags;
234
+
235
+ return throttle_configure_tgm(bs, tgm, options, errp);
236
+}
237
+
238
+static void throttle_close(BlockDriverState *bs)
239
+{
240
+ ThrottleGroupMember *tgm = bs->opaque;
241
+ throttle_group_unregister_tgm(tgm);
242
+}
243
+
244
+
245
+static int64_t throttle_getlength(BlockDriverState *bs)
246
+{
247
+ return bdrv_getlength(bs->file->bs);
248
+}
249
+
250
+static int coroutine_fn throttle_co_preadv(BlockDriverState *bs,
251
+ uint64_t offset, uint64_t bytes,
252
+ QEMUIOVector *qiov, int flags)
253
+{
254
+
255
+ ThrottleGroupMember *tgm = bs->opaque;
256
+ throttle_group_co_io_limits_intercept(tgm, bytes, false);
257
+
258
+ return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
259
+}
260
+
261
+static int coroutine_fn throttle_co_pwritev(BlockDriverState *bs,
262
+ uint64_t offset, uint64_t bytes,
263
+ QEMUIOVector *qiov, int flags)
264
+{
265
+ ThrottleGroupMember *tgm = bs->opaque;
266
+ throttle_group_co_io_limits_intercept(tgm, bytes, true);
267
+
268
+ return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
269
+}
270
+
271
+static int coroutine_fn throttle_co_pwrite_zeroes(BlockDriverState *bs,
272
+ int64_t offset, int bytes,
273
+ BdrvRequestFlags flags)
274
+{
275
+ ThrottleGroupMember *tgm = bs->opaque;
276
+ throttle_group_co_io_limits_intercept(tgm, bytes, true);
277
+
278
+ return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
279
+}
280
+
281
+static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
282
+ int64_t offset, int bytes)
283
+{
284
+ ThrottleGroupMember *tgm = bs->opaque;
285
+ throttle_group_co_io_limits_intercept(tgm, bytes, true);
286
+
287
+ return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
288
+}
289
+
290
+static int throttle_co_flush(BlockDriverState *bs)
291
+{
292
+ return bdrv_co_flush(bs->file->bs);
293
+}
294
+
295
+static void throttle_detach_aio_context(BlockDriverState *bs)
296
+{
297
+ ThrottleGroupMember *tgm = bs->opaque;
298
+ throttle_group_detach_aio_context(tgm);
299
+}
300
+
301
+static void throttle_attach_aio_context(BlockDriverState *bs,
302
+ AioContext *new_context)
303
+{
304
+ ThrottleGroupMember *tgm = bs->opaque;
305
+ throttle_group_attach_aio_context(tgm, new_context);
306
+}
307
+
308
+static int throttle_reopen_prepare(BDRVReopenState *reopen_state,
309
+ BlockReopenQueue *queue, Error **errp)
310
+{
311
+ ThrottleGroupMember *tgm;
312
+
313
+ assert(reopen_state != NULL);
314
+ assert(reopen_state->bs != NULL);
315
+
316
+ reopen_state->opaque = g_new0(ThrottleGroupMember, 1);
317
+ tgm = reopen_state->opaque;
318
+
319
+ return throttle_configure_tgm(reopen_state->bs, tgm, reopen_state->options,
320
+ errp);
321
+}
322
+
323
+static void throttle_reopen_commit(BDRVReopenState *reopen_state)
324
+{
325
+ ThrottleGroupMember *old_tgm = reopen_state->bs->opaque;
326
+ ThrottleGroupMember *new_tgm = reopen_state->opaque;
327
+
328
+ throttle_group_unregister_tgm(old_tgm);
329
+ g_free(old_tgm);
330
+ reopen_state->bs->opaque = new_tgm;
331
+ reopen_state->opaque = NULL;
332
+}
333
+
334
+static void throttle_reopen_abort(BDRVReopenState *reopen_state)
335
+{
336
+ ThrottleGroupMember *tgm = reopen_state->opaque;
337
+
338
+ throttle_group_unregister_tgm(tgm);
339
+ g_free(tgm);
340
+ reopen_state->opaque = NULL;
341
+}
342
+
343
+static bool throttle_recurse_is_first_non_filter(BlockDriverState *bs,
344
+ BlockDriverState *candidate)
345
+{
346
+ return bdrv_recurse_is_first_non_filter(bs->file->bs, candidate);
347
+}
348
+
349
+static BlockDriver bdrv_throttle = {
350
+ .format_name = "throttle",
351
+ .protocol_name = "throttle",
352
+ .instance_size = sizeof(ThrottleGroupMember),
353
+
354
+ .bdrv_file_open = throttle_open,
355
+ .bdrv_close = throttle_close,
356
+ .bdrv_co_flush = throttle_co_flush,
357
+
358
+ .bdrv_child_perm = bdrv_filter_default_perms,
359
+
360
+ .bdrv_getlength = throttle_getlength,
361
+
362
+ .bdrv_co_preadv = throttle_co_preadv,
363
+ .bdrv_co_pwritev = throttle_co_pwritev,
364
+
365
+ .bdrv_co_pwrite_zeroes = throttle_co_pwrite_zeroes,
366
+ .bdrv_co_pdiscard = throttle_co_pdiscard,
367
+
368
+ .bdrv_recurse_is_first_non_filter = throttle_recurse_is_first_non_filter,
369
+
370
+ .bdrv_attach_aio_context = throttle_attach_aio_context,
371
+ .bdrv_detach_aio_context = throttle_detach_aio_context,
372
+
373
+ .bdrv_reopen_prepare = throttle_reopen_prepare,
374
+ .bdrv_reopen_commit = throttle_reopen_commit,
375
+ .bdrv_reopen_abort = throttle_reopen_abort,
376
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
377
+
378
+ .is_filter = true,
379
+};
380
+
381
+static void bdrv_throttle_init(void)
382
+{
383
+ bdrv_register(&bdrv_throttle);
384
+}
385
+
386
+block_init(bdrv_throttle_init);
387
diff --git a/block/Makefile.objs b/block/Makefile.objs
388
index XXXXXXX..XXXXXXX 100644
420
index XXXXXXX..XXXXXXX 100644
389
--- a/block/Makefile.objs
421
--- a/hw/block/Makefile.objs
390
+++ b/block/Makefile.objs
422
+++ b/hw/block/Makefile.objs
391
@@ -XXX,XX +XXX,XX @@ block-obj-y += accounting.o dirty-bitmap.o
423
@@ -XXX,XX +XXX,XX @@ common-obj-$(CONFIG_PFLASH_CFI02) += pflash_cfi02.o
392
block-obj-y += write-threshold.o
424
common-obj-$(CONFIG_XEN) += xen-block.o
393
block-obj-y += backup.o
425
common-obj-$(CONFIG_ECC) += ecc.o
394
block-obj-$(CONFIG_REPLICATION) += replication.o
426
common-obj-$(CONFIG_ONENAND) += onenand.o
395
+block-obj-y += throttle.o
427
-common-obj-$(CONFIG_NVME_PCI) += nvme.o
396
428
common-obj-$(CONFIG_SWIM) += swim.o
397
block-obj-y += crypto.o
429
398
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""
399
--
452
--
400
2.13.5
453
2.25.3
401
454
402
455
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
The QMP handler qmp_object_add() and the implementation of --object in
2
qemu-storage-daemon can share most of the code. Currently,
3
qemu-storage-daemon calls qmp_object_add(), but this is not correct
4
because different visitors need to be used.
2
5
3
ThrottleGroup is converted to an object. This will allow the future
6
As a first step towards a fix, make qmp_object_add() a wrapper around a
4
throttle block filter drive easy creation and configuration of throttle
7
new function user_creatable_add_dict() that can get an additional
5
groups in QMP and cli.
8
parameter. The handling of "props" is only required for compatibility
9
and not required for the qemu-storage-daemon command line, so it stays
10
in qmp_object_add().
6
11
7
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
8
struct for all throttle configuration needs in QMP.
9
10
ThrottleGroups can be created via CLI as
11
-object throttle-group,id=foo,x-iops-total=100,x-..
12
where x-* are individual limit properties. Since we can't add non-scalar
13
properties in -object this interface must be used instead. However,
14
setting these properties must be disabled after initialization because
15
certain combinations of limits are forbidden and thus configuration
16
changes should be done in one transaction. The individual properties
17
will go away when support for non-scalar values in CLI is implemented
18
and thus are marked as experimental.
19
20
ThrottleGroup also has a `limits` property that uses the ThrottleLimits
21
struct. It can be used to create ThrottleGroups or set the
22
configuration in existing groups as follows:
23
24
{ "execute": "object-add",
25
"arguments": {
26
"qom-type": "throttle-group",
27
"id": "foo",
28
"props" : {
29
"limits": {
30
"iops-total": 100
31
}
32
}
33
}
34
}
35
{ "execute" : "qom-set",
36
"arguments" : {
37
"path" : "foo",
38
"property" : "limits",
39
"value" : {
40
"iops-total" : 99
41
}
42
}
43
}
44
45
This also means a group's configuration can be fetched with qom-get.
46
47
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
48
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
49
Reviewed-by: Alberto Garcia <berto@igalia.com>
50
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
13
---
52
qapi/block-core.json | 48 +++++
14
include/qom/object_interfaces.h | 12 ++++++++++++
53
include/block/throttle-groups.h | 3 +
15
qom/object_interfaces.c | 27 +++++++++++++++++++++++++++
54
include/qemu/throttle-options.h | 59 ++++--
16
qom/qom-qmp-cmds.c | 24 +-----------------------
55
include/qemu/throttle.h | 3 +
17
3 files changed, 40 insertions(+), 23 deletions(-)
56
block/throttle-groups.c | 424 ++++++++++++++++++++++++++++++++++++----
57
tests/test-throttle.c | 1 +
58
util/throttle.c | 151 ++++++++++++++
59
7 files changed, 628 insertions(+), 61 deletions(-)
60
18
61
diff --git a/qapi/block-core.json b/qapi/block-core.json
19
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
62
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
63
--- a/qapi/block-core.json
21
--- a/include/qom/object_interfaces.h
64
+++ b/qapi/block-core.json
22
+++ b/include/qom/object_interfaces.h
23
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
24
const QDict *qdict,
25
Visitor *v, Error **errp);
26
27
+/**
28
+ * user_creatable_add_dict:
29
+ * @qdict: the object definition
30
+ * @errp: if an error occurs, a pointer to an area to store the error
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
65
@@ -XXX,XX +XXX,XX @@
46
@@ -XXX,XX +XXX,XX @@
66
'*iops_size': 'int', '*group': 'str' } }
47
#include "qapi/qmp/qerror.h"
67
48
#include "qapi/qmp/qjson.h"
68
##
49
#include "qapi/qmp/qstring.h"
69
+# @ThrottleLimits:
50
+#include "qapi/qobject-input-visitor.h"
70
+#
51
#include "qom/object_interfaces.h"
71
+# Limit parameters for throttling.
52
#include "qemu/help_option.h"
72
+# Since some limit combinations are illegal, limits should always be set in one
53
#include "qemu/module.h"
73
+# transaction. All fields are optional. When setting limits, if a field is
54
@@ -XXX,XX +XXX,XX @@ out:
74
+# missing the current value is not changed.
55
return obj;
75
+#
56
}
76
+# @iops-total: limit total I/O operations per second
57
77
+# @iops-total-max: I/O operations burst
58
+void user_creatable_add_dict(QDict *qdict, Error **errp)
78
+# @iops-total-max-length: length of the iops-total-max burst period, in seconds
59
+{
79
+# It must only be set if @iops-total-max is set as well.
60
+ Visitor *v;
80
+# @iops-read: limit read operations per second
61
+ Object *obj;
81
+# @iops-read-max: I/O operations read burst
62
+ g_autofree char *type = NULL;
82
+# @iops-read-max-length: length of the iops-read-max burst period, in seconds
63
+ g_autofree char *id = NULL;
83
+# It must only be set if @iops-read-max is set as well.
84
+# @iops-write: limit write operations per second
85
+# @iops-write-max: I/O operations write burst
86
+# @iops-write-max-length: length of the iops-write-max burst period, in seconds
87
+# It must only be set if @iops-write-max is set as well.
88
+# @bps-total: limit total bytes per second
89
+# @bps-total-max: total bytes burst
90
+# @bps-total-max-length: length of the bps-total-max burst period, in seconds.
91
+# It must only be set if @bps-total-max is set as well.
92
+# @bps-read: limit read bytes per second
93
+# @bps-read-max: total bytes read burst
94
+# @bps-read-max-length: length of the bps-read-max burst period, in seconds
95
+# It must only be set if @bps-read-max is set as well.
96
+# @bps-write: limit write bytes per second
97
+# @bps-write-max: total bytes write burst
98
+# @bps-write-max-length: length of the bps-write-max burst period, in seconds
99
+# It must only be set if @bps-write-max is set as well.
100
+# @iops-size: when limiting by iops max size of an I/O in bytes
101
+#
102
+# Since: 2.11
103
+##
104
+{ 'struct': 'ThrottleLimits',
105
+ 'data': { '*iops-total' : 'int', '*iops-total-max' : 'int',
106
+ '*iops-total-max-length' : 'int', '*iops-read' : 'int',
107
+ '*iops-read-max' : 'int', '*iops-read-max-length' : 'int',
108
+ '*iops-write' : 'int', '*iops-write-max' : 'int',
109
+ '*iops-write-max-length' : 'int', '*bps-total' : 'int',
110
+ '*bps-total-max' : 'int', '*bps-total-max-length' : 'int',
111
+ '*bps-read' : 'int', '*bps-read-max' : 'int',
112
+ '*bps-read-max-length' : 'int', '*bps-write' : 'int',
113
+ '*bps-write-max' : 'int', '*bps-write-max-length' : 'int',
114
+ '*iops-size' : 'int' } }
115
+
64
+
116
+##
65
+ type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
117
# @block-stream:
66
+ if (!type) {
118
#
67
+ error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
119
# Copy data from a backing file into a block device.
120
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
121
index XXXXXXX..XXXXXXX 100644
122
--- a/include/block/throttle-groups.h
123
+++ b/include/block/throttle-groups.h
124
@@ -XXX,XX +XXX,XX @@ typedef struct ThrottleGroupMember {
125
126
} ThrottleGroupMember;
127
128
+#define TYPE_THROTTLE_GROUP "throttle-group"
129
+#define THROTTLE_GROUP(obj) OBJECT_CHECK(ThrottleGroup, (obj), TYPE_THROTTLE_GROUP)
130
+
131
const char *throttle_group_get_name(ThrottleGroupMember *tgm);
132
133
ThrottleState *throttle_group_incref(const char *name);
134
diff --git a/include/qemu/throttle-options.h b/include/qemu/throttle-options.h
135
index XXXXXXX..XXXXXXX 100644
136
--- a/include/qemu/throttle-options.h
137
+++ b/include/qemu/throttle-options.h
138
@@ -XXX,XX +XXX,XX @@
139
#ifndef THROTTLE_OPTIONS_H
140
#define THROTTLE_OPTIONS_H
141
142
+#define QEMU_OPT_IOPS_TOTAL "iops-total"
143
+#define QEMU_OPT_IOPS_TOTAL_MAX "iops-total-max"
144
+#define QEMU_OPT_IOPS_TOTAL_MAX_LENGTH "iops-total-max-length"
145
+#define QEMU_OPT_IOPS_READ "iops-read"
146
+#define QEMU_OPT_IOPS_READ_MAX "iops-read-max"
147
+#define QEMU_OPT_IOPS_READ_MAX_LENGTH "iops-read-max-length"
148
+#define QEMU_OPT_IOPS_WRITE "iops-write"
149
+#define QEMU_OPT_IOPS_WRITE_MAX "iops-write-max"
150
+#define QEMU_OPT_IOPS_WRITE_MAX_LENGTH "iops-write-max-length"
151
+#define QEMU_OPT_BPS_TOTAL "bps-total"
152
+#define QEMU_OPT_BPS_TOTAL_MAX "bps-total-max"
153
+#define QEMU_OPT_BPS_TOTAL_MAX_LENGTH "bps-total-max-length"
154
+#define QEMU_OPT_BPS_READ "bps-read"
155
+#define QEMU_OPT_BPS_READ_MAX "bps-read-max"
156
+#define QEMU_OPT_BPS_READ_MAX_LENGTH "bps-read-max-length"
157
+#define QEMU_OPT_BPS_WRITE "bps-write"
158
+#define QEMU_OPT_BPS_WRITE_MAX "bps-write-max"
159
+#define QEMU_OPT_BPS_WRITE_MAX_LENGTH "bps-write-max-length"
160
+#define QEMU_OPT_IOPS_SIZE "iops-size"
161
+
162
+#define THROTTLE_OPT_PREFIX "throttling."
163
#define THROTTLE_OPTS \
164
{ \
165
- .name = "throttling.iops-total",\
166
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,\
167
.type = QEMU_OPT_NUMBER,\
168
.help = "limit total I/O operations per second",\
169
},{ \
170
- .name = "throttling.iops-read",\
171
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,\
172
.type = QEMU_OPT_NUMBER,\
173
.help = "limit read operations per second",\
174
},{ \
175
- .name = "throttling.iops-write",\
176
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,\
177
.type = QEMU_OPT_NUMBER,\
178
.help = "limit write operations per second",\
179
},{ \
180
- .name = "throttling.bps-total",\
181
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,\
182
.type = QEMU_OPT_NUMBER,\
183
.help = "limit total bytes per second",\
184
},{ \
185
- .name = "throttling.bps-read",\
186
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,\
187
.type = QEMU_OPT_NUMBER,\
188
.help = "limit read bytes per second",\
189
},{ \
190
- .name = "throttling.bps-write",\
191
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,\
192
.type = QEMU_OPT_NUMBER,\
193
.help = "limit write bytes per second",\
194
},{ \
195
- .name = "throttling.iops-total-max",\
196
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX,\
197
.type = QEMU_OPT_NUMBER,\
198
.help = "I/O operations burst",\
199
},{ \
200
- .name = "throttling.iops-read-max",\
201
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX,\
202
.type = QEMU_OPT_NUMBER,\
203
.help = "I/O operations read burst",\
204
},{ \
205
- .name = "throttling.iops-write-max",\
206
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX,\
207
.type = QEMU_OPT_NUMBER,\
208
.help = "I/O operations write burst",\
209
},{ \
210
- .name = "throttling.bps-total-max",\
211
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX,\
212
.type = QEMU_OPT_NUMBER,\
213
.help = "total bytes burst",\
214
},{ \
215
- .name = "throttling.bps-read-max",\
216
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX,\
217
.type = QEMU_OPT_NUMBER,\
218
.help = "total bytes read burst",\
219
},{ \
220
- .name = "throttling.bps-write-max",\
221
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX,\
222
.type = QEMU_OPT_NUMBER,\
223
.help = "total bytes write burst",\
224
},{ \
225
- .name = "throttling.iops-total-max-length",\
226
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX_LENGTH,\
227
.type = QEMU_OPT_NUMBER,\
228
.help = "length of the iops-total-max burst period, in seconds",\
229
},{ \
230
- .name = "throttling.iops-read-max-length",\
231
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX_LENGTH,\
232
.type = QEMU_OPT_NUMBER,\
233
.help = "length of the iops-read-max burst period, in seconds",\
234
},{ \
235
- .name = "throttling.iops-write-max-length",\
236
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX_LENGTH,\
237
.type = QEMU_OPT_NUMBER,\
238
.help = "length of the iops-write-max burst period, in seconds",\
239
},{ \
240
- .name = "throttling.bps-total-max-length",\
241
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH,\
242
.type = QEMU_OPT_NUMBER,\
243
.help = "length of the bps-total-max burst period, in seconds",\
244
},{ \
245
- .name = "throttling.bps-read-max-length",\
246
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,\
247
.type = QEMU_OPT_NUMBER,\
248
.help = "length of the bps-read-max burst period, in seconds",\
249
},{ \
250
- .name = "throttling.bps-write-max-length",\
251
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH,\
252
.type = QEMU_OPT_NUMBER,\
253
.help = "length of the bps-write-max burst period, in seconds",\
254
},{ \
255
- .name = "throttling.iops-size",\
256
+ .name = THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE,\
257
.type = QEMU_OPT_NUMBER,\
258
.help = "when limiting by iops max size of an I/O in bytes",\
259
}
260
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
261
index XXXXXXX..XXXXXXX 100644
262
--- a/include/qemu/throttle.h
263
+++ b/include/qemu/throttle.h
264
@@ -XXX,XX +XXX,XX @@ bool throttle_schedule_timer(ThrottleState *ts,
265
bool is_write);
266
267
void throttle_account(ThrottleState *ts, bool is_write, uint64_t size);
268
+void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg,
269
+ Error **errp);
270
+void throttle_config_to_limits(ThrottleConfig *cfg, ThrottleLimits *var);
271
272
#endif
273
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/block/throttle-groups.c
276
+++ b/block/throttle-groups.c
277
@@ -XXX,XX +XXX,XX @@
278
#include "qemu/osdep.h"
279
#include "sysemu/block-backend.h"
280
#include "block/throttle-groups.h"
281
+#include "qemu/throttle-options.h"
282
#include "qemu/queue.h"
283
#include "qemu/thread.h"
284
#include "sysemu/qtest.h"
285
+#include "qapi/error.h"
286
+#include "qapi-visit.h"
287
+#include "qom/object.h"
288
+#include "qom/object_interfaces.h"
289
+
290
+static void throttle_group_obj_init(Object *obj);
291
+static void throttle_group_obj_complete(UserCreatable *obj, Error **errp);
292
293
/* The ThrottleGroup structure (with its ThrottleState) is shared
294
* among different ThrottleGroupMembers and it's independent from
295
@@ -XXX,XX +XXX,XX @@
296
* that ThrottleGroupMember has throttled requests in the queue.
297
*/
298
typedef struct ThrottleGroup {
299
+ Object parent_obj;
300
+
301
+ /* refuse individual property change if initialization is complete */
302
+ bool is_initialized;
303
char *name; /* This is constant during the lifetime of the group */
304
305
QemuMutex lock; /* This lock protects the following four fields */
306
@@ -XXX,XX +XXX,XX @@ typedef struct ThrottleGroup {
307
bool any_timer_armed[2];
308
QEMUClockType clock_type;
309
310
- /* These two are protected by the global throttle_groups_lock */
311
- unsigned refcount;
312
+ /* This field is protected by the global QEMU mutex */
313
QTAILQ_ENTRY(ThrottleGroup) list;
314
} ThrottleGroup;
315
316
-static QemuMutex throttle_groups_lock;
317
+/* This is protected by the global QEMU mutex */
318
static QTAILQ_HEAD(, ThrottleGroup) throttle_groups =
319
QTAILQ_HEAD_INITIALIZER(throttle_groups);
320
321
+
322
+/* This function reads throttle_groups and must be called under the global
323
+ * mutex.
324
+ */
325
+static ThrottleGroup *throttle_group_by_name(const char *name)
326
+{
327
+ ThrottleGroup *iter;
328
+
329
+ /* Look for an existing group with that name */
330
+ QTAILQ_FOREACH(iter, &throttle_groups, list) {
331
+ if (!g_strcmp0(name, iter->name)) {
332
+ return iter;
333
+ }
334
+ }
335
+
336
+ return NULL;
337
+}
338
+
339
/* Increments the reference count of a ThrottleGroup given its name.
340
*
341
* If no ThrottleGroup is found with the given name a new one is
342
* created.
343
*
344
+ * This function edits throttle_groups and must be called under the global
345
+ * mutex.
346
+ *
347
* @name: the name of the ThrottleGroup
348
* @ret: the ThrottleState member of the ThrottleGroup
349
*/
350
ThrottleState *throttle_group_incref(const char *name)
351
{
352
ThrottleGroup *tg = NULL;
353
- ThrottleGroup *iter;
354
-
355
- qemu_mutex_lock(&throttle_groups_lock);
356
357
/* Look for an existing group with that name */
358
- QTAILQ_FOREACH(iter, &throttle_groups, list) {
359
- if (!strcmp(name, iter->name)) {
360
- tg = iter;
361
- break;
362
- }
363
- }
364
-
365
- /* Create a new one if not found */
366
- if (!tg) {
367
- tg = g_new0(ThrottleGroup, 1);
368
+ tg = throttle_group_by_name(name);
369
+
370
+ if (tg) {
371
+ object_ref(OBJECT(tg));
372
+ } else {
373
+ /* Create a new one if not found */
374
+ /* new ThrottleGroup obj will have a refcnt = 1 */
375
+ tg = THROTTLE_GROUP(object_new(TYPE_THROTTLE_GROUP));
376
tg->name = g_strdup(name);
377
- tg->clock_type = QEMU_CLOCK_REALTIME;
378
-
379
- if (qtest_enabled()) {
380
- /* For testing block IO throttling only */
381
- tg->clock_type = QEMU_CLOCK_VIRTUAL;
382
- }
383
- qemu_mutex_init(&tg->lock);
384
- throttle_init(&tg->ts);
385
- QLIST_INIT(&tg->head);
386
-
387
- QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
388
+ throttle_group_obj_complete(USER_CREATABLE(tg), &error_abort);
389
}
390
391
- tg->refcount++;
392
-
393
- qemu_mutex_unlock(&throttle_groups_lock);
394
-
395
return &tg->ts;
396
}
397
398
@@ -XXX,XX +XXX,XX @@ ThrottleState *throttle_group_incref(const char *name)
399
* When the reference count reaches zero the ThrottleGroup is
400
* destroyed.
401
*
402
+ * This function edits throttle_groups and must be called under the global
403
+ * mutex.
404
+ *
405
* @ts: The ThrottleGroup to unref, given by its ThrottleState member
406
*/
407
void throttle_group_unref(ThrottleState *ts)
408
{
409
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
410
-
411
- qemu_mutex_lock(&throttle_groups_lock);
412
- if (--tg->refcount == 0) {
413
- QTAILQ_REMOVE(&throttle_groups, tg, list);
414
- qemu_mutex_destroy(&tg->lock);
415
- g_free(tg->name);
416
- g_free(tg);
417
- }
418
- qemu_mutex_unlock(&throttle_groups_lock);
419
+ object_unref(OBJECT(tg));
420
}
421
422
/* Get the name from a ThrottleGroupMember's group. The name (and the pointer)
423
@@ -XXX,XX +XXX,XX @@ static void write_timer_cb(void *opaque)
424
* its timers and updating its throttle_state pointer to point to it. If a
425
* throttling group with that name does not exist yet, it will be created.
426
*
427
+ * This function edits throttle_groups and must be called under the global
428
+ * mutex.
429
+ *
430
* @tgm: the ThrottleGroupMember to insert
431
* @groupname: the name of the group
432
* @ctx: the AioContext to use
433
@@ -XXX,XX +XXX,XX @@ void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
434
tgm->aio_context = NULL;
435
}
436
437
+#undef THROTTLE_OPT_PREFIX
438
+#define THROTTLE_OPT_PREFIX "x-"
439
+
440
+/* Helper struct and array for QOM property setter/getter */
441
+typedef struct {
442
+ const char *name;
443
+ BucketType type;
444
+ enum {
445
+ AVG,
446
+ MAX,
447
+ BURST_LENGTH,
448
+ IOPS_SIZE,
449
+ } category;
450
+} ThrottleParamInfo;
451
+
452
+static ThrottleParamInfo properties[] = {
453
+ {
454
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL,
455
+ THROTTLE_OPS_TOTAL, AVG,
456
+ },
457
+ {
458
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX,
459
+ THROTTLE_OPS_TOTAL, MAX,
460
+ },
461
+ {
462
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_TOTAL_MAX_LENGTH,
463
+ THROTTLE_OPS_TOTAL, BURST_LENGTH,
464
+ },
465
+ {
466
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ,
467
+ THROTTLE_OPS_READ, AVG,
468
+ },
469
+ {
470
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX,
471
+ THROTTLE_OPS_READ, MAX,
472
+ },
473
+ {
474
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_READ_MAX_LENGTH,
475
+ THROTTLE_OPS_READ, BURST_LENGTH,
476
+ },
477
+ {
478
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE,
479
+ THROTTLE_OPS_WRITE, AVG,
480
+ },
481
+ {
482
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX,
483
+ THROTTLE_OPS_WRITE, MAX,
484
+ },
485
+ {
486
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_WRITE_MAX_LENGTH,
487
+ THROTTLE_OPS_WRITE, BURST_LENGTH,
488
+ },
489
+ {
490
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL,
491
+ THROTTLE_BPS_TOTAL, AVG,
492
+ },
493
+ {
494
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX,
495
+ THROTTLE_BPS_TOTAL, MAX,
496
+ },
497
+ {
498
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_TOTAL_MAX_LENGTH,
499
+ THROTTLE_BPS_TOTAL, BURST_LENGTH,
500
+ },
501
+ {
502
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ,
503
+ THROTTLE_BPS_READ, AVG,
504
+ },
505
+ {
506
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX,
507
+ THROTTLE_BPS_READ, MAX,
508
+ },
509
+ {
510
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_READ_MAX_LENGTH,
511
+ THROTTLE_BPS_READ, BURST_LENGTH,
512
+ },
513
+ {
514
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE,
515
+ THROTTLE_BPS_WRITE, AVG,
516
+ },
517
+ {
518
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX,
519
+ THROTTLE_BPS_WRITE, MAX,
520
+ },
521
+ {
522
+ THROTTLE_OPT_PREFIX QEMU_OPT_BPS_WRITE_MAX_LENGTH,
523
+ THROTTLE_BPS_WRITE, BURST_LENGTH,
524
+ },
525
+ {
526
+ THROTTLE_OPT_PREFIX QEMU_OPT_IOPS_SIZE,
527
+ 0, IOPS_SIZE,
528
+ }
529
+};
530
+
531
+/* This function edits throttle_groups and must be called under the global
532
+ * mutex */
533
+static void throttle_group_obj_init(Object *obj)
534
+{
535
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
536
+
537
+ tg->clock_type = QEMU_CLOCK_REALTIME;
538
+ if (qtest_enabled()) {
539
+ /* For testing block IO throttling only */
540
+ tg->clock_type = QEMU_CLOCK_VIRTUAL;
541
+ }
542
+ tg->is_initialized = false;
543
+ qemu_mutex_init(&tg->lock);
544
+ throttle_init(&tg->ts);
545
+ QLIST_INIT(&tg->head);
546
+}
547
+
548
+/* This function edits throttle_groups and must be called under the global
549
+ * mutex */
550
+static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
551
+{
552
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
553
+ ThrottleConfig cfg;
554
+
555
+ /* set group name to object id if it exists */
556
+ if (!tg->name && tg->parent_obj.parent) {
557
+ tg->name = object_get_canonical_path_component(OBJECT(obj));
558
+ }
559
+ /* We must have a group name at this point */
560
+ assert(tg->name);
561
+
562
+ /* error if name is duplicate */
563
+ if (throttle_group_by_name(tg->name) != NULL) {
564
+ error_setg(errp, "A group with this name already exists");
565
+ return;
68
+ return;
566
+ }
69
+ }
70
+ qdict_del(qdict, "qom-type");
567
+
71
+
568
+ /* check validity */
72
+ id = g_strdup(qdict_get_try_str(qdict, "id"));
569
+ throttle_get_config(&tg->ts, &cfg);
73
+ if (!id) {
570
+ if (!throttle_is_valid(&cfg, errp)) {
74
+ error_setg(errp, QERR_MISSING_PARAMETER, "id");
571
+ return;
75
+ return;
572
+ }
76
+ }
573
+ throttle_config(&tg->ts, tg->clock_type, &cfg);
77
+ qdict_del(qdict, "id");
574
+ QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
78
+
575
+ tg->is_initialized = true;
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);
576
+}
83
+}
577
+
84
578
+/* This function edits throttle_groups and must be called under the global
85
Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
579
+ * mutex */
580
+static void throttle_group_obj_finalize(Object *obj)
581
+{
582
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
583
+ if (tg->is_initialized) {
584
+ QTAILQ_REMOVE(&throttle_groups, tg, list);
585
+ }
586
+ qemu_mutex_destroy(&tg->lock);
587
+ g_free(tg->name);
588
+}
589
+
590
+static void throttle_group_set(Object *obj, Visitor *v, const char * name,
591
+ void *opaque, Error **errp)
592
+
593
+{
594
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
595
+ ThrottleConfig *cfg;
596
+ ThrottleParamInfo *info = opaque;
597
+ Error *local_err = NULL;
598
+ int64_t value;
599
+
600
+ /* If we have finished initialization, don't accept individual property
601
+ * changes through QOM. Throttle configuration limits must be set in one
602
+ * transaction, as certain combinations are invalid.
603
+ */
604
+ if (tg->is_initialized) {
605
+ error_setg(&local_err, "Property cannot be set after initialization");
606
+ goto ret;
607
+ }
608
+
609
+ visit_type_int64(v, name, &value, &local_err);
610
+ if (local_err) {
611
+ goto ret;
612
+ }
613
+ if (value < 0) {
614
+ error_setg(&local_err, "Property values cannot be negative");
615
+ goto ret;
616
+ }
617
+
618
+ cfg = &tg->ts.cfg;
619
+ switch (info->category) {
620
+ case AVG:
621
+ cfg->buckets[info->type].avg = value;
622
+ break;
623
+ case MAX:
624
+ cfg->buckets[info->type].max = value;
625
+ break;
626
+ case BURST_LENGTH:
627
+ if (value > UINT_MAX) {
628
+ error_setg(&local_err, "%s value must be in the"
629
+ "range [0, %u]", info->name, UINT_MAX);
630
+ goto ret;
631
+ }
632
+ cfg->buckets[info->type].burst_length = value;
633
+ break;
634
+ case IOPS_SIZE:
635
+ cfg->op_size = value;
636
+ break;
637
+ }
638
+
639
+ret:
640
+ error_propagate(errp, local_err);
641
+ return;
642
+
643
+}
644
+
645
+static void throttle_group_get(Object *obj, Visitor *v, const char *name,
646
+ void *opaque, Error **errp)
647
+{
648
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
649
+ ThrottleConfig cfg;
650
+ ThrottleParamInfo *info = opaque;
651
+ int64_t value;
652
+
653
+ throttle_get_config(&tg->ts, &cfg);
654
+ switch (info->category) {
655
+ case AVG:
656
+ value = cfg.buckets[info->type].avg;
657
+ break;
658
+ case MAX:
659
+ value = cfg.buckets[info->type].max;
660
+ break;
661
+ case BURST_LENGTH:
662
+ value = cfg.buckets[info->type].burst_length;
663
+ break;
664
+ case IOPS_SIZE:
665
+ value = cfg.op_size;
666
+ break;
667
+ }
668
+
669
+ visit_type_int64(v, name, &value, errp);
670
+}
671
+
672
+static void throttle_group_set_limits(Object *obj, Visitor *v,
673
+ const char *name, void *opaque,
674
+ Error **errp)
675
+
676
+{
677
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
678
+ ThrottleConfig cfg;
679
+ ThrottleLimits arg = { 0 };
680
+ ThrottleLimits *argp = &arg;
681
+ Error *local_err = NULL;
682
+
683
+ visit_type_ThrottleLimits(v, name, &argp, &local_err);
684
+ if (local_err) {
685
+ goto ret;
686
+ }
687
+ qemu_mutex_lock(&tg->lock);
688
+ throttle_get_config(&tg->ts, &cfg);
689
+ throttle_limits_to_config(argp, &cfg, &local_err);
690
+ if (local_err) {
691
+ goto unlock;
692
+ }
693
+ throttle_config(&tg->ts, tg->clock_type, &cfg);
694
+
695
+unlock:
696
+ qemu_mutex_unlock(&tg->lock);
697
+ret:
698
+ error_propagate(errp, local_err);
699
+ return;
700
+}
701
+
702
+static void throttle_group_get_limits(Object *obj, Visitor *v,
703
+ const char *name, void *opaque,
704
+ Error **errp)
705
+{
706
+ ThrottleGroup *tg = THROTTLE_GROUP(obj);
707
+ ThrottleConfig cfg;
708
+ ThrottleLimits arg = { 0 };
709
+ ThrottleLimits *argp = &arg;
710
+
711
+ qemu_mutex_lock(&tg->lock);
712
+ throttle_get_config(&tg->ts, &cfg);
713
+ qemu_mutex_unlock(&tg->lock);
714
+
715
+ throttle_config_to_limits(&cfg, argp);
716
+
717
+ visit_type_ThrottleLimits(v, name, &argp, errp);
718
+}
719
+
720
+static bool throttle_group_can_be_deleted(UserCreatable *uc)
721
+{
722
+ return OBJECT(uc)->ref == 1;
723
+}
724
+
725
+static void throttle_group_obj_class_init(ObjectClass *klass, void *class_data)
726
+{
727
+ size_t i = 0;
728
+ UserCreatableClass *ucc = USER_CREATABLE_CLASS(klass);
729
+
730
+ ucc->complete = throttle_group_obj_complete;
731
+ ucc->can_be_deleted = throttle_group_can_be_deleted;
732
+
733
+ /* individual properties */
734
+ for (i = 0; i < sizeof(properties) / sizeof(ThrottleParamInfo); i++) {
735
+ object_class_property_add(klass,
736
+ properties[i].name,
737
+ "int",
738
+ throttle_group_get,
739
+ throttle_group_set,
740
+ NULL, &properties[i],
741
+ &error_abort);
742
+ }
743
+
744
+ /* ThrottleLimits */
745
+ object_class_property_add(klass,
746
+ "limits", "ThrottleLimits",
747
+ throttle_group_get_limits,
748
+ throttle_group_set_limits,
749
+ NULL, NULL,
750
+ &error_abort);
751
+}
752
+
753
+static const TypeInfo throttle_group_info = {
754
+ .name = TYPE_THROTTLE_GROUP,
755
+ .parent = TYPE_OBJECT,
756
+ .class_init = throttle_group_obj_class_init,
757
+ .instance_size = sizeof(ThrottleGroup),
758
+ .instance_init = throttle_group_obj_init,
759
+ .instance_finalize = throttle_group_obj_finalize,
760
+ .interfaces = (InterfaceInfo[]) {
761
+ { TYPE_USER_CREATABLE },
762
+ { }
763
+ },
764
+};
765
+
766
static void throttle_groups_init(void)
767
{
86
{
768
- qemu_mutex_init(&throttle_groups_lock);
87
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
769
+ type_register_static(&throttle_group_info);
88
index XXXXXXX..XXXXXXX 100644
89
--- a/qom/qom-qmp-cmds.c
90
+++ b/qom/qom-qmp-cmds.c
91
@@ -XXX,XX +XXX,XX @@
92
#include "qapi/qapi-commands-qom.h"
93
#include "qapi/qmp/qdict.h"
94
#include "qapi/qmp/qerror.h"
95
-#include "qapi/qobject-input-visitor.h"
96
#include "qemu/cutils.h"
97
#include "qom/object_interfaces.h"
98
#include "qom/qom-qobject.h"
99
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
100
{
101
QObject *props;
102
QDict *pdict;
103
- Visitor *v;
104
- Object *obj;
105
- g_autofree char *type = NULL;
106
- g_autofree char *id = NULL;
107
-
108
- type = g_strdup(qdict_get_try_str(qdict, "qom-type"));
109
- if (!type) {
110
- error_setg(errp, QERR_MISSING_PARAMETER, "qom-type");
111
- return;
112
- }
113
- qdict_del(qdict, "qom-type");
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);
126
}
127
128
- v = qobject_input_visitor_new(QOBJECT(qdict));
129
- obj = user_creatable_add_type(type, id, qdict, v, errp);
130
- visit_free(v);
131
- object_unref(obj);
132
+ user_creatable_add_dict(qdict, errp);
770
}
133
}
771
134
772
-block_init(throttle_groups_init);
135
void qmp_object_del(const char *id, Error **errp)
773
+type_init(throttle_groups_init);
774
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
775
index XXXXXXX..XXXXXXX 100644
776
--- a/tests/test-throttle.c
777
+++ b/tests/test-throttle.c
778
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
779
qemu_init_main_loop(&error_fatal);
780
ctx = qemu_get_aio_context();
781
bdrv_init();
782
+ module_call_init(MODULE_INIT_QOM);
783
784
do {} while (g_main_context_iteration(NULL, false));
785
786
diff --git a/util/throttle.c b/util/throttle.c
787
index XXXXXXX..XXXXXXX 100644
788
--- a/util/throttle.c
789
+++ b/util/throttle.c
790
@@ -XXX,XX +XXX,XX @@ void throttle_account(ThrottleState *ts, bool is_write, uint64_t size)
791
}
792
}
793
794
+/* return a ThrottleConfig based on the options in a ThrottleLimits
795
+ *
796
+ * @arg: the ThrottleLimits object to read from
797
+ * @cfg: the ThrottleConfig to edit
798
+ * @errp: error object
799
+ */
800
+void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg,
801
+ Error **errp)
802
+{
803
+ if (arg->has_bps_total) {
804
+ cfg->buckets[THROTTLE_BPS_TOTAL].avg = arg->bps_total;
805
+ }
806
+ if (arg->has_bps_read) {
807
+ cfg->buckets[THROTTLE_BPS_READ].avg = arg->bps_read;
808
+ }
809
+ if (arg->has_bps_write) {
810
+ cfg->buckets[THROTTLE_BPS_WRITE].avg = arg->bps_write;
811
+ }
812
+
813
+ if (arg->has_iops_total) {
814
+ cfg->buckets[THROTTLE_OPS_TOTAL].avg = arg->iops_total;
815
+ }
816
+ if (arg->has_iops_read) {
817
+ cfg->buckets[THROTTLE_OPS_READ].avg = arg->iops_read;
818
+ }
819
+ if (arg->has_iops_write) {
820
+ cfg->buckets[THROTTLE_OPS_WRITE].avg = arg->iops_write;
821
+ }
822
+
823
+ if (arg->has_bps_total_max) {
824
+ cfg->buckets[THROTTLE_BPS_TOTAL].max = arg->bps_total_max;
825
+ }
826
+ if (arg->has_bps_read_max) {
827
+ cfg->buckets[THROTTLE_BPS_READ].max = arg->bps_read_max;
828
+ }
829
+ if (arg->has_bps_write_max) {
830
+ cfg->buckets[THROTTLE_BPS_WRITE].max = arg->bps_write_max;
831
+ }
832
+ if (arg->has_iops_total_max) {
833
+ cfg->buckets[THROTTLE_OPS_TOTAL].max = arg->iops_total_max;
834
+ }
835
+ if (arg->has_iops_read_max) {
836
+ cfg->buckets[THROTTLE_OPS_READ].max = arg->iops_read_max;
837
+ }
838
+ if (arg->has_iops_write_max) {
839
+ cfg->buckets[THROTTLE_OPS_WRITE].max = arg->iops_write_max;
840
+ }
841
+
842
+ if (arg->has_bps_total_max_length) {
843
+ if (arg->bps_total_max_length > UINT_MAX) {
844
+ error_setg(errp, "bps-total-max-length value must be in"
845
+ " the range [0, %u]", UINT_MAX);
846
+ return;
847
+ }
848
+ cfg->buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_total_max_length;
849
+ }
850
+ if (arg->has_bps_read_max_length) {
851
+ if (arg->bps_read_max_length > UINT_MAX) {
852
+ error_setg(errp, "bps-read-max-length value must be in"
853
+ " the range [0, %u]", UINT_MAX);
854
+ return;
855
+ }
856
+ cfg->buckets[THROTTLE_BPS_READ].burst_length = arg->bps_read_max_length;
857
+ }
858
+ if (arg->has_bps_write_max_length) {
859
+ if (arg->bps_write_max_length > UINT_MAX) {
860
+ error_setg(errp, "bps-write-max-length value must be in"
861
+ " the range [0, %u]", UINT_MAX);
862
+ return;
863
+ }
864
+ cfg->buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_write_max_length;
865
+ }
866
+ if (arg->has_iops_total_max_length) {
867
+ if (arg->iops_total_max_length > UINT_MAX) {
868
+ error_setg(errp, "iops-total-max-length value must be in"
869
+ " the range [0, %u]", UINT_MAX);
870
+ return;
871
+ }
872
+ cfg->buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_total_max_length;
873
+ }
874
+ if (arg->has_iops_read_max_length) {
875
+ if (arg->iops_read_max_length > UINT_MAX) {
876
+ error_setg(errp, "iops-read-max-length value must be in"
877
+ " the range [0, %u]", UINT_MAX);
878
+ return;
879
+ }
880
+ cfg->buckets[THROTTLE_OPS_READ].burst_length = arg->iops_read_max_length;
881
+ }
882
+ if (arg->has_iops_write_max_length) {
883
+ if (arg->iops_write_max_length > UINT_MAX) {
884
+ error_setg(errp, "iops-write-max-length value must be in"
885
+ " the range [0, %u]", UINT_MAX);
886
+ return;
887
+ }
888
+ cfg->buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_write_max_length;
889
+ }
890
+
891
+ if (arg->has_iops_size) {
892
+ cfg->op_size = arg->iops_size;
893
+ }
894
+
895
+ throttle_is_valid(cfg, errp);
896
+}
897
+
898
+/* write the options of a ThrottleConfig to a ThrottleLimits
899
+ *
900
+ * @cfg: the ThrottleConfig to read from
901
+ * @var: the ThrottleLimits to write to
902
+ */
903
+void throttle_config_to_limits(ThrottleConfig *cfg, ThrottleLimits *var)
904
+{
905
+ var->bps_total = cfg->buckets[THROTTLE_BPS_TOTAL].avg;
906
+ var->bps_read = cfg->buckets[THROTTLE_BPS_READ].avg;
907
+ var->bps_write = cfg->buckets[THROTTLE_BPS_WRITE].avg;
908
+ var->iops_total = cfg->buckets[THROTTLE_OPS_TOTAL].avg;
909
+ var->iops_read = cfg->buckets[THROTTLE_OPS_READ].avg;
910
+ var->iops_write = cfg->buckets[THROTTLE_OPS_WRITE].avg;
911
+ var->bps_total_max = cfg->buckets[THROTTLE_BPS_TOTAL].max;
912
+ var->bps_read_max = cfg->buckets[THROTTLE_BPS_READ].max;
913
+ var->bps_write_max = cfg->buckets[THROTTLE_BPS_WRITE].max;
914
+ var->iops_total_max = cfg->buckets[THROTTLE_OPS_TOTAL].max;
915
+ var->iops_read_max = cfg->buckets[THROTTLE_OPS_READ].max;
916
+ var->iops_write_max = cfg->buckets[THROTTLE_OPS_WRITE].max;
917
+ var->bps_total_max_length = cfg->buckets[THROTTLE_BPS_TOTAL].burst_length;
918
+ var->bps_read_max_length = cfg->buckets[THROTTLE_BPS_READ].burst_length;
919
+ var->bps_write_max_length = cfg->buckets[THROTTLE_BPS_WRITE].burst_length;
920
+ var->iops_total_max_length = cfg->buckets[THROTTLE_OPS_TOTAL].burst_length;
921
+ var->iops_read_max_length = cfg->buckets[THROTTLE_OPS_READ].burst_length;
922
+ var->iops_write_max_length = cfg->buckets[THROTTLE_OPS_WRITE].burst_length;
923
+ var->iops_size = cfg->op_size;
924
+
925
+ var->has_bps_total = true;
926
+ var->has_bps_read = true;
927
+ var->has_bps_write = true;
928
+ var->has_iops_total = true;
929
+ var->has_iops_read = true;
930
+ var->has_iops_write = true;
931
+ var->has_bps_total_max = true;
932
+ var->has_bps_read_max = true;
933
+ var->has_bps_write_max = true;
934
+ var->has_iops_total_max = true;
935
+ var->has_iops_read_max = true;
936
+ var->has_iops_write_max = true;
937
+ var->has_bps_read_max_length = true;
938
+ var->has_bps_total_max_length = true;
939
+ var->has_bps_write_max_length = true;
940
+ var->has_iops_total_max_length = true;
941
+ var->has_iops_read_max_length = true;
942
+ var->has_iops_write_max_length = true;
943
+ var->has_iops_size = true;
944
+}
945
--
136
--
946
2.13.5
137
2.25.3
947
138
948
139
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
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
Now that bdrv_truncate is passed to bs->file by default, remove the
5
qmp_object_add(), however, uses the normal QObject input visitor, which
4
callback from block/blkdebug.c and set is_filter to true. is_filter also gives
6
expects a QDict where all properties already have the QType that matches
5
access to other callbacks that are forwarded automatically to bs->file for
7
the data type required by the QOM object type.
6
filters.
7
8
8
Reviewed-by: Eric Blake <eblake@redhat.com>
9
Change the --object implementation in qemu-storage-daemon so that it
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
doesn't call qmp_object_add(), but calls user_creatable_add_dict()
10
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
11
directly instead and pass it a new keyval boolean that decides which
12
visitor must be used.
13
14
Reported-by: Coiby Xu <coiby.xu@gmail.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
16
---
13
block/blkdebug.c | 8 +-------
17
include/qom/object_interfaces.h | 6 +++++-
14
1 file changed, 1 insertion(+), 7 deletions(-)
18
qemu-storage-daemon.c | 4 +---
19
qom/object_interfaces.c | 8 ++++++--
20
qom/qom-qmp-cmds.c | 2 +-
21
4 files changed, 13 insertions(+), 7 deletions(-)
15
22
16
diff --git a/block/blkdebug.c b/block/blkdebug.c
23
diff --git a/include/qom/object_interfaces.h b/include/qom/object_interfaces.h
17
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
18
--- a/block/blkdebug.c
25
--- a/include/qom/object_interfaces.h
19
+++ b/block/blkdebug.c
26
+++ b/include/qom/object_interfaces.h
20
@@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
27
@@ -XXX,XX +XXX,XX @@ Object *user_creatable_add_type(const char *type, const char *id,
21
return bdrv_getlength(bs->file->bs);
28
/**
29
* user_creatable_add_dict:
30
* @qdict: the object definition
31
+ * @keyval: if true, use a keyval visitor for processing @qdict (i.e.
32
+ * assume that all @qdict values are strings); otherwise, use
33
+ * the normal QObject visitor (i.e. assume all @qdict values
34
+ * have the QType expected by the QOM object type)
35
* @errp: if an error occurs, a pointer to an area to store the error
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
48
index XXXXXXX..XXXXXXX 100644
49
--- a/qemu-storage-daemon.c
50
+++ b/qemu-storage-daemon.c
51
@@ -XXX,XX +XXX,XX @@ static void process_options(int argc, char *argv[])
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;
22
}
76
}
23
77
24
-static int blkdebug_truncate(BlockDriverState *bs, int64_t offset,
78
-void user_creatable_add_dict(QDict *qdict, Error **errp)
25
- PreallocMode prealloc, Error **errp)
79
+void user_creatable_add_dict(QDict *qdict, bool keyval, Error **errp)
26
-{
27
- return bdrv_truncate(bs->file, offset, prealloc, errp);
28
-}
29
-
30
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
31
{
80
{
32
BDRVBlkdebugState *s = bs->opaque;
81
Visitor *v;
33
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
82
Object *obj;
34
.format_name = "blkdebug",
83
@@ -XXX,XX +XXX,XX @@ void user_creatable_add_dict(QDict *qdict, Error **errp)
35
.protocol_name = "blkdebug",
84
}
36
.instance_size = sizeof(BDRVBlkdebugState),
85
qdict_del(qdict, "id");
37
+ .is_filter = true,
86
38
87
- v = qobject_input_visitor_new(QOBJECT(qdict));
39
.bdrv_parse_filename = blkdebug_parse_filename,
88
+ if (keyval) {
40
.bdrv_file_open = blkdebug_open,
89
+ v = qobject_input_visitor_new_keyval(QOBJECT(qdict));
41
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
90
+ } else {
42
.bdrv_child_perm = bdrv_filter_default_perms,
91
+ v = qobject_input_visitor_new(QOBJECT(qdict));
43
92
+ }
44
.bdrv_getlength = blkdebug_getlength,
93
obj = user_creatable_add_type(type, id, qdict, v, errp);
45
- .bdrv_truncate = blkdebug_truncate,
94
visit_free(v);
46
.bdrv_refresh_filename = blkdebug_refresh_filename,
95
object_unref(obj);
47
.bdrv_refresh_limits = blkdebug_refresh_limits,
96
diff --git a/qom/qom-qmp-cmds.c b/qom/qom-qmp-cmds.c
48
97
index XXXXXXX..XXXXXXX 100644
98
--- a/qom/qom-qmp-cmds.c
99
+++ b/qom/qom-qmp-cmds.c
100
@@ -XXX,XX +XXX,XX @@ void qmp_object_add(QDict *qdict, QObject **ret_data, Error **errp)
101
qobject_unref(pdict);
102
}
103
104
- user_creatable_add_dict(qdict, errp);
105
+ user_creatable_add_dict(qdict, false, errp);
106
}
107
108
void qmp_object_del(const char *id, Error **errp)
49
--
109
--
50
2.13.5
110
2.25.3
51
111
52
112
diff view generated by jsdifflib