1
The following changes since commit 98bfaac788be0ca63d7d010c8d4ba100ff1d8278:
1
The following changes since commit b34181056c04e05db6c632063012beaee7006a37:
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/rth/tags/pull-sh4-20180709' into staging (2018-07-09 22:44:22 +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 cd47d792d7a27a57f4b621e2ff1ed8f4e83de1e9:
10
10
11
qcow2: move qcow2_store_persistent_dirty_bitmaps() before cache flushing (2017-09-06 14:40:18 +0200)
11
block: Use common write req handling in truncate (2018-07-10 16:46:22 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block layer patches
14
Block layer patches:
15
16
- Copy offloading fixes for when the copy increases the image size
17
- Temporary revert of the removal of deprecated -drive options
18
- Fix request serialisation in the image fleecing scenario
19
- Fix copy-on-read crash with unaligned image size
20
- Fix another drain crash
15
21
16
----------------------------------------------------------------
22
----------------------------------------------------------------
17
Daniel P. Berrange (1):
23
Ari Sundholm (2):
18
block: document semantics of bdrv_co_preadv|pwritev
24
qapi/block-core.json: Add missing documentation for blklogwrites log-append option
25
block/blklogwrites: Make sure the log sector size is not too small
19
26
20
Eric Blake (2):
27
Cornelia Huck (4):
21
qcow: Change signature of get_cluster_offset()
28
Revert "block: Remove dead deprecation warning code"
22
qcow: Check failure of bdrv_getlength() and bdrv_truncate()
29
Revert "block: Remove deprecated -drive option serial"
30
Revert "block: Remove deprecated -drive option addr"
31
Revert "block: Remove deprecated -drive geometry options"
23
32
24
Manos Pitsidianakis (10):
33
Fam Zheng (11):
25
block: pass bdrv_* methods to bs->file by default in block filters
34
iotests: 222: Don't run with luks
26
block: remove unused bdrv_media_changed
35
block: Prefix file driver trace points with "file_"
27
block: remove bdrv_truncate callback in blkdebug
36
block: Add copy offloading trace points
28
block: add default implementations for bdrv_co_get_block_status()
37
block: Use BdrvChild to discard
29
block: move ThrottleGroup membership to ThrottleGroupMember
38
block: Use uint64_t for BdrvTrackedRequest byte fields
30
block: add aio_context field in ThrottleGroupMember
39
block: Extract common write req handling
31
block: tidy ThrottleGroupMember initializations
40
block: Fix handling of image enlarging write
32
block: convert ThrottleGroup to object with QOM
41
block: Use common req handling for discard
33
block: add throttle block filter driver
42
block: Use common req handling in copy offloading
34
qemu-iotests: add 184 for throttle filter driver
43
block: Fix bdrv_co_truncate overlap check
44
block: Use common write req handling in truncate
35
45
36
Pavel Butsykin (1):
46
Kevin Wolf (3):
37
qcow2: move qcow2_store_persistent_dirty_bitmaps() before cache flushing
47
block: Poll after drain on attaching a node
48
test-bdrv-drain: Test bdrv_append() to drained node
49
block: Fix copy-on-read crash with partial final cluster
38
50
39
qapi/block-core.json | 66 +++-
51
Vladimir Sementsov-Ogievskiy (4):
40
include/block/block.h | 1 -
52
block/io: fix copy_range
41
include/block/block_int.h | 56 ++-
53
block: split flags in copy_range
42
include/block/throttle-groups.h | 52 ++-
54
block: add BDRV_REQ_SERIALISING flag
43
include/qemu/throttle-options.h | 60 +++-
55
block/backup: fix fleecing scheme: use serialized writes
44
include/qemu/throttle.h | 3 +
45
include/sysemu/block-backend.h | 20 +-
46
block.c | 35 +-
47
block/blkdebug.c | 20 +-
48
block/block-backend.c | 62 ++--
49
block/commit.c | 12 +-
50
block/io.c | 26 ++
51
block/mirror.c | 12 +-
52
block/qapi.c | 8 +-
53
block/qcow.c | 153 ++++----
54
block/qcow2.c | 16 +-
55
block/raw-format.c | 6 -
56
block/throttle-groups.c | 750 ++++++++++++++++++++++++++++++----------
57
block/throttle.c | 237 +++++++++++++
58
blockdev.c | 4 +-
59
tests/test-throttle.c | 111 +++---
60
util/throttle.c | 151 ++++++++
61
block/Makefile.objs | 1 +
62
tests/qemu-iotests/184 | 205 +++++++++++
63
tests/qemu-iotests/184.out | 302 ++++++++++++++++
64
tests/qemu-iotests/group | 1 +
65
26 files changed, 1917 insertions(+), 453 deletions(-)
66
create mode 100644 block/throttle.c
67
create mode 100755 tests/qemu-iotests/184
68
create mode 100644 tests/qemu-iotests/184.out
69
56
57
qapi/block-core.json | 2 +
58
include/block/block.h | 41 +++++-
59
include/block/block_int.h | 21 ++-
60
include/hw/block/block.h | 1 +
61
include/sysemu/block-backend.h | 3 +-
62
include/sysemu/blockdev.h | 3 +
63
block.c | 2 +-
64
block/backup.c | 20 ++-
65
block/blkdebug.c | 2 +-
66
block/blklogwrites.c | 7 +-
67
block/blkreplay.c | 2 +-
68
block/block-backend.c | 8 +-
69
block/copy-on-read.c | 2 +-
70
block/file-posix.c | 25 ++--
71
block/file-win32.c | 2 +-
72
block/io.c | 318 ++++++++++++++++++++++++++++-------------
73
block/iscsi.c | 12 +-
74
block/mirror.c | 2 +-
75
block/qcow2-refcount.c | 2 +-
76
block/qcow2.c | 20 +--
77
block/raw-format.c | 26 ++--
78
block/throttle.c | 2 +-
79
blockdev.c | 110 ++++++++++++++
80
device-hotplug.c | 4 +
81
hw/block/block.c | 27 ++++
82
hw/block/nvme.c | 1 +
83
hw/block/virtio-blk.c | 1 +
84
hw/ide/qdev.c | 1 +
85
hw/scsi/scsi-disk.c | 1 +
86
hw/usb/dev-storage.c | 1 +
87
qemu-img.c | 2 +-
88
tests/ahci-test.c | 6 +-
89
tests/hd-geo-test.c | 37 ++++-
90
tests/ide-test.c | 8 +-
91
tests/test-bdrv-drain.c | 43 ++++++
92
block/trace-events | 10 +-
93
hmp-commands.hx | 1 +
94
qemu-doc.texi | 15 ++
95
qemu-options.hx | 14 +-
96
tests/qemu-iotests/197 | 9 ++
97
tests/qemu-iotests/197.out | 8 ++
98
tests/qemu-iotests/222 | 2 +
99
42 files changed, 647 insertions(+), 177 deletions(-)
100
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
Commit dcf94a23b1 ('block: Don't poll in parent drain callbacks')
2
removed polling in bdrv_child_cb_drained_begin() on the grounds that the
3
original bdrv_drain() already will poll and BdrvChildRole.drained_begin
4
calls must not cause graph changes (and therefore must not call
5
aio_poll() or the recursion through the graph will break.
2
6
3
This function is not used anywhere, so remove it.
7
This reasoning is correct for calls through bdrv_do_drained_begin().
8
However, BdrvChildRole.drained_begin is also called when a node that is
9
already in a drained section (i.e. bdrv_do_drained_begin() has already
10
returned and therefore can't poll any more) is attached to a new parent.
11
In this case, we must explicitly poll to have all requests completed
12
before the drained new child can be attached to the parent.
4
13
5
Markus Armbruster adds:
14
In bdrv_replace_child_noperm(), we know that we're not inside the
6
The i82078 floppy device model used to call bdrv_media_changed() to
15
recursion of bdrv_do_drained_begin() because graph changes are not
7
implement its media change bit when backed by a host floppy. This
16
allowed there, and bdrv_replace_child_noperm() is a graph change. The
8
went away in 21fcf36 "fdc: simplify media change handling".
17
call of BdrvChildRole.drained_begin() must therefore be followed by a
9
Probably broke host floppy media change. Host floppy pass-through
18
BDRV_POLL_WHILE() that waits for the completion of requests.
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
19
14
Reviewed-by: Eric Blake <eblake@redhat.com>
20
Reported-by: Max Reitz <mreitz@redhat.com>
15
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
---
22
---
19
include/block/block.h | 1 -
23
include/block/block.h | 8 ++++++++
20
include/block/block_int.h | 1 -
24
include/block/block_int.h | 3 +++
21
block.c | 14 --------------
25
block.c | 2 +-
22
block/raw-format.c | 6 ------
26
block/io.c | 26 ++++++++++++++++++++------
23
4 files changed, 22 deletions(-)
27
4 files changed, 32 insertions(+), 7 deletions(-)
24
28
25
diff --git a/include/block/block.h b/include/block/block.h
29
diff --git a/include/block/block.h b/include/block/block.h
26
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/block.h
31
--- a/include/block/block.h
28
+++ b/include/block/block.h
32
+++ b/include/block/block.h
29
@@ -XXX,XX +XXX,XX @@ int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only,
33
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
30
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
34
bool ignore_bds_parents);
31
bool bdrv_is_sg(BlockDriverState *bs);
35
32
bool bdrv_is_inserted(BlockDriverState *bs);
36
/**
33
-int bdrv_media_changed(BlockDriverState *bs);
37
+ * bdrv_parent_drained_begin_single:
34
void bdrv_lock_medium(BlockDriverState *bs, bool locked);
38
+ *
35
void bdrv_eject(BlockDriverState *bs, bool eject_flag);
39
+ * Begin a quiesced section for the parent of @c. If @poll is true, wait for
36
const char *bdrv_get_format_name(BlockDriverState *bs);
40
+ * any pending activity to cease.
41
+ */
42
+void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll);
43
+
44
+/**
45
* bdrv_parent_drained_end:
46
*
47
* End a quiesced section of all users of @bs. This is part of
37
diff --git a/include/block/block_int.h b/include/block/block_int.h
48
diff --git a/include/block/block_int.h b/include/block/block_int.h
38
index XXXXXXX..XXXXXXX 100644
49
index XXXXXXX..XXXXXXX 100644
39
--- a/include/block/block_int.h
50
--- a/include/block/block_int.h
40
+++ b/include/block/block_int.h
51
+++ b/include/block/block_int.h
41
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
52
@@ -XXX,XX +XXX,XX @@ struct BdrvChildRole {
42
53
* requests after returning from .drained_begin() until .drained_end() is
43
/* removable device specific */
54
* called.
44
bool (*bdrv_is_inserted)(BlockDriverState *bs);
55
*
45
- int (*bdrv_media_changed)(BlockDriverState *bs);
56
+ * These functions must not change the graph (and therefore also must not
46
void (*bdrv_eject)(BlockDriverState *bs, bool eject_flag);
57
+ * call aio_poll(), which could change the graph indirectly).
47
void (*bdrv_lock_medium)(BlockDriverState *bs, bool locked);
58
+ *
48
59
* Note that this can be nested. If drained_begin() was called twice, new
60
* I/O is allowed only after drained_end() was called twice, too.
61
*/
49
diff --git a/block.c b/block.c
62
diff --git a/block.c b/block.c
50
index XXXXXXX..XXXXXXX 100644
63
index XXXXXXX..XXXXXXX 100644
51
--- a/block.c
64
--- a/block.c
52
+++ b/block.c
65
+++ b/block.c
53
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_inserted(BlockDriverState *bs)
66
@@ -XXX,XX +XXX,XX @@ static void bdrv_replace_child_noperm(BdrvChild *child,
67
}
68
assert(num >= 0);
69
for (i = 0; i < num; i++) {
70
- child->role->drained_begin(child);
71
+ bdrv_parent_drained_begin_single(child, true);
72
}
73
}
74
75
diff --git a/block/io.c b/block/io.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/io.c
78
+++ b/block/io.c
79
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_begin(BlockDriverState *bs, BdrvChild *ignore,
80
if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
81
continue;
82
}
83
- if (c->role->drained_begin) {
84
- c->role->drained_begin(c);
85
- }
86
+ bdrv_parent_drained_begin_single(c, false);
87
}
54
}
88
}
55
89
56
/**
90
@@ -XXX,XX +XXX,XX @@ void bdrv_parent_drained_end(BlockDriverState *bs, BdrvChild *ignore,
57
- * Return whether the media changed since the last call to this
91
}
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
75
index XXXXXXX..XXXXXXX 100644
76
--- a/block/raw-format.c
77
+++ b/block/raw-format.c
78
@@ -XXX,XX +XXX,XX @@ static int raw_truncate(BlockDriverState *bs, int64_t offset,
79
return bdrv_truncate(bs->file, offset, prealloc, errp);
80
}
92
}
81
93
82
-static int raw_media_changed(BlockDriverState *bs)
94
+static bool bdrv_parent_drained_poll_single(BdrvChild *c)
83
-{
95
+{
84
- return bdrv_media_changed(bs->file->bs);
96
+ if (c->role->drained_poll) {
85
-}
97
+ return c->role->drained_poll(c);
86
-
98
+ }
87
static void raw_eject(BlockDriverState *bs, bool eject_flag)
99
+ return false;
100
+}
101
+
102
static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
103
bool ignore_bds_parents)
88
{
104
{
89
bdrv_eject(bs->file->bs, eject_flag);
105
@@ -XXX,XX +XXX,XX @@ static bool bdrv_parent_drained_poll(BlockDriverState *bs, BdrvChild *ignore,
90
@@ -XXX,XX +XXX,XX @@ BlockDriver bdrv_raw = {
106
if (c == ignore || (ignore_bds_parents && c->role->parent_is_bds)) {
91
.bdrv_refresh_limits = &raw_refresh_limits,
107
continue;
92
.bdrv_probe_blocksizes = &raw_probe_blocksizes,
108
}
93
.bdrv_probe_geometry = &raw_probe_geometry,
109
- if (c->role->drained_poll) {
94
- .bdrv_media_changed = &raw_media_changed,
110
- busy |= c->role->drained_poll(c);
95
.bdrv_eject = &raw_eject,
111
- }
96
.bdrv_lock_medium = &raw_lock_medium,
112
+ busy |= bdrv_parent_drained_poll_single(c);
97
.bdrv_co_ioctl = &raw_co_ioctl,
113
}
114
115
return busy;
116
}
117
118
+void bdrv_parent_drained_begin_single(BdrvChild *c, bool poll)
119
+{
120
+ if (c->role->drained_begin) {
121
+ c->role->drained_begin(c);
122
+ }
123
+ if (poll) {
124
+ BDRV_POLL_WHILE(c->bs, bdrv_parent_drained_poll_single(c));
125
+ }
126
+}
127
+
128
static void bdrv_merge_limits(BlockLimits *dst, const BlockLimits *src)
129
{
130
dst->opt_transfer = MAX(dst->opt_transfer, src->opt_transfer);
98
--
131
--
99
2.13.5
132
2.13.6
100
133
101
134
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
2
3
timer_cb() needs to know about the current Aio context of the throttle
4
request that is woken up. In order to make ThrottleGroupMember backend
5
agnostic, this information is stored in an aio_context field instead of
6
accessing it from BlockBackend.
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>
1
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
2
---
13
include/block/throttle-groups.h | 7 ++++-
3
tests/test-bdrv-drain.c | 43 +++++++++++++++++++++++++++++++++++++++++++
14
block/block-backend.c | 15 ++++------
4
1 file changed, 43 insertions(+)
15
block/throttle-groups.c | 38 ++++++++++++++++---------
16
tests/test-throttle.c | 63 +++++++++++++++++++++--------------------
17
4 files changed, 69 insertions(+), 54 deletions(-)
18
5
19
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
6
diff --git a/tests/test-bdrv-drain.c b/tests/test-bdrv-drain.c
20
index XXXXXXX..XXXXXXX 100644
7
index XXXXXXX..XXXXXXX 100644
21
--- a/include/block/throttle-groups.h
8
--- a/tests/test-bdrv-drain.c
22
+++ b/include/block/throttle-groups.h
9
+++ b/tests/test-bdrv-drain.c
23
@@ -XXX,XX +XXX,XX @@
10
@@ -XXX,XX +XXX,XX @@ static void test_detach_by_driver_cb(void)
24
*/
11
test_detach_indirect(false);
25
26
typedef struct ThrottleGroupMember {
27
+ AioContext *aio_context;
28
/* throttled_reqs_lock protects the CoQueues for throttled requests. */
29
CoMutex throttled_reqs_lock;
30
CoQueue throttled_reqs[2];
31
@@ -XXX,XX +XXX,XX @@ void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
32
void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
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
51
--- a/block/block-backend.c
52
+++ b/block/block-backend.c
53
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
54
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
55
{
56
BlockDriverState *bs = blk_bs(blk);
57
- ThrottleTimers *tt;
58
+ ThrottleGroupMember *tgm = &blk->public.throttle_group_member;
59
60
if (bs) {
61
- if (blk->public.throttle_group_member.throttle_state) {
62
- tt = &blk->public.throttle_group_member.throttle_timers;
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
}
74
}
12
}
75
13
76
@@ -XXX,XX +XXX,XX @@ void blk_io_limits_disable(BlockBackend *blk)
14
+static void test_append_to_drained(void)
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
+{
15
+{
169
+ ThrottleTimers *tt = &tgm->throttle_timers;
16
+ BlockBackend *blk;
170
+ throttle_timers_attach_aio_context(tt, new_context);
17
+ BlockDriverState *base, *overlay;
171
+ tgm->aio_context = new_context;
18
+ BDRVTestState *base_s, *overlay_s;
19
+
20
+ blk = blk_new(BLK_PERM_ALL, BLK_PERM_ALL);
21
+ base = bdrv_new_open_driver(&bdrv_test, "base", BDRV_O_RDWR, &error_abort);
22
+ base_s = base->opaque;
23
+ blk_insert_bs(blk, base, &error_abort);
24
+
25
+ overlay = bdrv_new_open_driver(&bdrv_test, "overlay", BDRV_O_RDWR,
26
+ &error_abort);
27
+ overlay_s = overlay->opaque;
28
+
29
+ do_drain_begin(BDRV_DRAIN, base);
30
+ g_assert_cmpint(base->quiesce_counter, ==, 1);
31
+ g_assert_cmpint(base_s->drain_count, ==, 1);
32
+ g_assert_cmpint(base->in_flight, ==, 0);
33
+
34
+ /* Takes ownership of overlay, so we don't have to unref it later */
35
+ bdrv_append(overlay, base, &error_abort);
36
+ g_assert_cmpint(base->in_flight, ==, 0);
37
+ g_assert_cmpint(overlay->in_flight, ==, 0);
38
+
39
+ g_assert_cmpint(base->quiesce_counter, ==, 1);
40
+ g_assert_cmpint(base_s->drain_count, ==, 1);
41
+ g_assert_cmpint(overlay->quiesce_counter, ==, 1);
42
+ g_assert_cmpint(overlay_s->drain_count, ==, 1);
43
+
44
+ do_drain_end(BDRV_DRAIN, base);
45
+
46
+ g_assert_cmpint(base->quiesce_counter, ==, 0);
47
+ g_assert_cmpint(base_s->drain_count, ==, 0);
48
+ g_assert_cmpint(overlay->quiesce_counter, ==, 0);
49
+ g_assert_cmpint(overlay_s->drain_count, ==, 0);
50
+
51
+ bdrv_unref(base);
52
+ blk_unref(blk);
172
+}
53
+}
173
+
54
+
174
+void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
55
int main(int argc, char **argv)
175
+{
56
{
176
+ ThrottleTimers *tt = &tgm->throttle_timers;
57
int ret;
177
+ throttle_timers_detach_aio_context(tt);
58
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
178
+ tgm->aio_context = NULL;
59
g_test_add_func("/bdrv-drain/detach/parent_cb", test_detach_by_parent_cb);
179
+}
60
g_test_add_func("/bdrv-drain/detach/driver_cb", test_detach_by_driver_cb);
61
62
+ g_test_add_func("/bdrv-drain/attach/drain", test_append_to_drained);
180
+
63
+
181
static void throttle_groups_init(void)
64
ret = g_test_run();
182
{
65
qemu_event_destroy(&done_event);
183
qemu_mutex_init(&throttle_groups_lock);
66
return ret;
184
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
185
index XXXXXXX..XXXXXXX 100644
186
--- a/tests/test-throttle.c
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
+
205
/* fill the structures with crap */
206
memset(&ts, 1, sizeof(ts));
207
- memset(&tt, 1, sizeof(tt));
208
+ memset(tt, 1, sizeof(*tt));
209
210
/* init structures */
211
throttle_init(&ts);
212
- throttle_timers_init(&tt, ctx, QEMU_CLOCK_VIRTUAL,
213
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
214
read_timer_cb, write_timer_cb, &ts);
215
216
/* check initialized fields */
217
- g_assert(tt.clock_type == QEMU_CLOCK_VIRTUAL);
218
- g_assert(tt.timers[0]);
219
- g_assert(tt.timers[1]);
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
--
67
--
358
2.13.5
68
2.13.6
359
69
360
70
diff view generated by jsdifflib
New patch
1
If the virtual disk size isn't aligned to full clusters,
2
bdrv_co_do_copy_on_readv() may get pnum == 0 before having the full
3
cluster completed, which will let it run into an assertion failure:
1
4
5
qemu-io: block/io.c:1203: bdrv_co_do_copy_on_readv: Assertion `skip_bytes < pnum' failed.
6
7
Check for EOF, assert that we read at least as much as the read request
8
originally wanted to have (which is true at EOF because otherwise
9
bdrv_check_byte_request() would already have returned an error) and
10
return success early even though we couldn't copy the full cluster.
11
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
14
block/io.c | 6 ++++++
15
tests/qemu-iotests/197 | 9 +++++++++
16
tests/qemu-iotests/197.out | 8 ++++++++
17
3 files changed, 23 insertions(+)
18
19
diff --git a/block/io.c b/block/io.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/block/io.c
22
+++ b/block/io.c
23
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BdrvChild *child,
24
pnum = MIN(cluster_bytes, max_transfer);
25
}
26
27
+ /* Stop at EOF if the image ends in the middle of the cluster */
28
+ if (ret == 0 && pnum == 0) {
29
+ assert(progress >= bytes);
30
+ break;
31
+ }
32
+
33
assert(skip_bytes < pnum);
34
35
if (ret <= 0) {
36
diff --git a/tests/qemu-iotests/197 b/tests/qemu-iotests/197
37
index XXXXXXX..XXXXXXX 100755
38
--- a/tests/qemu-iotests/197
39
+++ b/tests/qemu-iotests/197
40
@@ -XXX,XX +XXX,XX @@ $QEMU_IO -f qcow2 -c map "$TEST_WRAP"
41
_check_test_img
42
$QEMU_IMG compare -f $IMGFMT -F qcow2 "$TEST_IMG" "$TEST_WRAP"
43
44
+echo
45
+echo '=== Partial final cluster ==='
46
+echo
47
+
48
+_make_test_img 1024
49
+$QEMU_IO -f $IMGFMT -C -c 'read 0 1024' "$TEST_IMG" | _filter_qemu_io
50
+$QEMU_IO -f $IMGFMT -c map "$TEST_IMG"
51
+_check_test_img
52
+
53
# success, all done
54
echo '*** done'
55
status=0
56
diff --git a/tests/qemu-iotests/197.out b/tests/qemu-iotests/197.out
57
index XXXXXXX..XXXXXXX 100644
58
--- a/tests/qemu-iotests/197.out
59
+++ b/tests/qemu-iotests/197.out
60
@@ -XXX,XX +XXX,XX @@ can't open device TEST_DIR/t.wrap.qcow2: Can't use copy-on-read on read-only dev
61
1023.938 MiB (0x3fff0000) bytes not allocated at offset 3 GiB (0xc0010000)
62
No errors were found on the image.
63
Images are identical.
64
+
65
+=== Partial final cluster ===
66
+
67
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1024
68
+read 1024/1024 bytes at offset 0
69
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
70
+1 KiB (0x400) bytes allocated at offset 0 bytes (0x0)
71
+No errors were found on the image.
72
*** done
73
--
74
2.13.6
75
76
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
Luks needs special parameters to operate the image. Since this test is
4
focusing on image fleecing, skip skip that format.
5
6
Signed-off-by: Fam Zheng <famz@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
tests/qemu-iotests/222 | 2 ++
10
1 file changed, 2 insertions(+)
11
12
diff --git a/tests/qemu-iotests/222 b/tests/qemu-iotests/222
13
index XXXXXXX..XXXXXXX 100644
14
--- a/tests/qemu-iotests/222
15
+++ b/tests/qemu-iotests/222
16
@@ -XXX,XX +XXX,XX @@ import iotests
17
from iotests import log, qemu_img, qemu_io, qemu_io_silent
18
19
iotests.verify_platform(['linux'])
20
+iotests.verify_image_format(supported_fmts=['qcow2', 'qcow', 'qed', 'vmdk',
21
+ 'vhdx', 'raw'])
22
23
patterns = [("0x5d", "0", "64k"),
24
("0xd5", "1M", "64k"),
25
--
26
2.13.6
27
28
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Here two things are fixed:
4
5
1. Architecture
6
7
On each recursion step, we go to the child of src or dst, only for one
8
of them. So, it's wrong to create tracked requests for both on each
9
step. It leads to tracked requests duplication.
10
11
2. Wait for serializing requests on write path independently of
12
BDRV_REQ_NO_SERIALISING
13
14
Before commit 9ded4a01149 "backup: Use copy offloading",
15
BDRV_REQ_NO_SERIALISING was used for only one case: read in
16
copy-on-write operation during backup. Also, the flag was handled only
17
on read path (in bdrv_co_preadv and bdrv_aligned_preadv).
18
19
After 9ded4a01149, flag is used for not waiting serializing operations
20
on backup target (in same case of copy-on-write operation). This
21
behavior change is unsubstantiated and potentially dangerous, let's
22
drop it and add additional asserts and documentation.
23
24
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
25
Reviewed-by: Fam Zheng <famz@redhat.com>
26
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
27
---
28
include/block/block.h | 12 ++++++++++++
29
block/io.c | 42 +++++++++++++++++++++++++++---------------
30
2 files changed, 39 insertions(+), 15 deletions(-)
31
32
diff --git a/include/block/block.h b/include/block/block.h
33
index XXXXXXX..XXXXXXX 100644
34
--- a/include/block/block.h
35
+++ b/include/block/block.h
36
@@ -XXX,XX +XXX,XX @@ typedef enum {
37
* opened with BDRV_O_UNMAP.
38
*/
39
BDRV_REQ_MAY_UNMAP = 0x4,
40
+
41
+ /*
42
+ * The BDRV_REQ_NO_SERIALISING flag is only valid for reads and means that
43
+ * we don't want wait_serialising_requests() during the read operation.
44
+ *
45
+ * This flag is used for backup copy-on-write operations, when we need to
46
+ * read old data before write (write notifier triggered). It is okay since
47
+ * we already waited for other serializing requests in the initiating write
48
+ * (see bdrv_aligned_pwritev), and it is necessary if the initiating write
49
+ * is already serializing (without the flag, the read would deadlock
50
+ * waiting for the serialising write to complete).
51
+ */
52
BDRV_REQ_NO_SERIALISING = 0x8,
53
BDRV_REQ_FUA = 0x10,
54
BDRV_REQ_WRITE_COMPRESSED = 0x20,
55
diff --git a/block/io.c b/block/io.c
56
index XXXXXXX..XXXXXXX 100644
57
--- a/block/io.c
58
+++ b/block/io.c
59
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
60
max_transfer = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_transfer, INT_MAX),
61
align);
62
63
+ /* BDRV_REQ_NO_SERIALISING is only for read operation */
64
+ assert(!(flags & BDRV_REQ_NO_SERIALISING));
65
waited = wait_serialising_requests(req);
66
assert(!waited || !req->serialising);
67
assert(req->overlap_offset <= offset);
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
69
BdrvRequestFlags flags,
70
bool recurse_src)
71
{
72
- BdrvTrackedRequest src_req, dst_req;
73
+ BdrvTrackedRequest req;
74
int ret;
75
76
if (!dst || !dst->bs) {
77
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
78
|| src->bs->encrypted || dst->bs->encrypted) {
79
return -ENOTSUP;
80
}
81
- bdrv_inc_in_flight(src->bs);
82
- bdrv_inc_in_flight(dst->bs);
83
- tracked_request_begin(&src_req, src->bs, src_offset,
84
- bytes, BDRV_TRACKED_READ);
85
- tracked_request_begin(&dst_req, dst->bs, dst_offset,
86
- bytes, BDRV_TRACKED_WRITE);
87
88
- if (!(flags & BDRV_REQ_NO_SERIALISING)) {
89
- wait_serialising_requests(&src_req);
90
- wait_serialising_requests(&dst_req);
91
- }
92
if (recurse_src) {
93
+ bdrv_inc_in_flight(src->bs);
94
+ tracked_request_begin(&req, src->bs, src_offset, bytes,
95
+ BDRV_TRACKED_READ);
96
+
97
+ if (!(flags & BDRV_REQ_NO_SERIALISING)) {
98
+ wait_serialising_requests(&req);
99
+ }
100
+
101
ret = src->bs->drv->bdrv_co_copy_range_from(src->bs,
102
src, src_offset,
103
dst, dst_offset,
104
bytes, flags);
105
+
106
+ tracked_request_end(&req);
107
+ bdrv_dec_in_flight(src->bs);
108
} else {
109
+ bdrv_inc_in_flight(dst->bs);
110
+ tracked_request_begin(&req, dst->bs, dst_offset, bytes,
111
+ BDRV_TRACKED_WRITE);
112
+
113
+ /* BDRV_REQ_NO_SERIALISING is only for read operation,
114
+ * so we ignore it in flags.
115
+ */
116
+ wait_serialising_requests(&req);
117
+
118
ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
119
src, src_offset,
120
dst, dst_offset,
121
bytes, flags);
122
+
123
+ tracked_request_end(&req);
124
+ bdrv_dec_in_flight(dst->bs);
125
}
126
- tracked_request_end(&src_req);
127
- tracked_request_end(&dst_req);
128
- bdrv_dec_in_flight(src->bs);
129
- bdrv_dec_in_flight(dst->bs);
130
+
131
return ret;
132
}
133
134
--
135
2.13.6
136
137
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
This commit eliminates the 1:1 relationship between BlockBackend and
3
Pass read flags and write flags separately. This is needed to handle
4
throttle group state. Users will be able to create multiple throttle
4
coming BDRV_REQ_NO_SERIALISING clearly in following patches.
5
nodes, each with its own throttle group state, in the future. The
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
5
11
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
Reviewed-by: Fam Zheng <famz@redhat.com>
13
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
9
---
16
include/block/throttle-groups.h | 39 +++++-
10
include/block/block.h | 3 ++-
17
include/sysemu/block-backend.h | 20 +--
11
include/block/block_int.h | 14 +++++++++----
18
block/block-backend.c | 66 +++++----
12
include/sysemu/block-backend.h | 3 ++-
19
block/qapi.c | 8 +-
13
block/backup.c | 2 +-
20
block/throttle-groups.c | 288 ++++++++++++++++++++--------------------
14
block/block-backend.c | 5 +++--
21
blockdev.c | 4 +-
15
block/file-posix.c | 21 +++++++++++--------
22
tests/test-throttle.c | 53 ++++----
16
block/io.c | 46 +++++++++++++++++++++++-------------------
23
7 files changed, 252 insertions(+), 226 deletions(-)
17
block/iscsi.c | 9 ++++++---
18
block/qcow2.c | 20 +++++++++---------
19
block/raw-format.c | 24 ++++++++++++++--------
20
qemu-img.c | 2 +-
21
11 files changed, 90 insertions(+), 59 deletions(-)
24
22
25
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
23
diff --git a/include/block/block.h b/include/block/block.h
26
index XXXXXXX..XXXXXXX 100644
24
index XXXXXXX..XXXXXXX 100644
27
--- a/include/block/throttle-groups.h
25
--- a/include/block/block.h
28
+++ b/include/block/throttle-groups.h
26
+++ b/include/block/block.h
29
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host);
30
#include "qemu/throttle.h"
28
**/
31
#include "block/block_int.h"
29
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
32
30
BdrvChild *dst, uint64_t dst_offset,
33
-const char *throttle_group_get_name(BlockBackend *blk);
31
- uint64_t bytes, BdrvRequestFlags flags);
34
+/* The ThrottleGroupMember structure indicates membership in a ThrottleGroup
32
+ uint64_t bytes, BdrvRequestFlags read_flags,
35
+ * and holds related data.
33
+ BdrvRequestFlags write_flags);
36
+ */
34
#endif
37
+
35
diff --git a/include/block/block_int.h b/include/block/block_int.h
38
+typedef struct ThrottleGroupMember {
36
index XXXXXXX..XXXXXXX 100644
39
+ /* throttled_reqs_lock protects the CoQueues for throttled requests. */
37
--- a/include/block/block_int.h
40
+ CoMutex throttled_reqs_lock;
38
+++ b/include/block/block_int.h
41
+ CoQueue throttled_reqs[2];
39
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
42
+
40
BdrvChild *dst,
43
+ /* Nonzero if the I/O limits are currently being ignored; generally
41
uint64_t dst_offset,
44
+ * it is zero. Accessed with atomic operations.
42
uint64_t bytes,
45
+ */
43
- BdrvRequestFlags flags);
46
+ unsigned int io_limits_disabled;
44
+ BdrvRequestFlags read_flags,
47
+
45
+ BdrvRequestFlags write_flags);
48
+ /* The following fields are protected by the ThrottleGroup lock.
46
49
+ * See the ThrottleGroup documentation for details.
47
/* Map [offset, offset + nbytes) range onto a child of bs to copy data to,
50
+ * throttle_state tells us if I/O limits are configured. */
48
* and invoke bdrv_co_copy_range_to(child, src, ...), or perform the copy
51
+ ThrottleState *throttle_state;
49
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
52
+ ThrottleTimers throttle_timers;
50
BdrvChild *dst,
53
+ unsigned pending_reqs[2];
51
uint64_t dst_offset,
54
+ QLIST_ENTRY(ThrottleGroupMember) round_robin;
52
uint64_t bytes,
55
+
53
- BdrvRequestFlags flags);
56
+} ThrottleGroupMember;
54
+ BdrvRequestFlags read_flags,
57
+
55
+ BdrvRequestFlags write_flags);
58
+const char *throttle_group_get_name(ThrottleGroupMember *tgm);
56
59
57
/*
60
ThrottleState *throttle_group_incref(const char *name);
58
* Building block for bdrv_block_status[_above] and
61
void throttle_group_unref(ThrottleState *ts);
59
@@ -XXX,XX +XXX,XX @@ void blockdev_close_all_bdrv_states(void);
62
60
63
-void throttle_group_config(BlockBackend *blk, ThrottleConfig *cfg);
61
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
64
-void throttle_group_get_config(BlockBackend *blk, ThrottleConfig *cfg);
62
BdrvChild *dst, uint64_t dst_offset,
65
+void throttle_group_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
63
- uint64_t bytes, BdrvRequestFlags flags);
66
+void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg);
64
+ uint64_t bytes,
67
65
+ BdrvRequestFlags read_flags,
68
-void throttle_group_register_blk(BlockBackend *blk, const char *groupname);
66
+ BdrvRequestFlags write_flags);
69
-void throttle_group_unregister_blk(BlockBackend *blk);
67
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
70
-void throttle_group_restart_blk(BlockBackend *blk);
68
BdrvChild *dst, uint64_t dst_offset,
71
+void throttle_group_register_tgm(ThrottleGroupMember *tgm,
69
- uint64_t bytes, BdrvRequestFlags flags);
72
+ const char *groupname);
70
+ uint64_t bytes,
73
+void throttle_group_unregister_tgm(ThrottleGroupMember *tgm);
71
+ BdrvRequestFlags read_flags,
74
+void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
72
+ BdrvRequestFlags write_flags);
75
73
76
-void coroutine_fn throttle_group_co_io_limits_intercept(BlockBackend *blk,
74
int refresh_total_sectors(BlockDriverState *bs, int64_t hint);
77
+void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
78
unsigned int bytes,
79
bool is_write);
80
75
81
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
76
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
82
index XXXXXXX..XXXXXXX 100644
77
index XXXXXXX..XXXXXXX 100644
83
--- a/include/sysemu/block-backend.h
78
--- a/include/sysemu/block-backend.h
84
+++ b/include/sysemu/block-backend.h
79
+++ b/include/sysemu/block-backend.h
85
@@ -XXX,XX +XXX,XX @@ typedef struct BlockDevOps {
80
@@ -XXX,XX +XXX,XX @@ void blk_unregister_buf(BlockBackend *blk, void *host);
86
81
87
/* This struct is embedded in (the private) BlockBackend struct and contains
82
int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
88
* fields that must be public. This is in particular for QLIST_ENTRY() and
83
BlockBackend *blk_out, int64_t off_out,
89
- * friends so that BlockBackends can be kept in lists outside block-backend.c */
84
- int bytes, BdrvRequestFlags flags);
90
+ * friends so that BlockBackends can be kept in lists outside block-backend.c
85
+ int bytes, BdrvRequestFlags read_flags,
91
+ * */
86
+ BdrvRequestFlags write_flags);
92
typedef struct BlockBackendPublic {
87
93
- /* throttled_reqs_lock protects the CoQueues for throttled requests. */
88
#endif
94
- CoMutex throttled_reqs_lock;
89
diff --git a/block/backup.c b/block/backup.c
95
- CoQueue throttled_reqs[2];
90
index XXXXXXX..XXXXXXX 100644
96
-
91
--- a/block/backup.c
97
- /* Nonzero if the I/O limits are currently being ignored; generally
92
+++ b/block/backup.c
98
- * it is zero. Accessed with atomic operations.
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
99
- */
94
hbitmap_reset(job->copy_bitmap, start / job->cluster_size,
100
- unsigned int io_limits_disabled;
95
nr_clusters);
101
-
96
ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
102
- /* The following fields are protected by the ThrottleGroup lock.
97
- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0);
103
- * See the ThrottleGroup documentation for details.
98
+ is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0, 0);
104
- * throttle_state tells us if I/O limits are configured. */
99
if (ret < 0) {
105
- ThrottleState *throttle_state;
100
trace_backup_do_cow_copy_range_fail(job, start, ret);
106
- ThrottleTimers throttle_timers;
101
hbitmap_set(job->copy_bitmap, start / job->cluster_size,
107
- unsigned pending_reqs[2];
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
102
diff --git a/block/block-backend.c b/block/block-backend.c
114
index XXXXXXX..XXXXXXX 100644
103
index XXXXXXX..XXXXXXX 100644
115
--- a/block/block-backend.c
104
--- a/block/block-backend.c
116
+++ b/block/block-backend.c
105
+++ b/block/block-backend.c
117
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
106
@@ -XXX,XX +XXX,XX @@ void blk_unregister_buf(BlockBackend *blk, void *host)
118
blk->shared_perm = shared_perm;
107
119
blk_set_enable_write_cache(blk, true);
108
int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
120
109
BlockBackend *blk_out, int64_t off_out,
121
- qemu_co_mutex_init(&blk->public.throttled_reqs_lock);
110
- int bytes, BdrvRequestFlags flags)
122
- qemu_co_queue_init(&blk->public.throttled_reqs[0]);
111
+ int bytes, BdrvRequestFlags read_flags,
123
- qemu_co_queue_init(&blk->public.throttled_reqs[1]);
112
+ BdrvRequestFlags write_flags)
124
+ qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock);
113
{
125
+ qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]);
114
int r;
126
+ qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]);
115
r = blk_check_byte_request(blk_in, off_in, bytes);
127
block_acct_init(&blk->stats);
116
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_copy_range(BlockBackend *blk_in, int64_t off_in,
128
117
}
129
notifier_list_init(&blk->remove_bs_notifiers);
118
return bdrv_co_copy_range(blk_in->root, off_in,
130
@@ -XXX,XX +XXX,XX @@ static void blk_delete(BlockBackend *blk)
119
blk_out->root, off_out,
131
assert(!blk->refcnt);
120
- bytes, flags);
132
assert(!blk->name);
121
+ bytes, read_flags, write_flags);
133
assert(!blk->dev);
122
}
134
- if (blk->public.throttle_state) {
123
diff --git a/block/file-posix.c b/block/file-posix.c
135
+ if (blk->public.throttle_group_member.throttle_state) {
124
index XXXXXXX..XXXXXXX 100644
136
blk_io_limits_disable(blk);
125
--- a/block/file-posix.c
137
}
126
+++ b/block/file-posix.c
138
if (blk->root) {
127
@@ -XXX,XX +XXX,XX @@ static void raw_abort_perm_update(BlockDriverState *bs)
139
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_by_public(BlockBackendPublic *public)
128
raw_handle_perm_lock(bs, RAW_PL_ABORT, 0, 0, NULL);
140
*/
129
}
141
void blk_remove_bs(BlockBackend *blk)
130
142
{
131
-static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
143
+ ThrottleTimers *tt;
132
- BdrvChild *src, uint64_t src_offset,
144
+
133
- BdrvChild *dst, uint64_t dst_offset,
145
notifier_list_notify(&blk->remove_bs_notifiers, blk);
134
- uint64_t bytes, BdrvRequestFlags flags)
146
- if (blk->public.throttle_state) {
135
+static int coroutine_fn raw_co_copy_range_from(
147
- throttle_timers_detach_aio_context(&blk->public.throttle_timers);
136
+ BlockDriverState *bs, BdrvChild *src, uint64_t src_offset,
148
+ if (blk->public.throttle_group_member.throttle_state) {
137
+ BdrvChild *dst, uint64_t dst_offset, uint64_t bytes,
149
+ tt = &blk->public.throttle_group_member.throttle_timers;
138
+ BdrvRequestFlags read_flags, BdrvRequestFlags write_flags)
150
+ throttle_timers_detach_aio_context(tt);
139
{
151
}
140
- return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags);
152
141
+ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
153
blk_update_root_state(blk);
142
+ read_flags, write_flags);
154
@@ -XXX,XX +XXX,XX @@ int blk_insert_bs(BlockBackend *blk, BlockDriverState *bs, Error **errp)
143
}
155
bdrv_ref(bs);
144
156
145
static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
157
notifier_list_notify(&blk->insert_bs_notifiers, blk);
146
- BdrvChild *src, uint64_t src_offset,
158
- if (blk->public.throttle_state) {
147
- BdrvChild *dst, uint64_t dst_offset,
159
+ if (blk->public.throttle_group_member.throttle_state) {
148
- uint64_t bytes, BdrvRequestFlags flags)
160
throttle_timers_attach_aio_context(
149
+ BdrvChild *src,
161
- &blk->public.throttle_timers, bdrv_get_aio_context(bs));
150
+ uint64_t src_offset,
162
+ &blk->public.throttle_group_member.throttle_timers,
151
+ BdrvChild *dst,
163
+ bdrv_get_aio_context(bs));
152
+ uint64_t dst_offset,
164
}
153
+ uint64_t bytes,
165
154
+ BdrvRequestFlags read_flags,
166
return 0;
155
+ BdrvRequestFlags write_flags)
167
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset,
156
{
168
bdrv_inc_in_flight(bs);
157
BDRVRawState *s = bs->opaque;
169
158
BDRVRawState *src_s;
170
/* throttling disk I/O */
159
diff --git a/block/io.c b/block/io.c
171
- if (blk->public.throttle_state) {
160
index XXXXXXX..XXXXXXX 100644
172
- throttle_group_co_io_limits_intercept(blk, bytes, false);
161
--- a/block/io.c
173
+ if (blk->public.throttle_group_member.throttle_state) {
162
+++ b/block/io.c
174
+ throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
163
@@ -XXX,XX +XXX,XX @@ void bdrv_unregister_buf(BlockDriverState *bs, void *host)
175
+ bytes, false);
164
}
176
}
165
}
177
166
178
ret = bdrv_co_preadv(blk->root, offset, bytes, qiov, flags);
167
-static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
179
@@ -XXX,XX +XXX,XX @@ int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset,
168
- uint64_t src_offset,
180
}
169
- BdrvChild *dst,
181
170
- uint64_t dst_offset,
182
bdrv_inc_in_flight(bs);
171
- uint64_t bytes,
183
-
172
- BdrvRequestFlags flags,
184
/* throttling disk I/O */
173
- bool recurse_src)
185
- if (blk->public.throttle_state) {
174
+static int coroutine_fn bdrv_co_copy_range_internal(
186
- throttle_group_co_io_limits_intercept(blk, bytes, true);
175
+ BdrvChild *src, uint64_t src_offset, BdrvChild *dst,
187
+ if (blk->public.throttle_group_member.throttle_state) {
176
+ uint64_t dst_offset, uint64_t bytes,
188
+ throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
177
+ BdrvRequestFlags read_flags, BdrvRequestFlags write_flags,
189
+ bytes, true);
178
+ bool recurse_src)
190
}
179
{
191
180
BdrvTrackedRequest req;
192
if (!blk->enable_write_cache) {
181
int ret;
193
@@ -XXX,XX +XXX,XX @@ static AioContext *blk_aiocb_get_aio_context(BlockAIOCB *acb)
182
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
194
void blk_set_aio_context(BlockBackend *blk, AioContext *new_context)
183
if (ret) {
195
{
184
return ret;
196
BlockDriverState *bs = blk_bs(blk);
185
}
197
+ ThrottleTimers *tt;
186
- if (flags & BDRV_REQ_ZERO_WRITE) {
198
187
- return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, flags);
199
if (bs) {
188
+ if (write_flags & BDRV_REQ_ZERO_WRITE) {
200
- if (blk->public.throttle_state) {
189
+ return bdrv_co_pwrite_zeroes(dst, dst_offset, bytes, write_flags);
201
- throttle_timers_detach_aio_context(&blk->public.throttle_timers);
190
}
202
+ if (blk->public.throttle_group_member.throttle_state) {
191
203
+ tt = &blk->public.throttle_group_member.throttle_timers;
192
if (!src || !src->bs) {
204
+ throttle_timers_detach_aio_context(tt);
193
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
194
tracked_request_begin(&req, src->bs, src_offset, bytes,
195
BDRV_TRACKED_READ);
196
197
- if (!(flags & BDRV_REQ_NO_SERIALISING)) {
198
+ if (!(read_flags & BDRV_REQ_NO_SERIALISING)) {
199
wait_serialising_requests(&req);
205
}
200
}
206
bdrv_set_aio_context(bs, new_context);
201
207
- if (blk->public.throttle_state) {
202
ret = src->bs->drv->bdrv_co_copy_range_from(src->bs,
208
- throttle_timers_attach_aio_context(&blk->public.throttle_timers,
203
src, src_offset,
209
- new_context);
204
dst, dst_offset,
210
+ if (blk->public.throttle_group_member.throttle_state) {
205
- bytes, flags);
211
+ tt = &blk->public.throttle_group_member.throttle_timers;
206
+ bytes,
212
+ throttle_timers_attach_aio_context(tt, new_context);
207
+ read_flags, write_flags);
208
209
tracked_request_end(&req);
210
bdrv_dec_in_flight(src->bs);
211
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
212
tracked_request_begin(&req, dst->bs, dst_offset, bytes,
213
BDRV_TRACKED_WRITE);
214
215
- /* BDRV_REQ_NO_SERIALISING is only for read operation,
216
- * so we ignore it in flags.
217
- */
218
+ /* BDRV_REQ_NO_SERIALISING is only for read operation */
219
+ assert(!(write_flags & BDRV_REQ_NO_SERIALISING));
220
wait_serialising_requests(&req);
221
222
ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
223
src, src_offset,
224
dst, dst_offset,
225
- bytes, flags);
226
+ bytes,
227
+ read_flags, write_flags);
228
229
tracked_request_end(&req);
230
bdrv_dec_in_flight(dst->bs);
231
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(BdrvChild *src,
232
* semantics. */
233
int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
234
BdrvChild *dst, uint64_t dst_offset,
235
- uint64_t bytes, BdrvRequestFlags flags)
236
+ uint64_t bytes,
237
+ BdrvRequestFlags read_flags,
238
+ BdrvRequestFlags write_flags)
239
{
240
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
241
- bytes, flags, true);
242
+ bytes, read_flags, write_flags, true);
243
}
244
245
/* Copy range from @src to @dst.
246
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
247
* semantics. */
248
int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
249
BdrvChild *dst, uint64_t dst_offset,
250
- uint64_t bytes, BdrvRequestFlags flags)
251
+ uint64_t bytes,
252
+ BdrvRequestFlags read_flags,
253
+ BdrvRequestFlags write_flags)
254
{
255
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
256
- bytes, flags, false);
257
+ bytes, read_flags, write_flags, false);
258
}
259
260
int coroutine_fn bdrv_co_copy_range(BdrvChild *src, uint64_t src_offset,
261
BdrvChild *dst, uint64_t dst_offset,
262
- uint64_t bytes, BdrvRequestFlags flags)
263
+ uint64_t bytes, BdrvRequestFlags read_flags,
264
+ BdrvRequestFlags write_flags)
265
{
266
return bdrv_co_copy_range_from(src, src_offset,
267
dst, dst_offset,
268
- bytes, flags);
269
+ bytes, read_flags, write_flags);
270
}
271
272
static void bdrv_parent_cb_resize(BlockDriverState *bs)
273
diff --git a/block/iscsi.c b/block/iscsi.c
274
index XXXXXXX..XXXXXXX 100644
275
--- a/block/iscsi.c
276
+++ b/block/iscsi.c
277
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn iscsi_co_copy_range_from(BlockDriverState *bs,
278
BdrvChild *dst,
279
uint64_t dst_offset,
280
uint64_t bytes,
281
- BdrvRequestFlags flags)
282
+ BdrvRequestFlags read_flags,
283
+ BdrvRequestFlags write_flags)
284
{
285
- return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes, flags);
286
+ return bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
287
+ read_flags, write_flags);
288
}
289
290
static struct scsi_task *iscsi_xcopy_task(int param_len)
291
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn iscsi_co_copy_range_to(BlockDriverState *bs,
292
BdrvChild *dst,
293
uint64_t dst_offset,
294
uint64_t bytes,
295
- BdrvRequestFlags flags)
296
+ BdrvRequestFlags read_flags,
297
+ BdrvRequestFlags write_flags)
298
{
299
IscsiLun *dst_lun = dst->bs->opaque;
300
IscsiLun *src_lun;
301
diff --git a/block/qcow2.c b/block/qcow2.c
302
index XXXXXXX..XXXXXXX 100644
303
--- a/block/qcow2.c
304
+++ b/block/qcow2.c
305
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn
306
qcow2_co_copy_range_from(BlockDriverState *bs,
307
BdrvChild *src, uint64_t src_offset,
308
BdrvChild *dst, uint64_t dst_offset,
309
- uint64_t bytes, BdrvRequestFlags flags)
310
+ uint64_t bytes, BdrvRequestFlags read_flags,
311
+ BdrvRequestFlags write_flags)
312
{
313
BDRVQcow2State *s = bs->opaque;
314
int ret;
315
unsigned int cur_bytes; /* number of bytes in current iteration */
316
BdrvChild *child = NULL;
317
- BdrvRequestFlags cur_flags;
318
+ BdrvRequestFlags cur_write_flags;
319
320
assert(!bs->encrypted);
321
qemu_co_mutex_lock(&s->lock);
322
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
323
uint64_t copy_offset = 0;
324
/* prepare next request */
325
cur_bytes = MIN(bytes, INT_MAX);
326
- cur_flags = flags;
327
+ cur_write_flags = write_flags;
328
329
ret = qcow2_get_cluster_offset(bs, src_offset, &cur_bytes, &copy_offset);
330
if (ret < 0) {
331
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
332
if (bs->backing && bs->backing->bs) {
333
int64_t backing_length = bdrv_getlength(bs->backing->bs);
334
if (src_offset >= backing_length) {
335
- cur_flags |= BDRV_REQ_ZERO_WRITE;
336
+ cur_write_flags |= BDRV_REQ_ZERO_WRITE;
337
} else {
338
child = bs->backing;
339
cur_bytes = MIN(cur_bytes, backing_length - src_offset);
340
copy_offset = src_offset;
341
}
342
} else {
343
- cur_flags |= BDRV_REQ_ZERO_WRITE;
344
+ cur_write_flags |= BDRV_REQ_ZERO_WRITE;
345
}
346
break;
347
348
case QCOW2_CLUSTER_ZERO_PLAIN:
349
case QCOW2_CLUSTER_ZERO_ALLOC:
350
- cur_flags |= BDRV_REQ_ZERO_WRITE;
351
+ cur_write_flags |= BDRV_REQ_ZERO_WRITE;
352
break;
353
354
case QCOW2_CLUSTER_COMPRESSED:
355
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_from(BlockDriverState *bs,
356
ret = bdrv_co_copy_range_from(child,
357
copy_offset,
358
dst, dst_offset,
359
- cur_bytes, cur_flags);
360
+ cur_bytes, read_flags, cur_write_flags);
361
qemu_co_mutex_lock(&s->lock);
362
if (ret < 0) {
363
goto out;
364
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn
365
qcow2_co_copy_range_to(BlockDriverState *bs,
366
BdrvChild *src, uint64_t src_offset,
367
BdrvChild *dst, uint64_t dst_offset,
368
- uint64_t bytes, BdrvRequestFlags flags)
369
+ uint64_t bytes, BdrvRequestFlags read_flags,
370
+ BdrvRequestFlags write_flags)
371
{
372
BDRVQcow2State *s = bs->opaque;
373
int offset_in_cluster;
374
@@ -XXX,XX +XXX,XX @@ qcow2_co_copy_range_to(BlockDriverState *bs,
375
ret = bdrv_co_copy_range_to(src, src_offset,
376
bs->file,
377
cluster_offset + offset_in_cluster,
378
- cur_bytes, flags);
379
+ cur_bytes, read_flags, write_flags);
380
qemu_co_mutex_lock(&s->lock);
381
if (ret < 0) {
382
goto fail;
383
diff --git a/block/raw-format.c b/block/raw-format.c
384
index XXXXXXX..XXXXXXX 100644
385
--- a/block/raw-format.c
386
+++ b/block/raw-format.c
387
@@ -XXX,XX +XXX,XX @@ static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
388
}
389
390
static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
391
- BdrvChild *src, uint64_t src_offset,
392
- BdrvChild *dst, uint64_t dst_offset,
393
- uint64_t bytes, BdrvRequestFlags flags)
394
+ BdrvChild *src,
395
+ uint64_t src_offset,
396
+ BdrvChild *dst,
397
+ uint64_t dst_offset,
398
+ uint64_t bytes,
399
+ BdrvRequestFlags read_flags,
400
+ BdrvRequestFlags write_flags)
401
{
402
int ret;
403
404
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_from(BlockDriverState *bs,
405
return ret;
406
}
407
return bdrv_co_copy_range_from(bs->file, src_offset, dst, dst_offset,
408
- bytes, flags);
409
+ bytes, read_flags, write_flags);
410
}
411
412
static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
413
- BdrvChild *src, uint64_t src_offset,
414
- BdrvChild *dst, uint64_t dst_offset,
415
- uint64_t bytes, BdrvRequestFlags flags)
416
+ BdrvChild *src,
417
+ uint64_t src_offset,
418
+ BdrvChild *dst,
419
+ uint64_t dst_offset,
420
+ uint64_t bytes,
421
+ BdrvRequestFlags read_flags,
422
+ BdrvRequestFlags write_flags)
423
{
424
int ret;
425
426
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_copy_range_to(BlockDriverState *bs,
427
return ret;
428
}
429
return bdrv_co_copy_range_to(src, src_offset, bs->file, dst_offset, bytes,
430
- flags);
431
+ read_flags, write_flags);
432
}
433
434
BlockDriver bdrv_raw = {
435
diff --git a/qemu-img.c b/qemu-img.c
436
index XXXXXXX..XXXXXXX 100644
437
--- a/qemu-img.c
438
+++ b/qemu-img.c
439
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn convert_co_copy_range(ImgConvertState *s, int64_t sector
440
441
ret = blk_co_copy_range(blk, offset, s->target,
442
sector_num << BDRV_SECTOR_BITS,
443
- n << BDRV_SECTOR_BITS, 0);
444
+ n << BDRV_SECTOR_BITS, 0, 0);
445
if (ret < 0) {
446
return ret;
213
}
447
}
214
}
215
}
216
@@ -XXX,XX +XXX,XX @@ int blk_commit_all(void)
217
/* throttling disk I/O limits */
218
void blk_set_io_limits(BlockBackend *blk, ThrottleConfig *cfg)
219
{
220
- throttle_group_config(blk, cfg);
221
+ throttle_group_config(&blk->public.throttle_group_member, cfg);
222
}
223
224
void blk_io_limits_disable(BlockBackend *blk)
225
{
226
- assert(blk->public.throttle_state);
227
+ assert(blk->public.throttle_group_member.throttle_state);
228
bdrv_drained_begin(blk_bs(blk));
229
- throttle_group_unregister_blk(blk);
230
+ throttle_group_unregister_tgm(&blk->public.throttle_group_member);
231
bdrv_drained_end(blk_bs(blk));
232
}
233
234
/* should be called before blk_set_io_limits if a limit is set */
235
void blk_io_limits_enable(BlockBackend *blk, const char *group)
236
{
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
}
871
tg->tokens[i] = token;
872
}
873
}
874
875
- /* remove the current blk from the list */
876
- QLIST_REMOVE(blkp, round_robin);
877
- throttle_timers_destroy(&blkp->throttle_timers);
878
+ /* remove the current tgm from the list */
879
+ QLIST_REMOVE(tgm, round_robin);
880
+ throttle_timers_destroy(&tgm->throttle_timers);
881
qemu_mutex_unlock(&tg->lock);
882
883
throttle_group_unref(&tg->ts);
884
- blkp->throttle_state = NULL;
885
+ tgm->throttle_state = NULL;
886
}
887
888
static void throttle_groups_init(void)
889
diff --git a/blockdev.c b/blockdev.c
890
index XXXXXXX..XXXXXXX 100644
891
--- a/blockdev.c
892
+++ b/blockdev.c
893
@@ -XXX,XX +XXX,XX @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
894
if (throttle_enabled(&cfg)) {
895
/* Enable I/O limits if they're not enabled yet, otherwise
896
* just update the throttling group. */
897
- if (!blk_get_public(blk)->throttle_state) {
898
+ if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
899
blk_io_limits_enable(blk,
900
arg->has_group ? arg->group :
901
arg->has_device ? arg->device :
902
@@ -XXX,XX +XXX,XX @@ void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
903
}
904
/* Set the new throttling configuration */
905
blk_set_io_limits(blk, &cfg);
906
- } else if (blk_get_public(blk)->throttle_state) {
907
+ } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
908
/* If all throttling settings are set to 0, disable I/O limits */
909
blk_io_limits_disable(blk);
910
}
911
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
912
index XXXXXXX..XXXXXXX 100644
913
--- a/tests/test-throttle.c
914
+++ b/tests/test-throttle.c
915
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
916
ThrottleConfig cfg1, cfg2;
917
BlockBackend *blk1, *blk2, *blk3;
918
BlockBackendPublic *blkp1, *blkp2, *blkp3;
919
+ ThrottleGroupMember *tgm1, *tgm2, *tgm3;
920
921
/* No actual I/O is performed on these devices */
922
blk1 = blk_new(0, BLK_PERM_ALL);
923
@@ -XXX,XX +XXX,XX @@ static void test_groups(void)
924
blkp2 = blk_get_public(blk2);
925
blkp3 = blk_get_public(blk3);
926
927
- g_assert(blkp1->throttle_state == NULL);
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
--
448
--
1004
2.13.5
449
2.13.6
1005
450
1006
451
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
2
2
3
block/throttle.c uses existing I/O throttle infrastructure inside a
3
Serialized writes should be used in copy-on-write of backup(sync=none)
4
block filter driver. I/O operations are intercepted in the filter's
4
for image fleecing scheme.
5
read/write coroutines, and referred to block/throttle-groups.c
6
5
7
The driver can be used with the syntax
6
We need to change an assert in bdrv_aligned_pwritev, added in
8
-drive driver=throttle,file.filename=foo.qcow2,throttle-group=bar
7
28de2dcd88de. The assert may fail now, because call to
8
wait_serialising_requests here may become first call to it for this
9
request with serializing flag set. It occurs if the request is aligned
10
(otherwise, we should already set serializing flag before calling
11
bdrv_aligned_pwritev and correspondingly waited for all intersecting
12
requests). However, for aligned requests, we should not care about
13
outdating of previously read data, as there no such data. Therefore,
14
let's just update an assert to not care about aligned requests.
9
15
10
which registers the throttle filter node with the ThrottleGroup 'bar'. The
16
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
11
given group must be created beforehand with object-add or -object.
17
Reviewed-by: Fam Zheng <famz@redhat.com>
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>
16
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
18
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
---
19
---
18
qapi/block-core.json | 18 ++-
20
include/block/block.h | 14 +++++++++++++-
19
include/block/throttle-groups.h | 5 +
21
block/io.c | 28 +++++++++++++++++++++++++++-
20
include/qemu/throttle-options.h | 1 +
22
2 files changed, 40 insertions(+), 2 deletions(-)
21
block/throttle-groups.c | 15 ++-
22
block/throttle.c | 237 ++++++++++++++++++++++++++++++++++++++++
23
block/Makefile.objs | 1 +
24
6 files changed, 275 insertions(+), 2 deletions(-)
25
create mode 100644 block/throttle.c
26
23
27
diff --git a/qapi/block-core.json b/qapi/block-core.json
24
diff --git a/include/block/block.h b/include/block/block.h
28
index XXXXXXX..XXXXXXX 100644
25
index XXXXXXX..XXXXXXX 100644
29
--- a/qapi/block-core.json
26
--- a/include/block/block.h
30
+++ b/qapi/block-core.json
27
+++ b/include/block/block.h
31
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@ typedef enum {
32
# Drivers that are supported in block device operations.
29
* content. */
33
#
30
BDRV_REQ_WRITE_UNCHANGED = 0x40,
34
# @vxhs: Since 2.10
31
35
+# @throttle: Since 2.11
32
+ /*
36
#
33
+ * BDRV_REQ_SERIALISING forces request serialisation for writes.
37
# Since: 2.9
34
+ * It is used to ensure that writes to the backing file of a backup process
38
##
35
+ * target cannot race with a read of the backup target that defers to the
39
@@ -XXX,XX +XXX,XX @@
36
+ * backing file.
40
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
37
+ *
41
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
38
+ * Note, that BDRV_REQ_SERIALISING is _not_ opposite in meaning to
42
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
39
+ * BDRV_REQ_NO_SERIALISING. A more descriptive name for the latter might be
43
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
40
+ * _DO_NOT_WAIT_FOR_SERIALISING, except that is too long.
44
+ 'throttle', 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
41
+ */
45
42
+ BDRV_REQ_SERIALISING = 0x80,
46
##
43
+
47
# @BlockdevOptionsFile:
44
/* Mask of valid flags */
48
@@ -XXX,XX +XXX,XX @@
45
- BDRV_REQ_MASK = 0x7f,
49
'*tls-creds': 'str' } }
46
+ BDRV_REQ_MASK = 0xff,
50
47
} BdrvRequestFlags;
51
##
48
52
+# @BlockdevOptionsThrottle:
49
typedef struct BlockSizes {
53
+#
50
diff --git a/block/io.c b/block/io.c
54
+# Driver specific block device options for the throttle driver
55
+#
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
51
index XXXXXXX..XXXXXXX 100644
79
--- a/include/block/throttle-groups.h
52
--- a/block/io.c
80
+++ b/include/block/throttle-groups.h
53
+++ b/block/io.c
81
@@ -XXX,XX +XXX,XX @@ void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
54
@@ -XXX,XX +XXX,XX @@ static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
82
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
55
req->overlap_bytes = MAX(req->overlap_bytes, overlap_bytes);
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
}
56
}
111
57
112
+/* This function reads throttle_groups and must be called under the global
58
+static bool is_request_serialising_and_aligned(BdrvTrackedRequest *req)
113
+ * mutex.
114
+ */
115
+bool throttle_group_exists(const char *name)
116
+{
59
+{
117
+ return throttle_group_by_name(name) != NULL;
60
+ /*
61
+ * If the request is serialising, overlap_offset and overlap_bytes are set,
62
+ * so we can check if the request is aligned. Otherwise, don't care and
63
+ * return false.
64
+ */
65
+
66
+ return req->serialising && (req->offset == req->overlap_offset) &&
67
+ (req->bytes == req->overlap_bytes);
118
+}
68
+}
119
+
69
+
120
/* Increments the reference count of a ThrottleGroup given its name.
70
/**
121
*
71
* Round a region to cluster boundaries
122
* If no ThrottleGroup is found with the given name a new one is
72
*/
123
@@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
73
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_preadv(BdrvChild *child,
124
ThrottleGroupMember *token;
74
mark_request_serialising(req, bdrv_get_cluster_size(bs));
125
int i;
75
}
126
76
127
+ if (!ts) {
77
+ /* BDRV_REQ_SERIALISING is only for write operation */
128
+ /* Discard already unregistered tgm */
78
+ assert(!(flags & BDRV_REQ_SERIALISING));
129
+ return;
79
+
80
if (!(flags & BDRV_REQ_NO_SERIALISING)) {
81
wait_serialising_requests(req);
82
}
83
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
84
85
/* BDRV_REQ_NO_SERIALISING is only for read operation */
86
assert(!(flags & BDRV_REQ_NO_SERIALISING));
87
+
88
+ if (flags & BDRV_REQ_SERIALISING) {
89
+ mark_request_serialising(req, bdrv_get_cluster_size(bs));
130
+ }
90
+ }
131
+
91
+
132
assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
92
waited = wait_serialising_requests(req);
133
assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
93
- assert(!waited || !req->serialising);
134
assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
94
+ assert(!waited || !req->serialising ||
135
@@ -XXX,XX +XXX,XX @@ static void throttle_group_obj_complete(UserCreatable *obj, Error **errp)
95
+ is_request_serialising_and_aligned(req));
136
assert(tg->name);
96
assert(req->overlap_offset <= offset);
137
97
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
138
/* error if name is duplicate */
98
if (flags & BDRV_REQ_WRITE_UNCHANGED) {
139
- if (throttle_group_by_name(tg->name) != NULL) {
99
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(
140
+ if (throttle_group_exists(tg->name)) {
100
tracked_request_begin(&req, src->bs, src_offset, bytes,
141
error_setg(errp, "A group with this name already exists");
101
BDRV_TRACKED_READ);
142
return;
102
143
}
103
+ /* BDRV_REQ_SERIALISING is only for write operation */
144
diff --git a/block/throttle.c b/block/throttle.c
104
+ assert(!(read_flags & BDRV_REQ_SERIALISING));
145
new file mode 100644
105
if (!(read_flags & BDRV_REQ_NO_SERIALISING)) {
146
index XXXXXXX..XXXXXXX
106
wait_serialising_requests(&req);
147
--- /dev/null
107
}
148
+++ b/block/throttle.c
108
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(
149
@@ -XXX,XX +XXX,XX @@
109
150
+/*
110
/* BDRV_REQ_NO_SERIALISING is only for read operation */
151
+ * QEMU block throttling filter driver infrastructure
111
assert(!(write_flags & BDRV_REQ_NO_SERIALISING));
152
+ *
112
+ if (write_flags & BDRV_REQ_SERIALISING) {
153
+ * Copyright (c) 2017 Manos Pitsidianakis
113
+ mark_request_serialising(&req, bdrv_get_cluster_size(dst->bs));
154
+ *
114
+ }
155
+ * This program is free software; you can redistribute it and/or
115
wait_serialising_requests(&req);
156
+ * modify it under the terms of the GNU General Public License as
116
157
+ * published by the Free Software Foundation; either version 2 or
117
ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
158
+ * (at your option) version 3 of the License.
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
+ }
202
+
203
+ group_name = qemu_opt_get(opts, QEMU_OPT_THROTTLE_GROUP_NAME);
204
+ if (!group_name) {
205
+ error_setg(errp, "Please specify a throttle group");
206
+ ret = -EINVAL;
207
+ goto fin;
208
+ } else if (!throttle_group_exists(group_name)) {
209
+ error_setg(errp, "Throttle group '%s' does not exist", group_name);
210
+ ret = -EINVAL;
211
+ goto fin;
212
+ }
213
+
214
+ /* Register membership to group with name group_name */
215
+ throttle_group_register_tgm(tgm, group_name, bdrv_get_aio_context(bs));
216
+ ret = 0;
217
+fin:
218
+ qemu_opts_del(opts);
219
+ return ret;
220
+}
221
+
222
+static int throttle_open(BlockDriverState *bs, QDict *options,
223
+ int flags, Error **errp)
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
389
--- a/block/Makefile.objs
390
+++ b/block/Makefile.objs
391
@@ -XXX,XX +XXX,XX @@ block-obj-y += accounting.o dirty-bitmap.o
392
block-obj-y += write-threshold.o
393
block-obj-y += backup.o
394
block-obj-$(CONFIG_REPLICATION) += replication.o
395
+block-obj-y += throttle.o
396
397
block-obj-y += crypto.o
398
399
--
118
--
400
2.13.5
119
2.13.6
401
120
402
121
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
Fleecing scheme works as follows: we want a kind of temporary snapshot
4
of active drive A. We create temporary image B, with B->backing = A.
5
Then we start backup(sync=none) from A to B. From this point, B reads
6
as point-in-time snapshot of A (A continues to be active drive,
7
accepting guest IO).
8
9
This scheme needs some additional synchronization between reads from B
10
and backup COW operations, otherwise, the following situation is
11
theoretically possible:
12
13
(assume B is qcow2, client is NBD client, reading from B)
14
15
1. client starts reading and take qcow2 mutex in qcow2_co_preadv, and
16
goes up to l2 table loading (assume cache miss)
17
18
2) guest write => backup COW => qcow2 write =>
19
try to take qcow2 mutex => waiting
20
21
3. l2 table loaded, we see that cluster is UNALLOCATED, go to
22
"case QCOW2_CLUSTER_UNALLOCATED" and unlock mutex before
23
bdrv_co_preadv(bs->backing, ...)
24
25
4) aha, mutex unlocked, backup COW continues, and we finally finish
26
guest write and change cluster in our active disk A
27
28
5. actually, do bdrv_co_preadv(bs->backing, ...) and read
29
_new updated_ data.
30
31
To avoid this, let's make backup writes serializing, to not intersect
32
with reads from B.
33
34
Note: we expand range of handled cases from (sync=none and
35
B->backing = A) to just (A in backing chain of B), to finally allow
36
safe reading from B during backup for all cases when A in backing chain
37
of B, i.e. B formally looks like point-in-time snapshot of A.
38
39
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
40
Reviewed-by: Fam Zheng <famz@redhat.com>
41
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
42
---
43
block/backup.c | 20 ++++++++++++++------
44
1 file changed, 14 insertions(+), 6 deletions(-)
45
46
diff --git a/block/backup.c b/block/backup.c
47
index XXXXXXX..XXXXXXX 100644
48
--- a/block/backup.c
49
+++ b/block/backup.c
50
@@ -XXX,XX +XXX,XX @@ typedef struct BackupBlockJob {
51
HBitmap *copy_bitmap;
52
bool use_copy_range;
53
int64_t copy_range_size;
54
+
55
+ bool serialize_target_writes;
56
} BackupBlockJob;
57
58
static const BlockJobDriver backup_job_driver;
59
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
60
QEMUIOVector qiov;
61
BlockBackend *blk = job->common.blk;
62
int nbytes;
63
+ int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
64
+ int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
65
66
hbitmap_reset(job->copy_bitmap, start / job->cluster_size, 1);
67
nbytes = MIN(job->cluster_size, job->len - start);
68
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
69
iov.iov_len = nbytes;
70
qemu_iovec_init_external(&qiov, &iov, 1);
71
72
- ret = blk_co_preadv(blk, start, qiov.size, &qiov,
73
- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0);
74
+ ret = blk_co_preadv(blk, start, qiov.size, &qiov, read_flags);
75
if (ret < 0) {
76
trace_backup_do_cow_read_fail(job, start, ret);
77
if (error_is_read) {
78
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_bounce_buffer(BackupBlockJob *job,
79
80
if (qemu_iovec_is_zero(&qiov)) {
81
ret = blk_co_pwrite_zeroes(job->target, start,
82
- qiov.size, BDRV_REQ_MAY_UNMAP);
83
+ qiov.size, write_flags | BDRV_REQ_MAY_UNMAP);
84
} else {
85
ret = blk_co_pwritev(job->target, start,
86
- qiov.size, &qiov,
87
- job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0);
88
+ qiov.size, &qiov, write_flags |
89
+ (job->compress ? BDRV_REQ_WRITE_COMPRESSED : 0));
90
}
91
if (ret < 0) {
92
trace_backup_do_cow_write_fail(job, start, ret);
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
94
int nr_clusters;
95
BlockBackend *blk = job->common.blk;
96
int nbytes;
97
+ int read_flags = is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0;
98
+ int write_flags = job->serialize_target_writes ? BDRV_REQ_SERIALISING : 0;
99
100
assert(QEMU_IS_ALIGNED(job->copy_range_size, job->cluster_size));
101
nbytes = MIN(job->copy_range_size, end - start);
102
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn backup_cow_with_offload(BackupBlockJob *job,
103
hbitmap_reset(job->copy_bitmap, start / job->cluster_size,
104
nr_clusters);
105
ret = blk_co_copy_range(blk, start, job->target, start, nbytes,
106
- is_write_notifier ? BDRV_REQ_NO_SERIALISING : 0, 0);
107
+ read_flags, write_flags);
108
if (ret < 0) {
109
trace_backup_do_cow_copy_range_fail(job, start, ret);
110
hbitmap_set(job->copy_bitmap, start / job->cluster_size,
111
@@ -XXX,XX +XXX,XX @@ BlockJob *backup_job_create(const char *job_id, BlockDriverState *bs,
112
sync_bitmap : NULL;
113
job->compress = compress;
114
115
+ /* Detect image-fleecing (and similar) schemes */
116
+ job->serialize_target_writes = bdrv_chain_contains(target, bs);
117
+
118
/* If there is no backing file on the target, we cannot rely on COW if our
119
* backup cluster size is smaller than the target cluster size. Even for
120
* targets with a backing file, try to avoid COW if possible. */
121
--
122
2.13.6
123
124
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Ari Sundholm <ari@tuxera.com>
2
2
3
ThrottleGroup is converted to an object. This will allow the future
3
This was accidentally omitted. Thanks to Eric Blake for spotting this.
4
throttle block filter drive easy creation and configuration of throttle
5
groups in QMP and cli.
6
4
7
A new QAPI struct, ThrottleLimits, is introduced to provide a shared
5
Signed-off-by: Ari Sundholm <ari@tuxera.com>
8
struct for all throttle configuration needs in QMP.
6
Reviewed-by: Eric Blake <eblake@redhat.com>
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>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
51
---
8
---
52
qapi/block-core.json | 48 +++++
9
qapi/block-core.json | 2 ++
53
include/block/throttle-groups.h | 3 +
10
1 file changed, 2 insertions(+)
54
include/qemu/throttle-options.h | 59 ++++--
55
include/qemu/throttle.h | 3 +
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
11
61
diff --git a/qapi/block-core.json b/qapi/block-core.json
12
diff --git a/qapi/block-core.json b/qapi/block-core.json
62
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
63
--- a/qapi/block-core.json
14
--- a/qapi/block-core.json
64
+++ b/qapi/block-core.json
15
+++ b/qapi/block-core.json
65
@@ -XXX,XX +XXX,XX @@
16
@@ -XXX,XX +XXX,XX @@
66
'*iops_size': 'int', '*group': 'str' } }
17
# @log-sector-size: sector size used in logging writes to @file, determines
67
18
# granularity of offsets and sizes of writes (default: 512)
68
##
19
#
69
+# @ThrottleLimits:
20
+# @log-append: append to an existing log (default: false)
70
+#
21
+#
71
+# Limit parameters for throttling.
22
# @log-super-update-interval: interval of write requests after which the log
72
+# Since some limit combinations are illegal, limits should always be set in one
23
# super block is updated to disk (default: 4096)
73
+# transaction. All fields are optional. When setting limits, if a field is
74
+# missing the current value is not changed.
75
+#
76
+# @iops-total: limit total I/O operations per second
77
+# @iops-total-max: I/O operations burst
78
+# @iops-total-max-length: length of the iops-total-max burst period, in seconds
79
+# It must only be set if @iops-total-max is set as well.
80
+# @iops-read: limit read operations per second
81
+# @iops-read-max: I/O operations read burst
82
+# @iops-read-max-length: length of the iops-read-max burst period, in seconds
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
+
116
+##
117
# @block-stream:
118
#
24
#
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;
566
+ }
567
+
568
+ /* check validity */
569
+ throttle_get_config(&tg->ts, &cfg);
570
+ if (!throttle_is_valid(&cfg, errp)) {
571
+ return;
572
+ }
573
+ throttle_config(&tg->ts, tg->clock_type, &cfg);
574
+ QTAILQ_INSERT_TAIL(&throttle_groups, tg, list);
575
+ tg->is_initialized = true;
576
+}
577
+
578
+/* This function edits throttle_groups and must be called under the global
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
{
768
- qemu_mutex_init(&throttle_groups_lock);
769
+ type_register_static(&throttle_group_info);
770
}
771
772
-block_init(throttle_groups_init);
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
--
25
--
946
2.13.5
26
2.13.6
947
27
948
28
diff view generated by jsdifflib
New patch
1
From: Ari Sundholm <ari@tuxera.com>
1
2
3
The sector size needs to be large enough to accommodate the data
4
structures for the log super block and log write entries. This was
5
previously not properly checked, which made it possible to cause
6
QEMU to badly misbehave.
7
8
Signed-off-by: Ari Sundholm <ari@tuxera.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
block/blklogwrites.c | 5 ++++-
12
1 file changed, 4 insertions(+), 1 deletion(-)
13
14
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
15
index XXXXXXX..XXXXXXX 100644
16
--- a/block/blklogwrites.c
17
+++ b/block/blklogwrites.c
18
@@ -XXX,XX +XXX,XX @@ static inline uint32_t blk_log_writes_log2(uint32_t value)
19
20
static inline bool blk_log_writes_sector_size_valid(uint32_t sector_size)
21
{
22
- return sector_size < (1ull << 24) && is_power_of_2(sector_size);
23
+ return is_power_of_2(sector_size) &&
24
+ sector_size >= sizeof(struct log_write_super) &&
25
+ sector_size >= sizeof(struct log_write_entry) &&
26
+ sector_size < (1ull << 24);
27
}
28
29
static uint64_t blk_log_writes_find_cur_log_sector(BdrvChild *log,
30
--
31
2.13.6
32
33
diff view generated by jsdifflib
New patch
1
From: Cornelia Huck <cohuck@redhat.com>
1
2
3
This reverts commit 6266e900b8083945cb766b45c124fb3c42932cb3.
4
5
Some deprecated -drive options were still in use by libvirt, only
6
fixed with libvirt commit b340c6c614 ("qemu: format serial and geometry
7
on frontend disk device"), which is not yet in any released version
8
of libvirt.
9
10
So let's hold off removing the deprecated options for one more QEMU
11
release.
12
13
Reported-by: Christian Borntraeger <borntraeger@de.ibm.com>
14
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
15
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
16
---
17
blockdev.c | 12 ++++++++++++
18
1 file changed, 12 insertions(+)
19
20
diff --git a/blockdev.c b/blockdev.c
21
index XXXXXXX..XXXXXXX 100644
22
--- a/blockdev.c
23
+++ b/blockdev.c
24
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
25
const char *filename;
26
Error *local_err = NULL;
27
int i;
28
+ const char *deprecated[] = {
29
+ };
30
31
/* Change legacy command line options into QMP ones */
32
static const struct {
33
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
34
goto fail;
35
}
36
37
+ /* Other deprecated options */
38
+ if (!qtest_enabled()) {
39
+ for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
40
+ if (qemu_opt_get(legacy_opts, deprecated[i]) != NULL) {
41
+ error_report("'%s' is deprecated, please use the corresponding "
42
+ "option of '-device' instead", deprecated[i]);
43
+ }
44
+ }
45
+ }
46
+
47
/* Media type */
48
value = qemu_opt_get(legacy_opts, "media");
49
if (value) {
50
--
51
2.13.6
52
53
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Cornelia Huck <cohuck@redhat.com>
2
2
3
Move the CoMutex and CoQueue inits inside throttle_group_register_tgm()
3
This reverts commit b0083267444a5e0f28391f6c2831a539f878d424.
4
which is called whenever a ThrottleGroupMember is initialized. There's
4
5
no need for them to be separate.
5
Hold off removing this for one more QEMU release (current libvirt
6
6
release still uses it.)
7
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
9
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
---
10
---
12
block/block-backend.c | 3 ---
11
include/hw/block/block.h | 1 +
13
block/throttle-groups.c | 3 +++
12
include/sysemu/blockdev.h | 1 +
14
2 files changed, 3 insertions(+), 3 deletions(-)
13
block/block-backend.c | 1 +
15
14
blockdev.c | 10 ++++++++++
15
hw/block/block.c | 13 +++++++++++++
16
hw/block/nvme.c | 1 +
17
hw/block/virtio-blk.c | 1 +
18
hw/ide/qdev.c | 1 +
19
hw/scsi/scsi-disk.c | 1 +
20
hw/usb/dev-storage.c | 1 +
21
tests/ahci-test.c | 6 +++---
22
tests/ide-test.c | 8 ++++----
23
qemu-doc.texi | 5 +++++
24
qemu-options.hx | 6 +++++-
25
14 files changed, 48 insertions(+), 8 deletions(-)
26
27
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
28
index XXXXXXX..XXXXXXX 100644
29
--- a/include/hw/block/block.h
30
+++ b/include/hw/block/block.h
31
@@ -XXX,XX +XXX,XX @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
32
33
/* Configuration helpers */
34
35
+void blkconf_serial(BlockConf *conf, char **serial);
36
bool blkconf_geometry(BlockConf *conf, int *trans,
37
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
38
Error **errp);
39
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
40
index XXXXXXX..XXXXXXX 100644
41
--- a/include/sysemu/blockdev.h
42
+++ b/include/sysemu/blockdev.h
43
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
44
bool is_default; /* Added by default_drive() ? */
45
int media_cd;
46
QemuOpts *opts;
47
+ char *serial;
48
QTAILQ_ENTRY(DriveInfo) next;
49
};
50
16
diff --git a/block/block-backend.c b/block/block-backend.c
51
diff --git a/block/block-backend.c b/block/block-backend.c
17
index XXXXXXX..XXXXXXX 100644
52
index XXXXXXX..XXXXXXX 100644
18
--- a/block/block-backend.c
53
--- a/block/block-backend.c
19
+++ b/block/block-backend.c
54
+++ b/block/block-backend.c
20
@@ -XXX,XX +XXX,XX @@ BlockBackend *blk_new(uint64_t perm, uint64_t shared_perm)
55
@@ -XXX,XX +XXX,XX @@ static void drive_info_del(DriveInfo *dinfo)
21
blk->shared_perm = shared_perm;
56
return;
22
blk_set_enable_write_cache(blk, true);
57
}
23
58
qemu_opts_del(dinfo->opts);
24
- qemu_co_mutex_init(&blk->public.throttle_group_member.throttled_reqs_lock);
59
+ g_free(dinfo->serial);
25
- qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[0]);
60
g_free(dinfo);
26
- qemu_co_queue_init(&blk->public.throttle_group_member.throttled_reqs[1]);
27
block_acct_init(&blk->stats);
28
29
notifier_list_init(&blk->remove_bs_notifiers);
30
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
31
index XXXXXXX..XXXXXXX 100644
32
--- a/block/throttle-groups.c
33
+++ b/block/throttle-groups.c
34
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
35
read_timer_cb,
36
write_timer_cb,
37
tgm);
38
+ qemu_co_mutex_init(&tgm->throttled_reqs_lock);
39
+ qemu_co_queue_init(&tgm->throttled_reqs[0]);
40
+ qemu_co_queue_init(&tgm->throttled_reqs[1]);
41
42
qemu_mutex_unlock(&tg->lock);
43
}
61
}
62
63
diff --git a/blockdev.c b/blockdev.c
64
index XXXXXXX..XXXXXXX 100644
65
--- a/blockdev.c
66
+++ b/blockdev.c
67
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
68
.type = QEMU_OPT_STRING,
69
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
70
},{
71
+ .name = "serial",
72
+ .type = QEMU_OPT_STRING,
73
+ .help = "disk serial number",
74
+ },{
75
.name = "file",
76
.type = QEMU_OPT_STRING,
77
.help = "file name",
78
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
79
const char *werror, *rerror;
80
bool read_only = false;
81
bool copy_on_read;
82
+ const char *serial;
83
const char *filename;
84
Error *local_err = NULL;
85
int i;
86
const char *deprecated[] = {
87
+ "serial"
88
};
89
90
/* Change legacy command line options into QMP ones */
91
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
92
goto fail;
93
}
94
95
+ /* Serial number */
96
+ serial = qemu_opt_get(legacy_opts, "serial");
97
+
98
/* no id supplied -> create one */
99
if (qemu_opts_id(all_opts) == NULL) {
100
char *new_id;
101
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
102
dinfo->type = type;
103
dinfo->bus = bus_id;
104
dinfo->unit = unit_id;
105
+ dinfo->serial = g_strdup(serial);
106
107
blk_set_legacy_dinfo(blk, dinfo);
108
109
diff --git a/hw/block/block.c b/hw/block/block.c
110
index XXXXXXX..XXXXXXX 100644
111
--- a/hw/block/block.c
112
+++ b/hw/block/block.c
113
@@ -XXX,XX +XXX,XX @@
114
#include "qapi/qapi-types-block.h"
115
#include "qemu/error-report.h"
116
117
+void blkconf_serial(BlockConf *conf, char **serial)
118
+{
119
+ DriveInfo *dinfo;
120
+
121
+ if (!*serial) {
122
+ /* try to fall back to value set with legacy -drive serial=... */
123
+ dinfo = blk_legacy_dinfo(conf->blk);
124
+ if (dinfo) {
125
+ *serial = g_strdup(dinfo->serial);
126
+ }
127
+ }
128
+}
129
+
130
void blkconf_blocksizes(BlockConf *conf)
131
{
132
BlockBackend *blk = conf->blk;
133
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
134
index XXXXXXX..XXXXXXX 100644
135
--- a/hw/block/nvme.c
136
+++ b/hw/block/nvme.c
137
@@ -XXX,XX +XXX,XX @@ static void nvme_realize(PCIDevice *pci_dev, Error **errp)
138
return;
139
}
140
141
+ blkconf_serial(&n->conf, &n->serial);
142
if (!n->serial) {
143
error_setg(errp, "serial property not set");
144
return;
145
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
146
index XXXXXXX..XXXXXXX 100644
147
--- a/hw/block/virtio-blk.c
148
+++ b/hw/block/virtio-blk.c
149
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
150
return;
151
}
152
153
+ blkconf_serial(&conf->conf, &conf->serial);
154
if (!blkconf_apply_backend_options(&conf->conf,
155
blk_is_read_only(conf->conf.blk), true,
156
errp)) {
157
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
158
index XXXXXXX..XXXXXXX 100644
159
--- a/hw/ide/qdev.c
160
+++ b/hw/ide/qdev.c
161
@@ -XXX,XX +XXX,XX @@ static void ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind, Error **errp)
162
return;
163
}
164
165
+ blkconf_serial(&dev->conf, &dev->serial);
166
if (kind != IDE_CD) {
167
if (!blkconf_geometry(&dev->conf, &dev->chs_trans, 65535, 16, 255,
168
errp)) {
169
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
170
index XXXXXXX..XXXXXXX 100644
171
--- a/hw/scsi/scsi-disk.c
172
+++ b/hw/scsi/scsi-disk.c
173
@@ -XXX,XX +XXX,XX @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
174
return;
175
}
176
177
+ blkconf_serial(&s->qdev.conf, &s->serial);
178
blkconf_blocksizes(&s->qdev.conf);
179
180
if (s->qdev.conf.logical_block_size >
181
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
182
index XXXXXXX..XXXXXXX 100644
183
--- a/hw/usb/dev-storage.c
184
+++ b/hw/usb/dev-storage.c
185
@@ -XXX,XX +XXX,XX @@ static void usb_msd_storage_realize(USBDevice *dev, Error **errp)
186
return;
187
}
188
189
+ blkconf_serial(&s->conf, &dev->serial);
190
blkconf_blocksizes(&s->conf);
191
if (!blkconf_apply_backend_options(&s->conf, blk_is_read_only(blk), true,
192
errp)) {
193
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
194
index XXXXXXX..XXXXXXX 100644
195
--- a/tests/ahci-test.c
196
+++ b/tests/ahci-test.c
197
@@ -XXX,XX +XXX,XX @@ static AHCIQState *ahci_boot(const char *cli, ...)
198
s = ahci_vboot(cli, ap);
199
va_end(ap);
200
} else {
201
- cli = "-drive if=none,id=drive0,file=%s,cache=writeback,format=%s"
202
+ cli = "-drive if=none,id=drive0,file=%s,cache=writeback,serial=%s"
203
+ ",format=%s"
204
" -M q35 "
205
"-device ide-hd,drive=drive0 "
206
- "-global ide-hd.serial=%s "
207
"-global ide-hd.ver=%s";
208
- s = ahci_boot(cli, tmp_path, imgfmt, "testdisk", "version");
209
+ s = ahci_boot(cli, tmp_path, "testdisk", imgfmt, "version");
210
}
211
212
return s;
213
diff --git a/tests/ide-test.c b/tests/ide-test.c
214
index XXXXXXX..XXXXXXX 100644
215
--- a/tests/ide-test.c
216
+++ b/tests/ide-test.c
217
@@ -XXX,XX +XXX,XX @@ static void test_bmdma_no_busmaster(void)
218
static void test_bmdma_setup(void)
219
{
220
ide_test_start(
221
- "-drive file=%s,if=ide,cache=writeback,format=raw "
222
- "-global ide-hd.serial=%s -global ide-hd.ver=%s",
223
+ "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
224
+ "-global ide-hd.ver=%s",
225
tmp_path, "testdisk", "version");
226
qtest_irq_intercept_in(global_qtest, "ioapic");
227
}
228
@@ -XXX,XX +XXX,XX @@ static void test_identify(void)
229
int ret;
230
231
ide_test_start(
232
- "-drive file=%s,if=ide,cache=writeback,format=raw "
233
- "-global ide-hd.serial=%s -global ide-hd.ver=%s",
234
+ "-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
235
+ "-global ide-hd.ver=%s",
236
tmp_path, "testdisk", "version");
237
238
dev = get_pci_device(&bmdma_bar, &ide_bar);
239
diff --git a/qemu-doc.texi b/qemu-doc.texi
240
index XXXXXXX..XXXXXXX 100644
241
--- a/qemu-doc.texi
242
+++ b/qemu-doc.texi
243
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
244
(for embedded NICs). The new syntax allows different settings to be
245
provided per NIC.
246
247
+@subsection -drive serial=... (since 2.10.0)
248
+
249
+The drive serial argument is replaced by the the serial argument
250
+that can be specified with the ``-device'' parameter.
251
+
252
@subsection -usbdevice (since 2.10.0)
253
254
The ``-usbdevice DEV'' argument is now a synonym for setting
255
diff --git a/qemu-options.hx b/qemu-options.hx
256
index XXXXXXX..XXXXXXX 100644
257
--- a/qemu-options.hx
258
+++ b/qemu-options.hx
259
@@ -XXX,XX +XXX,XX @@ ETEXI
260
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
261
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
262
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
263
- " [,snapshot=on|off][,rerror=ignore|stop|report]\n"
264
+ " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
265
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
266
" [,readonly=on|off][,copy-on-read=on|off]\n"
267
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
268
@@ -XXX,XX +XXX,XX @@ The default mode is @option{cache=writeback}.
269
Specify which disk @var{format} will be used rather than detecting
270
the format. Can be used to specify format=raw to avoid interpreting
271
an untrusted format header.
272
+@item serial=@var{serial}
273
+This option specifies the serial number to assign to the device. This
274
+parameter is deprecated, use the corresponding parameter of @code{-device}
275
+instead.
276
@item werror=@var{action},rerror=@var{action}
277
Specify which @var{action} to take on write and read errors. Valid actions are:
278
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
44
--
279
--
45
2.13.5
280
2.13.6
46
281
47
282
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Cornelia Huck <cohuck@redhat.com>
2
2
3
The following functions fail if bs->drv is a filter and does not
3
This reverts commit eae3bd1eb7c6b105d30ec06008b3bc3dfc5f45bb.
4
implement them:
5
4
6
bdrv_probe_blocksizes
5
Reverted to avoid conflicts for geometry options revert.
7
bdrv_probe_geometry
8
bdrv_truncate
9
bdrv_has_zero_init
10
bdrv_get_info
11
6
12
Instead, the call should be passed to bs->file if it exists, to allow
7
Signed-off-by: Cornelia Huck <cohuck@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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
22
---
9
---
23
include/block/block_int.h | 6 +++++-
10
include/sysemu/blockdev.h | 1 +
24
block.c | 21 +++++++++++++++++++--
11
blockdev.c | 17 ++++++++++++++++-
25
2 files changed, 24 insertions(+), 3 deletions(-)
12
device-hotplug.c | 4 ++++
13
qemu-doc.texi | 5 +++++
14
qemu-options.hx | 5 ++++-
15
5 files changed, 30 insertions(+), 2 deletions(-)
26
16
27
diff --git a/include/block/block_int.h b/include/block/block_int.h
17
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
28
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
29
--- a/include/block/block_int.h
19
--- a/include/sysemu/blockdev.h
30
+++ b/include/block/block_int.h
20
+++ b/include/sysemu/blockdev.h
31
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
21
@@ -XXX,XX +XXX,XX @@ typedef enum {
32
const char *format_name;
22
} BlockInterfaceType;
33
int instance_size;
23
34
24
struct DriveInfo {
35
- /* set to true if the BlockDriver is a block filter */
25
+ const char *devaddr;
36
+ /* set to true if the BlockDriver is a block filter. Block filters pass
26
BlockInterfaceType type;
37
+ * certain callbacks that refer to data (see block.c) to their bs->file if
27
int bus;
38
+ * the driver doesn't implement them. Drivers that do not wish to forward
28
int unit;
39
+ * must implement them and return -ENOTSUP.
29
diff --git a/blockdev.c b/blockdev.c
40
+ */
41
bool is_filter;
42
/* for snapshots block filter like Quorum can implement the
43
* following recursive callback.
44
diff --git a/block.c b/block.c
45
index XXXXXXX..XXXXXXX 100644
30
index XXXXXXX..XXXXXXX 100644
46
--- a/block.c
31
--- a/blockdev.c
47
+++ b/block.c
32
+++ b/blockdev.c
48
@@ -XXX,XX +XXX,XX @@ int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
33
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
49
34
.type = QEMU_OPT_STRING,
50
if (drv && drv->bdrv_probe_blocksizes) {
35
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
51
return drv->bdrv_probe_blocksizes(bs, bsz);
36
},{
52
+ } else if (drv && drv->is_filter && bs->file) {
37
+ .name = "addr",
53
+ return bdrv_probe_blocksizes(bs->file->bs, bsz);
38
+ .type = QEMU_OPT_STRING,
39
+ .help = "pci address (virtio only)",
40
+ },{
41
.name = "serial",
42
.type = QEMU_OPT_STRING,
43
.help = "disk serial number",
44
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
45
DriveMediaType media = MEDIA_DISK;
46
BlockInterfaceType type;
47
int max_devs, bus_id, unit_id, index;
48
+ const char *devaddr;
49
const char *werror, *rerror;
50
bool read_only = false;
51
bool copy_on_read;
52
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
53
Error *local_err = NULL;
54
int i;
55
const char *deprecated[] = {
56
- "serial"
57
+ "serial", "addr"
58
};
59
60
/* Change legacy command line options into QMP ones */
61
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
54
}
62
}
55
63
56
return -ENOTSUP;
64
/* Add virtio block device */
57
@@ -XXX,XX +XXX,XX @@ int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
65
+ devaddr = qemu_opt_get(legacy_opts, "addr");
58
66
+ if (devaddr && type != IF_VIRTIO) {
59
if (drv && drv->bdrv_probe_geometry) {
67
+ error_report("addr is not supported by this bus type");
60
return drv->bdrv_probe_geometry(bs, geo);
68
+ goto fail;
61
+ } else if (drv && drv->is_filter && bs->file) {
69
+ }
62
+ return bdrv_probe_geometry(bs->file->bs, geo);
70
+
71
if (type == IF_VIRTIO) {
72
QemuOpts *devopts;
73
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
74
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
75
}
76
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
77
&error_abort);
78
+ if (devaddr) {
79
+ qemu_opt_set(devopts, "addr", devaddr, &error_abort);
80
+ }
63
}
81
}
64
82
65
return -ENOTSUP;
83
filename = qemu_opt_get(legacy_opts, "file");
66
@@ -XXX,XX +XXX,XX @@ int bdrv_truncate(BdrvChild *child, int64_t offset, PreallocMode prealloc,
84
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
67
85
dinfo->type = type;
68
assert(child->perm & BLK_PERM_RESIZE);
86
dinfo->bus = bus_id;
69
87
dinfo->unit = unit_id;
70
+ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
88
+ dinfo->devaddr = devaddr;
71
if (!drv) {
89
dinfo->serial = g_strdup(serial);
72
error_setg(errp, "No medium inserted");
90
73
return -ENOMEDIUM;
91
blk_set_legacy_dinfo(blk, dinfo);
92
diff --git a/device-hotplug.c b/device-hotplug.c
93
index XXXXXXX..XXXXXXX 100644
94
--- a/device-hotplug.c
95
+++ b/device-hotplug.c
96
@@ -XXX,XX +XXX,XX @@ void hmp_drive_add(Monitor *mon, const QDict *qdict)
97
if (!dinfo) {
98
goto err;
74
}
99
}
75
if (!drv->bdrv_truncate) {
100
+ if (dinfo->devaddr) {
76
+ if (bs->file && drv->is_filter) {
101
+ monitor_printf(mon, "Parameter addr not supported\n");
77
+ return bdrv_truncate(bs->file, offset, prealloc, errp);
102
+ goto err;
78
+ }
79
error_setg(errp, "Image format driver does not support resize");
80
return -ENOTSUP;
81
}
82
@@ -XXX,XX +XXX,XX @@ int bdrv_has_zero_init(BlockDriverState *bs)
83
if (bs->drv->bdrv_has_zero_init) {
84
return bs->drv->bdrv_has_zero_init(bs);
85
}
86
+ if (bs->file && bs->drv->is_filter) {
87
+ return bdrv_has_zero_init(bs->file->bs);
88
+ }
103
+ }
89
104
90
/* safe default */
105
switch (dinfo->type) {
91
return 0;
106
case IF_NONE:
92
@@ -XXX,XX +XXX,XX @@ void bdrv_get_backing_filename(BlockDriverState *bs,
107
diff --git a/qemu-doc.texi b/qemu-doc.texi
93
int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
108
index XXXXXXX..XXXXXXX 100644
94
{
109
--- a/qemu-doc.texi
95
BlockDriver *drv = bs->drv;
110
+++ b/qemu-doc.texi
96
- if (!drv)
111
@@ -XXX,XX +XXX,XX @@ provided per NIC.
97
+ /* if bs->drv == NULL, bs is closed, so there's nothing to do here */
112
The drive serial argument is replaced by the the serial argument
98
+ if (!drv) {
113
that can be specified with the ``-device'' parameter.
99
return -ENOMEDIUM;
114
100
- if (!drv->bdrv_get_info)
115
+@subsection -drive addr=... (since 2.10.0)
101
+ }
116
+
102
+ if (!drv->bdrv_get_info) {
117
+The drive addr argument is replaced by the the addr argument
103
+ if (bs->file && drv->is_filter) {
118
+that can be specified with the ``-device'' parameter.
104
+ return bdrv_get_info(bs->file->bs, bdi);
119
+
105
+ }
120
@subsection -usbdevice (since 2.10.0)
106
return -ENOTSUP;
121
107
+ }
122
The ``-usbdevice DEV'' argument is now a synonym for setting
108
memset(bdi, 0, sizeof(*bdi));
123
diff --git a/qemu-options.hx b/qemu-options.hx
109
return drv->bdrv_get_info(bs, bdi);
124
index XXXXXXX..XXXXXXX 100644
110
}
125
--- a/qemu-options.hx
126
+++ b/qemu-options.hx
127
@@ -XXX,XX +XXX,XX @@ ETEXI
128
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
129
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
130
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
131
- " [,snapshot=on|off][,serial=s][,rerror=ignore|stop|report]\n"
132
+ " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
133
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
134
" [,readonly=on|off][,copy-on-read=on|off]\n"
135
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
136
@@ -XXX,XX +XXX,XX @@ an untrusted format header.
137
This option specifies the serial number to assign to the device. This
138
parameter is deprecated, use the corresponding parameter of @code{-device}
139
instead.
140
+@item addr=@var{addr}
141
+Specify the controller's PCI address (if=virtio only). This parameter is
142
+deprecated, use the corresponding parameter of @code{-device} instead.
143
@item werror=@var{action},rerror=@var{action}
144
Specify which @var{action} to take on write and read errors. Valid actions are:
145
"ignore" (ignore the error and try to continue), "stop" (pause QEMU),
111
--
146
--
112
2.13.5
147
2.13.6
113
148
114
149
diff view generated by jsdifflib
New patch
1
1
From: Cornelia Huck <cohuck@redhat.com>
2
3
This reverts commit a7aff6dd10b16b67e8b142d0c94c5d92c3fe88f6.
4
5
Hold off removing this for one more QEMU release (current libvirt
6
release still uses it.)
7
8
Signed-off-by: Cornelia Huck <cohuck@redhat.com>
9
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
---
11
include/sysemu/blockdev.h | 1 +
12
blockdev.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++-
13
hw/block/block.c | 14 +++++++++
14
tests/hd-geo-test.c | 37 ++++++++++++++++++-----
15
hmp-commands.hx | 1 +
16
qemu-doc.texi | 5 ++++
17
qemu-options.hx | 7 ++++-
18
7 files changed, 131 insertions(+), 9 deletions(-)
19
20
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/sysemu/blockdev.h
23
+++ b/include/sysemu/blockdev.h
24
@@ -XXX,XX +XXX,XX @@ struct DriveInfo {
25
int auto_del; /* see blockdev_mark_auto_del() */
26
bool is_default; /* Added by default_drive() ? */
27
int media_cd;
28
+ int cyls, heads, secs, trans;
29
QemuOpts *opts;
30
char *serial;
31
QTAILQ_ENTRY(DriveInfo) next;
32
diff --git a/blockdev.c b/blockdev.c
33
index XXXXXXX..XXXXXXX 100644
34
--- a/blockdev.c
35
+++ b/blockdev.c
36
@@ -XXX,XX +XXX,XX @@ QemuOptsList qemu_legacy_drive_opts = {
37
.type = QEMU_OPT_STRING,
38
.help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
39
},{
40
+ .name = "cyls",
41
+ .type = QEMU_OPT_NUMBER,
42
+ .help = "number of cylinders (ide disk geometry)",
43
+ },{
44
+ .name = "heads",
45
+ .type = QEMU_OPT_NUMBER,
46
+ .help = "number of heads (ide disk geometry)",
47
+ },{
48
+ .name = "secs",
49
+ .type = QEMU_OPT_NUMBER,
50
+ .help = "number of sectors (ide disk geometry)",
51
+ },{
52
+ .name = "trans",
53
+ .type = QEMU_OPT_STRING,
54
+ .help = "chs translation (auto, lba, none)",
55
+ },{
56
.name = "addr",
57
.type = QEMU_OPT_STRING,
58
.help = "pci address (virtio only)",
59
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
60
QemuOpts *legacy_opts;
61
DriveMediaType media = MEDIA_DISK;
62
BlockInterfaceType type;
63
+ int cyls, heads, secs, translation;
64
int max_devs, bus_id, unit_id, index;
65
const char *devaddr;
66
const char *werror, *rerror;
67
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
68
Error *local_err = NULL;
69
int i;
70
const char *deprecated[] = {
71
- "serial", "addr"
72
+ "serial", "trans", "secs", "heads", "cyls", "addr"
73
};
74
75
/* Change legacy command line options into QMP ones */
76
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
77
type = block_default_type;
78
}
79
80
+ /* Geometry */
81
+ cyls = qemu_opt_get_number(legacy_opts, "cyls", 0);
82
+ heads = qemu_opt_get_number(legacy_opts, "heads", 0);
83
+ secs = qemu_opt_get_number(legacy_opts, "secs", 0);
84
+
85
+ if (cyls || heads || secs) {
86
+ if (cyls < 1) {
87
+ error_report("invalid physical cyls number");
88
+ goto fail;
89
+ }
90
+ if (heads < 1) {
91
+ error_report("invalid physical heads number");
92
+ goto fail;
93
+ }
94
+ if (secs < 1) {
95
+ error_report("invalid physical secs number");
96
+ goto fail;
97
+ }
98
+ }
99
+
100
+ translation = BIOS_ATA_TRANSLATION_AUTO;
101
+ value = qemu_opt_get(legacy_opts, "trans");
102
+ if (value != NULL) {
103
+ if (!cyls) {
104
+ error_report("'%s' trans must be used with cyls, heads and secs",
105
+ value);
106
+ goto fail;
107
+ }
108
+ if (!strcmp(value, "none")) {
109
+ translation = BIOS_ATA_TRANSLATION_NONE;
110
+ } else if (!strcmp(value, "lba")) {
111
+ translation = BIOS_ATA_TRANSLATION_LBA;
112
+ } else if (!strcmp(value, "large")) {
113
+ translation = BIOS_ATA_TRANSLATION_LARGE;
114
+ } else if (!strcmp(value, "rechs")) {
115
+ translation = BIOS_ATA_TRANSLATION_RECHS;
116
+ } else if (!strcmp(value, "auto")) {
117
+ translation = BIOS_ATA_TRANSLATION_AUTO;
118
+ } else {
119
+ error_report("'%s' invalid translation type", value);
120
+ goto fail;
121
+ }
122
+ }
123
+
124
+ if (media == MEDIA_CDROM) {
125
+ if (cyls || secs || heads) {
126
+ error_report("CHS can't be set with media=cdrom");
127
+ goto fail;
128
+ }
129
+ }
130
+
131
/* Device address specified by bus/unit or index.
132
* If none was specified, try to find the first free one. */
133
bus_id = qemu_opt_get_number(legacy_opts, "bus", 0);
134
@@ -XXX,XX +XXX,XX @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
135
dinfo = g_malloc0(sizeof(*dinfo));
136
dinfo->opts = all_opts;
137
138
+ dinfo->cyls = cyls;
139
+ dinfo->heads = heads;
140
+ dinfo->secs = secs;
141
+ dinfo->trans = translation;
142
+
143
dinfo->type = type;
144
dinfo->bus = bus_id;
145
dinfo->unit = unit_id;
146
diff --git a/hw/block/block.c b/hw/block/block.c
147
index XXXXXXX..XXXXXXX 100644
148
--- a/hw/block/block.c
149
+++ b/hw/block/block.c
150
@@ -XXX,XX +XXX,XX @@ bool blkconf_geometry(BlockConf *conf, int *ptrans,
151
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
152
Error **errp)
153
{
154
+ DriveInfo *dinfo;
155
+
156
+ if (!conf->cyls && !conf->heads && !conf->secs) {
157
+ /* try to fall back to value set with legacy -drive cyls=... */
158
+ dinfo = blk_legacy_dinfo(conf->blk);
159
+ if (dinfo) {
160
+ conf->cyls = dinfo->cyls;
161
+ conf->heads = dinfo->heads;
162
+ conf->secs = dinfo->secs;
163
+ if (ptrans) {
164
+ *ptrans = dinfo->trans;
165
+ }
166
+ }
167
+ }
168
if (!conf->cyls && !conf->heads && !conf->secs) {
169
hd_geometry_guess(conf->blk,
170
&conf->cyls, &conf->heads, &conf->secs,
171
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
172
index XXXXXXX..XXXXXXX 100644
173
--- a/tests/hd-geo-test.c
174
+++ b/tests/hd-geo-test.c
175
@@ -XXX,XX +XXX,XX @@ static void setup_mbr(int img_idx, MBRcontents mbr)
176
177
static int setup_ide(int argc, char *argv[], int argv_sz,
178
int ide_idx, const char *dev, int img_idx,
179
- MBRcontents mbr)
180
+ MBRcontents mbr, const char *opts)
181
{
182
char *s1, *s2, *s3;
183
184
@@ -XXX,XX +XXX,XX @@ static int setup_ide(int argc, char *argv[], int argv_sz,
185
s3 = g_strdup(",media=cdrom");
186
}
187
argc = append_arg(argc, argv, argv_sz,
188
- g_strdup_printf("%s%s%s", s1, s2, s3));
189
+ g_strdup_printf("%s%s%s%s", s1, s2, s3, opts));
190
g_free(s1);
191
g_free(s2);
192
g_free(s3);
193
@@ -XXX,XX +XXX,XX @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
194
for (i = 0; i < backend_last; i++) {
195
cur_ide[i] = &hd_chst[i][mbr];
196
dev = use_device ? (is_hd(cur_ide[i]) ? "ide-hd" : "ide-cd") : NULL;
197
- argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr);
198
+ argc = setup_ide(argc, argv, ARGV_SIZE, i, dev, i, mbr, "");
199
}
200
args = g_strjoinv(" ", argv);
201
qtest_start(args);
202
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
203
const CHST expected_chst = { secs / (4 * 32) , 4, 32, trans };
204
205
argc = setup_common(argv, ARGV_SIZE);
206
- opts = g_strdup_printf("%s,%scyls=%d,heads=%d,secs=%d",
207
- dev, trans ? "bios-chs-trans=lba," : "",
208
+ opts = g_strdup_printf("%s,%s%scyls=%d,heads=%d,secs=%d",
209
+ dev ?: "",
210
+ trans && dev ? "bios-chs-" : "",
211
+ trans ? "trans=lba," : "",
212
expected_chst.cyls, expected_chst.heads,
213
expected_chst.secs);
214
cur_ide[0] = &expected_chst;
215
- argc = setup_ide(argc, argv, ARGV_SIZE, 0, opts, backend_small, mbr_chs);
216
+ argc = setup_ide(argc, argv, ARGV_SIZE,
217
+ 0, dev ? opts : NULL, backend_small, mbr_chs,
218
+ dev ? "" : opts);
219
g_free(opts);
220
args = g_strjoinv(" ", argv);
221
qtest_start(args);
222
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_user(const char *dev, bool trans)
223
}
224
225
/*
226
+ * Test case: IDE device (if=ide) with explicit CHS
227
+ */
228
+static void test_ide_drive_user_chs(void)
229
+{
230
+ test_ide_drive_user(NULL, false);
231
+}
232
+
233
+/*
234
+ * Test case: IDE device (if=ide) with explicit CHS and translation
235
+ */
236
+static void test_ide_drive_user_chst(void)
237
+{
238
+ test_ide_drive_user(NULL, true);
239
+}
240
+
241
+/*
242
* Test case: IDE device (if=none) with explicit CHS
243
*/
244
static void test_ide_device_user_chs(void)
245
@@ -XXX,XX +XXX,XX @@ static void test_ide_drive_cd_0(void)
246
for (i = 0; i <= backend_empty; i++) {
247
ide_idx = backend_empty - i;
248
cur_ide[ide_idx] = &hd_chst[i][mbr_blank];
249
- argc = setup_ide(argc, argv, ARGV_SIZE, ide_idx, NULL, i, mbr_blank);
250
+ argc = setup_ide(argc, argv, ARGV_SIZE,
251
+ ide_idx, NULL, i, mbr_blank, "");
252
}
253
args = g_strjoinv(" ", argv);
254
qtest_start(args);
255
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
256
qtest_add_func("hd-geo/ide/drive/mbr/blank", test_ide_drive_mbr_blank);
257
qtest_add_func("hd-geo/ide/drive/mbr/lba", test_ide_drive_mbr_lba);
258
qtest_add_func("hd-geo/ide/drive/mbr/chs", test_ide_drive_mbr_chs);
259
+ qtest_add_func("hd-geo/ide/drive/user/chs", test_ide_drive_user_chs);
260
+ qtest_add_func("hd-geo/ide/drive/user/chst", test_ide_drive_user_chst);
261
qtest_add_func("hd-geo/ide/drive/cd_0", test_ide_drive_cd_0);
262
qtest_add_func("hd-geo/ide/device/mbr/blank", test_ide_device_mbr_blank);
263
qtest_add_func("hd-geo/ide/device/mbr/lba", test_ide_device_mbr_lba);
264
diff --git a/hmp-commands.hx b/hmp-commands.hx
265
index XXXXXXX..XXXXXXX 100644
266
--- a/hmp-commands.hx
267
+++ b/hmp-commands.hx
268
@@ -XXX,XX +XXX,XX @@ ETEXI
269
.params = "[-n] [[<domain>:]<bus>:]<slot>\n"
270
"[file=file][,if=type][,bus=n]\n"
271
"[,unit=m][,media=d][,index=i]\n"
272
+ "[,cyls=c,heads=h,secs=s[,trans=t]]\n"
273
"[,snapshot=on|off][,cache=on|off]\n"
274
"[,readonly=on|off][,copy-on-read=on|off]",
275
.help = "add drive to PCI storage controller",
276
diff --git a/qemu-doc.texi b/qemu-doc.texi
277
index XXXXXXX..XXXXXXX 100644
278
--- a/qemu-doc.texi
279
+++ b/qemu-doc.texi
280
@@ -XXX,XX +XXX,XX @@ with ``-device ...,netdev=x''), or ``-nic user,smb=/some/dir''
281
(for embedded NICs). The new syntax allows different settings to be
282
provided per NIC.
283
284
+@subsection -drive cyls=...,heads=...,secs=...,trans=... (since 2.10.0)
285
+
286
+The drive geometry arguments are replaced by the the geometry arguments
287
+that can be specified with the ``-device'' parameter.
288
+
289
@subsection -drive serial=... (since 2.10.0)
290
291
The drive serial argument is replaced by the the serial argument
292
diff --git a/qemu-options.hx b/qemu-options.hx
293
index XXXXXXX..XXXXXXX 100644
294
--- a/qemu-options.hx
295
+++ b/qemu-options.hx
296
@@ -XXX,XX +XXX,XX @@ ETEXI
297
298
DEF("drive", HAS_ARG, QEMU_OPTION_drive,
299
"-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n"
300
+ " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n"
301
" [,cache=writethrough|writeback|none|directsync|unsafe][,format=f]\n"
302
- " [,snapshot=on|off][,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
303
+ " [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
304
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
305
" [,readonly=on|off][,copy-on-read=on|off]\n"
306
" [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
307
@@ -XXX,XX +XXX,XX @@ This option defines where is connected the drive by using an index in the list
308
of available connectors of a given interface type.
309
@item media=@var{media}
310
This option defines the type of the media: disk or cdrom.
311
+@item cyls=@var{c},heads=@var{h},secs=@var{s}[,trans=@var{t}]
312
+Force disk physical geometry and the optional BIOS translation (trans=none or
313
+lba). These parameters are deprecated, use the corresponding parameters
314
+of @code{-device} instead.
315
@item snapshot=@var{snapshot}
316
@var{snapshot} is "on" or "off" and controls snapshot mode for the given drive
317
(see @option{-snapshot}).
318
--
319
2.13.6
320
321
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
With in one module, trace points usually have a common prefix named
4
after the module name. paio_submit and paio_submit_co are the only two
5
trace points so far in the two file protocol drivers. As we are adding
6
more, having a common prefix here is better so that trace points can be
7
enabled with a glob. Rename them.
8
9
Suggested-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Fam Zheng <famz@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
13
block/file-posix.c | 2 +-
14
block/file-win32.c | 2 +-
15
block/trace-events | 4 ++--
16
3 files changed, 4 insertions(+), 4 deletions(-)
17
18
diff --git a/block/file-posix.c b/block/file-posix.c
19
index XXXXXXX..XXXXXXX 100644
20
--- a/block/file-posix.c
21
+++ b/block/file-posix.c
22
@@ -XXX,XX +XXX,XX @@ static int paio_submit_co_full(BlockDriverState *bs, int fd,
23
assert(qiov->size == bytes);
24
}
25
26
- trace_paio_submit_co(offset, bytes, type);
27
+ trace_file_paio_submit_co(offset, bytes, type);
28
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
29
return thread_pool_submit_co(pool, aio_worker, acb);
30
}
31
diff --git a/block/file-win32.c b/block/file-win32.c
32
index XXXXXXX..XXXXXXX 100644
33
--- a/block/file-win32.c
34
+++ b/block/file-win32.c
35
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *paio_submit(BlockDriverState *bs, HANDLE hfile,
36
acb->aio_nbytes = count;
37
acb->aio_offset = offset;
38
39
- trace_paio_submit(acb, opaque, offset, count, type);
40
+ trace_file_paio_submit(acb, opaque, offset, count, type);
41
pool = aio_get_thread_pool(bdrv_get_aio_context(bs));
42
return thread_pool_submit_aio(pool, aio_worker, acb, cb, opaque);
43
}
44
diff --git a/block/trace-events b/block/trace-events
45
index XXXXXXX..XXXXXXX 100644
46
--- a/block/trace-events
47
+++ b/block/trace-events
48
@@ -XXX,XX +XXX,XX @@ qmp_block_stream(void *bs, void *job) "bs %p job %p"
49
50
# block/file-win32.c
51
# block/file-posix.c
52
-paio_submit_co(int64_t offset, int count, int type) "offset %"PRId64" count %d type %d"
53
-paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "acb %p opaque %p offset %"PRId64" count %d type %d"
54
+file_paio_submit_co(int64_t offset, int count, int type) "offset %"PRId64" count %d type %d"
55
+file_paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "acb %p opaque %p offset %"PRId64" count %d type %d"
56
57
# block/qcow2.c
58
qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset 0x%" PRIx64 " bytes %d"
59
--
60
2.13.6
61
62
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
A few trace points that can help reveal what is happening in a copy
4
offloading I/O path.
5
6
Signed-off-by: Fam Zheng <famz@redhat.com>
7
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
---
9
block/file-posix.c | 2 ++
10
block/io.c | 4 ++++
11
block/iscsi.c | 3 +++
12
block/trace-events | 6 ++++++
13
4 files changed, 15 insertions(+)
14
15
diff --git a/block/file-posix.c b/block/file-posix.c
16
index XXXXXXX..XXXXXXX 100644
17
--- a/block/file-posix.c
18
+++ b/block/file-posix.c
19
@@ -XXX,XX +XXX,XX @@ static ssize_t handle_aiocb_copy_range(RawPosixAIOData *aiocb)
20
ssize_t ret = copy_file_range(aiocb->aio_fildes, &in_off,
21
aiocb->aio_fd2, &out_off,
22
bytes, 0);
23
+ trace_file_copy_file_range(aiocb->bs, aiocb->aio_fildes, in_off,
24
+ aiocb->aio_fd2, out_off, bytes, 0, ret);
25
if (ret == 0) {
26
/* No progress (e.g. when beyond EOF), let the caller fall back to
27
* buffer I/O. */
28
diff --git a/block/io.c b/block/io.c
29
index XXXXXXX..XXXXXXX 100644
30
--- a/block/io.c
31
+++ b/block/io.c
32
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_from(BdrvChild *src, uint64_t src_offset,
33
BdrvRequestFlags read_flags,
34
BdrvRequestFlags write_flags)
35
{
36
+ trace_bdrv_co_copy_range_from(src, src_offset, dst, dst_offset, bytes,
37
+ read_flags, write_flags);
38
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
39
bytes, read_flags, write_flags, true);
40
}
41
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_copy_range_to(BdrvChild *src, uint64_t src_offset,
42
BdrvRequestFlags read_flags,
43
BdrvRequestFlags write_flags)
44
{
45
+ trace_bdrv_co_copy_range_to(src, src_offset, dst, dst_offset, bytes,
46
+ read_flags, write_flags);
47
return bdrv_co_copy_range_internal(src, src_offset, dst, dst_offset,
48
bytes, read_flags, write_flags, false);
49
}
50
diff --git a/block/iscsi.c b/block/iscsi.c
51
index XXXXXXX..XXXXXXX 100644
52
--- a/block/iscsi.c
53
+++ b/block/iscsi.c
54
@@ -XXX,XX +XXX,XX @@
55
#include "qapi/qmp/qstring.h"
56
#include "crypto/secret.h"
57
#include "scsi/utils.h"
58
+#include "trace.h"
59
60
/* Conflict between scsi/utils.h and libiscsi! :( */
61
#define SCSI_XFER_NONE ISCSI_XFER_NONE
62
@@ -XXX,XX +XXX,XX @@ retry:
63
}
64
65
out_unlock:
66
+
67
+ trace_iscsi_xcopy(src_lun, src_offset, dst_lun, dst_offset, bytes, r);
68
g_free(iscsi_task.task);
69
qemu_mutex_unlock(&dst_lun->mutex);
70
g_free(iscsi_task.err_str);
71
diff --git a/block/trace-events b/block/trace-events
72
index XXXXXXX..XXXXXXX 100644
73
--- a/block/trace-events
74
+++ b/block/trace-events
75
@@ -XXX,XX +XXX,XX @@ bdrv_co_preadv(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs
76
bdrv_co_pwritev(void *bs, int64_t offset, int64_t nbytes, unsigned int flags) "bs %p offset %"PRId64" nbytes %"PRId64" flags 0x%x"
77
bdrv_co_pwrite_zeroes(void *bs, int64_t offset, int count, int flags) "bs %p offset %"PRId64" count %d flags 0x%x"
78
bdrv_co_do_copy_on_readv(void *bs, int64_t offset, unsigned int bytes, int64_t cluster_offset, int64_t cluster_bytes) "bs %p offset %"PRId64" bytes %u cluster_offset %"PRId64" cluster_bytes %"PRId64
79
+bdrv_co_copy_range_from(void *src, uint64_t src_offset, void *dst, uint64_t dst_offset, uint64_t bytes, int read_flags, int write_flags) "src %p offset %"PRIu64" dst %p offset %"PRIu64" bytes %"PRIu64" rw flags 0x%x 0x%x"
80
+bdrv_co_copy_range_to(void *src, uint64_t src_offset, void *dst, uint64_t dst_offset, uint64_t bytes, int read_flags, int write_flags) "src %p offset %"PRIu64" dst %p offset %"PRIu64" bytes %"PRIu64" rw flags 0x%x 0x%x"
81
82
# block/stream.c
83
stream_one_iteration(void *s, int64_t offset, uint64_t bytes, int is_allocated) "s %p offset %" PRId64 " bytes %" PRIu64 " is_allocated %d"
84
@@ -XXX,XX +XXX,XX @@ qmp_block_stream(void *bs, void *job) "bs %p job %p"
85
# block/file-posix.c
86
file_paio_submit_co(int64_t offset, int count, int type) "offset %"PRId64" count %d type %d"
87
file_paio_submit(void *acb, void *opaque, int64_t offset, int count, int type) "acb %p opaque %p offset %"PRId64" count %d type %d"
88
+file_copy_file_range(void *bs, int src, int64_t src_off, int dst, int64_t dst_off, int64_t bytes, int flags, int64_t ret) "bs %p src_fd %d offset %"PRIu64" dst_fd %d offset %"PRIu64" bytes %"PRIu64" flags %d ret %"PRId64
89
90
# block/qcow2.c
91
qcow2_writev_start_req(void *co, int64_t offset, int bytes) "co %p offset 0x%" PRIx64 " bytes %d"
92
@@ -XXX,XX +XXX,XX @@ nvme_free_req_queue_wait(void *q) "q %p"
93
nvme_cmd_map_qiov(void *s, void *cmd, void *req, void *qiov, int entries) "s %p cmd %p req %p qiov %p entries %d"
94
nvme_cmd_map_qiov_pages(void *s, int i, uint64_t page) "s %p page[%d] 0x%"PRIx64
95
nvme_cmd_map_qiov_iov(void *s, int i, void *page, int pages) "s %p iov[%d] %p pages %d"
96
+
97
+# block/iscsi.c
98
+iscsi_xcopy(void *src_lun, uint64_t src_off, void *dst_lun, uint64_t dst_off, uint64_t bytes, int ret) "src_lun %p offset %"PRIu64" dst_lun %p offset %"PRIu64" bytes %"PRIu64" ret %d"
99
--
100
2.13.6
101
102
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
bdrv_co_get_block_status_from_file() and
3
Other I/O functions are already using a BdrvChild pointer in the API, so
4
bdrv_co_get_block_status_from_backing() set *file to bs->file and
4
make discard do the same. It makes it possible to initiate the same
5
bs->backing respectively, so that bdrv_co_get_block_status() can recurse
5
permission checks before doing I/O, and much easier to share the
6
to them. Future block drivers won't have to duplicate code to implement
6
helper functions for this, which will be added and used by write,
7
this.
7
truncate and copy range paths.
8
8
9
Reviewed-by: Fam Zheng <famz@redhat.com>
9
Signed-off-by: Fam Zheng <famz@redhat.com>
10
Reviewed-by: Eric Blake <eblake@redhat.com>
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
14
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
15
---
11
---
16
include/block/block_int.h | 18 ++++++++++++++++++
12
include/block/block.h | 4 ++--
17
block/blkdebug.c | 12 +-----------
13
block/blkdebug.c | 2 +-
18
block/commit.c | 12 +-----------
14
block/blklogwrites.c | 2 +-
19
block/io.c | 26 ++++++++++++++++++++++++++
15
block/blkreplay.c | 2 +-
20
block/mirror.c | 12 +-----------
16
block/block-backend.c | 2 +-
21
5 files changed, 47 insertions(+), 33 deletions(-)
17
block/copy-on-read.c | 2 +-
22
18
block/io.c | 18 +++++++++---------
23
diff --git a/include/block/block_int.h b/include/block/block_int.h
19
block/mirror.c | 2 +-
24
index XXXXXXX..XXXXXXX 100644
20
block/qcow2-refcount.c | 2 +-
25
--- a/include/block/block_int.h
21
block/raw-format.c | 2 +-
26
+++ b/include/block/block_int.h
22
block/throttle.c | 2 +-
27
@@ -XXX,XX +XXX,XX @@ void bdrv_format_default_perms(BlockDriverState *bs, BdrvChild *c,
23
11 files changed, 20 insertions(+), 20 deletions(-)
28
uint64_t perm, uint64_t shared,
24
29
uint64_t *nperm, uint64_t *nshared);
25
diff --git a/include/block/block.h b/include/block/block.h
30
26
index XXXXXXX..XXXXXXX 100644
31
+/*
27
--- a/include/block/block.h
32
+ * Default implementation for drivers to pass bdrv_co_get_block_status() to
28
+++ b/include/block/block.h
33
+ * their file.
29
@@ -XXX,XX +XXX,XX @@ AioWait *bdrv_get_aio_wait(BlockDriverState *bs);
34
+ */
30
bdrv_get_aio_context(bs_), \
35
+int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
31
cond); })
36
+ int64_t sector_num,
32
37
+ int nb_sectors,
33
-int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
38
+ int *pnum,
34
-int bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset, int bytes);
39
+ BlockDriverState **file);
35
+int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes);
40
+/*
36
+int bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes);
41
+ * Default implementation for drivers to pass bdrv_co_get_block_status() to
37
int bdrv_has_zero_init_1(BlockDriverState *bs);
42
+ * their backing file.
38
int bdrv_has_zero_init(BlockDriverState *bs);
43
+ */
39
bool bdrv_unallocated_blocks_are_zero(BlockDriverState *bs);
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
40
diff --git a/block/blkdebug.c b/block/blkdebug.c
53
index XXXXXXX..XXXXXXX 100644
41
index XXXXXXX..XXXXXXX 100644
54
--- a/block/blkdebug.c
42
--- a/block/blkdebug.c
55
+++ b/block/blkdebug.c
43
+++ b/block/blkdebug.c
56
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
44
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkdebug_co_pdiscard(BlockDriverState *bs,
57
return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
45
return err;
58
}
46
}
59
47
60
-static int64_t coroutine_fn blkdebug_co_get_block_status(
48
- return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
61
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
49
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
62
- BlockDriverState **file)
50
}
63
-{
51
64
- *pnum = nb_sectors;
52
static int coroutine_fn blkdebug_co_block_status(BlockDriverState *bs,
65
- *file = bs->file->bs;
53
diff --git a/block/blklogwrites.c b/block/blklogwrites.c
66
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
54
index XXXXXXX..XXXXXXX 100644
67
- (sector_num << BDRV_SECTOR_BITS);
55
--- a/block/blklogwrites.c
68
-}
56
+++ b/block/blklogwrites.c
69
-
57
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blk_log_writes_co_do_file_flush(BlkLogWritesFileReq *fr)
70
static void blkdebug_close(BlockDriverState *bs)
58
static int coroutine_fn
71
{
59
blk_log_writes_co_do_file_pdiscard(BlkLogWritesFileReq *fr)
72
BDRVBlkdebugState *s = bs->opaque;
60
{
73
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
61
- return bdrv_co_pdiscard(fr->bs->file->bs, fr->offset, fr->bytes);
74
.bdrv_co_flush_to_disk = blkdebug_co_flush,
62
+ return bdrv_co_pdiscard(fr->bs->file, fr->offset, fr->bytes);
75
.bdrv_co_pwrite_zeroes = blkdebug_co_pwrite_zeroes,
63
}
76
.bdrv_co_pdiscard = blkdebug_co_pdiscard,
64
77
- .bdrv_co_get_block_status = blkdebug_co_get_block_status,
65
static int coroutine_fn
78
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_file,
66
diff --git a/block/blkreplay.c b/block/blkreplay.c
79
67
index XXXXXXX..XXXXXXX 100755
80
.bdrv_debug_event = blkdebug_debug_event,
68
--- a/block/blkreplay.c
81
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
69
+++ b/block/blkreplay.c
82
diff --git a/block/commit.c b/block/commit.c
70
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn blkreplay_co_pdiscard(BlockDriverState *bs,
83
index XXXXXXX..XXXXXXX 100644
71
int64_t offset, int bytes)
84
--- a/block/commit.c
72
{
85
+++ b/block/commit.c
73
uint64_t reqid = blkreplay_next_id();
86
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_commit_top_preadv(BlockDriverState *bs,
74
- int ret = bdrv_co_pdiscard(bs->file->bs, offset, bytes);
87
return bdrv_co_preadv(bs->backing, offset, bytes, qiov, flags);
75
+ int ret = bdrv_co_pdiscard(bs->file, offset, bytes);
88
}
76
block_request_create(reqid, bs, qemu_coroutine_self());
89
77
qemu_coroutine_yield();
90
-static int64_t coroutine_fn bdrv_commit_top_get_block_status(
78
91
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
79
diff --git a/block/block-backend.c b/block/block-backend.c
92
- BlockDriverState **file)
80
index XXXXXXX..XXXXXXX 100644
93
-{
81
--- a/block/block-backend.c
94
- *pnum = nb_sectors;
82
+++ b/block/block-backend.c
95
- *file = bs->backing->bs;
83
@@ -XXX,XX +XXX,XX @@ int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes)
96
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
84
return ret;
97
- (sector_num << BDRV_SECTOR_BITS);
85
}
98
-}
86
99
-
87
- return bdrv_co_pdiscard(blk_bs(blk), offset, bytes);
100
static void bdrv_commit_top_refresh_filename(BlockDriverState *bs, QDict *opts)
88
+ return bdrv_co_pdiscard(blk->root, offset, bytes);
101
{
89
}
102
bdrv_refresh_filename(bs->backing->bs);
90
103
@@ -XXX,XX +XXX,XX @@ static void bdrv_commit_top_child_perm(BlockDriverState *bs, BdrvChild *c,
91
int blk_co_flush(BlockBackend *blk)
104
static BlockDriver bdrv_commit_top = {
92
diff --git a/block/copy-on-read.c b/block/copy-on-read.c
105
.format_name = "commit_top",
93
index XXXXXXX..XXXXXXX 100644
106
.bdrv_co_preadv = bdrv_commit_top_preadv,
94
--- a/block/copy-on-read.c
107
- .bdrv_co_get_block_status = bdrv_commit_top_get_block_status,
95
+++ b/block/copy-on-read.c
108
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,
96
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn cor_co_pwrite_zeroes(BlockDriverState *bs,
109
.bdrv_refresh_filename = bdrv_commit_top_refresh_filename,
97
static int coroutine_fn cor_co_pdiscard(BlockDriverState *bs,
110
.bdrv_close = bdrv_commit_top_close,
98
int64_t offset, int bytes)
111
.bdrv_child_perm = bdrv_commit_top_child_perm,
99
{
100
- return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
101
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
102
}
103
104
112
diff --git a/block/io.c b/block/io.c
105
diff --git a/block/io.c b/block/io.c
113
index XXXXXXX..XXXXXXX 100644
106
index XXXXXXX..XXXXXXX 100644
114
--- a/block/io.c
107
--- a/block/io.c
115
+++ b/block/io.c
108
+++ b/block/io.c
116
@@ -XXX,XX +XXX,XX @@ typedef struct BdrvCoGetBlockStatusData {
109
@@ -XXX,XX +XXX,XX @@ int bdrv_flush(BlockDriverState *bs)
117
bool done;
110
}
118
} BdrvCoGetBlockStatusData;
111
119
112
typedef struct DiscardCo {
120
+int64_t coroutine_fn bdrv_co_get_block_status_from_file(BlockDriverState *bs,
113
- BlockDriverState *bs;
121
+ int64_t sector_num,
114
+ BdrvChild *child;
122
+ int nb_sectors,
115
int64_t offset;
123
+ int *pnum,
116
int bytes;
124
+ BlockDriverState **file)
117
int ret;
125
+{
118
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn bdrv_pdiscard_co_entry(void *opaque)
126
+ assert(bs->file && bs->file->bs);
119
{
127
+ *pnum = nb_sectors;
120
DiscardCo *rwco = opaque;
128
+ *file = bs->file->bs;
121
129
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
122
- rwco->ret = bdrv_co_pdiscard(rwco->bs, rwco->offset, rwco->bytes);
130
+ (sector_num << BDRV_SECTOR_BITS);
123
+ rwco->ret = bdrv_co_pdiscard(rwco->child, rwco->offset, rwco->bytes);
131
+}
124
}
132
+
125
133
+int64_t coroutine_fn bdrv_co_get_block_status_from_backing(BlockDriverState *bs,
126
-int coroutine_fn bdrv_co_pdiscard(BlockDriverState *bs, int64_t offset,
134
+ int64_t sector_num,
127
- int bytes)
135
+ int nb_sectors,
128
+int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
136
+ int *pnum,
129
{
137
+ BlockDriverState **file)
130
BdrvTrackedRequest req;
138
+{
131
int max_pdiscard, ret;
139
+ assert(bs->backing && bs->backing->bs);
132
int head, tail, align;
140
+ *pnum = nb_sectors;
133
+ BlockDriverState *bs = child->bs;
141
+ *file = bs->backing->bs;
134
142
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
135
- if (!bs->drv) {
143
+ (sector_num << BDRV_SECTOR_BITS);
136
+ if (!bs || !bs->drv) {
144
+}
137
return -ENOMEDIUM;
145
+
138
}
146
/*
139
147
* Returns the allocation status of the specified sectors.
140
@@ -XXX,XX +XXX,XX @@ out:
148
* Drivers not implementing the functionality are assumed to not support
141
return ret;
142
}
143
144
-int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
145
+int bdrv_pdiscard(BdrvChild *child, int64_t offset, int bytes)
146
{
147
Coroutine *co;
148
DiscardCo rwco = {
149
- .bs = bs,
150
+ .child = child,
151
.offset = offset,
152
.bytes = bytes,
153
.ret = NOT_DONE,
154
@@ -XXX,XX +XXX,XX @@ int bdrv_pdiscard(BlockDriverState *bs, int64_t offset, int bytes)
155
bdrv_pdiscard_co_entry(&rwco);
156
} else {
157
co = qemu_coroutine_create(bdrv_pdiscard_co_entry, &rwco);
158
- bdrv_coroutine_enter(bs, co);
159
- BDRV_POLL_WHILE(bs, rwco.ret == NOT_DONE);
160
+ bdrv_coroutine_enter(child->bs, co);
161
+ BDRV_POLL_WHILE(child->bs, rwco.ret == NOT_DONE);
162
}
163
164
return rwco.ret;
149
diff --git a/block/mirror.c b/block/mirror.c
165
diff --git a/block/mirror.c b/block/mirror.c
150
index XXXXXXX..XXXXXXX 100644
166
index XXXXXXX..XXXXXXX 100644
151
--- a/block/mirror.c
167
--- a/block/mirror.c
152
+++ b/block/mirror.c
168
+++ b/block/mirror.c
153
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_flush(BlockDriverState *bs)
169
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_mirror_top_do_write(BlockDriverState *bs,
154
return bdrv_co_flush(bs->backing->bs);
170
break;
155
}
171
156
172
case MIRROR_METHOD_DISCARD:
157
-static int64_t coroutine_fn bdrv_mirror_top_get_block_status(
173
- ret = bdrv_co_pdiscard(bs->backing->bs, offset, bytes);
158
- BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum,
174
+ ret = bdrv_co_pdiscard(bs->backing, offset, bytes);
159
- BlockDriverState **file)
175
break;
160
-{
176
161
- *pnum = nb_sectors;
177
default:
162
- *file = bs->backing->bs;
178
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
163
- return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
179
index XXXXXXX..XXXXXXX 100644
164
- (sector_num << BDRV_SECTOR_BITS);
180
--- a/block/qcow2-refcount.c
165
-}
181
+++ b/block/qcow2-refcount.c
166
-
182
@@ -XXX,XX +XXX,XX @@ void qcow2_process_discards(BlockDriverState *bs, int ret)
167
static int coroutine_fn bdrv_mirror_top_pwrite_zeroes(BlockDriverState *bs,
183
168
int64_t offset, int bytes, BdrvRequestFlags flags)
184
/* Discard is optional, ignore the return value */
169
{
185
if (ret >= 0) {
170
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_mirror_top = {
186
- bdrv_pdiscard(bs->file->bs, d->offset, d->bytes);
171
.bdrv_co_pwrite_zeroes = bdrv_mirror_top_pwrite_zeroes,
187
+ bdrv_pdiscard(bs->file, d->offset, d->bytes);
172
.bdrv_co_pdiscard = bdrv_mirror_top_pdiscard,
188
}
173
.bdrv_co_flush = bdrv_mirror_top_flush,
189
174
- .bdrv_co_get_block_status = bdrv_mirror_top_get_block_status,
190
g_free(d);
175
+ .bdrv_co_get_block_status = bdrv_co_get_block_status_from_backing,
191
diff --git a/block/raw-format.c b/block/raw-format.c
176
.bdrv_refresh_filename = bdrv_mirror_top_refresh_filename,
192
index XXXXXXX..XXXXXXX 100644
177
.bdrv_close = bdrv_mirror_top_close,
193
--- a/block/raw-format.c
178
.bdrv_child_perm = bdrv_mirror_top_child_perm,
194
+++ b/block/raw-format.c
195
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_pdiscard(BlockDriverState *bs,
196
if (ret) {
197
return ret;
198
}
199
- return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
200
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
201
}
202
203
static int64_t raw_getlength(BlockDriverState *bs)
204
diff --git a/block/throttle.c b/block/throttle.c
205
index XXXXXXX..XXXXXXX 100644
206
--- a/block/throttle.c
207
+++ b/block/throttle.c
208
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn throttle_co_pdiscard(BlockDriverState *bs,
209
ThrottleGroupMember *tgm = bs->opaque;
210
throttle_group_co_io_limits_intercept(tgm, bytes, true);
211
212
- return bdrv_co_pdiscard(bs->file->bs, offset, bytes);
213
+ return bdrv_co_pdiscard(bs->file, offset, bytes);
214
}
215
216
static int throttle_co_flush(BlockDriverState *bs)
179
--
217
--
180
2.13.5
218
2.13.6
181
219
182
220
diff view generated by jsdifflib
1
From: "Daniel P. Berrange" <berrange@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
This matches the types used for bytes in the rest parts of block layer.
4
Reviewed-by: Eric Blake <eblake@redhat.com>
4
In the case of bdrv_co_truncate, new_bytes can be the image size which
5
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
5
probably doesn't fit in a 32 bit int.
6
7
Signed-off-by: Fam Zheng <famz@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
9
---
8
include/block/block_int.h | 31 +++++++++++++++++++++++++++++++
10
include/block/block_int.h | 4 ++--
9
1 file changed, 31 insertions(+)
11
block/io.c | 8 +++++---
12
2 files changed, 7 insertions(+), 5 deletions(-)
10
13
11
diff --git a/include/block/block_int.h b/include/block/block_int.h
14
diff --git a/include/block/block_int.h b/include/block/block_int.h
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/include/block/block_int.h
16
--- a/include/block/block_int.h
14
+++ b/include/block/block_int.h
17
+++ b/include/block/block_int.h
15
@@ -XXX,XX +XXX,XX @@ struct BlockDriver {
18
@@ -XXX,XX +XXX,XX @@ enum BdrvTrackedRequestType {
16
19
typedef struct BdrvTrackedRequest {
17
int coroutine_fn (*bdrv_co_readv)(BlockDriverState *bs,
20
BlockDriverState *bs;
18
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
21
int64_t offset;
22
- unsigned int bytes;
23
+ uint64_t bytes;
24
enum BdrvTrackedRequestType type;
25
26
bool serialising;
27
int64_t overlap_offset;
28
- unsigned int overlap_bytes;
29
+ uint64_t overlap_bytes;
30
31
QLIST_ENTRY(BdrvTrackedRequest) list;
32
Coroutine *co; /* owner, used for deadlock detection */
33
diff --git a/block/io.c b/block/io.c
34
index XXXXXXX..XXXXXXX 100644
35
--- a/block/io.c
36
+++ b/block/io.c
37
@@ -XXX,XX +XXX,XX @@ static void tracked_request_end(BdrvTrackedRequest *req)
38
static void tracked_request_begin(BdrvTrackedRequest *req,
39
BlockDriverState *bs,
40
int64_t offset,
41
- unsigned int bytes,
42
+ uint64_t bytes,
43
enum BdrvTrackedRequestType type)
44
{
45
+ assert(bytes <= INT64_MAX && offset <= INT64_MAX - bytes);
19
+
46
+
20
+ /**
47
*req = (BdrvTrackedRequest){
21
+ * @offset: position in bytes to read at
48
.bs = bs,
22
+ * @bytes: number of bytes to read
49
.offset = offset,
23
+ * @qiov: the buffers to fill with read data
50
@@ -XXX,XX +XXX,XX @@ static void tracked_request_begin(BdrvTrackedRequest *req,
24
+ * @flags: currently unused, always 0
51
static void mark_request_serialising(BdrvTrackedRequest *req, uint64_t align)
25
+ *
52
{
26
+ * @offset and @bytes will be a multiple of 'request_alignment',
53
int64_t overlap_offset = req->offset & ~(align - 1);
27
+ * but the length of individual @qiov elements does not have to
54
- unsigned int overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
28
+ * be a multiple.
55
+ uint64_t overlap_bytes = ROUND_UP(req->offset + req->bytes, align)
29
+ *
56
- overlap_offset;
30
+ * @bytes will always equal the total size of @qiov, and will be
57
31
+ * no larger than 'max_transfer'.
58
if (!req->serialising) {
32
+ *
59
@@ -XXX,XX +XXX,XX @@ static int bdrv_get_cluster_size(BlockDriverState *bs)
33
+ * The buffer in @qiov may point directly to guest memory.
60
}
34
+ */
61
35
int coroutine_fn (*bdrv_co_preadv)(BlockDriverState *bs,
62
static bool tracked_request_overlaps(BdrvTrackedRequest *req,
36
uint64_t offset, uint64_t bytes, QEMUIOVector *qiov, int flags);
63
- int64_t offset, unsigned int bytes)
37
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
64
+ int64_t offset, uint64_t bytes)
38
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
65
{
39
int coroutine_fn (*bdrv_co_writev_flags)(BlockDriverState *bs,
66
/* aaaa bbbb */
40
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov, int flags);
67
if (offset >= req->overlap_offset + req->overlap_bytes) {
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
--
68
--
60
2.13.5
69
2.13.6
61
70
62
71
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Reviewed-by: Alberto Garcia <berto@igalia.com>
3
As a mechanical refactoring patch, this is the first step towards
4
Signed-off-by: Manos Pitsidianakis <el13635@mail.ntua.gr>
4
unified and more correct write code paths. This is helpful because
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
multiple BlockDriverState fields need to be updated after modifying
6
image data, and it's hard to maintain in multiple places such as copy
7
offload, discard and truncate.
8
9
Suggested-by: Kevin Wolf <kwolf@redhat.com>
10
Signed-off-by: Fam Zheng <famz@redhat.com>
6
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
11
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
7
---
12
---
8
tests/qemu-iotests/184 | 205 ++++++++++++++++++++++++++++++
13
block/io.c | 91 +++++++++++++++++++++++++++++++++++++++-----------------------
9
tests/qemu-iotests/184.out | 302 +++++++++++++++++++++++++++++++++++++++++++++
14
1 file changed, 57 insertions(+), 34 deletions(-)
10
tests/qemu-iotests/group | 1 +
11
3 files changed, 508 insertions(+)
12
create mode 100755 tests/qemu-iotests/184
13
create mode 100644 tests/qemu-iotests/184.out
14
15
15
diff --git a/tests/qemu-iotests/184 b/tests/qemu-iotests/184
16
diff --git a/block/io.c b/block/io.c
16
new file mode 100755
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX
18
--- a/block/io.c
18
--- /dev/null
19
+++ b/block/io.c
19
+++ b/tests/qemu-iotests/184
20
@@ -XXX,XX +XXX,XX @@ fail:
20
@@ -XXX,XX +XXX,XX @@
21
return ret;
21
+#!/bin/bash
22
}
22
+#
23
23
+# Test I/O throttle block filter driver interface
24
+static inline int coroutine_fn
24
+#
25
+bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
25
+# Copyright (C) 2017 Manos Pitsidianakis
26
+ BdrvTrackedRequest *req, int flags)
26
+#
27
+{
27
+# This program is free software; you can redistribute it and/or modify
28
+ BlockDriverState *bs = child->bs;
28
+# it under the terms of the GNU General Public License as published by
29
+ bool waited;
29
+# the Free Software Foundation; either version 2 of the License, or
30
+ int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
30
+# (at your option) any later version.
31
+#
32
+# This program is distributed in the hope that it will be useful,
33
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
34
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
+# GNU General Public License for more details.
36
+#
37
+# 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/>.
39
+#
40
+
31
+
41
+# creator
32
+ if (bs->read_only) {
42
+owner="Manos Pitsidianakis"
33
+ return -EPERM;
34
+ }
43
+
35
+
44
+seq=`basename $0`
36
+ /* BDRV_REQ_NO_SERIALISING is only for read operation */
45
+echo "QA output created by $seq"
37
+ assert(!(flags & BDRV_REQ_NO_SERIALISING));
38
+ assert(!(bs->open_flags & BDRV_O_INACTIVE));
39
+ assert((bs->open_flags & BDRV_O_NO_IO) == 0);
40
+ assert(!(flags & ~BDRV_REQ_MASK));
46
+
41
+
47
+here=`pwd`
42
+ if (flags & BDRV_REQ_SERIALISING) {
48
+status=1    # failure is the default!
43
+ mark_request_serialising(req, bdrv_get_cluster_size(bs));
44
+ }
49
+
45
+
50
+_cleanup()
46
+ waited = wait_serialising_requests(req);
51
+{
52
+ _cleanup_test_img
53
+}
54
+trap "_cleanup; exit \$status" 0 1 2 3 15
55
+
47
+
56
+# get standard environment, filters and checks
48
+ assert(!waited || !req->serialising ||
57
+. ./common.rc
49
+ is_request_serialising_and_aligned(req));
58
+. ./common.filter
50
+ assert(req->overlap_offset <= offset);
51
+ assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
59
+
52
+
60
+_supported_fmt qcow2
53
+ if (flags & BDRV_REQ_WRITE_UNCHANGED) {
61
+_supported_proto file
54
+ assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
62
+_supported_os Linux
55
+ } else {
63
+
56
+ assert(child->perm & BLK_PERM_WRITE);
64
+function do_run_qemu()
57
+ }
65
+{
58
+ assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
66
+ echo Testing: "$@" | _filter_imgfmt
59
+ return notifier_with_return_list_notify(&bs->before_write_notifiers, req);
67
+ $QEMU -nographic -qmp-pretty stdio -serial none "$@"
68
+ echo
69
+}
60
+}
70
+
61
+
71
+function run_qemu()
62
+static inline void coroutine_fn
63
+bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
64
+ BdrvTrackedRequest *req, int ret)
72
+{
65
+{
73
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_qmp\
66
+ int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
74
+ | _filter_qemu_io | _filter_generated_node_ids
67
+ BlockDriverState *bs = child->bs;
75
+}
76
+
68
+
77
+_make_test_img 64M
69
+ atomic_inc(&bs->write_gen);
78
+test_throttle=$($QEMU_IMG --help|grep throttle)
70
+ bdrv_set_dirty(bs, offset, bytes);
79
+[ "$test_throttle" = "" ] && _supported_fmt throttle
80
+
71
+
81
+echo
72
+ stat64_max(&bs->wr_highest_offset, offset + bytes);
82
+echo "== checking interface =="
83
+
73
+
84
+run_qemu <<EOF
74
+ if (ret == 0) {
85
+{ "execute": "qmp_capabilities" }
75
+ bs->total_sectors = MAX(bs->total_sectors, end_sector);
86
+{ "execute": "blockdev-add",
87
+ "arguments": {
88
+ "driver": "$IMGFMT",
89
+ "node-name": "disk0",
90
+ "file": {
91
+ "driver": "file",
92
+ "filename": "$TEST_IMG"
93
+ }
94
+ }
95
+}
96
+{ "execute": "object-add",
97
+ "arguments": {
98
+ "qom-type": "throttle-group",
99
+ "id": "group0",
100
+ "props": {
101
+ "limits" : {
102
+ "iops-total": 1000
103
+ }
104
+ }
105
+ }
106
+}
107
+{ "execute": "blockdev-add",
108
+ "arguments": {
109
+ "driver": "throttle",
110
+ "node-name": "throttle0",
111
+ "throttle-group": "group0",
112
+ "file": "disk0"
113
+ }
114
+}
115
+{ "execute": "query-named-block-nodes" }
116
+{ "execute": "query-block" }
117
+{ "execute": "quit" }
118
+EOF
119
+
120
+echo
121
+echo "== property changes in ThrottleGroup =="
122
+
123
+run_qemu <<EOF
124
+{ "execute": "qmp_capabilities" }
125
+{ "execute": "object-add",
126
+ "arguments": {
127
+ "qom-type": "throttle-group",
128
+ "id": "group0",
129
+ "props" : {
130
+ "limits": {
131
+ "iops-total": 1000
132
+ }
133
+ }
134
+ }
135
+}
136
+{ "execute" : "qom-get",
137
+ "arguments" : {
138
+ "path" : "group0",
139
+ "property" : "limits"
140
+ }
141
+}
142
+{ "execute" : "qom-set",
143
+ "arguments" : {
144
+ "path" : "group0",
145
+ "property" : "limits",
146
+ "value" : {
147
+ "iops-total" : 0
148
+ }
149
+ }
150
+}
151
+{ "execute" : "qom-get",
152
+ "arguments" : {
153
+ "path" : "group0",
154
+ "property" : "limits"
155
+ }
156
+}
157
+{ "execute": "quit" }
158
+EOF
159
+
160
+echo
161
+echo "== object creation/set errors =="
162
+
163
+run_qemu <<EOF
164
+{ "execute": "qmp_capabilities" }
165
+{ "execute": "object-add",
166
+ "arguments": {
167
+ "qom-type": "throttle-group",
168
+ "id": "group0",
169
+ "props" : {
170
+ "limits": {
171
+ "iops-total": 1000
172
+ }
173
+ }
174
+ }
175
+}
176
+{ "execute" : "qom-set",
177
+ "arguments" : {
178
+ "path" : "group0",
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
228
index XXXXXXX..XXXXXXX
229
--- /dev/null
230
+++ b/tests/qemu-iotests/184.out
231
@@ -XXX,XX +XXX,XX @@
232
+QA output created by 184
233
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
234
+
235
+== checking interface ==
236
+Testing:
237
+{
238
+ QMP_VERSION
239
+}
240
+{
241
+ "return": {
242
+ }
243
+}
244
+{
245
+ "return": {
246
+ }
247
+}
248
+{
249
+ "return": {
250
+ }
251
+}
252
+{
253
+ "return": {
254
+ }
255
+}
256
+{
257
+ "return": [
258
+ {
259
+ "iops_rd": 0,
260
+ "detect_zeroes": "off",
261
+ "image": {
262
+ "virtual-size": 67108864,
263
+ "filename": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
264
+ "cluster-size": 65536,
265
+ "format": "throttle",
266
+ "actual-size": 200704,
267
+ "dirty-flag": false
268
+ },
269
+ "iops_wr": 0,
270
+ "ro": false,
271
+ "node-name": "throttle0",
272
+ "backing_file_depth": 0,
273
+ "drv": "throttle",
274
+ "iops": 0,
275
+ "bps_wr": 0,
276
+ "write_threshold": 0,
277
+ "encrypted": false,
278
+ "bps": 0,
279
+ "bps_rd": 0,
280
+ "cache": {
281
+ "no-flush": false,
282
+ "direct": false,
283
+ "writeback": true
284
+ },
285
+ "file": "json:{\"throttle-group\": \"group0\", \"driver\": \"throttle\", \"file\": {\"driver\": \"qcow2\", \"file\": {\"driver\": \"file\", \"filename\": \"TEST_DIR/t.qcow2\"}}}",
286
+ "encryption_key_missing": false
287
+ },
288
+ {
289
+ "iops_rd": 0,
290
+ "detect_zeroes": "off",
291
+ "image": {
292
+ "virtual-size": 67108864,
293
+ "filename": "TEST_DIR/t.qcow2",
294
+ "cluster-size": 65536,
295
+ "format": "qcow2",
296
+ "actual-size": 200704,
297
+ "format-specific": {
298
+ "type": "qcow2",
299
+ "data": {
300
+ "compat": "1.1",
301
+ "lazy-refcounts": false,
302
+ "refcount-bits": 16,
303
+ "corrupt": false
304
+ }
305
+ },
306
+ "dirty-flag": false
307
+ },
308
+ "iops_wr": 0,
309
+ "ro": false,
310
+ "node-name": "disk0",
311
+ "backing_file_depth": 0,
312
+ "drv": "qcow2",
313
+ "iops": 0,
314
+ "bps_wr": 0,
315
+ "write_threshold": 0,
316
+ "encrypted": false,
317
+ "bps": 0,
318
+ "bps_rd": 0,
319
+ "cache": {
320
+ "no-flush": false,
321
+ "direct": false,
322
+ "writeback": true
323
+ },
324
+ "file": "TEST_DIR/t.qcow2",
325
+ "encryption_key_missing": false
326
+ },
327
+ {
328
+ "iops_rd": 0,
329
+ "detect_zeroes": "off",
330
+ "image": {
331
+ "virtual-size": 197120,
332
+ "filename": "TEST_DIR/t.qcow2",
333
+ "format": "file",
334
+ "actual-size": 200704,
335
+ "dirty-flag": false
336
+ },
337
+ "iops_wr": 0,
338
+ "ro": false,
339
+ "node-name": "NODE_NAME",
340
+ "backing_file_depth": 0,
341
+ "drv": "file",
342
+ "iops": 0,
343
+ "bps_wr": 0,
344
+ "write_threshold": 0,
345
+ "encrypted": false,
346
+ "bps": 0,
347
+ "bps_rd": 0,
348
+ "cache": {
349
+ "no-flush": false,
350
+ "direct": false,
351
+ "writeback": true
352
+ },
353
+ "file": "TEST_DIR/t.qcow2",
354
+ "encryption_key_missing": false
355
+ }
356
+ ]
357
+}
358
+{
359
+ "return": [
360
+ ]
361
+}
362
+{
363
+ "return": {
364
+ }
365
+}
366
+{
367
+ "timestamp": {
368
+ "seconds": TIMESTAMP,
369
+ "microseconds": TIMESTAMP
370
+ },
371
+ "event": "SHUTDOWN",
372
+ "data": {
373
+ "guest": false
374
+ }
76
+ }
375
+}
77
+}
376
+
78
+
377
+
79
/*
378
+== property changes in ThrottleGroup ==
80
* Forwards an already correctly aligned write request to the BlockDriver,
379
+Testing:
81
* after possibly fragmenting it.
380
+{
82
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
381
+ QMP_VERSION
83
{
382
+}
84
BlockDriverState *bs = child->bs;
383
+{
85
BlockDriver *drv = bs->drv;
384
+ "return": {
86
- bool waited;
385
+ }
87
int ret;
386
+}
88
387
+{
89
- int64_t end_sector = DIV_ROUND_UP(offset + bytes, BDRV_SECTOR_SIZE);
388
+ "return": {
90
uint64_t bytes_remaining = bytes;
389
+ }
91
int max_transfer;
390
+}
92
391
+{
93
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
392
+ "return": {
94
assert((offset & (align - 1)) == 0);
393
+ "bps-read-max-length": 1,
95
assert((bytes & (align - 1)) == 0);
394
+ "iops-read-max-length": 1,
96
assert(!qiov || bytes == qiov->size);
395
+ "bps-read-max": 0,
97
- assert((bs->open_flags & BDRV_O_NO_IO) == 0);
396
+ "bps-total": 0,
98
- assert(!(flags & ~BDRV_REQ_MASK));
397
+ "iops-total-max-length": 1,
99
max_transfer = QEMU_ALIGN_DOWN(MIN_NON_ZERO(bs->bl.max_transfer, INT_MAX),
398
+ "iops-total": 1000,
100
align);
399
+ "iops-write-max": 0,
101
400
+ "bps-write": 0,
102
- /* BDRV_REQ_NO_SERIALISING is only for read operation */
401
+ "bps-total-max": 0,
103
- assert(!(flags & BDRV_REQ_NO_SERIALISING));
402
+ "bps-write-max": 0,
104
-
403
+ "iops-size": 0,
105
- if (flags & BDRV_REQ_SERIALISING) {
404
+ "iops-read": 0,
106
- mark_request_serialising(req, bdrv_get_cluster_size(bs));
405
+ "iops-write-max-length": 1,
107
- }
406
+ "iops-write": 0,
108
-
407
+ "bps-total-max-length": 1,
109
- waited = wait_serialising_requests(req);
408
+ "iops-read-max": 0,
110
- assert(!waited || !req->serialising ||
409
+ "bps-read": 0,
111
- is_request_serialising_and_aligned(req));
410
+ "bps-write-max-length": 1,
112
- assert(req->overlap_offset <= offset);
411
+ "iops-total-max": 0
113
- assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
412
+ }
114
- if (flags & BDRV_REQ_WRITE_UNCHANGED) {
413
+}
115
- assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
414
+{
116
- } else {
415
+ "return": {
117
- assert(child->perm & BLK_PERM_WRITE);
416
+ }
118
- }
417
+}
119
- assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
418
+{
120
-
419
+ "return": {
121
- ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
420
+ "bps-read-max-length": 1,
122
+ ret = bdrv_co_write_req_prepare(child, offset, bytes, req, flags);
421
+ "iops-read-max-length": 1,
123
422
+ "bps-read-max": 0,
124
if (!ret && bs->detect_zeroes != BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF &&
423
+ "bps-total": 0,
125
!(flags & BDRV_REQ_ZERO_WRITE) && drv->bdrv_co_pwrite_zeroes &&
424
+ "iops-total-max-length": 1,
126
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
425
+ "iops-total": 0,
127
}
426
+ "iops-write-max": 0,
128
bdrv_debug_event(bs, BLKDBG_PWRITEV_DONE);
427
+ "bps-write": 0,
129
428
+ "bps-total-max": 0,
130
- atomic_inc(&bs->write_gen);
429
+ "bps-write-max": 0,
131
- bdrv_set_dirty(bs, offset, bytes);
430
+ "iops-size": 0,
132
-
431
+ "iops-read": 0,
133
- stat64_max(&bs->wr_highest_offset, offset + bytes);
432
+ "iops-write-max-length": 1,
134
-
433
+ "iops-write": 0,
135
if (ret >= 0) {
434
+ "bps-total-max-length": 1,
136
- bs->total_sectors = MAX(bs->total_sectors, end_sector);
435
+ "iops-read-max": 0,
137
ret = 0;
436
+ "bps-read": 0,
138
}
437
+ "bps-write-max-length": 1,
139
+ bdrv_co_write_req_finish(child, offset, bytes, req, ret);
438
+ "iops-total-max": 0
140
439
+ }
141
return ret;
440
+}
142
}
441
+{
143
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pwritev(BdrvChild *child,
442
+ "return": {
144
if (!bs->drv) {
443
+ }
145
return -ENOMEDIUM;
444
+}
146
}
445
+{
147
- if (bs->read_only) {
446
+ "timestamp": {
148
- return -EPERM;
447
+ "seconds": TIMESTAMP,
149
- }
448
+ "microseconds": TIMESTAMP
150
- assert(!(bs->open_flags & BDRV_O_INACTIVE));
449
+ },
151
450
+ "event": "SHUTDOWN",
152
ret = bdrv_check_byte_request(bs, offset, bytes);
451
+ "data": {
153
if (ret < 0) {
452
+ "guest": false
453
+ }
454
+}
455
+
456
+
457
+== object creation/set errors ==
458
+Testing:
459
+{
460
+ QMP_VERSION
461
+}
462
+{
463
+ "return": {
464
+ }
465
+}
466
+{
467
+ "return": {
468
+ }
469
+}
470
+{
471
+ "error": {
472
+ "class": "GenericError",
473
+ "desc": "Property cannot be set after initialization"
474
+ }
475
+}
476
+{
477
+ "error": {
478
+ "class": "GenericError",
479
+ "desc": "bps/iops/max total values and read/write values cannot be used at the same time"
480
+ }
481
+}
482
+{
483
+ "return": {
484
+ }
485
+}
486
+{
487
+ "timestamp": {
488
+ "seconds": TIMESTAMP,
489
+ "microseconds": TIMESTAMP
490
+ },
491
+ "event": "SHUTDOWN",
492
+ "data": {
493
+ "guest": false
494
+ }
495
+}
496
+
497
+
498
+== don't specify group ==
499
+Testing:
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
535
index XXXXXXX..XXXXXXX 100644
536
--- a/tests/qemu-iotests/group
537
+++ b/tests/qemu-iotests/group
538
@@ -XXX,XX +XXX,XX @@
539
181 rw auto migration
540
182 rw auto quick
541
183 rw auto migration
542
+184 rw auto quick
543
185 rw auto
544
186 rw auto
545
187 rw auto
546
--
154
--
547
2.13.5
155
2.13.6
548
156
549
157
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
The old signature has an ambiguous meaning for a return of 0:
3
Two problems exist when a write request that enlarges the image (i.e.
4
either no allocation was requested or necessary, or an error
4
write beyond EOF) finishes:
5
occurred (but any errno associated with the error is lost to
6
the caller, which then has to assume EIO).
7
5
8
Better is to follow the example of qcow2, by changing the
6
1) parent is not notified about size change;
9
signature to have a separate return value that cleanly
7
2) dirty bitmap is not resized although we try to set the dirty bits;
10
distinguishes between failure and success, along with a
11
parameter that cleanly holds a 64-bit value. Then update all
12
callers.
13
8
14
While auditing that all return paths return a negative errno
9
Fix them just like how bdrv_co_truncate works.
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
10
18
Suggested-by: Kevin Wolf <kwolf@redhat.com>
11
Reported-by: Kevin Wolf <kwolf@redhat.com>
19
Signed-off-by: Eric Blake <eblake@redhat.com>
12
Signed-off-by: Fam Zheng <famz@redhat.com>
20
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
21
---
14
---
22
block/qcow.c | 123 +++++++++++++++++++++++++++++++++++------------------------
15
block/io.c | 10 +++++++---
23
1 file changed, 73 insertions(+), 50 deletions(-)
16
1 file changed, 7 insertions(+), 3 deletions(-)
24
17
25
diff --git a/block/qcow.c b/block/qcow.c
18
diff --git a/block/io.c b/block/io.c
26
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
27
--- a/block/qcow.c
20
--- a/block/io.c
28
+++ b/block/qcow.c
21
+++ b/block/io.c
29
@@ -XXX,XX +XXX,XX @@ static int qcow_reopen_prepare(BDRVReopenState *state,
22
@@ -XXX,XX +XXX,XX @@
30
* 'compressed_size'. 'compressed_size' must be > 0 and <
23
31
* cluster_size
24
static AioWait drain_all_aio_wait;
32
*
25
33
- * return 0 if not allocated.
26
+static void bdrv_parent_cb_resize(BlockDriverState *bs);
34
+ * return 0 if not allocated, 1 if *result is assigned, and negative
27
static int coroutine_fn bdrv_co_do_pwrite_zeroes(BlockDriverState *bs,
35
+ * errno on failure.
28
int64_t offset, int bytes, BdrvRequestFlags flags);
36
*/
29
37
-static uint64_t get_cluster_offset(BlockDriverState *bs,
30
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
38
- uint64_t offset, int allocate,
31
BlockDriverState *bs = child->bs;
39
- int compressed_size,
32
40
- int n_start, int n_end)
33
atomic_inc(&bs->write_gen);
41
+static int get_cluster_offset(BlockDriverState *bs,
34
- bdrv_set_dirty(bs, offset, bytes);
42
+ uint64_t offset, int allocate,
35
43
+ int compressed_size,
36
stat64_max(&bs->wr_highest_offset, offset + bytes);
44
+ int n_start, int n_end, uint64_t *result)
37
45
{
38
- if (ret == 0) {
46
BDRVQcowState *s = bs->opaque;
39
- bs->total_sectors = MAX(bs->total_sectors, end_sector);
47
- int min_index, i, j, l1_index, l2_index;
40
+ if (ret == 0 &&
48
+ int min_index, i, j, l1_index, l2_index, ret;
41
+ end_sector > bs->total_sectors) {
49
uint64_t l2_offset, *l2_table, cluster_offset, tmp;
42
+ bs->total_sectors = end_sector;
50
uint32_t min_count;
43
+ bdrv_parent_cb_resize(bs);
51
int new_l2_table;
44
+ bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
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
}
45
}
73
for(i = 0; i < L2_CACHE_SIZE; i++) {
46
+ bdrv_set_dirty(bs, offset, bytes);
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
}
47
}
162
48
163
static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs,
49
/*
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
--
50
--
281
2.13.5
51
2.13.6
282
52
283
53
diff view generated by jsdifflib
1
From: Manos Pitsidianakis <el13635@mail.ntua.gr>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Now that bdrv_truncate is passed to bs->file by default, remove the
3
Reuse the new bdrv_co_write_req_prepare/finish helpers. The variation
4
callback from block/blkdebug.c and set is_filter to true. is_filter also gives
4
here is that discard requests don't affect bs->wr_highest_offset, and it
5
access to other callbacks that are forwarded automatically to bs->file for
5
cannot extend the image.
6
filters.
7
6
8
Reviewed-by: Eric Blake <eblake@redhat.com>
7
Signed-off-by: Fam Zheng <famz@redhat.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>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
12
---
9
---
13
block/blkdebug.c | 8 +-------
10
block/io.c | 33 +++++++++++++++++++++++----------
14
1 file changed, 1 insertion(+), 7 deletions(-)
11
1 file changed, 23 insertions(+), 10 deletions(-)
15
12
16
diff --git a/block/blkdebug.c b/block/blkdebug.c
13
diff --git a/block/io.c b/block/io.c
17
index XXXXXXX..XXXXXXX 100644
14
index XXXXXXX..XXXXXXX 100644
18
--- a/block/blkdebug.c
15
--- a/block/io.c
19
+++ b/block/blkdebug.c
16
+++ b/block/io.c
20
@@ -XXX,XX +XXX,XX @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
17
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
21
return bdrv_getlength(bs->file->bs);
18
19
atomic_inc(&bs->write_gen);
20
21
- stat64_max(&bs->wr_highest_offset, offset + bytes);
22
-
23
+ /*
24
+ * Discard cannot extend the image, but in error handling cases, such as
25
+ * when reverting a qcow2 cluster allocation, the discarded range can pass
26
+ * the end of image file, so we cannot assert about BDRV_TRACKED_DISCARD
27
+ * here. Instead, just skip it, since semantically a discard request
28
+ * beyond EOF cannot expand the image anyway.
29
+ */
30
if (ret == 0 &&
31
- end_sector > bs->total_sectors) {
32
+ end_sector > bs->total_sectors &&
33
+ req->type != BDRV_TRACKED_DISCARD) {
34
bs->total_sectors = end_sector;
35
bdrv_parent_cb_resize(bs);
36
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
37
}
38
- bdrv_set_dirty(bs, offset, bytes);
39
+ if (req->bytes) {
40
+ switch (req->type) {
41
+ case BDRV_TRACKED_WRITE:
42
+ stat64_max(&bs->wr_highest_offset, offset + bytes);
43
+ /* fall through, to set dirty bits */
44
+ case BDRV_TRACKED_DISCARD:
45
+ bdrv_set_dirty(bs, offset, bytes);
46
+ break;
47
+ default:
48
+ break;
49
+ }
50
+ }
22
}
51
}
23
52
24
-static int blkdebug_truncate(BlockDriverState *bs, int64_t offset,
53
/*
25
- PreallocMode prealloc, Error **errp)
54
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
26
-{
55
ret = bdrv_check_byte_request(bs, offset, bytes);
27
- return bdrv_truncate(bs->file, offset, prealloc, errp);
56
if (ret < 0) {
28
-}
57
return ret;
29
-
58
- } else if (bs->read_only) {
30
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
59
- return -EPERM;
31
{
60
}
32
BDRVBlkdebugState *s = bs->opaque;
61
- assert(!(bs->open_flags & BDRV_O_INACTIVE));
33
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
62
34
.format_name = "blkdebug",
63
/* Do nothing if disabled. */
35
.protocol_name = "blkdebug",
64
if (!(bs->open_flags & BDRV_O_UNMAP)) {
36
.instance_size = sizeof(BDRVBlkdebugState),
65
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
37
+ .is_filter = true,
66
bdrv_inc_in_flight(bs);
38
67
tracked_request_begin(&req, bs, offset, bytes, BDRV_TRACKED_DISCARD);
39
.bdrv_parse_filename = blkdebug_parse_filename,
68
40
.bdrv_file_open = blkdebug_open,
69
- ret = notifier_with_return_list_notify(&bs->before_write_notifiers, &req);
41
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_blkdebug = {
70
+ ret = bdrv_co_write_req_prepare(child, offset, bytes, &req, 0);
42
.bdrv_child_perm = bdrv_filter_default_perms,
71
if (ret < 0) {
43
72
goto out;
44
.bdrv_getlength = blkdebug_getlength,
73
}
45
- .bdrv_truncate = blkdebug_truncate,
74
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_pdiscard(BdrvChild *child, int64_t offset, int bytes)
46
.bdrv_refresh_filename = blkdebug_refresh_filename,
75
}
47
.bdrv_refresh_limits = blkdebug_refresh_limits,
76
ret = 0;
48
77
out:
78
- atomic_inc(&bs->write_gen);
79
- bdrv_set_dirty(bs, req.offset, req.bytes);
80
+ bdrv_co_write_req_finish(child, req.offset, req.bytes, &req, ret);
81
tracked_request_end(&req);
82
bdrv_dec_in_flight(bs);
83
return ret;
49
--
84
--
50
2.13.5
85
2.13.6
51
86
52
87
diff view generated by jsdifflib
New patch
1
From: Fam Zheng <famz@redhat.com>
1
2
3
This brings the request handling logic inline with write and discard,
4
fixing write_gen, resize_cb, dirty bitmaps and image size refreshing.
5
The last of these issues broke iotest case 222, which is now fixed.
6
7
Signed-off-by: Fam Zheng <famz@redhat.com>
8
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
9
---
10
block/io.c | 24 ++++++++++--------------
11
1 file changed, 10 insertions(+), 14 deletions(-)
12
13
diff --git a/block/io.c b/block/io.c
14
index XXXXXXX..XXXXXXX 100644
15
--- a/block/io.c
16
+++ b/block/io.c
17
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn bdrv_co_copy_range_internal(
18
bdrv_inc_in_flight(dst->bs);
19
tracked_request_begin(&req, dst->bs, dst_offset, bytes,
20
BDRV_TRACKED_WRITE);
21
-
22
- /* BDRV_REQ_NO_SERIALISING is only for read operation */
23
- assert(!(write_flags & BDRV_REQ_NO_SERIALISING));
24
- if (write_flags & BDRV_REQ_SERIALISING) {
25
- mark_request_serialising(&req, bdrv_get_cluster_size(dst->bs));
26
- }
27
- wait_serialising_requests(&req);
28
-
29
- ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
30
- src, src_offset,
31
- dst, dst_offset,
32
- bytes,
33
- read_flags, write_flags);
34
-
35
+ ret = bdrv_co_write_req_prepare(dst, dst_offset, bytes, &req,
36
+ write_flags);
37
+ if (!ret) {
38
+ ret = dst->bs->drv->bdrv_co_copy_range_to(dst->bs,
39
+ src, src_offset,
40
+ dst, dst_offset,
41
+ bytes,
42
+ read_flags, write_flags);
43
+ }
44
+ bdrv_co_write_req_finish(dst, dst_offset, bytes, &req, ret);
45
tracked_request_end(&req);
46
bdrv_dec_in_flight(dst->bs);
47
}
48
--
49
2.13.6
50
51
diff view generated by jsdifflib
1
From: Eric Blake <eblake@redhat.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
Omitting the check for whether bdrv_getlength() and bdrv_truncate()
3
If we are growing the image and potentially using preallocation for the
4
failed meant that it was theoretically possible to return an
4
new area, we need to make sure that no write requests are made to the
5
incorrect offset to the caller. More likely, conditions for either
5
"preallocated" area which is [@old_size, @offset), not
6
of these functions to fail would also cause one of our other calls
6
[@offset, offset * 2 - @old_size).
7
(such as bdrv_pread() or bdrv_pwrite_sync()) to also fail, but
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
7
11
Use osdep.h macros instead of open-coded rounding while in the
8
Signed-off-by: Fam Zheng <famz@redhat.com>
12
area.
9
Reviewed-by: Eric Blake <eblake@redhat.com>
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
block/io.c | 3 ++-
19
1 file changed, 22 insertions(+), 8 deletions(-)
13
1 file changed, 2 insertions(+), 1 deletion(-)
20
14
21
diff --git a/block/qcow.c b/block/qcow.c
15
diff --git a/block/io.c b/block/io.c
22
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
23
--- a/block/qcow.c
17
--- a/block/io.c
24
+++ b/block/qcow.c
18
+++ b/block/io.c
25
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
19
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
26
{
20
}
27
BDRVQcowState *s = bs->opaque;
21
28
int min_index, i, j, l1_index, l2_index, ret;
22
bdrv_inc_in_flight(bs);
29
- uint64_t l2_offset, *l2_table, cluster_offset, tmp;
23
- tracked_request_begin(&req, bs, offset, new_bytes, BDRV_TRACKED_TRUNCATE);
30
+ int64_t l2_offset;
24
+ tracked_request_begin(&req, bs, offset - new_bytes, new_bytes,
31
+ uint64_t *l2_table, cluster_offset, tmp;
25
+ BDRV_TRACKED_TRUNCATE);
32
uint32_t min_count;
26
33
int new_l2_table;
27
/* If we are growing the image and potentially using preallocation for the
34
28
* new area, we need to make sure that no write requests are made to it
35
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
36
return 0;
37
/* allocate a new l2 entry */
38
l2_offset = bdrv_getlength(bs->file->bs);
39
+ if (l2_offset < 0) {
40
+ return l2_offset;
41
+ }
42
/* round to cluster size */
43
- l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1);
44
+ l2_offset = QEMU_ALIGN_UP(l2_offset, s->cluster_size);
45
/* update the L1 entry */
46
s->l1_table[l1_index] = l2_offset;
47
tmp = cpu_to_be64(l2_offset);
48
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
49
return -EIO;
50
}
51
cluster_offset = bdrv_getlength(bs->file->bs);
52
- cluster_offset = (cluster_offset + s->cluster_size - 1) &
53
- ~(s->cluster_size - 1);
54
+ if ((int64_t) cluster_offset < 0) {
55
+ return cluster_offset;
56
+ }
57
+ cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
58
/* write the cluster content */
59
ret = bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache,
60
s->cluster_size);
61
@@ -XXX,XX +XXX,XX @@ static int get_cluster_offset(BlockDriverState *bs,
62
}
63
} else {
64
cluster_offset = bdrv_getlength(bs->file->bs);
65
+ if ((int64_t) cluster_offset < 0) {
66
+ return cluster_offset;
67
+ }
68
if (allocate == 1) {
69
/* round to cluster size */
70
- cluster_offset = (cluster_offset + s->cluster_size - 1) &
71
- ~(s->cluster_size - 1);
72
- bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
73
- PREALLOC_MODE_OFF, NULL);
74
+ cluster_offset = QEMU_ALIGN_UP(cluster_offset, s->cluster_size);
75
+ if (cluster_offset + s->cluster_size > INT64_MAX) {
76
+ return -E2BIG;
77
+ }
78
+ ret = bdrv_truncate(bs->file, cluster_offset + s->cluster_size,
79
+ PREALLOC_MODE_OFF, NULL);
80
+ if (ret < 0) {
81
+ return ret;
82
+ }
83
/* if encrypted, we must initialize the cluster
84
content which won't be written */
85
if (bs->encrypted &&
86
--
29
--
87
2.13.5
30
2.13.6
88
31
89
32
diff view generated by jsdifflib
1
From: Pavel Butsykin <pbutsykin@virtuozzo.com>
1
From: Fam Zheng <famz@redhat.com>
2
2
3
After calling qcow2_inactivate(), all qcow2 caches must be flushed, but this
3
Truncation is the last to convert from open coded req handling to
4
may not happen, because the last call qcow2_store_persistent_dirty_bitmaps()
4
reusing helpers. This time the permission check in prepare has to adapt
5
can lead to marking l2/refcont cache as dirty.
5
to the new caller: it checks a different permission bit, and doesn't
6
trigger the before write notifier.
6
7
7
Let's move qcow2_store_persistent_dirty_bitmaps() before the caсhe flushing
8
Also, truncation should always trigger a bs->total_sectors update and in
8
to fix it.
9
turn call parent resize_cb. Update the condition in finish helper, too.
9
10
10
Cc: qemu-stable@nongnu.org
11
It's intended to do a duplicated bs->read_only check before calling
11
Signed-off-by: Pavel Butsykin <pbutsykin@virtuozzo.com>
12
bdrv_co_write_req_prepare() so that we can be more informative with the
13
error message, as bdrv_co_write_req_prepare() doesn't have Error
14
parameter.
15
16
Signed-off-by: Fam Zheng <famz@redhat.com>
12
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
17
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
13
---
18
---
14
block/qcow2.c | 16 ++++++++--------
19
block/io.c | 55 +++++++++++++++++++++++++++++++++++--------------------
15
1 file changed, 8 insertions(+), 8 deletions(-)
20
1 file changed, 35 insertions(+), 20 deletions(-)
16
21
17
diff --git a/block/qcow2.c b/block/qcow2.c
22
diff --git a/block/io.c b/block/io.c
18
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
19
--- a/block/qcow2.c
24
--- a/block/io.c
20
+++ b/block/qcow2.c
25
+++ b/block/io.c
21
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
26
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_prepare(BdrvChild *child, int64_t offset, uint64_t bytes,
22
int ret, result = 0;
27
is_request_serialising_and_aligned(req));
23
Error *local_err = NULL;
28
assert(req->overlap_offset <= offset);
24
29
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
25
+ qcow2_store_persistent_dirty_bitmaps(bs, &local_err);
30
+ assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
26
+ if (local_err != NULL) {
31
27
+ result = -EINVAL;
32
- if (flags & BDRV_REQ_WRITE_UNCHANGED) {
28
+ error_report_err(local_err);
33
- assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
29
+ error_report("Persistent bitmaps are lost for node '%s'",
34
- } else {
30
+ bdrv_get_device_or_node_name(bs));
35
- assert(child->perm & BLK_PERM_WRITE);
36
+ switch (req->type) {
37
+ case BDRV_TRACKED_WRITE:
38
+ case BDRV_TRACKED_DISCARD:
39
+ if (flags & BDRV_REQ_WRITE_UNCHANGED) {
40
+ assert(child->perm & (BLK_PERM_WRITE_UNCHANGED | BLK_PERM_WRITE));
41
+ } else {
42
+ assert(child->perm & BLK_PERM_WRITE);
43
+ }
44
+ return notifier_with_return_list_notify(&bs->before_write_notifiers,
45
+ req);
46
+ case BDRV_TRACKED_TRUNCATE:
47
+ assert(child->perm & BLK_PERM_RESIZE);
48
+ return 0;
49
+ default:
50
+ abort();
51
}
52
- assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
53
- return notifier_with_return_list_notify(&bs->before_write_notifiers, req);
54
}
55
56
static inline void coroutine_fn
57
@@ -XXX,XX +XXX,XX @@ bdrv_co_write_req_finish(BdrvChild *child, int64_t offset, uint64_t bytes,
58
* beyond EOF cannot expand the image anyway.
59
*/
60
if (ret == 0 &&
61
- end_sector > bs->total_sectors &&
62
- req->type != BDRV_TRACKED_DISCARD) {
63
+ (req->type == BDRV_TRACKED_TRUNCATE ||
64
+ end_sector > bs->total_sectors) &&
65
+ req->type != BDRV_TRACKED_DISCARD) {
66
bs->total_sectors = end_sector;
67
bdrv_parent_cb_resize(bs);
68
bdrv_dirty_bitmap_truncate(bs, end_sector << BDRV_SECTOR_BITS);
69
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
70
int64_t old_size, new_bytes;
71
int ret;
72
73
- assert(child->perm & BLK_PERM_RESIZE);
74
75
/* if bs->drv == NULL, bs is closed, so there's nothing to do here */
76
if (!drv) {
77
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
78
* concurrently or they might be overwritten by preallocation. */
79
if (new_bytes) {
80
mark_request_serialising(&req, 1);
81
- wait_serialising_requests(&req);
31
+ }
82
+ }
32
+
83
+ if (bs->read_only) {
33
ret = qcow2_cache_flush(bs, s->l2_table_cache);
84
+ error_setg(errp, "Image is read-only");
34
if (ret) {
85
+ ret = -EACCES;
35
result = ret;
86
+ goto out;
36
@@ -XXX,XX +XXX,XX @@ static int qcow2_inactivate(BlockDriverState *bs)
87
+ }
37
strerror(-ret));
88
+ ret = bdrv_co_write_req_prepare(child, offset - new_bytes, new_bytes, &req,
89
+ 0);
90
+ if (ret < 0) {
91
+ error_setg_errno(errp, -ret,
92
+ "Failed to prepare request for truncation");
93
+ goto out;
38
}
94
}
39
95
40
- qcow2_store_persistent_dirty_bitmaps(bs, &local_err);
96
if (!drv->bdrv_co_truncate) {
41
- if (local_err != NULL) {
97
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
42
- result = -EINVAL;
98
ret = -ENOTSUP;
43
- error_report_err(local_err);
99
goto out;
44
- error_report("Persistent bitmaps are lost for node '%s'",
100
}
45
- bdrv_get_device_or_node_name(bs));
101
- if (bs->read_only) {
102
- error_setg(errp, "Image is read-only");
103
- ret = -EACCES;
104
- goto out;
46
- }
105
- }
47
-
106
-
48
if (result == 0) {
107
- assert(!(bs->open_flags & BDRV_O_INACTIVE));
49
qcow2_mark_clean(bs);
108
109
ret = drv->bdrv_co_truncate(bs, offset, prealloc, errp);
110
if (ret < 0) {
111
@@ -XXX,XX +XXX,XX @@ int coroutine_fn bdrv_co_truncate(BdrvChild *child, int64_t offset,
112
} else {
113
offset = bs->total_sectors * BDRV_SECTOR_SIZE;
50
}
114
}
115
- bdrv_dirty_bitmap_truncate(bs, offset);
116
- bdrv_parent_cb_resize(bs);
117
- atomic_inc(&bs->write_gen);
118
+ /* It's possible that truncation succeeded but refresh_total_sectors
119
+ * failed, but the latter doesn't affect how we should finish the request.
120
+ * Pass 0 as the last parameter so that dirty bitmaps etc. are handled. */
121
+ bdrv_co_write_req_finish(child, offset - new_bytes, new_bytes, &req, 0);
122
123
out:
124
tracked_request_end(&req);
51
--
125
--
52
2.13.5
126
2.13.6
53
127
54
128
diff view generated by jsdifflib