1
The following changes since commit bfec359afba088aaacc7d316f43302f28c6e642a:
1
The following changes since commit f5fe7c17ac4e309e47e78f0f9761aebc8d2f2c81:
2
2
3
Merge remote-tracking branch 'remotes/armbru/tags/pull-qdev-2017-04-21' into staging (2017-04-21 11:42:03 +0100)
3
Merge tag 'pull-tcg-20230823-2' of https://gitlab.com/rth7680/qemu into staging (2023-08-28 16:07:04 -0400)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/codyprime/qemu-kvm-jtc.git tags/block-pull-request
7
https://gitlab.com/hreitz/qemu.git tags/pull-block-2023-09-01
8
8
9
for you to fetch changes up to 1507631e438930bc07f776f303af127a9cdb4d41:
9
for you to fetch changes up to 380448464dd89291cf7fd7434be6c225482a334d:
10
10
11
qemu-iotests: _cleanup_qemu must be called on exit (2017-04-21 08:32:44 -0400)
11
tests/file-io-error: New test (2023-08-29 13:01:24 +0200)
12
12
13
----------------------------------------------------------------
13
----------------------------------------------------------------
14
Block patches
14
15
15
Block patches for 2.10
16
- Fix for file-posix's zoning code crashing on I/O errors
17
- Throttling refactoring
16
18
17
----------------------------------------------------------------
19
----------------------------------------------------------------
20
Hanna Czenczek (5):
21
file-posix: Clear bs->bl.zoned on error
22
file-posix: Check bs->bl.zoned for zone info
23
file-posix: Fix zone update in I/O error path
24
file-posix: Simplify raw_co_prw's 'out' zone code
25
tests/file-io-error: New test
18
26
19
Ashish Mittal (2):
27
Zhenwei Pi (9):
20
block/vxhs.c: Add support for a new block device type called "vxhs"
28
throttle: introduce enum ThrottleDirection
21
block/vxhs.c: Add qemu-iotests for new block device type "vxhs"
29
test-throttle: use enum ThrottleDirection
30
throttle: support read-only and write-only
31
test-throttle: test read only and write only
32
cryptodev: use NULL throttle timer cb for read direction
33
throttle: use enum ThrottleDirection instead of bool is_write
34
throttle: use THROTTLE_MAX/ARRAY_SIZE for hard code
35
fsdev: Use ThrottleDirection instread of bool is_write
36
block/throttle-groups: Use ThrottleDirection instread of bool is_write
22
37
23
Jeff Cody (10):
38
fsdev/qemu-fsdev-throttle.h | 4 +-
24
qemu-iotests: exclude vxhs from image creation via protocol
39
include/block/throttle-groups.h | 6 +-
25
block: add bdrv_set_read_only() helper function
40
include/qemu/throttle.h | 16 +-
26
block: do not set BDS read_only if copy_on_read enabled
41
backends/cryptodev.c | 12 +-
27
block: honor BDRV_O_ALLOW_RDWR when clearing bs->read_only
42
block/block-backend.c | 4 +-
28
block: code movement
43
block/file-posix.c | 42 +++---
29
block: introduce bdrv_can_set_read_only()
44
block/throttle-groups.c | 163 +++++++++++----------
30
block: use bdrv_can_set_read_only() during reopen
45
block/throttle.c | 8 +-
31
block/rbd - update variable names to more apt names
46
fsdev/qemu-fsdev-throttle.c | 18 ++-
32
block/rbd: Add support for reopen()
47
hw/9pfs/cofile.c | 4 +-
33
qemu-iotests: _cleanup_qemu must be called on exit
48
tests/unit/test-throttle.c | 76 +++++++++-
34
49
util/throttle.c | 84 +++++++----
35
block.c | 56 +++-
50
tests/qemu-iotests/tests/file-io-error | 119 +++++++++++++++
36
block/Makefile.objs | 2 +
51
tests/qemu-iotests/tests/file-io-error.out | 33 +++++
37
block/bochs.c | 5 +-
52
14 files changed, 418 insertions(+), 171 deletions(-)
38
block/cloop.c | 5 +-
53
create mode 100755 tests/qemu-iotests/tests/file-io-error
39
block/dmg.c | 6 +-
54
create mode 100644 tests/qemu-iotests/tests/file-io-error.out
40
block/rbd.c | 65 +++--
41
block/trace-events | 17 ++
42
block/vvfat.c | 19 +-
43
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++
44
configure | 39 +++
45
include/block/block.h | 2 +
46
qapi/block-core.json | 23 +-
47
tests/qemu-iotests/017 | 1 +
48
tests/qemu-iotests/020 | 1 +
49
tests/qemu-iotests/028 | 1 +
50
tests/qemu-iotests/029 | 1 +
51
tests/qemu-iotests/073 | 1 +
52
tests/qemu-iotests/094 | 11 +-
53
tests/qemu-iotests/102 | 5 +-
54
tests/qemu-iotests/109 | 1 +
55
tests/qemu-iotests/114 | 1 +
56
tests/qemu-iotests/117 | 1 +
57
tests/qemu-iotests/130 | 2 +
58
tests/qemu-iotests/134 | 1 +
59
tests/qemu-iotests/140 | 1 +
60
tests/qemu-iotests/141 | 1 +
61
tests/qemu-iotests/143 | 1 +
62
tests/qemu-iotests/156 | 2 +
63
tests/qemu-iotests/158 | 1 +
64
tests/qemu-iotests/common | 6 +
65
tests/qemu-iotests/common.config | 13 +
66
tests/qemu-iotests/common.filter | 1 +
67
tests/qemu-iotests/common.rc | 19 ++
68
33 files changed, 844 insertions(+), 42 deletions(-)
69
create mode 100644 block/vxhs.c
70
55
71
--
56
--
72
2.9.3
57
2.41.0
73
74
diff view generated by jsdifflib
1
This adds support for reopen in rbd, for changing between r/w and r/o.
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
2
3
Note, that this is only a flag change, but we will block a change from
3
Use enum ThrottleDirection instead of number index.
4
r/o to r/w if we are using an RBD internal snapshot.
5
4
6
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
5
Reviewed-by: Alberto Garcia <berto@igalia.com>
7
Signed-off-by: Jeff Cody <jcody@redhat.com>
6
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
7
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
9
Message-id: d4e87539167ec6527d44c97b164eabcccf96e4f3.1491597120.git.jcody@redhat.com
8
Message-Id: <20230728022006.1098509-2-pizhenwei@bytedance.com>
9
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
10
---
10
---
11
block/rbd.c | 21 +++++++++++++++++++++
11
include/qemu/throttle.h | 11 ++++++++---
12
1 file changed, 21 insertions(+)
12
util/throttle.c | 16 +++++++++-------
13
2 files changed, 17 insertions(+), 10 deletions(-)
13
14
14
diff --git a/block/rbd.c b/block/rbd.c
15
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/block/rbd.c
17
--- a/include/qemu/throttle.h
17
+++ b/block/rbd.c
18
+++ b/include/qemu/throttle.h
18
@@ -XXX,XX +XXX,XX @@ failed_opts:
19
@@ -XXX,XX +XXX,XX @@ typedef struct ThrottleState {
19
return r;
20
int64_t previous_leak; /* timestamp of the last leak done */
21
} ThrottleState;
22
23
+typedef enum {
24
+ THROTTLE_READ = 0,
25
+ THROTTLE_WRITE,
26
+ THROTTLE_MAX
27
+} ThrottleDirection;
28
+
29
typedef struct ThrottleTimers {
30
- QEMUTimer *timers[2]; /* timers used to do the throttling */
31
+ QEMUTimer *timers[THROTTLE_MAX]; /* timers used to do the throttling */
32
QEMUClockType clock_type; /* the clock used */
33
34
/* Callbacks */
35
- QEMUTimerCB *read_timer_cb;
36
- QEMUTimerCB *write_timer_cb;
37
+ QEMUTimerCB *timer_cb[THROTTLE_MAX];
38
void *timer_opaque;
39
} ThrottleTimers;
40
41
diff --git a/util/throttle.c b/util/throttle.c
42
index XXXXXXX..XXXXXXX 100644
43
--- a/util/throttle.c
44
+++ b/util/throttle.c
45
@@ -XXX,XX +XXX,XX @@ static bool throttle_compute_timer(ThrottleState *ts,
46
void throttle_timers_attach_aio_context(ThrottleTimers *tt,
47
AioContext *new_context)
48
{
49
- tt->timers[0] = aio_timer_new(new_context, tt->clock_type, SCALE_NS,
50
- tt->read_timer_cb, tt->timer_opaque);
51
- tt->timers[1] = aio_timer_new(new_context, tt->clock_type, SCALE_NS,
52
- tt->write_timer_cb, tt->timer_opaque);
53
+ tt->timers[THROTTLE_READ] =
54
+ aio_timer_new(new_context, tt->clock_type, SCALE_NS,
55
+ tt->timer_cb[THROTTLE_READ], tt->timer_opaque);
56
+ tt->timers[THROTTLE_WRITE] =
57
+ aio_timer_new(new_context, tt->clock_type, SCALE_NS,
58
+ tt->timer_cb[THROTTLE_WRITE], tt->timer_opaque);
20
}
59
}
21
60
22
+
61
/*
23
+/* Since RBD is currently always opened R/W via the API,
62
@@ -XXX,XX +XXX,XX @@ void throttle_timers_init(ThrottleTimers *tt,
24
+ * we just need to check if we are using a snapshot or not, in
63
memset(tt, 0, sizeof(ThrottleTimers));
25
+ * order to determine if we will allow it to be R/W */
64
26
+static int qemu_rbd_reopen_prepare(BDRVReopenState *state,
65
tt->clock_type = clock_type;
27
+ BlockReopenQueue *queue, Error **errp)
66
- tt->read_timer_cb = read_timer_cb;
28
+{
67
- tt->write_timer_cb = write_timer_cb;
29
+ BDRVRBDState *s = state->bs->opaque;
68
+ tt->timer_cb[THROTTLE_READ] = read_timer_cb;
30
+ int ret = 0;
69
+ tt->timer_cb[THROTTLE_WRITE] = write_timer_cb;
31
+
70
tt->timer_opaque = timer_opaque;
32
+ if (s->snap && state->flags & BDRV_O_RDWR) {
71
throttle_timers_attach_aio_context(tt, aio_context);
33
+ error_setg(errp,
72
}
34
+ "Cannot change node '%s' to r/w when using RBD snapshot",
73
@@ -XXX,XX +XXX,XX @@ void throttle_timers_detach_aio_context(ThrottleTimers *tt)
35
+ bdrv_get_device_or_node_name(state->bs));
36
+ ret = -EINVAL;
37
+ }
38
+
39
+ return ret;
40
+}
41
+
42
static void qemu_rbd_close(BlockDriverState *bs)
43
{
74
{
44
BDRVRBDState *s = bs->opaque;
75
int i;
45
@@ -XXX,XX +XXX,XX @@ static BlockDriver bdrv_rbd = {
76
46
.bdrv_parse_filename = qemu_rbd_parse_filename,
77
- for (i = 0; i < 2; i++) {
47
.bdrv_file_open = qemu_rbd_open,
78
+ for (i = 0; i < THROTTLE_MAX; i++) {
48
.bdrv_close = qemu_rbd_close,
79
throttle_timer_destroy(&tt->timers[i]);
49
+ .bdrv_reopen_prepare = qemu_rbd_reopen_prepare,
80
}
50
.bdrv_create = qemu_rbd_create,
81
}
51
.bdrv_has_zero_init = bdrv_has_zero_init_1,
52
.bdrv_get_info = qemu_rbd_getinfo,
53
--
82
--
54
2.9.3
83
2.41.0
55
56
diff view generated by jsdifflib
1
Move bdrv_is_read_only() up with its friends.
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
2
3
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
Use enum ThrottleDirection instead in the throttle test codes.
4
Reviewed-by: John Snow <jsnow@redhat.com>
4
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
5
Reviewed-by: Alberto Garcia <berto@igalia.com>
6
Message-id: 73b2399459760c32506f9407efb9dddb3a2789de.1491597120.git.jcody@redhat.com
6
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
7
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
8
Message-Id: <20230728022006.1098509-3-pizhenwei@bytedance.com>
9
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
7
---
10
---
8
block.c | 10 +++++-----
11
tests/unit/test-throttle.c | 6 +++---
9
1 file changed, 5 insertions(+), 5 deletions(-)
12
1 file changed, 3 insertions(+), 3 deletions(-)
10
13
11
diff --git a/block.c b/block.c
14
diff --git a/tests/unit/test-throttle.c b/tests/unit/test-throttle.c
12
index XXXXXXX..XXXXXXX 100644
15
index XXXXXXX..XXXXXXX 100644
13
--- a/block.c
16
--- a/tests/unit/test-throttle.c
14
+++ b/block.c
17
+++ b/tests/unit/test-throttle.c
15
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
18
@@ -XXX,XX +XXX,XX @@ static void test_init(void)
19
20
/* check initialized fields */
21
g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
22
- g_assert(tt->timers[0]);
23
- g_assert(tt->timers[1]);
24
+ g_assert(tt->timers[THROTTLE_READ]);
25
+ g_assert(tt->timers[THROTTLE_WRITE]);
26
27
/* check other fields where cleared */
28
g_assert(!ts.previous_leak);
29
@@ -XXX,XX +XXX,XX @@ static void test_destroy(void)
30
throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
31
read_timer_cb, write_timer_cb, &ts);
32
throttle_timers_destroy(tt);
33
- for (i = 0; i < 2; i++) {
34
+ for (i = 0; i < THROTTLE_MAX; i++) {
35
g_assert(!tt->timers[i]);
16
}
36
}
17
}
37
}
18
19
+bool bdrv_is_read_only(BlockDriverState *bs)
20
+{
21
+ return bs->read_only;
22
+}
23
+
24
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
25
{
26
/* Do not set read_only if copy_on_read is enabled */
27
@@ -XXX,XX +XXX,XX @@ void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
28
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
29
}
30
31
-bool bdrv_is_read_only(BlockDriverState *bs)
32
-{
33
- return bs->read_only;
34
-}
35
-
36
bool bdrv_is_sg(BlockDriverState *bs)
37
{
38
return bs->sg;
39
--
38
--
40
2.9.3
39
2.41.0
41
42
diff view generated by jsdifflib
1
We have a helper wrapper for checking for the BDS read_only flag,
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
add a helper wrapper to set the read_only flag as well.
3
2
4
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
3
Only one direction is necessary in several scenarios:
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
4
- a read-only disk
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
- operations on a device are considered as *write* only. For example,
7
Message-id: 9b18972d05f5fa2ac16c014f0af98d680553048d.1491597120.git.jcody@redhat.com
6
encrypt/decrypt/sign/verify operations on a cryptodev use a single
7
*write* timer(read timer callback is defined, but never invoked).
8
9
Allow a single direction in throttle, this reduces memory, and uplayer
10
does not need a dummy callback any more.
11
12
Reviewed-by: Alberto Garcia <berto@igalia.com>
13
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
14
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
15
Message-Id: <20230728022006.1098509-4-pizhenwei@bytedance.com>
16
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
8
---
17
---
9
block.c | 5 +++++
18
util/throttle.c | 42 ++++++++++++++++++++++++++++--------------
10
block/bochs.c | 2 +-
19
1 file changed, 28 insertions(+), 14 deletions(-)
11
block/cloop.c | 2 +-
12
block/dmg.c | 2 +-
13
block/rbd.c | 2 +-
14
block/vvfat.c | 4 ++--
15
include/block/block.h | 1 +
16
7 files changed, 12 insertions(+), 6 deletions(-)
17
20
18
diff --git a/block.c b/block.c
21
diff --git a/util/throttle.c b/util/throttle.c
19
index XXXXXXX..XXXXXXX 100644
22
index XXXXXXX..XXXXXXX 100644
20
--- a/block.c
23
--- a/util/throttle.c
21
+++ b/block.c
24
+++ b/util/throttle.c
22
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
25
@@ -XXX,XX +XXX,XX @@ static bool throttle_compute_timer(ThrottleState *ts,
26
void throttle_timers_attach_aio_context(ThrottleTimers *tt,
27
AioContext *new_context)
28
{
29
- tt->timers[THROTTLE_READ] =
30
- aio_timer_new(new_context, tt->clock_type, SCALE_NS,
31
- tt->timer_cb[THROTTLE_READ], tt->timer_opaque);
32
- tt->timers[THROTTLE_WRITE] =
33
- aio_timer_new(new_context, tt->clock_type, SCALE_NS,
34
- tt->timer_cb[THROTTLE_WRITE], tt->timer_opaque);
35
+ ThrottleDirection dir;
36
+
37
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
38
+ if (tt->timer_cb[dir]) {
39
+ tt->timers[dir] =
40
+ aio_timer_new(new_context, tt->clock_type, SCALE_NS,
41
+ tt->timer_cb[dir], tt->timer_opaque);
42
+ }
43
+ }
44
}
45
46
/*
47
@@ -XXX,XX +XXX,XX @@ void throttle_timers_init(ThrottleTimers *tt,
48
QEMUTimerCB *write_timer_cb,
49
void *timer_opaque)
50
{
51
+ assert(read_timer_cb || write_timer_cb);
52
memset(tt, 0, sizeof(ThrottleTimers));
53
54
tt->clock_type = clock_type;
55
@@ -XXX,XX +XXX,XX @@ void throttle_timers_init(ThrottleTimers *tt,
56
/* destroy a timer */
57
static void throttle_timer_destroy(QEMUTimer **timer)
58
{
59
- assert(*timer != NULL);
60
+ if (*timer == NULL) {
61
+ return;
62
+ }
63
64
timer_free(*timer);
65
*timer = NULL;
66
@@ -XXX,XX +XXX,XX @@ static void throttle_timer_destroy(QEMUTimer **timer)
67
/* Remove timers from event loop */
68
void throttle_timers_detach_aio_context(ThrottleTimers *tt)
69
{
70
- int i;
71
+ ThrottleDirection dir;
72
73
- for (i = 0; i < THROTTLE_MAX; i++) {
74
- throttle_timer_destroy(&tt->timers[i]);
75
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
76
+ throttle_timer_destroy(&tt->timers[dir]);
23
}
77
}
24
}
78
}
25
79
26
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
80
@@ -XXX,XX +XXX,XX @@ void throttle_timers_destroy(ThrottleTimers *tt)
27
+{
81
/* is any throttling timer configured */
28
+ bs->read_only = read_only;
82
bool throttle_timers_are_initialized(ThrottleTimers *tt)
29
+}
83
{
84
- if (tt->timers[0]) {
85
- return true;
86
+ ThrottleDirection dir;
30
+
87
+
31
void bdrv_get_full_backing_filename_from_filename(const char *backed,
88
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
32
const char *backing,
89
+ if (tt->timers[dir]) {
33
char *dest, size_t sz,
90
+ return true;
34
diff --git a/block/bochs.c b/block/bochs.c
91
+ }
35
index XXXXXXX..XXXXXXX 100644
36
--- a/block/bochs.c
37
+++ b/block/bochs.c
38
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
39
return -EINVAL;
40
}
92
}
41
93
42
- bs->read_only = true; /* no write support yet */
94
return false;
43
+ bdrv_set_read_only(bs, true); /* no write support yet */
95
@@ -XXX,XX +XXX,XX @@ bool throttle_schedule_timer(ThrottleState *ts,
44
96
{
45
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
97
int64_t now = qemu_clock_get_ns(tt->clock_type);
46
if (ret < 0) {
98
int64_t next_timestamp;
47
diff --git a/block/cloop.c b/block/cloop.c
99
+ QEMUTimer *timer;
48
index XXXXXXX..XXXXXXX 100644
100
bool must_wait;
49
--- a/block/cloop.c
101
50
+++ b/block/cloop.c
102
+ timer = is_write ? tt->timers[THROTTLE_WRITE] : tt->timers[THROTTLE_READ];
51
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
103
+ assert(timer);
52
return -EINVAL;
104
+
105
must_wait = throttle_compute_timer(ts,
106
is_write,
107
now,
108
@@ -XXX,XX +XXX,XX @@ bool throttle_schedule_timer(ThrottleState *ts,
53
}
109
}
54
110
55
- bs->read_only = true;
111
/* request throttled and timer pending -> do nothing */
56
+ bdrv_set_read_only(bs, true);
112
- if (timer_pending(tt->timers[is_write])) {
57
113
+ if (timer_pending(timer)) {
58
/* read header */
114
return true;
59
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
60
diff --git a/block/dmg.c b/block/dmg.c
61
index XXXXXXX..XXXXXXX 100644
62
--- a/block/dmg.c
63
+++ b/block/dmg.c
64
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
65
}
115
}
66
116
67
block_module_load_one("dmg-bz2");
117
/* request throttled and timer not pending -> arm timer */
68
- bs->read_only = true;
118
- timer_mod(tt->timers[is_write], next_timestamp);
69
+ bdrv_set_read_only(bs, true);
119
+ timer_mod(timer, next_timestamp);
70
120
return true;
71
s->n_chunks = 0;
121
}
72
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
122
73
diff --git a/block/rbd.c b/block/rbd.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/rbd.c
76
+++ b/block/rbd.c
77
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
78
goto failed_open;
79
}
80
81
- bs->read_only = (s->snap != NULL);
82
+ bdrv_set_read_only(bs, (s->snap != NULL));
83
84
qemu_opts_del(opts);
85
return 0;
86
diff --git a/block/vvfat.c b/block/vvfat.c
87
index XXXXXXX..XXXXXXX 100644
88
--- a/block/vvfat.c
89
+++ b/block/vvfat.c
90
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
91
s->current_cluster=0xffffffff;
92
93
/* read only is the default for safety */
94
- bs->read_only = true;
95
+ bdrv_set_read_only(bs, true);
96
s->qcow = NULL;
97
s->qcow_filename = NULL;
98
s->fat2 = NULL;
99
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
100
if (ret < 0) {
101
goto fail;
102
}
103
- bs->read_only = false;
104
+ bdrv_set_read_only(bs, false);
105
}
106
107
bs->total_sectors = cyls * heads * secs;
108
diff --git a/include/block/block.h b/include/block/block.h
109
index XXXXXXX..XXXXXXX 100644
110
--- a/include/block/block.h
111
+++ b/include/block/block.h
112
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
113
int64_t sector_num, int nb_sectors, int *pnum);
114
115
bool bdrv_is_read_only(BlockDriverState *bs);
116
+void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
117
bool bdrv_is_sg(BlockDriverState *bs);
118
bool bdrv_is_inserted(BlockDriverState *bs);
119
int bdrv_media_changed(BlockDriverState *bs);
120
--
123
--
121
2.9.3
124
2.41.0
122
123
diff view generated by jsdifflib
1
Introduce check function for setting read_only flags. Will return < 0 on
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
error, with appropriate Error value set. Does not alter any flags.
3
2
4
Signed-off-by: Jeff Cody <jcody@redhat.com>
3
Reviewed-by: Alberto Garcia <berto@igalia.com>
5
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
4
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
6
Reviewed-by: John Snow <jsnow@redhat.com>
5
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
7
Message-id: e2bba34ac3bc76a0c42adc390413f358ae0566e8.1491597120.git.jcody@redhat.com
6
Message-Id: <20230728022006.1098509-5-pizhenwei@bytedance.com>
7
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
8
---
8
---
9
block.c | 14 +++++++++++++-
9
tests/unit/test-throttle.c | 66 ++++++++++++++++++++++++++++++++++++++
10
include/block/block.h | 1 +
10
1 file changed, 66 insertions(+)
11
2 files changed, 14 insertions(+), 1 deletion(-)
12
11
13
diff --git a/block.c b/block.c
12
diff --git a/tests/unit/test-throttle.c b/tests/unit/test-throttle.c
14
index XXXXXXX..XXXXXXX 100644
13
index XXXXXXX..XXXXXXX 100644
15
--- a/block.c
14
--- a/tests/unit/test-throttle.c
16
+++ b/block.c
15
+++ b/tests/unit/test-throttle.c
17
@@ -XXX,XX +XXX,XX @@ bool bdrv_is_read_only(BlockDriverState *bs)
16
@@ -XXX,XX +XXX,XX @@ static void test_init(void)
18
return bs->read_only;
17
throttle_timers_destroy(tt);
19
}
18
}
20
19
21
-int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
20
+static void test_init_readonly(void)
22
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
21
+{
23
{
22
+ int i;
24
/* Do not set read_only if copy_on_read is enabled */
23
+
25
if (bs->copy_on_read && read_only) {
24
+ tt = &tgm.throttle_timers;
26
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
25
+
27
return -EPERM;
26
+ /* fill the structures with crap */
28
}
27
+ memset(&ts, 1, sizeof(ts));
29
28
+ memset(tt, 1, sizeof(*tt));
30
+ return 0;
29
+
30
+ /* init structures */
31
+ throttle_init(&ts);
32
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
33
+ read_timer_cb, NULL, &ts);
34
+
35
+ /* check initialized fields */
36
+ g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
37
+ g_assert(tt->timers[THROTTLE_READ]);
38
+ g_assert(!tt->timers[THROTTLE_WRITE]);
39
+
40
+ /* check other fields where cleared */
41
+ g_assert(!ts.previous_leak);
42
+ g_assert(!ts.cfg.op_size);
43
+ for (i = 0; i < BUCKETS_COUNT; i++) {
44
+ g_assert(!ts.cfg.buckets[i].avg);
45
+ g_assert(!ts.cfg.buckets[i].max);
46
+ g_assert(!ts.cfg.buckets[i].level);
47
+ }
48
+
49
+ throttle_timers_destroy(tt);
31
+}
50
+}
32
+
51
+
33
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
52
+static void test_init_writeonly(void)
34
+{
53
+{
35
+ int ret = 0;
54
+ int i;
36
+
55
+
37
+ ret = bdrv_can_set_read_only(bs, read_only, errp);
56
+ tt = &tgm.throttle_timers;
38
+ if (ret < 0) {
57
+
39
+ return ret;
58
+ /* fill the structures with crap */
59
+ memset(&ts, 1, sizeof(ts));
60
+ memset(tt, 1, sizeof(*tt));
61
+
62
+ /* init structures */
63
+ throttle_init(&ts);
64
+ throttle_timers_init(tt, ctx, QEMU_CLOCK_VIRTUAL,
65
+ NULL, write_timer_cb, &ts);
66
+
67
+ /* check initialized fields */
68
+ g_assert(tt->clock_type == QEMU_CLOCK_VIRTUAL);
69
+ g_assert(!tt->timers[THROTTLE_READ]);
70
+ g_assert(tt->timers[THROTTLE_WRITE]);
71
+
72
+ /* check other fields where cleared */
73
+ g_assert(!ts.previous_leak);
74
+ g_assert(!ts.cfg.op_size);
75
+ for (i = 0; i < BUCKETS_COUNT; i++) {
76
+ g_assert(!ts.cfg.buckets[i].avg);
77
+ g_assert(!ts.cfg.buckets[i].max);
78
+ g_assert(!ts.cfg.buckets[i].level);
40
+ }
79
+ }
41
+
80
+
42
bs->read_only = read_only;
81
+ throttle_timers_destroy(tt);
43
return 0;
82
+}
44
}
83
+
45
diff --git a/include/block/block.h b/include/block/block.h
84
static void test_destroy(void)
46
index XXXXXXX..XXXXXXX 100644
85
{
47
--- a/include/block/block.h
86
int i;
48
+++ b/include/block/block.h
87
@@ -XXX,XX +XXX,XX @@ int main(int argc, char **argv)
49
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
88
g_test_add_func("/throttle/leak_bucket", test_leak_bucket);
50
int64_t sector_num, int nb_sectors, int *pnum);
89
g_test_add_func("/throttle/compute_wait", test_compute_wait);
51
90
g_test_add_func("/throttle/init", test_init);
52
bool bdrv_is_read_only(BlockDriverState *bs);
91
+ g_test_add_func("/throttle/init_readonly", test_init_readonly);
53
+int bdrv_can_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
92
+ g_test_add_func("/throttle/init_writeonly", test_init_writeonly);
54
int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
93
g_test_add_func("/throttle/destroy", test_destroy);
55
bool bdrv_is_sg(BlockDriverState *bs);
94
g_test_add_func("/throttle/have_timer", test_have_timer);
56
bool bdrv_is_inserted(BlockDriverState *bs);
95
g_test_add_func("/throttle/detach_attach", test_detach_attach);
57
--
96
--
58
2.9.3
97
2.41.0
59
60
diff view generated by jsdifflib
1
Update 'clientname' to be 'user', which tracks better with both
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
the QAPI and rados variable naming.
3
2
4
Update 'name' to be 'image_name', as it indicates the rbd image.
3
Operations on a cryptodev are considered as *write* only, the callback
5
Naming it 'image' would have been ideal, but we are using that for
4
of read direction is never invoked. Use NULL instead of an unreachable
6
the rados_image_t value returned by rbd_open().
5
path(cryptodev_backend_throttle_timer_cb on read direction).
7
6
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
7
The dummy read timer(never invoked) is already removed here, it means
9
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
that the 'FIXME' tag is no longer needed.
10
Reviewed-by: John Snow <jsnow@redhat.com>
9
11
Message-id: b7ec1fb2e1cf36f9b6911631447a5b0422590b7d.1491597120.git.jcody@redhat.com
10
Reviewed-by: Alberto Garcia <berto@igalia.com>
11
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
12
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
13
Message-Id: <20230728022006.1098509-6-pizhenwei@bytedance.com>
14
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
12
---
15
---
13
block/rbd.c | 33 +++++++++++++++++----------------
16
backends/cryptodev.c | 3 +--
14
1 file changed, 17 insertions(+), 16 deletions(-)
17
1 file changed, 1 insertion(+), 2 deletions(-)
15
18
16
diff --git a/block/rbd.c b/block/rbd.c
19
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
17
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
18
--- a/block/rbd.c
21
--- a/backends/cryptodev.c
19
+++ b/block/rbd.c
22
+++ b/backends/cryptodev.c
20
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVRBDState {
23
@@ -XXX,XX +XXX,XX @@ static void cryptodev_backend_set_throttle(CryptoDevBackend *backend, int field,
21
rados_t cluster;
24
if (!enabled) {
22
rados_ioctx_t io_ctx;
25
throttle_init(&backend->ts);
23
rbd_image_t image;
26
throttle_timers_init(&backend->tt, qemu_get_aio_context(),
24
- char *name;
27
- QEMU_CLOCK_REALTIME,
25
+ char *image_name;
28
- cryptodev_backend_throttle_timer_cb, /* FIXME */
26
char *snap;
29
+ QEMU_CLOCK_REALTIME, NULL,
27
} BDRVRBDState;
30
cryptodev_backend_throttle_timer_cb, backend);
28
29
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
30
int64_t bytes = 0;
31
int64_t objsize;
32
int obj_order = 0;
33
- const char *pool, *name, *conf, *clientname, *keypairs;
34
+ const char *pool, *image_name, *conf, *user, *keypairs;
35
const char *secretid;
36
rados_t cluster;
37
rados_ioctx_t io_ctx;
38
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
39
*/
40
pool = qdict_get_try_str(options, "pool");
41
conf = qdict_get_try_str(options, "conf");
42
- clientname = qdict_get_try_str(options, "user");
43
- name = qdict_get_try_str(options, "image");
44
+ user = qdict_get_try_str(options, "user");
45
+ image_name = qdict_get_try_str(options, "image");
46
keypairs = qdict_get_try_str(options, "=keyvalue-pairs");
47
48
- ret = rados_create(&cluster, clientname);
49
+ ret = rados_create(&cluster, user);
50
if (ret < 0) {
51
error_setg_errno(errp, -ret, "error initializing");
52
goto exit;
53
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
54
goto shutdown;
55
}
31
}
56
32
57
- ret = rbd_create(io_ctx, name, bytes, &obj_order);
58
+ ret = rbd_create(io_ctx, image_name, bytes, &obj_order);
59
if (ret < 0) {
60
error_setg_errno(errp, -ret, "error rbd create");
61
}
62
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
63
Error **errp)
64
{
65
BDRVRBDState *s = bs->opaque;
66
- const char *pool, *snap, *conf, *clientname, *name, *keypairs;
67
+ const char *pool, *snap, *conf, *user, *image_name, *keypairs;
68
const char *secretid;
69
QemuOpts *opts;
70
Error *local_err = NULL;
71
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
72
pool = qemu_opt_get(opts, "pool");
73
conf = qemu_opt_get(opts, "conf");
74
snap = qemu_opt_get(opts, "snapshot");
75
- clientname = qemu_opt_get(opts, "user");
76
- name = qemu_opt_get(opts, "image");
77
+ user = qemu_opt_get(opts, "user");
78
+ image_name = qemu_opt_get(opts, "image");
79
keypairs = qemu_opt_get(opts, "=keyvalue-pairs");
80
81
- if (!pool || !name) {
82
+ if (!pool || !image_name) {
83
error_setg(errp, "Parameters 'pool' and 'image' are required");
84
r = -EINVAL;
85
goto failed_opts;
86
}
87
88
- r = rados_create(&s->cluster, clientname);
89
+ r = rados_create(&s->cluster, user);
90
if (r < 0) {
91
error_setg_errno(errp, -r, "error initializing");
92
goto failed_opts;
93
}
94
95
s->snap = g_strdup(snap);
96
- s->name = g_strdup(name);
97
+ s->image_name = g_strdup(image_name);
98
99
/* try default location when conf=NULL, but ignore failure */
100
r = rados_conf_read_file(s->cluster, conf);
101
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
102
}
103
104
/* rbd_open is always r/w */
105
- r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
106
+ r = rbd_open(s->io_ctx, s->image_name, &s->image, s->snap);
107
if (r < 0) {
108
- error_setg_errno(errp, -r, "error reading header from %s", s->name);
109
+ error_setg_errno(errp, -r, "error reading header from %s",
110
+ s->image_name);
111
goto failed_open;
112
}
113
114
@@ -XXX,XX +XXX,XX @@ failed_open:
115
failed_shutdown:
116
rados_shutdown(s->cluster);
117
g_free(s->snap);
118
- g_free(s->name);
119
+ g_free(s->image_name);
120
failed_opts:
121
qemu_opts_del(opts);
122
g_free(mon_host);
123
@@ -XXX,XX +XXX,XX @@ static void qemu_rbd_close(BlockDriverState *bs)
124
rbd_close(s->image);
125
rados_ioctx_destroy(s->io_ctx);
126
g_free(s->snap);
127
- g_free(s->name);
128
+ g_free(s->image_name);
129
rados_shutdown(s->cluster);
130
}
131
132
--
33
--
133
2.9.3
34
2.41.0
134
135
diff view generated by jsdifflib
New patch
1
From: zhenwei pi <pizhenwei@bytedance.com>
1
2
3
enum ThrottleDirection is already there, use ThrottleDirection instead
4
of 'bool is_write' for throttle API, also modify related codes from
5
block, fsdev, cryptodev and tests.
6
7
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
8
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
9
Message-Id: <20230728022006.1098509-7-pizhenwei@bytedance.com>
10
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
11
---
12
include/qemu/throttle.h | 5 +++--
13
backends/cryptodev.c | 9 +++++----
14
block/throttle-groups.c | 6 ++++--
15
fsdev/qemu-fsdev-throttle.c | 8 +++++---
16
tests/unit/test-throttle.c | 4 ++--
17
util/throttle.c | 31 +++++++++++++++++--------------
18
6 files changed, 36 insertions(+), 27 deletions(-)
19
20
diff --git a/include/qemu/throttle.h b/include/qemu/throttle.h
21
index XXXXXXX..XXXXXXX 100644
22
--- a/include/qemu/throttle.h
23
+++ b/include/qemu/throttle.h
24
@@ -XXX,XX +XXX,XX @@ void throttle_config_init(ThrottleConfig *cfg);
25
/* usage */
26
bool throttle_schedule_timer(ThrottleState *ts,
27
ThrottleTimers *tt,
28
- bool is_write);
29
+ ThrottleDirection direction);
30
31
-void throttle_account(ThrottleState *ts, bool is_write, uint64_t size);
32
+void throttle_account(ThrottleState *ts, ThrottleDirection direction,
33
+ uint64_t size);
34
void throttle_limits_to_config(ThrottleLimits *arg, ThrottleConfig *cfg,
35
Error **errp);
36
void throttle_config_to_limits(ThrottleConfig *cfg, ThrottleLimits *var);
37
diff --git a/backends/cryptodev.c b/backends/cryptodev.c
38
index XXXXXXX..XXXXXXX 100644
39
--- a/backends/cryptodev.c
40
+++ b/backends/cryptodev.c
41
@@ -XXX,XX +XXX,XX @@ static void cryptodev_backend_throttle_timer_cb(void *opaque)
42
continue;
43
}
44
45
- throttle_account(&backend->ts, true, ret);
46
+ throttle_account(&backend->ts, THROTTLE_WRITE, ret);
47
cryptodev_backend_operation(backend, op_info);
48
if (throttle_enabled(&backend->tc) &&
49
- throttle_schedule_timer(&backend->ts, &backend->tt, true)) {
50
+ throttle_schedule_timer(&backend->ts, &backend->tt,
51
+ THROTTLE_WRITE)) {
52
break;
53
}
54
}
55
@@ -XXX,XX +XXX,XX @@ int cryptodev_backend_crypto_operation(
56
goto do_account;
57
}
58
59
- if (throttle_schedule_timer(&backend->ts, &backend->tt, true) ||
60
+ if (throttle_schedule_timer(&backend->ts, &backend->tt, THROTTLE_WRITE) ||
61
!QTAILQ_EMPTY(&backend->opinfos)) {
62
QTAILQ_INSERT_TAIL(&backend->opinfos, op_info, next);
63
return 0;
64
@@ -XXX,XX +XXX,XX @@ do_account:
65
return ret;
66
}
67
68
- throttle_account(&backend->ts, true, ret);
69
+ throttle_account(&backend->ts, THROTTLE_WRITE, ret);
70
71
return cryptodev_backend_operation(backend, op_info);
72
}
73
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/throttle-groups.c
76
+++ b/block/throttle-groups.c
77
@@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
78
ThrottleState *ts = tgm->throttle_state;
79
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
80
ThrottleTimers *tt = &tgm->throttle_timers;
81
+ ThrottleDirection direction = is_write ? THROTTLE_WRITE : THROTTLE_READ;
82
bool must_wait;
83
84
if (qatomic_read(&tgm->io_limits_disabled)) {
85
@@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
86
return true;
87
}
88
89
- must_wait = throttle_schedule_timer(ts, tt, is_write);
90
+ must_wait = throttle_schedule_timer(ts, tt, direction);
91
92
/* If a timer just got armed, set tgm as the current token */
93
if (must_wait) {
94
@@ -XXX,XX +XXX,XX @@ void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
95
bool must_wait;
96
ThrottleGroupMember *token;
97
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
98
+ ThrottleDirection direction = is_write ? THROTTLE_WRITE : THROTTLE_READ;
99
100
assert(bytes >= 0);
101
102
@@ -XXX,XX +XXX,XX @@ void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm
103
}
104
105
/* The I/O will be executed, so do the accounting */
106
- throttle_account(tgm->throttle_state, is_write, bytes);
107
+ throttle_account(tgm->throttle_state, direction, bytes);
108
109
/* Schedule the next request */
110
schedule_next_request(tgm, is_write);
111
diff --git a/fsdev/qemu-fsdev-throttle.c b/fsdev/qemu-fsdev-throttle.c
112
index XXXXXXX..XXXXXXX 100644
113
--- a/fsdev/qemu-fsdev-throttle.c
114
+++ b/fsdev/qemu-fsdev-throttle.c
115
@@ -XXX,XX +XXX,XX @@ void fsdev_throttle_init(FsThrottle *fst)
116
void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, bool is_write,
117
struct iovec *iov, int iovcnt)
118
{
119
+ ThrottleDirection direction = is_write ? THROTTLE_WRITE : THROTTLE_READ;
120
+
121
if (throttle_enabled(&fst->cfg)) {
122
- if (throttle_schedule_timer(&fst->ts, &fst->tt, is_write) ||
123
+ if (throttle_schedule_timer(&fst->ts, &fst->tt, direction) ||
124
!qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
125
qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL);
126
}
127
128
- throttle_account(&fst->ts, is_write, iov_size(iov, iovcnt));
129
+ throttle_account(&fst->ts, direction, iov_size(iov, iovcnt));
130
131
if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) &&
132
- !throttle_schedule_timer(&fst->ts, &fst->tt, is_write)) {
133
+ !throttle_schedule_timer(&fst->ts, &fst->tt, direction)) {
134
qemu_co_queue_next(&fst->throttled_reqs[is_write]);
135
}
136
}
137
diff --git a/tests/unit/test-throttle.c b/tests/unit/test-throttle.c
138
index XXXXXXX..XXXXXXX 100644
139
--- a/tests/unit/test-throttle.c
140
+++ b/tests/unit/test-throttle.c
141
@@ -XXX,XX +XXX,XX @@ static bool do_test_accounting(bool is_ops, /* are we testing bps or ops */
142
throttle_config(&ts, QEMU_CLOCK_VIRTUAL, &cfg);
143
144
/* account a read */
145
- throttle_account(&ts, false, size);
146
+ throttle_account(&ts, THROTTLE_READ, size);
147
/* account a write */
148
- throttle_account(&ts, true, size);
149
+ throttle_account(&ts, THROTTLE_WRITE, size);
150
151
/* check total result */
152
index = to_test[is_ops][0];
153
diff --git a/util/throttle.c b/util/throttle.c
154
index XXXXXXX..XXXXXXX 100644
155
--- a/util/throttle.c
156
+++ b/util/throttle.c
157
@@ -XXX,XX +XXX,XX @@ int64_t throttle_compute_wait(LeakyBucket *bkt)
158
159
/* This function compute the time that must be waited while this IO
160
*
161
- * @is_write: true if the current IO is a write, false if it's a read
162
+ * @direction: throttle direction
163
* @ret: time to wait
164
*/
165
static int64_t throttle_compute_wait_for(ThrottleState *ts,
166
- bool is_write)
167
+ ThrottleDirection direction)
168
{
169
BucketType to_check[2][4] = { {THROTTLE_BPS_TOTAL,
170
THROTTLE_OPS_TOTAL,
171
@@ -XXX,XX +XXX,XX @@ static int64_t throttle_compute_wait_for(ThrottleState *ts,
172
int i;
173
174
for (i = 0; i < 4; i++) {
175
- BucketType index = to_check[is_write][i];
176
+ BucketType index = to_check[direction][i];
177
wait = throttle_compute_wait(&ts->cfg.buckets[index]);
178
if (wait > max_wait) {
179
max_wait = wait;
180
@@ -XXX,XX +XXX,XX @@ static int64_t throttle_compute_wait_for(ThrottleState *ts,
181
182
/* compute the timer for this type of operation
183
*
184
- * @is_write: the type of operation
185
+ * @direction: throttle direction
186
* @now: the current clock timestamp
187
* @next_timestamp: the resulting timer
188
* @ret: true if a timer must be set
189
*/
190
static bool throttle_compute_timer(ThrottleState *ts,
191
- bool is_write,
192
+ ThrottleDirection direction,
193
int64_t now,
194
int64_t *next_timestamp)
195
{
196
@@ -XXX,XX +XXX,XX @@ static bool throttle_compute_timer(ThrottleState *ts,
197
throttle_do_leak(ts, now);
198
199
/* compute the wait time if any */
200
- wait = throttle_compute_wait_for(ts, is_write);
201
+ wait = throttle_compute_wait_for(ts, direction);
202
203
/* if the code must wait compute when the next timer should fire */
204
if (wait) {
205
@@ -XXX,XX +XXX,XX @@ void throttle_get_config(ThrottleState *ts, ThrottleConfig *cfg)
206
* NOTE: this function is not unit tested due to it's usage of timer_mod
207
*
208
* @tt: the timers structure
209
- * @is_write: the type of operation (read/write)
210
+ * @direction: throttle direction
211
* @ret: true if the timer has been scheduled else false
212
*/
213
bool throttle_schedule_timer(ThrottleState *ts,
214
ThrottleTimers *tt,
215
- bool is_write)
216
+ ThrottleDirection direction)
217
{
218
int64_t now = qemu_clock_get_ns(tt->clock_type);
219
int64_t next_timestamp;
220
QEMUTimer *timer;
221
bool must_wait;
222
223
- timer = is_write ? tt->timers[THROTTLE_WRITE] : tt->timers[THROTTLE_READ];
224
+ assert(direction < THROTTLE_MAX);
225
+ timer = tt->timers[direction];
226
assert(timer);
227
228
must_wait = throttle_compute_timer(ts,
229
- is_write,
230
+ direction,
231
now,
232
&next_timestamp);
233
234
@@ -XXX,XX +XXX,XX @@ bool throttle_schedule_timer(ThrottleState *ts,
235
236
/* do the accounting for this operation
237
*
238
- * @is_write: the type of operation (read/write)
239
+ * @direction: throttle direction
240
* @size: the size of the operation
241
*/
242
-void throttle_account(ThrottleState *ts, bool is_write, uint64_t size)
243
+void throttle_account(ThrottleState *ts, ThrottleDirection direction,
244
+ uint64_t size)
245
{
246
const BucketType bucket_types_size[2][2] = {
247
{ THROTTLE_BPS_TOTAL, THROTTLE_BPS_READ },
248
@@ -XXX,XX +XXX,XX @@ void throttle_account(ThrottleState *ts, bool is_write, uint64_t size)
249
double units = 1.0;
250
unsigned i;
251
252
+ assert(direction < THROTTLE_MAX);
253
/* if cfg.op_size is defined and smaller than size we compute unit count */
254
if (ts->cfg.op_size && size > ts->cfg.op_size) {
255
units = (double) size / ts->cfg.op_size;
256
@@ -XXX,XX +XXX,XX @@ void throttle_account(ThrottleState *ts, bool is_write, uint64_t size)
257
for (i = 0; i < 2; i++) {
258
LeakyBucket *bkt;
259
260
- bkt = &ts->cfg.buckets[bucket_types_size[is_write][i]];
261
+ bkt = &ts->cfg.buckets[bucket_types_size[direction][i]];
262
bkt->level += size;
263
if (bkt->burst_length > 1) {
264
bkt->burst_level += size;
265
}
266
267
- bkt = &ts->cfg.buckets[bucket_types_units[is_write][i]];
268
+ bkt = &ts->cfg.buckets[bucket_types_units[direction][i]];
269
bkt->level += units;
270
if (bkt->burst_length > 1) {
271
bkt->burst_level += units;
272
--
273
2.41.0
diff view generated by jsdifflib
1
Signed-off-by: Jeff Cody <jcody@redhat.com>
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
2
3
Reviewed-by: John Snow <jsnow@redhat.com>
3
The first dimension of both to_check and
4
Message-id: 00aed7ffdd7be4b9ed9ce1007d50028a72b34ebe.1491597120.git.jcody@redhat.com
4
bucket_types_size/bucket_types_units is used as throttle direction,
5
use THROTTLE_MAX instead of hard coded number. Also use ARRAY_SIZE()
6
to avoid hard coded number for the second dimension.
7
8
Hanna noticed that the two array should be static. Yes, turn them
9
into static variables.
10
11
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
12
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
13
Message-Id: <20230728022006.1098509-8-pizhenwei@bytedance.com>
14
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
5
---
15
---
6
block.c | 14 ++++++++------
16
util/throttle.c | 11 ++++++-----
7
1 file changed, 8 insertions(+), 6 deletions(-)
17
1 file changed, 6 insertions(+), 5 deletions(-)
8
18
9
diff --git a/block.c b/block.c
19
diff --git a/util/throttle.c b/util/throttle.c
10
index XXXXXXX..XXXXXXX 100644
20
index XXXXXXX..XXXXXXX 100644
11
--- a/block.c
21
--- a/util/throttle.c
12
+++ b/block.c
22
+++ b/util/throttle.c
13
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
23
@@ -XXX,XX +XXX,XX @@ int64_t throttle_compute_wait(LeakyBucket *bkt)
14
BlockDriver *drv;
24
static int64_t throttle_compute_wait_for(ThrottleState *ts,
15
QemuOpts *opts;
25
ThrottleDirection direction)
16
const char *value;
26
{
17
+ bool read_only;
27
- BucketType to_check[2][4] = { {THROTTLE_BPS_TOTAL,
18
28
+ static const BucketType to_check[THROTTLE_MAX][4] = {
19
assert(reopen_state != NULL);
29
+ {THROTTLE_BPS_TOTAL,
20
assert(reopen_state->bs->drv != NULL);
30
THROTTLE_OPS_TOTAL,
21
@@ -XXX,XX +XXX,XX @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue,
31
THROTTLE_BPS_READ,
22
qdict_put(reopen_state->options, "driver", qstring_from_str(value));
32
THROTTLE_OPS_READ},
33
@@ -XXX,XX +XXX,XX @@ static int64_t throttle_compute_wait_for(ThrottleState *ts,
34
int64_t wait, max_wait = 0;
35
int i;
36
37
- for (i = 0; i < 4; i++) {
38
+ for (i = 0; i < ARRAY_SIZE(to_check[THROTTLE_READ]); i++) {
39
BucketType index = to_check[direction][i];
40
wait = throttle_compute_wait(&ts->cfg.buckets[index]);
41
if (wait > max_wait) {
42
@@ -XXX,XX +XXX,XX @@ bool throttle_schedule_timer(ThrottleState *ts,
43
void throttle_account(ThrottleState *ts, ThrottleDirection direction,
44
uint64_t size)
45
{
46
- const BucketType bucket_types_size[2][2] = {
47
+ static const BucketType bucket_types_size[THROTTLE_MAX][2] = {
48
{ THROTTLE_BPS_TOTAL, THROTTLE_BPS_READ },
49
{ THROTTLE_BPS_TOTAL, THROTTLE_BPS_WRITE }
50
};
51
- const BucketType bucket_types_units[2][2] = {
52
+ static const BucketType bucket_types_units[THROTTLE_MAX][2] = {
53
{ THROTTLE_OPS_TOTAL, THROTTLE_OPS_READ },
54
{ THROTTLE_OPS_TOTAL, THROTTLE_OPS_WRITE }
55
};
56
@@ -XXX,XX +XXX,XX @@ void throttle_account(ThrottleState *ts, ThrottleDirection direction,
57
units = (double) size / ts->cfg.op_size;
23
}
58
}
24
59
25
- /* if we are to stay read-only, do not allow permission change
60
- for (i = 0; i < 2; i++) {
26
- * to r/w */
61
+ for (i = 0; i < ARRAY_SIZE(bucket_types_size[THROTTLE_READ]); i++) {
27
- if (!(reopen_state->bs->open_flags & BDRV_O_ALLOW_RDWR) &&
62
LeakyBucket *bkt;
28
- reopen_state->flags & BDRV_O_RDWR) {
63
29
- error_setg(errp, "Node '%s' is read only",
64
bkt = &ts->cfg.buckets[bucket_types_size[direction][i]];
30
- bdrv_get_device_or_node_name(reopen_state->bs));
31
+ /* If we are to stay read-only, do not allow permission change
32
+ * to r/w. Attempting to set to r/w may fail if either BDRV_O_ALLOW_RDWR is
33
+ * not set, or if the BDS still has copy_on_read enabled */
34
+ read_only = !(reopen_state->flags & BDRV_O_RDWR);
35
+ ret = bdrv_can_set_read_only(reopen_state->bs, read_only, &local_err);
36
+ if (local_err) {
37
+ error_propagate(errp, local_err);
38
goto error;
39
}
40
41
--
65
--
42
2.9.3
66
2.41.0
43
44
diff view generated by jsdifflib
1
A few block drivers will set the BDS read_only flag from their
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
.bdrv_open() function. This means the bs->read_only flag could
3
be set after we enable copy_on_read, as the BDRV_O_COPY_ON_READ
4
flag check occurs prior to the call to bdrv->bdrv_open().
5
2
6
This adds an error return to bdrv_set_read_only(), and an error will be
3
'bool is_write' style is obsolete from throttle framework, adapt
7
return if we try to set the BDS to read_only while copy_on_read is
4
fsdev to the new style.
8
enabled.
9
5
10
This patch also changes the behavior of vvfat. Before, vvfat could
6
Cc: Greg Kurz <groug@kaod.org>
11
override the drive 'readonly' flag with its own, internal 'rw' flag.
7
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
8
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
9
Message-Id: <20230728022006.1098509-9-pizhenwei@bytedance.com>
10
Reviewed-by: Greg Kurz <groug@kaod.org>
11
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
12
---
13
fsdev/qemu-fsdev-throttle.h | 4 ++--
14
fsdev/qemu-fsdev-throttle.c | 14 +++++++-------
15
hw/9pfs/cofile.c | 4 ++--
16
3 files changed, 11 insertions(+), 11 deletions(-)
12
17
13
For instance, this -drive parameter would result in a writable image:
18
diff --git a/fsdev/qemu-fsdev-throttle.h b/fsdev/qemu-fsdev-throttle.h
14
15
"-drive format=vvfat,dir=/tmp/vvfat,rw,if=virtio,readonly=on"
16
17
This is not correct. Now, attempting to use the above -drive parameter
18
will result in an error (i.e., 'rw' is incompatible with 'readonly=on').
19
20
Signed-off-by: Jeff Cody <jcody@redhat.com>
21
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
22
Reviewed-by: John Snow <jsnow@redhat.com>
23
Message-id: 0c5b4c1cc2c651471b131f21376dfd5ea24d2196.1491597120.git.jcody@redhat.com
24
---
25
block.c | 10 +++++++++-
26
block/bochs.c | 5 ++++-
27
block/cloop.c | 5 ++++-
28
block/dmg.c | 6 +++++-
29
block/rbd.c | 11 ++++++++++-
30
block/vvfat.c | 19 +++++++++++++++----
31
include/block/block.h | 2 +-
32
7 files changed, 48 insertions(+), 10 deletions(-)
33
34
diff --git a/block.c b/block.c
35
index XXXXXXX..XXXXXXX 100644
19
index XXXXXXX..XXXXXXX 100644
36
--- a/block.c
20
--- a/fsdev/qemu-fsdev-throttle.h
37
+++ b/block.c
21
+++ b/fsdev/qemu-fsdev-throttle.h
38
@@ -XXX,XX +XXX,XX @@ void path_combine(char *dest, int dest_size,
22
@@ -XXX,XX +XXX,XX @@ typedef struct FsThrottle {
23
ThrottleState ts;
24
ThrottleTimers tt;
25
ThrottleConfig cfg;
26
- CoQueue throttled_reqs[2];
27
+ CoQueue throttled_reqs[THROTTLE_MAX];
28
} FsThrottle;
29
30
int fsdev_throttle_parse_opts(QemuOpts *, FsThrottle *, Error **);
31
32
void fsdev_throttle_init(FsThrottle *);
33
34
-void coroutine_fn fsdev_co_throttle_request(FsThrottle *, bool ,
35
+void coroutine_fn fsdev_co_throttle_request(FsThrottle *, ThrottleDirection ,
36
struct iovec *, int);
37
38
void fsdev_throttle_cleanup(FsThrottle *);
39
diff --git a/fsdev/qemu-fsdev-throttle.c b/fsdev/qemu-fsdev-throttle.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/fsdev/qemu-fsdev-throttle.c
42
+++ b/fsdev/qemu-fsdev-throttle.c
43
@@ -XXX,XX +XXX,XX @@ void fsdev_throttle_init(FsThrottle *fst)
39
}
44
}
40
}
45
}
41
46
42
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only)
47
-void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst, bool is_write,
43
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
48
+void coroutine_fn fsdev_co_throttle_request(FsThrottle *fst,
49
+ ThrottleDirection direction,
50
struct iovec *iov, int iovcnt)
44
{
51
{
45
+ /* Do not set read_only if copy_on_read is enabled */
52
- ThrottleDirection direction = is_write ? THROTTLE_WRITE : THROTTLE_READ;
46
+ if (bs->copy_on_read && read_only) {
53
-
47
+ error_setg(errp, "Can't set node '%s' to r/o with copy-on-read enabled",
54
+ assert(direction < THROTTLE_MAX);
48
+ bdrv_get_device_or_node_name(bs));
55
if (throttle_enabled(&fst->cfg)) {
49
+ return -EINVAL;
56
if (throttle_schedule_timer(&fst->ts, &fst->tt, direction) ||
50
+ }
57
- !qemu_co_queue_empty(&fst->throttled_reqs[is_write])) {
51
+
58
- qemu_co_queue_wait(&fst->throttled_reqs[is_write], NULL);
52
bs->read_only = read_only;
59
+ !qemu_co_queue_empty(&fst->throttled_reqs[direction])) {
53
+ return 0;
60
+ qemu_co_queue_wait(&fst->throttled_reqs[direction], NULL);
61
}
62
63
throttle_account(&fst->ts, direction, iov_size(iov, iovcnt));
64
65
- if (!qemu_co_queue_empty(&fst->throttled_reqs[is_write]) &&
66
+ if (!qemu_co_queue_empty(&fst->throttled_reqs[direction]) &&
67
!throttle_schedule_timer(&fst->ts, &fst->tt, direction)) {
68
- qemu_co_queue_next(&fst->throttled_reqs[is_write]);
69
+ qemu_co_queue_next(&fst->throttled_reqs[direction]);
70
}
71
}
54
}
72
}
55
73
diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c
56
void bdrv_get_full_backing_filename_from_filename(const char *backed,
57
diff --git a/block/bochs.c b/block/bochs.c
58
index XXXXXXX..XXXXXXX 100644
74
index XXXXXXX..XXXXXXX 100644
59
--- a/block/bochs.c
75
--- a/hw/9pfs/cofile.c
60
+++ b/block/bochs.c
76
+++ b/hw/9pfs/cofile.c
61
@@ -XXX,XX +XXX,XX @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
77
@@ -XXX,XX +XXX,XX @@ int coroutine_fn v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp,
62
return -EINVAL;
78
if (v9fs_request_cancelled(pdu)) {
79
return -EINTR;
63
}
80
}
64
81
- fsdev_co_throttle_request(s->ctx.fst, true, iov, iovcnt);
65
- bdrv_set_read_only(bs, true); /* no write support yet */
82
+ fsdev_co_throttle_request(s->ctx.fst, THROTTLE_WRITE, iov, iovcnt);
66
+ ret = bdrv_set_read_only(bs, true, errp); /* no write support yet */
83
v9fs_co_run_in_worker(
67
+ if (ret < 0) {
84
{
68
+ return ret;
85
err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset);
69
+ }
86
@@ -XXX,XX +XXX,XX @@ int coroutine_fn v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp,
70
87
if (v9fs_request_cancelled(pdu)) {
71
ret = bdrv_pread(bs->file, 0, &bochs, sizeof(bochs));
88
return -EINTR;
72
if (ret < 0) {
73
diff --git a/block/cloop.c b/block/cloop.c
74
index XXXXXXX..XXXXXXX 100644
75
--- a/block/cloop.c
76
+++ b/block/cloop.c
77
@@ -XXX,XX +XXX,XX @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
78
return -EINVAL;
79
}
89
}
80
90
- fsdev_co_throttle_request(s->ctx.fst, false, iov, iovcnt);
81
- bdrv_set_read_only(bs, true);
91
+ fsdev_co_throttle_request(s->ctx.fst, THROTTLE_READ, iov, iovcnt);
82
+ ret = bdrv_set_read_only(bs, true, errp);
92
v9fs_co_run_in_worker(
83
+ if (ret < 0) {
93
{
84
+ return ret;
94
err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset);
85
+ }
86
87
/* read header */
88
ret = bdrv_pread(bs->file, 128, &s->block_size, 4);
89
diff --git a/block/dmg.c b/block/dmg.c
90
index XXXXXXX..XXXXXXX 100644
91
--- a/block/dmg.c
92
+++ b/block/dmg.c
93
@@ -XXX,XX +XXX,XX @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
94
return -EINVAL;
95
}
96
97
+ ret = bdrv_set_read_only(bs, true, errp);
98
+ if (ret < 0) {
99
+ return ret;
100
+ }
101
+
102
block_module_load_one("dmg-bz2");
103
- bdrv_set_read_only(bs, true);
104
105
s->n_chunks = 0;
106
s->offsets = s->lengths = s->sectors = s->sectorcounts = NULL;
107
diff --git a/block/rbd.c b/block/rbd.c
108
index XXXXXXX..XXXXXXX 100644
109
--- a/block/rbd.c
110
+++ b/block/rbd.c
111
@@ -XXX,XX +XXX,XX @@ static int qemu_rbd_open(BlockDriverState *bs, QDict *options, int flags,
112
goto failed_shutdown;
113
}
114
115
+ /* rbd_open is always r/w */
116
r = rbd_open(s->io_ctx, s->name, &s->image, s->snap);
117
if (r < 0) {
118
error_setg_errno(errp, -r, "error reading header from %s", s->name);
119
goto failed_open;
120
}
121
122
- bdrv_set_read_only(bs, (s->snap != NULL));
123
+ /* If we are using an rbd snapshot, we must be r/o, otherwise
124
+ * leave as-is */
125
+ if (s->snap != NULL) {
126
+ r = bdrv_set_read_only(bs, true, &local_err);
127
+ if (r < 0) {
128
+ error_propagate(errp, local_err);
129
+ goto failed_open;
130
+ }
131
+ }
132
133
qemu_opts_del(opts);
134
return 0;
135
diff --git a/block/vvfat.c b/block/vvfat.c
136
index XXXXXXX..XXXXXXX 100644
137
--- a/block/vvfat.c
138
+++ b/block/vvfat.c
139
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
140
141
s->current_cluster=0xffffffff;
142
143
- /* read only is the default for safety */
144
- bdrv_set_read_only(bs, true);
145
s->qcow = NULL;
146
s->qcow_filename = NULL;
147
s->fat2 = NULL;
148
@@ -XXX,XX +XXX,XX @@ static int vvfat_open(BlockDriverState *bs, QDict *options, int flags,
149
s->sector_count = cyls * heads * secs - (s->first_sectors_number - 1);
150
151
if (qemu_opt_get_bool(opts, "rw", false)) {
152
- ret = enable_write_target(bs, errp);
153
+ if (!bdrv_is_read_only(bs)) {
154
+ ret = enable_write_target(bs, errp);
155
+ if (ret < 0) {
156
+ goto fail;
157
+ }
158
+ } else {
159
+ ret = -EPERM;
160
+ error_setg(errp,
161
+ "Unable to set VVFAT to 'rw' when drive is read-only");
162
+ goto fail;
163
+ }
164
+ } else {
165
+ /* read only is the default for safety */
166
+ ret = bdrv_set_read_only(bs, true, &local_err);
167
if (ret < 0) {
168
+ error_propagate(errp, local_err);
169
goto fail;
170
}
171
- bdrv_set_read_only(bs, false);
172
}
173
174
bs->total_sectors = cyls * heads * secs;
175
diff --git a/include/block/block.h b/include/block/block.h
176
index XXXXXXX..XXXXXXX 100644
177
--- a/include/block/block.h
178
+++ b/include/block/block.h
179
@@ -XXX,XX +XXX,XX @@ int bdrv_is_allocated_above(BlockDriverState *top, BlockDriverState *base,
180
int64_t sector_num, int nb_sectors, int *pnum);
181
182
bool bdrv_is_read_only(BlockDriverState *bs);
183
-void bdrv_set_read_only(BlockDriverState *bs, bool read_only);
184
+int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp);
185
bool bdrv_is_sg(BlockDriverState *bs);
186
bool bdrv_is_inserted(BlockDriverState *bs);
187
int bdrv_media_changed(BlockDriverState *bs);
188
--
95
--
189
2.9.3
96
2.41.0
190
191
diff view generated by jsdifflib
New patch
1
1
From: zhenwei pi <pizhenwei@bytedance.com>
2
3
'bool is_write' style is obsolete from throttle framework, adapt
4
block throttle groups to the new style:
5
- use ThrottleDirection instead of 'bool is_write'. Ex,
6
schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
7
-> schedule_next_request(ThrottleGroupMember *tgm, ThrottleDirection direction)
8
9
- use THROTTLE_MAX instead of hard code. Ex, ThrottleGroupMember *tokens[2]
10
-> ThrottleGroupMember *tokens[THROTTLE_MAX]
11
12
- use ThrottleDirection instead of hard code on iteration. Ex, (i = 0; i < 2; i++)
13
-> for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++)
14
15
Use a simple python script to test the new style:
16
#!/usr/bin/python3
17
import subprocess
18
import random
19
import time
20
21
commands = ['virsh blkdeviotune jammy vda --write-bytes-sec ', \
22
'virsh blkdeviotune jammy vda --write-iops-sec ', \
23
'virsh blkdeviotune jammy vda --read-bytes-sec ', \
24
'virsh blkdeviotune jammy vda --read-iops-sec ']
25
26
for loop in range(1, 1000):
27
time.sleep(random.randrange(3, 5))
28
command = commands[random.randrange(0, 3)] + str(random.randrange(0, 1000000))
29
subprocess.run(command, shell=True, check=True)
30
31
This works fine.
32
33
Signed-off-by: zhenwei pi <pizhenwei@bytedance.com>
34
Message-Id: <20230728022006.1098509-10-pizhenwei@bytedance.com>
35
Reviewed-by: Hanna Czenczek <hreitz@redhat.com>
36
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
37
---
38
include/block/throttle-groups.h | 6 +-
39
block/block-backend.c | 4 +-
40
block/throttle-groups.c | 161 ++++++++++++++++----------------
41
block/throttle.c | 8 +-
42
4 files changed, 90 insertions(+), 89 deletions(-)
43
44
diff --git a/include/block/throttle-groups.h b/include/block/throttle-groups.h
45
index XXXXXXX..XXXXXXX 100644
46
--- a/include/block/throttle-groups.h
47
+++ b/include/block/throttle-groups.h
48
@@ -XXX,XX +XXX,XX @@ typedef struct ThrottleGroupMember {
49
AioContext *aio_context;
50
/* throttled_reqs_lock protects the CoQueues for throttled requests. */
51
CoMutex throttled_reqs_lock;
52
- CoQueue throttled_reqs[2];
53
+ CoQueue throttled_reqs[THROTTLE_MAX];
54
55
/* Nonzero if the I/O limits are currently being ignored; generally
56
* it is zero. Accessed with atomic operations.
57
@@ -XXX,XX +XXX,XX @@ typedef struct ThrottleGroupMember {
58
* throttle_state tells us if I/O limits are configured. */
59
ThrottleState *throttle_state;
60
ThrottleTimers throttle_timers;
61
- unsigned pending_reqs[2];
62
+ unsigned pending_reqs[THROTTLE_MAX];
63
QLIST_ENTRY(ThrottleGroupMember) round_robin;
64
65
} ThrottleGroupMember;
66
@@ -XXX,XX +XXX,XX @@ void throttle_group_restart_tgm(ThrottleGroupMember *tgm);
67
68
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
69
int64_t bytes,
70
- bool is_write);
71
+ ThrottleDirection direction);
72
void throttle_group_attach_aio_context(ThrottleGroupMember *tgm,
73
AioContext *new_context);
74
void throttle_group_detach_aio_context(ThrottleGroupMember *tgm);
75
diff --git a/block/block-backend.c b/block/block-backend.c
76
index XXXXXXX..XXXXXXX 100644
77
--- a/block/block-backend.c
78
+++ b/block/block-backend.c
79
@@ -XXX,XX +XXX,XX @@ blk_co_do_preadv_part(BlockBackend *blk, int64_t offset, int64_t bytes,
80
/* throttling disk I/O */
81
if (blk->public.throttle_group_member.throttle_state) {
82
throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
83
- bytes, false);
84
+ bytes, THROTTLE_READ);
85
}
86
87
ret = bdrv_co_preadv_part(blk->root, offset, bytes, qiov, qiov_offset,
88
@@ -XXX,XX +XXX,XX @@ blk_co_do_pwritev_part(BlockBackend *blk, int64_t offset, int64_t bytes,
89
/* throttling disk I/O */
90
if (blk->public.throttle_group_member.throttle_state) {
91
throttle_group_co_io_limits_intercept(&blk->public.throttle_group_member,
92
- bytes, true);
93
+ bytes, THROTTLE_WRITE);
94
}
95
96
if (!blk->enable_write_cache) {
97
diff --git a/block/throttle-groups.c b/block/throttle-groups.c
98
index XXXXXXX..XXXXXXX 100644
99
--- a/block/throttle-groups.c
100
+++ b/block/throttle-groups.c
101
@@ -XXX,XX +XXX,XX @@
102
103
static void throttle_group_obj_init(Object *obj);
104
static void throttle_group_obj_complete(UserCreatable *obj, Error **errp);
105
-static void timer_cb(ThrottleGroupMember *tgm, bool is_write);
106
+static void timer_cb(ThrottleGroupMember *tgm, ThrottleDirection direction);
107
108
/* The ThrottleGroup structure (with its ThrottleState) is shared
109
* among different ThrottleGroupMembers and it's independent from
110
@@ -XXX,XX +XXX,XX @@ struct ThrottleGroup {
111
QemuMutex lock; /* This lock protects the following four fields */
112
ThrottleState ts;
113
QLIST_HEAD(, ThrottleGroupMember) head;
114
- ThrottleGroupMember *tokens[2];
115
- bool any_timer_armed[2];
116
+ ThrottleGroupMember *tokens[THROTTLE_MAX];
117
+ bool any_timer_armed[THROTTLE_MAX];
118
QEMUClockType clock_type;
119
120
/* This field is protected by the global QEMU mutex */
121
@@ -XXX,XX +XXX,XX @@ static ThrottleGroupMember *throttle_group_next_tgm(ThrottleGroupMember *tgm)
122
* This assumes that tg->lock is held.
123
*
124
* @tgm: the ThrottleGroupMember
125
- * @is_write: the type of operation (read/write)
126
+ * @direction: the ThrottleDirection
127
* @ret: whether the ThrottleGroupMember has pending requests.
128
*/
129
static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm,
130
- bool is_write)
131
+ ThrottleDirection direction)
132
{
133
- return tgm->pending_reqs[is_write];
134
+ return tgm->pending_reqs[direction];
135
}
136
137
/* Return the next ThrottleGroupMember in the round-robin sequence with pending
138
@@ -XXX,XX +XXX,XX @@ static inline bool tgm_has_pending_reqs(ThrottleGroupMember *tgm,
139
* This assumes that tg->lock is held.
140
*
141
* @tgm: the current ThrottleGroupMember
142
- * @is_write: the type of operation (read/write)
143
+ * @direction: the ThrottleDirection
144
* @ret: the next ThrottleGroupMember with pending requests, or tgm if
145
* there is none.
146
*/
147
static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
148
- bool is_write)
149
+ ThrottleDirection direction)
150
{
151
ThrottleState *ts = tgm->throttle_state;
152
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
153
@@ -XXX,XX +XXX,XX @@ static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
154
* it's being drained. Skip the round-robin search and return tgm
155
* immediately if it has pending requests. Otherwise we could be
156
* forcing it to wait for other member's throttled requests. */
157
- if (tgm_has_pending_reqs(tgm, is_write) &&
158
+ if (tgm_has_pending_reqs(tgm, direction) &&
159
qatomic_read(&tgm->io_limits_disabled)) {
160
return tgm;
161
}
162
163
- start = token = tg->tokens[is_write];
164
+ start = token = tg->tokens[direction];
165
166
/* get next bs round in round robin style */
167
token = throttle_group_next_tgm(token);
168
- while (token != start && !tgm_has_pending_reqs(token, is_write)) {
169
+ while (token != start && !tgm_has_pending_reqs(token, direction)) {
170
token = throttle_group_next_tgm(token);
171
}
172
173
@@ -XXX,XX +XXX,XX @@ static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
174
* then decide the token is the current tgm because chances are
175
* the current tgm got the current request queued.
176
*/
177
- if (token == start && !tgm_has_pending_reqs(token, is_write)) {
178
+ if (token == start && !tgm_has_pending_reqs(token, direction)) {
179
token = tgm;
180
}
181
182
/* Either we return the original TGM, or one with pending requests */
183
- assert(token == tgm || tgm_has_pending_reqs(token, is_write));
184
+ assert(token == tgm || tgm_has_pending_reqs(token, direction));
185
186
return token;
187
}
188
@@ -XXX,XX +XXX,XX @@ static ThrottleGroupMember *next_throttle_token(ThrottleGroupMember *tgm,
189
* This assumes that tg->lock is held.
190
*
191
* @tgm: the current ThrottleGroupMember
192
- * @is_write: the type of operation (read/write)
193
+ * @direction: the ThrottleDirection
194
* @ret: whether the I/O request needs to be throttled or not
195
*/
196
static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
197
- bool is_write)
198
+ ThrottleDirection direction)
199
{
200
ThrottleState *ts = tgm->throttle_state;
201
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
202
ThrottleTimers *tt = &tgm->throttle_timers;
203
- ThrottleDirection direction = is_write ? THROTTLE_WRITE : THROTTLE_READ;
204
bool must_wait;
205
206
if (qatomic_read(&tgm->io_limits_disabled)) {
207
@@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
208
}
209
210
/* Check if any of the timers in this group is already armed */
211
- if (tg->any_timer_armed[is_write]) {
212
+ if (tg->any_timer_armed[direction]) {
213
return true;
214
}
215
216
@@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
217
218
/* If a timer just got armed, set tgm as the current token */
219
if (must_wait) {
220
- tg->tokens[is_write] = tgm;
221
- tg->any_timer_armed[is_write] = true;
222
+ tg->tokens[direction] = tgm;
223
+ tg->any_timer_armed[direction] = true;
224
}
225
226
return must_wait;
227
@@ -XXX,XX +XXX,XX @@ static bool throttle_group_schedule_timer(ThrottleGroupMember *tgm,
228
* any request was actually pending.
229
*
230
* @tgm: the current ThrottleGroupMember
231
- * @is_write: the type of operation (read/write)
232
+ * @direction: the ThrottleDirection
233
*/
234
static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tgm,
235
- bool is_write)
236
+ ThrottleDirection direction)
237
{
238
bool ret;
239
240
qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
241
- ret = qemu_co_queue_next(&tgm->throttled_reqs[is_write]);
242
+ ret = qemu_co_queue_next(&tgm->throttled_reqs[direction]);
243
qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
244
245
return ret;
246
@@ -XXX,XX +XXX,XX @@ static bool coroutine_fn throttle_group_co_restart_queue(ThrottleGroupMember *tg
247
* This assumes that tg->lock is held.
248
*
249
* @tgm: the current ThrottleGroupMember
250
- * @is_write: the type of operation (read/write)
251
+ * @direction: the ThrottleDirection
252
*/
253
-static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
254
+static void schedule_next_request(ThrottleGroupMember *tgm,
255
+ ThrottleDirection direction)
256
{
257
ThrottleState *ts = tgm->throttle_state;
258
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
259
@@ -XXX,XX +XXX,XX @@ static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
260
ThrottleGroupMember *token;
261
262
/* Check if there's any pending request to schedule next */
263
- token = next_throttle_token(tgm, is_write);
264
- if (!tgm_has_pending_reqs(token, is_write)) {
265
+ token = next_throttle_token(tgm, direction);
266
+ if (!tgm_has_pending_reqs(token, direction)) {
267
return;
268
}
269
270
/* Set a timer for the request if it needs to be throttled */
271
- must_wait = throttle_group_schedule_timer(token, is_write);
272
+ must_wait = throttle_group_schedule_timer(token, direction);
273
274
/* If it doesn't have to wait, queue it for immediate execution */
275
if (!must_wait) {
276
/* Give preference to requests from the current tgm */
277
if (qemu_in_coroutine() &&
278
- throttle_group_co_restart_queue(tgm, is_write)) {
279
+ throttle_group_co_restart_queue(tgm, direction)) {
280
token = tgm;
281
} else {
282
ThrottleTimers *tt = &token->throttle_timers;
283
int64_t now = qemu_clock_get_ns(tg->clock_type);
284
- timer_mod(tt->timers[is_write], now);
285
- tg->any_timer_armed[is_write] = true;
286
+ timer_mod(tt->timers[direction], now);
287
+ tg->any_timer_armed[direction] = true;
288
}
289
- tg->tokens[is_write] = token;
290
+ tg->tokens[direction] = token;
291
}
292
}
293
294
@@ -XXX,XX +XXX,XX @@ static void schedule_next_request(ThrottleGroupMember *tgm, bool is_write)
295
*
296
* @tgm: the current ThrottleGroupMember
297
* @bytes: the number of bytes for this I/O
298
- * @is_write: the type of operation (read/write)
299
+ * @direction: the ThrottleDirection
300
*/
301
void coroutine_fn throttle_group_co_io_limits_intercept(ThrottleGroupMember *tgm,
302
int64_t bytes,
303
- bool is_write)
304
+ ThrottleDirection direction)
305
{
306
bool must_wait;
307
ThrottleGroupMember *token;
308
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
309
- ThrottleDirection direction = is_write ? THROTTLE_WRITE : THROTTLE_READ;
310
311
assert(bytes >= 0);
312
+ assert(direction < THROTTLE_MAX);
313
314
qemu_mutex_lock(&tg->lock);
315
316
/* First we check if this I/O has to be throttled. */
317
- token = next_throttle_token(tgm, is_write);
318
- must_wait = throttle_group_schedule_timer(token, is_write);
319
+ token = next_throttle_token(tgm, direction);
320
+ must_wait = throttle_group_schedule_timer(token, direction);
321
322
/* Wait if there's a timer set or queued requests of this type */
323
- if (must_wait || tgm->pending_reqs[is_write]) {
324
- tgm->pending_reqs[is_write]++;
325
+ if (must_wait || tgm->pending_reqs[direction]) {
326
+ tgm->pending_reqs[direction]++;
327
qemu_mutex_unlock(&tg->lock);
328
qemu_co_mutex_lock(&tgm->throttled_reqs_lock);
329
- qemu_co_queue_wait(&tgm->throttled_reqs[is_write],
330
+ qemu_co_queue_wait(&tgm->throttled_reqs[direction],
331
&tgm->throttled_reqs_lock);
332
qemu_co_mutex_unlock(&tgm->throttled_reqs_lock);
333
qemu_mutex_lock(&tg->lock);
334
- tgm->pending_reqs[is_write]--;
335
+ tgm->pending_reqs[direction]--;
336
}
337
338
/* The I/O will be executed, so do the accounting */
339
throttle_account(tgm->throttle_state, direction, bytes);
340
341
/* Schedule the next request */
342
- schedule_next_request(tgm, is_write);
343
+ schedule_next_request(tgm, direction);
344
345
qemu_mutex_unlock(&tg->lock);
346
}
347
348
typedef struct {
349
ThrottleGroupMember *tgm;
350
- bool is_write;
351
+ ThrottleDirection direction;
352
} RestartData;
353
354
static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
355
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
356
ThrottleGroupMember *tgm = data->tgm;
357
ThrottleState *ts = tgm->throttle_state;
358
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
359
- bool is_write = data->is_write;
360
+ ThrottleDirection direction = data->direction;
361
bool empty_queue;
362
363
- empty_queue = !throttle_group_co_restart_queue(tgm, is_write);
364
+ empty_queue = !throttle_group_co_restart_queue(tgm, direction);
365
366
/* If the request queue was empty then we have to take care of
367
* scheduling the next one */
368
if (empty_queue) {
369
qemu_mutex_lock(&tg->lock);
370
- schedule_next_request(tgm, is_write);
371
+ schedule_next_request(tgm, direction);
372
qemu_mutex_unlock(&tg->lock);
373
}
374
375
@@ -XXX,XX +XXX,XX @@ static void coroutine_fn throttle_group_restart_queue_entry(void *opaque)
376
aio_wait_kick();
377
}
378
379
-static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write)
380
+static void throttle_group_restart_queue(ThrottleGroupMember *tgm,
381
+ ThrottleDirection direction)
382
{
383
Coroutine *co;
384
RestartData *rd = g_new0(RestartData, 1);
385
386
rd->tgm = tgm;
387
- rd->is_write = is_write;
388
+ rd->direction = direction;
389
390
/* This function is called when a timer is fired or when
391
* throttle_group_restart_tgm() is called. Either way, there can
392
* be no timer pending on this tgm at this point */
393
- assert(!timer_pending(tgm->throttle_timers.timers[is_write]));
394
+ assert(!timer_pending(tgm->throttle_timers.timers[direction]));
395
396
qatomic_inc(&tgm->restart_pending);
397
398
@@ -XXX,XX +XXX,XX @@ static void throttle_group_restart_queue(ThrottleGroupMember *tgm, bool is_write
399
400
void throttle_group_restart_tgm(ThrottleGroupMember *tgm)
401
{
402
- int i;
403
+ ThrottleDirection dir;
404
405
if (tgm->throttle_state) {
406
- for (i = 0; i < 2; i++) {
407
- QEMUTimer *t = tgm->throttle_timers.timers[i];
408
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
409
+ QEMUTimer *t = tgm->throttle_timers.timers[dir];
410
if (timer_pending(t)) {
411
/* If there's a pending timer on this tgm, fire it now */
412
timer_del(t);
413
- timer_cb(tgm, i);
414
+ timer_cb(tgm, dir);
415
} else {
416
/* Else run the next request from the queue manually */
417
- throttle_group_restart_queue(tgm, i);
418
+ throttle_group_restart_queue(tgm, dir);
419
}
420
}
421
}
422
@@ -XXX,XX +XXX,XX @@ void throttle_group_get_config(ThrottleGroupMember *tgm, ThrottleConfig *cfg)
423
* because it had been throttled.
424
*
425
* @tgm: the ThrottleGroupMember whose request had been throttled
426
- * @is_write: the type of operation (read/write)
427
+ * @direction: the ThrottleDirection
428
*/
429
-static void timer_cb(ThrottleGroupMember *tgm, bool is_write)
430
+static void timer_cb(ThrottleGroupMember *tgm, ThrottleDirection direction)
431
{
432
ThrottleState *ts = tgm->throttle_state;
433
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
434
435
/* The timer has just been fired, so we can update the flag */
436
qemu_mutex_lock(&tg->lock);
437
- tg->any_timer_armed[is_write] = false;
438
+ tg->any_timer_armed[direction] = false;
439
qemu_mutex_unlock(&tg->lock);
440
441
/* Run the request that was waiting for this timer */
442
- throttle_group_restart_queue(tgm, is_write);
443
+ throttle_group_restart_queue(tgm, direction);
444
}
445
446
static void read_timer_cb(void *opaque)
447
{
448
- timer_cb(opaque, false);
449
+ timer_cb(opaque, THROTTLE_READ);
450
}
451
452
static void write_timer_cb(void *opaque)
453
{
454
- timer_cb(opaque, true);
455
+ timer_cb(opaque, THROTTLE_WRITE);
456
}
457
458
/* Register a ThrottleGroupMember from the throttling group, also initializing
459
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
460
const char *groupname,
461
AioContext *ctx)
462
{
463
- int i;
464
+ ThrottleDirection dir;
465
ThrottleState *ts = throttle_group_incref(groupname);
466
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
467
468
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
469
470
QEMU_LOCK_GUARD(&tg->lock);
471
/* If the ThrottleGroup is new set this ThrottleGroupMember as the token */
472
- for (i = 0; i < 2; i++) {
473
- if (!tg->tokens[i]) {
474
- tg->tokens[i] = tgm;
475
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
476
+ if (!tg->tokens[dir]) {
477
+ tg->tokens[dir] = tgm;
478
}
479
+ qemu_co_queue_init(&tgm->throttled_reqs[dir]);
480
}
481
482
QLIST_INSERT_HEAD(&tg->head, tgm, round_robin);
483
@@ -XXX,XX +XXX,XX @@ void throttle_group_register_tgm(ThrottleGroupMember *tgm,
484
write_timer_cb,
485
tgm);
486
qemu_co_mutex_init(&tgm->throttled_reqs_lock);
487
- qemu_co_queue_init(&tgm->throttled_reqs[0]);
488
- qemu_co_queue_init(&tgm->throttled_reqs[1]);
489
}
490
491
/* Unregister a ThrottleGroupMember from its group, removing it from the list,
492
@@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
493
ThrottleState *ts = tgm->throttle_state;
494
ThrottleGroup *tg = container_of(ts, ThrottleGroup, ts);
495
ThrottleGroupMember *token;
496
- int i;
497
+ ThrottleDirection dir;
498
499
if (!ts) {
500
/* Discard already unregistered tgm */
501
@@ -XXX,XX +XXX,XX @@ void throttle_group_unregister_tgm(ThrottleGroupMember *tgm)
502
AIO_WAIT_WHILE(tgm->aio_context, qatomic_read(&tgm->restart_pending) > 0);
503
504
WITH_QEMU_LOCK_GUARD(&tg->lock) {
505
- for (i = 0; i < 2; i++) {
506
- assert(tgm->pending_reqs[i] == 0);
507
- assert(qemu_co_queue_empty(&tgm->throttled_reqs[i]));
508
- assert(!timer_pending(tgm->throttle_timers.timers[i]));
509
- if (tg->tokens[i] == tgm) {
510
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
511
+ assert(tgm->pending_reqs[dir] == 0);
512
+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[dir]));
513
+ assert(!timer_pending(tgm->throttle_timers.timers[dir]));
514
+ if (tg->tokens[dir] == tgm) {
515
token = throttle_group_next_tgm(tgm);
516
/* Take care of the case where this is the last tgm in the group */
517
if (token == tgm) {
518
token = NULL;
519
}
520
- tg->tokens[i] = token;
521
+ tg->tokens[dir] = token;
522
}
523
}
524
525
@@ -XXX,XX +XXX,XX @@ void throttle_group_detach_aio_context(ThrottleGroupMember *tgm)
526
{
527
ThrottleGroup *tg = container_of(tgm->throttle_state, ThrottleGroup, ts);
528
ThrottleTimers *tt = &tgm->throttle_timers;
529
- int i;
530
+ ThrottleDirection dir;
531
532
/* Requests must have been drained */
533
- assert(tgm->pending_reqs[0] == 0 && tgm->pending_reqs[1] == 0);
534
- assert(qemu_co_queue_empty(&tgm->throttled_reqs[0]));
535
- assert(qemu_co_queue_empty(&tgm->throttled_reqs[1]));
536
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
537
+ assert(tgm->pending_reqs[dir] == 0);
538
+ assert(qemu_co_queue_empty(&tgm->throttled_reqs[dir]));
539
+ }
540
541
/* Kick off next ThrottleGroupMember, if necessary */
542
WITH_QEMU_LOCK_GUARD(&tg->lock) {
543
- for (i = 0; i < 2; i++) {
544
- if (timer_pending(tt->timers[i])) {
545
- tg->any_timer_armed[i] = false;
546
- schedule_next_request(tgm, i);
547
+ for (dir = THROTTLE_READ; dir < THROTTLE_MAX; dir++) {
548
+ if (timer_pending(tt->timers[dir])) {
549
+ tg->any_timer_armed[dir] = false;
550
+ schedule_next_request(tgm, dir);
551
}
552
}
553
}
554
diff --git a/block/throttle.c b/block/throttle.c
555
index XXXXXXX..XXXXXXX 100644
556
--- a/block/throttle.c
557
+++ b/block/throttle.c
558
@@ -XXX,XX +XXX,XX @@ throttle_co_preadv(BlockDriverState *bs, int64_t offset, int64_t bytes,
559
{
560
561
ThrottleGroupMember *tgm = bs->opaque;
562
- throttle_group_co_io_limits_intercept(tgm, bytes, false);
563
+ throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_READ);
564
565
return bdrv_co_preadv(bs->file, offset, bytes, qiov, flags);
566
}
567
@@ -XXX,XX +XXX,XX @@ throttle_co_pwritev(BlockDriverState *bs, int64_t offset, int64_t bytes,
568
QEMUIOVector *qiov, BdrvRequestFlags flags)
569
{
570
ThrottleGroupMember *tgm = bs->opaque;
571
- throttle_group_co_io_limits_intercept(tgm, bytes, true);
572
+ throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
573
574
return bdrv_co_pwritev(bs->file, offset, bytes, qiov, flags);
575
}
576
@@ -XXX,XX +XXX,XX @@ throttle_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset, int64_t bytes,
577
BdrvRequestFlags flags)
578
{
579
ThrottleGroupMember *tgm = bs->opaque;
580
- throttle_group_co_io_limits_intercept(tgm, bytes, true);
581
+ throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
582
583
return bdrv_co_pwrite_zeroes(bs->file, offset, bytes, flags);
584
}
585
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn GRAPH_RDLOCK
586
throttle_co_pdiscard(BlockDriverState *bs, int64_t offset, int64_t bytes)
587
{
588
ThrottleGroupMember *tgm = bs->opaque;
589
- throttle_group_co_io_limits_intercept(tgm, bytes, true);
590
+ throttle_group_co_io_limits_intercept(tgm, bytes, THROTTLE_WRITE);
591
592
return bdrv_co_pdiscard(bs->file, offset, bytes);
593
}
594
--
595
2.41.0
diff view generated by jsdifflib
1
For the tests that use the common.qemu functions for running a QEMU
1
bs->bl.zoned is what indicates whether the zone information is present
2
process, _cleanup_qemu must be called in the exit function.
2
and valid; it is the only thing that raw_refresh_zoned_limits() sets if
3
CONFIG_BLKZONED is not defined, and it is also the only thing that it
4
sets if CONFIG_BLKZONED is defined, but there are no zones.
3
5
4
If it is not, if the qemu process aborts, then not all of the droppings
6
Make sure that it is always set to BLK_Z_NONE if there is an error
5
are cleaned up (e.g. pidfile, fifos).
7
anywhere in raw_refresh_zoned_limits() so that we do not accidentally
8
announce zones while our information is incomplete or invalid.
6
9
7
This updates those tests that did not have a cleanup in qemu-iotests.
10
This also fixes a memory leak in the last error path in
11
raw_refresh_zoned_limits().
8
12
9
(I swapped spaces for tabs in test 102 as well)
13
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
14
Message-Id: <20230824155345.109765-2-hreitz@redhat.com>
15
Reviewed-by: Sam Li <faithilikerun@gmail.com>
16
---
17
block/file-posix.c | 21 ++++++++++++---------
18
1 file changed, 12 insertions(+), 9 deletions(-)
10
19
11
Reported-by: Eric Blake <eblake@redhat.com>
20
diff --git a/block/file-posix.c b/block/file-posix.c
12
Reviewed-by: Eric Blake <eblake@redhat.com>
21
index XXXXXXX..XXXXXXX 100644
13
Signed-off-by: Jeff Cody <jcody@redhat.com>
22
--- a/block/file-posix.c
14
Message-id: d59c2f6ad6c1da8b9b3c7f357c94a7122ccfc55a.1492544096.git.jcody@redhat.com
23
+++ b/block/file-posix.c
15
---
24
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
16
tests/qemu-iotests/028 | 1 +
25
BlockZoneModel zoned;
17
tests/qemu-iotests/094 | 11 ++++++++---
26
int ret;
18
tests/qemu-iotests/102 | 5 +++--
27
19
tests/qemu-iotests/109 | 1 +
28
- bs->bl.zoned = BLK_Z_NONE;
20
tests/qemu-iotests/117 | 1 +
29
-
21
tests/qemu-iotests/130 | 1 +
30
ret = get_sysfs_zoned_model(st, &zoned);
22
tests/qemu-iotests/140 | 1 +
31
if (ret < 0 || zoned == BLK_Z_NONE) {
23
tests/qemu-iotests/141 | 1 +
32
- return;
24
tests/qemu-iotests/143 | 1 +
33
+ goto no_zoned;
25
tests/qemu-iotests/156 | 1 +
34
}
26
10 files changed, 19 insertions(+), 5 deletions(-)
35
bs->bl.zoned = zoned;
27
36
28
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
37
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
29
index XXXXXXX..XXXXXXX 100755
38
if (ret < 0) {
30
--- a/tests/qemu-iotests/028
39
error_setg_errno(errp, -ret, "Unable to read chunk_sectors "
31
+++ b/tests/qemu-iotests/028
40
"sysfs attribute");
32
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
41
- return;
33
42
+ goto no_zoned;
34
_cleanup()
43
} else if (!ret) {
35
{
44
error_setg(errp, "Read 0 from chunk_sectors sysfs attribute");
36
+ _cleanup_qemu
45
- return;
37
rm -f "${TEST_IMG}.copy"
46
+ goto no_zoned;
38
_cleanup_test_img
47
}
48
bs->bl.zone_size = ret << BDRV_SECTOR_BITS;
49
50
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
51
if (ret < 0) {
52
error_setg_errno(errp, -ret, "Unable to read nr_zones "
53
"sysfs attribute");
54
- return;
55
+ goto no_zoned;
56
} else if (!ret) {
57
error_setg(errp, "Read 0 from nr_zones sysfs attribute");
58
- return;
59
+ goto no_zoned;
60
}
61
bs->bl.nr_zones = ret;
62
63
@@ -XXX,XX +XXX,XX @@ static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
64
ret = get_zones_wp(bs, s->fd, 0, bs->bl.nr_zones, 0);
65
if (ret < 0) {
66
error_setg_errno(errp, -ret, "report wps failed");
67
- bs->wps = NULL;
68
- return;
69
+ goto no_zoned;
70
}
71
qemu_co_mutex_init(&bs->wps->colock);
72
+ return;
73
+
74
+no_zoned:
75
+ bs->bl.zoned = BLK_Z_NONE;
76
+ g_free(bs->wps);
77
+ bs->wps = NULL;
39
}
78
}
40
diff --git a/tests/qemu-iotests/094 b/tests/qemu-iotests/094
79
#else /* !defined(CONFIG_BLKZONED) */
41
index XXXXXXX..XXXXXXX 100755
80
static void raw_refresh_zoned_limits(BlockDriverState *bs, struct stat *st,
42
--- a/tests/qemu-iotests/094
43
+++ b/tests/qemu-iotests/094
44
@@ -XXX,XX +XXX,XX @@ echo "QA output created by $seq"
45
here="$PWD"
46
status=1    # failure is the default!
47
48
-trap "exit \$status" 0 1 2 3 15
49
+_cleanup()
50
+{
51
+ _cleanup_qemu
52
+ _cleanup_test_img
53
+ rm -f "$TEST_DIR/source.$IMGFMT"
54
+}
55
+
56
+trap "_cleanup; exit \$status" 0 1 2 3 15
57
58
# get standard environment, filters and checks
59
. ./common.rc
60
@@ -XXX,XX +XXX,XX @@ _send_qemu_cmd $QEMU_HANDLE \
61
62
wait=1 _cleanup_qemu
63
64
-_cleanup_test_img
65
-rm -f "$TEST_DIR/source.$IMGFMT"
66
67
# success, all done
68
echo '*** done'
69
diff --git a/tests/qemu-iotests/102 b/tests/qemu-iotests/102
70
index XXXXXXX..XXXXXXX 100755
71
--- a/tests/qemu-iotests/102
72
+++ b/tests/qemu-iotests/102
73
@@ -XXX,XX +XXX,XX @@ seq=$(basename $0)
74
echo "QA output created by $seq"
75
76
here=$PWD
77
-status=1    # failure is the default!
78
+status=1 # failure is the default!
79
80
_cleanup()
81
{
82
-    _cleanup_test_img
83
+ _cleanup_qemu
84
+ _cleanup_test_img
85
}
86
trap "_cleanup; exit \$status" 0 1 2 3 15
87
88
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
89
index XXXXXXX..XXXXXXX 100755
90
--- a/tests/qemu-iotests/109
91
+++ b/tests/qemu-iotests/109
92
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
93
94
_cleanup()
95
{
96
+ _cleanup_qemu
97
rm -f $TEST_IMG.src
98
    _cleanup_test_img
99
}
100
diff --git a/tests/qemu-iotests/117 b/tests/qemu-iotests/117
101
index XXXXXXX..XXXXXXX 100755
102
--- a/tests/qemu-iotests/117
103
+++ b/tests/qemu-iotests/117
104
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
105
106
_cleanup()
107
{
108
+ _cleanup_qemu
109
    _cleanup_test_img
110
}
111
trap "_cleanup; exit \$status" 0 1 2 3 15
112
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
113
index XXXXXXX..XXXXXXX 100755
114
--- a/tests/qemu-iotests/130
115
+++ b/tests/qemu-iotests/130
116
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
117
118
_cleanup()
119
{
120
+ _cleanup_qemu
121
_cleanup_test_img
122
}
123
trap "_cleanup; exit \$status" 0 1 2 3 15
124
diff --git a/tests/qemu-iotests/140 b/tests/qemu-iotests/140
125
index XXXXXXX..XXXXXXX 100755
126
--- a/tests/qemu-iotests/140
127
+++ b/tests/qemu-iotests/140
128
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
129
130
_cleanup()
131
{
132
+ _cleanup_qemu
133
_cleanup_test_img
134
rm -f "$TEST_DIR/nbd"
135
}
136
diff --git a/tests/qemu-iotests/141 b/tests/qemu-iotests/141
137
index XXXXXXX..XXXXXXX 100755
138
--- a/tests/qemu-iotests/141
139
+++ b/tests/qemu-iotests/141
140
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
141
142
_cleanup()
143
{
144
+ _cleanup_qemu
145
_cleanup_test_img
146
rm -f "$TEST_DIR/{b,m,o}.$IMGFMT"
147
}
148
diff --git a/tests/qemu-iotests/143 b/tests/qemu-iotests/143
149
index XXXXXXX..XXXXXXX 100755
150
--- a/tests/qemu-iotests/143
151
+++ b/tests/qemu-iotests/143
152
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
153
154
_cleanup()
155
{
156
+ _cleanup_qemu
157
rm -f "$TEST_DIR/nbd"
158
}
159
trap "_cleanup; exit \$status" 0 1 2 3 15
160
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
161
index XXXXXXX..XXXXXXX 100755
162
--- a/tests/qemu-iotests/156
163
+++ b/tests/qemu-iotests/156
164
@@ -XXX,XX +XXX,XX @@ status=1    # failure is the default!
165
166
_cleanup()
167
{
168
+ _cleanup_qemu
169
rm -f "$TEST_IMG{,.target}{,.backing,.overlay}"
170
}
171
trap "_cleanup; exit \$status" 0 1 2 3 15
172
--
81
--
173
2.9.3
82
2.41.0
174
175
diff view generated by jsdifflib
1
The BDRV_O_ALLOW_RDWR flag allows / prohibits the changing of
1
Instead of checking bs->wps or bs->bl.zone_size for whether zone
2
the BDS 'read_only' state, but there are a few places where it
2
information is present, check bs->bl.zoned. That is the flag that
3
is ignored. In the bdrv_set_read_only() helper, make sure to
3
raw_refresh_zoned_limits() reliably sets to indicate zone support. If
4
honor the flag.
4
it is set to something other than BLK_Z_NONE, other values and objects
5
like bs->wps and bs->bl.zone_size must be non-null/zero and valid; if it
6
is not, we cannot rely on their validity.
5
7
6
Signed-off-by: Jeff Cody <jcody@redhat.com>
8
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Message-Id: <20230824155345.109765-3-hreitz@redhat.com>
8
Reviewed-by: John Snow <jsnow@redhat.com>
10
Reviewed-by: Sam Li <faithilikerun@gmail.com>
9
Message-id: be2e5fb2d285cbece2b6d06bed54a6f56520d251.1491597120.git.jcody@redhat.com
10
---
11
---
11
block.c | 7 +++++++
12
block/file-posix.c | 12 +++++++-----
12
1 file changed, 7 insertions(+)
13
1 file changed, 7 insertions(+), 5 deletions(-)
13
14
14
diff --git a/block.c b/block.c
15
diff --git a/block/file-posix.c b/block/file-posix.c
15
index XXXXXXX..XXXXXXX 100644
16
index XXXXXXX..XXXXXXX 100644
16
--- a/block.c
17
--- a/block/file-posix.c
17
+++ b/block.c
18
+++ b/block/file-posix.c
18
@@ -XXX,XX +XXX,XX @@ int bdrv_set_read_only(BlockDriverState *bs, bool read_only, Error **errp)
19
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
19
return -EINVAL;
20
if (fd_open(bs) < 0)
21
return -EIO;
22
#if defined(CONFIG_BLKZONED)
23
- if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) && bs->wps) {
24
+ if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
25
+ bs->bl.zoned != BLK_Z_NONE) {
26
qemu_co_mutex_lock(&bs->wps->colock);
27
- if (type & QEMU_AIO_ZONE_APPEND && bs->bl.zone_size) {
28
+ if (type & QEMU_AIO_ZONE_APPEND) {
29
int index = offset / bs->bl.zone_size;
30
offset = bs->wps->wp[index];
31
}
32
@@ -XXX,XX +XXX,XX @@ out:
33
{
34
BlockZoneWps *wps = bs->wps;
35
if (ret == 0) {
36
- if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND))
37
- && wps && bs->bl.zone_size) {
38
+ if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
39
+ bs->bl.zoned != BLK_Z_NONE) {
40
uint64_t *wp = &wps->wp[offset / bs->bl.zone_size];
41
if (!BDRV_ZT_IS_CONV(*wp)) {
42
if (type & QEMU_AIO_ZONE_APPEND) {
43
@@ -XXX,XX +XXX,XX @@ out:
44
}
20
}
45
}
21
46
22
+ /* Do not clear read_only if it is prohibited */
47
- if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) && wps) {
23
+ if (!read_only && !(bs->open_flags & BDRV_O_ALLOW_RDWR)) {
48
+ if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
24
+ error_setg(errp, "Node '%s' is read only",
49
+ bs->blk.zoned != BLK_Z_NONE) {
25
+ bdrv_get_device_or_node_name(bs));
50
qemu_co_mutex_unlock(&wps->colock);
26
+ return -EPERM;
51
}
27
+ }
28
+
29
bs->read_only = read_only;
30
return 0;
31
}
52
}
32
--
53
--
33
2.9.3
54
2.41.0
34
35
diff view generated by jsdifflib
1
The protocol VXHS does not support image creation. Some tests expect
1
We must check that zone information is present before running
2
to be able to create images through the protocol. Exclude VXHS from
2
update_zones_wp().
3
these tests.
4
3
5
Signed-off-by: Jeff Cody <jcody@redhat.com>
4
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2234374
5
Fixes: Coverity CID 1512459
6
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
7
Message-Id: <20230824155345.109765-4-hreitz@redhat.com>
8
Reviewed-by: Sam Li <faithilikerun@gmail.com>
6
---
9
---
7
tests/qemu-iotests/017 | 1 +
10
block/file-posix.c | 3 ++-
8
tests/qemu-iotests/020 | 1 +
11
1 file changed, 2 insertions(+), 1 deletion(-)
9
tests/qemu-iotests/029 | 1 +
10
tests/qemu-iotests/073 | 1 +
11
tests/qemu-iotests/114 | 1 +
12
tests/qemu-iotests/130 | 1 +
13
tests/qemu-iotests/134 | 1 +
14
tests/qemu-iotests/156 | 1 +
15
tests/qemu-iotests/158 | 1 +
16
9 files changed, 9 insertions(+)
17
12
18
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
13
diff --git a/block/file-posix.c b/block/file-posix.c
19
index XXXXXXX..XXXXXXX 100755
14
index XXXXXXX..XXXXXXX 100644
20
--- a/tests/qemu-iotests/017
15
--- a/block/file-posix.c
21
+++ b/tests/qemu-iotests/017
16
+++ b/block/file-posix.c
22
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
17
@@ -XXX,XX +XXX,XX @@ out:
23
# Any format supporting backing files
18
}
24
_supported_fmt qcow qcow2 vmdk qed
19
}
25
_supported_proto generic
20
} else {
26
+_unsupported_proto vxhs
21
- if (type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) {
27
_supported_os Linux
22
+ if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
28
_unsupported_imgopts "subformat=monolithicFlat" "subformat=twoGbMaxExtentFlat"
23
+ bs->bl.zoned != BLK_Z_NONE) {
29
24
update_zones_wp(bs, s->fd, 0, 1);
30
diff --git a/tests/qemu-iotests/020 b/tests/qemu-iotests/020
25
}
31
index XXXXXXX..XXXXXXX 100755
26
}
32
--- a/tests/qemu-iotests/020
33
+++ b/tests/qemu-iotests/020
34
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
35
# Any format supporting backing files
36
_supported_fmt qcow qcow2 vmdk qed
37
_supported_proto generic
38
+_unsupported_proto vxhs
39
_supported_os Linux
40
_unsupported_imgopts "subformat=monolithicFlat" \
41
"subformat=twoGbMaxExtentFlat" \
42
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
43
index XXXXXXX..XXXXXXX 100755
44
--- a/tests/qemu-iotests/029
45
+++ b/tests/qemu-iotests/029
46
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
47
# Any format supporting intenal snapshots
48
_supported_fmt qcow2
49
_supported_proto generic
50
+_unsupported_proto vxhs
51
_supported_os Linux
52
# Internal snapshots are (currently) impossible with refcount_bits=1
53
_unsupported_imgopts 'refcount_bits=1[^0-9]'
54
diff --git a/tests/qemu-iotests/073 b/tests/qemu-iotests/073
55
index XXXXXXX..XXXXXXX 100755
56
--- a/tests/qemu-iotests/073
57
+++ b/tests/qemu-iotests/073
58
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
59
60
_supported_fmt qcow2
61
_supported_proto generic
62
+_unsupported_proto vxhs
63
_supported_os Linux
64
65
CLUSTER_SIZE=64k
66
diff --git a/tests/qemu-iotests/114 b/tests/qemu-iotests/114
67
index XXXXXXX..XXXXXXX 100755
68
--- a/tests/qemu-iotests/114
69
+++ b/tests/qemu-iotests/114
70
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
71
72
_supported_fmt qcow2
73
_supported_proto generic
74
+_unsupported_proto vxhs
75
_supported_os Linux
76
77
78
diff --git a/tests/qemu-iotests/130 b/tests/qemu-iotests/130
79
index XXXXXXX..XXXXXXX 100755
80
--- a/tests/qemu-iotests/130
81
+++ b/tests/qemu-iotests/130
82
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
83
84
_supported_fmt qcow2
85
_supported_proto generic
86
+_unsupported_proto vxhs
87
_supported_os Linux
88
89
qemu_comm_method="monitor"
90
diff --git a/tests/qemu-iotests/134 b/tests/qemu-iotests/134
91
index XXXXXXX..XXXXXXX 100755
92
--- a/tests/qemu-iotests/134
93
+++ b/tests/qemu-iotests/134
94
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
95
96
_supported_fmt qcow2
97
_supported_proto generic
98
+_unsupported_proto vxhs
99
_supported_os Linux
100
101
102
diff --git a/tests/qemu-iotests/156 b/tests/qemu-iotests/156
103
index XXXXXXX..XXXXXXX 100755
104
--- a/tests/qemu-iotests/156
105
+++ b/tests/qemu-iotests/156
106
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
107
108
_supported_fmt qcow2 qed
109
_supported_proto generic
110
+_unsupported_proto vxhs
111
_supported_os Linux
112
113
# Create source disk
114
diff --git a/tests/qemu-iotests/158 b/tests/qemu-iotests/158
115
index XXXXXXX..XXXXXXX 100755
116
--- a/tests/qemu-iotests/158
117
+++ b/tests/qemu-iotests/158
118
@@ -XXX,XX +XXX,XX @@ trap "_cleanup; exit \$status" 0 1 2 3 15
119
120
_supported_fmt qcow2
121
_supported_proto generic
122
+_unsupported_proto vxhs
123
_supported_os Linux
124
125
126
--
27
--
127
2.9.3
28
2.41.0
128
129
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
We duplicate the same condition three times here, pull it out to the top
2
level.
2
3
3
These changes use a vxhs test server that is a part of the following
4
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
4
repository:
5
Message-Id: <20230824155345.109765-5-hreitz@redhat.com>
5
https://github.com/VeritasHyperScale/libqnio.git
6
Reviewed-by: Sam Li <faithilikerun@gmail.com>
7
---
8
block/file-posix.c | 18 +++++-------------
9
1 file changed, 5 insertions(+), 13 deletions(-)
6
10
7
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
11
diff --git a/block/file-posix.c b/block/file-posix.c
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
9
Reviewed-by: Jeff Cody <jcody@redhat.com>
10
Signed-off-by: Jeff Cody <jcody@redhat.com>
11
Message-id: 1491277689-24949-3-git-send-email-Ashish.Mittal@veritas.com
12
---
13
tests/qemu-iotests/common | 6 ++++++
14
tests/qemu-iotests/common.config | 13 +++++++++++++
15
tests/qemu-iotests/common.filter | 1 +
16
tests/qemu-iotests/common.rc | 19 +++++++++++++++++++
17
4 files changed, 39 insertions(+)
18
19
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
20
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/qemu-iotests/common
13
--- a/block/file-posix.c
22
+++ b/tests/qemu-iotests/common
14
+++ b/block/file-posix.c
23
@@ -XXX,XX +XXX,XX @@ check options
15
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn raw_co_prw(BlockDriverState *bs, uint64_t offset,
24
-ssh test ssh
16
25
-nfs test nfs
17
out:
26
-luks test luks
18
#if defined(CONFIG_BLKZONED)
27
+ -vxhs test vxhs
19
-{
28
-xdiff graphical mode diff
20
- BlockZoneWps *wps = bs->wps;
29
-nocache use O_DIRECT on backing file
21
- if (ret == 0) {
30
-misalign misalign memory allocations
22
- if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
31
@@ -XXX,XX +XXX,XX @@ testlist options
23
- bs->bl.zoned != BLK_Z_NONE) {
32
xpand=false
24
+ if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
33
;;
25
+ bs->bl.zoned != BLK_Z_NONE) {
34
26
+ BlockZoneWps *wps = bs->wps;
35
+ -vxhs)
27
+ if (ret == 0) {
36
+ IMGPROTO=vxhs
28
uint64_t *wp = &wps->wp[offset / bs->bl.zone_size];
37
+ xpand=false
29
if (!BDRV_ZT_IS_CONV(*wp)) {
38
+ ;;
30
if (type & QEMU_AIO_ZONE_APPEND) {
39
+
31
@@ -XXX,XX +XXX,XX @@ out:
40
-ssh)
32
*wp = offset + bytes;
41
IMGPROTO=ssh
33
}
42
xpand=false
34
}
43
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
35
- }
44
index XXXXXXX..XXXXXXX 100644
36
- } else {
45
--- a/tests/qemu-iotests/common.config
37
- if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
46
+++ b/tests/qemu-iotests/common.config
38
- bs->bl.zoned != BLK_Z_NONE) {
47
@@ -XXX,XX +XXX,XX @@ if [ -z "$QEMU_NBD_PROG" ]; then
39
+ } else {
48
export QEMU_NBD_PROG="`set_prog_path qemu-nbd`"
40
update_zones_wp(bs, s->fd, 0, 1);
49
fi
41
}
50
42
- }
51
+if [ -z "$QEMU_VXHS_PROG" ]; then
43
52
+ export QEMU_VXHS_PROG="`set_prog_path qnio_server`"
44
- if ((type & (QEMU_AIO_WRITE | QEMU_AIO_ZONE_APPEND)) &&
53
+fi
45
- bs->blk.zoned != BLK_Z_NONE) {
54
+
46
qemu_co_mutex_unlock(&wps->colock);
55
_qemu_wrapper()
47
}
56
{
48
-}
57
(
49
#endif
58
@@ -XXX,XX +XXX,XX @@ _qemu_nbd_wrapper()
50
return ret;
59
)
60
}
51
}
61
62
+_qemu_vxhs_wrapper()
63
+{
64
+ (
65
+ echo $BASHPID > "${TEST_DIR}/qemu-vxhs.pid"
66
+ exec "$QEMU_VXHS_PROG" $QEMU_VXHS_OPTIONS "$@"
67
+ )
68
+}
69
+
70
export QEMU=_qemu_wrapper
71
export QEMU_IMG=_qemu_img_wrapper
72
export QEMU_IO=_qemu_io_wrapper
73
export QEMU_NBD=_qemu_nbd_wrapper
74
+export QEMU_VXHS=_qemu_vxhs_wrapper
75
76
QEMU_IMG_EXTRA_ARGS=
77
if [ "$IMGOPTSSYNTAX" = "true" ]; then
78
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
79
index XXXXXXX..XXXXXXX 100644
80
--- a/tests/qemu-iotests/common.filter
81
+++ b/tests/qemu-iotests/common.filter
82
@@ -XXX,XX +XXX,XX @@ _filter_img_info()
83
-e "s#$TEST_DIR#TEST_DIR#g" \
84
-e "s#$IMGFMT#IMGFMT#g" \
85
-e 's#nbd://127.0.0.1:10810$#TEST_DIR/t.IMGFMT#g' \
86
+ -e 's#json.*vdisk-id.*vxhs"}}#TEST_DIR/t.IMGFMT#' \
87
-e "/encrypted: yes/d" \
88
-e "/cluster_size: [0-9]\\+/d" \
89
-e "/table_size: [0-9]\\+/d" \
90
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
91
index XXXXXXX..XXXXXXX 100644
92
--- a/tests/qemu-iotests/common.rc
93
+++ b/tests/qemu-iotests/common.rc
94
@@ -XXX,XX +XXX,XX @@ else
95
elif [ "$IMGPROTO" = "nfs" ]; then
96
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
97
TEST_IMG=$TEST_DIR/t.$IMGFMT
98
+ elif [ "$IMGPROTO" = "vxhs" ]; then
99
+ TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
100
+ TEST_IMG="vxhs://127.0.0.1:9999/t.$IMGFMT"
101
else
102
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
103
fi
104
@@ -XXX,XX +XXX,XX @@ _make_test_img()
105
eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
106
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
107
fi
108
+
109
+ # Start QNIO server on image directory for vxhs protocol
110
+ if [ $IMGPROTO = "vxhs" ]; then
111
+ eval "$QEMU_VXHS -d $TEST_DIR > /dev/null &"
112
+ sleep 1 # Wait for server to come up.
113
+ fi
114
}
115
116
_rm_test_img()
117
@@ -XXX,XX +XXX,XX @@ _cleanup_test_img()
118
fi
119
rm -f "$TEST_IMG_FILE"
120
;;
121
+ vxhs)
122
+ if [ -f "${TEST_DIR}/qemu-vxhs.pid" ]; then
123
+ local QEMU_VXHS_PID
124
+ read QEMU_VXHS_PID < "${TEST_DIR}/qemu-vxhs.pid"
125
+ kill ${QEMU_VXHS_PID} >/dev/null 2>&1
126
+ rm -f "${TEST_DIR}/qemu-vxhs.pid"
127
+ fi
128
+ rm -f "$TEST_IMG_FILE"
129
+ ;;
130
+
131
file)
132
_rm_test_img "$TEST_DIR/t.$IMGFMT"
133
_rm_test_img "$TEST_DIR/t.$IMGFMT.orig"
134
--
52
--
135
2.9.3
53
2.41.0
136
137
diff view generated by jsdifflib
1
From: Ashish Mittal <ashmit602@gmail.com>
1
This is a regression test for
2
https://bugzilla.redhat.com/show_bug.cgi?id=2234374.
2
3
3
Source code for the qnio library that this code loads can be downloaded from:
4
All this test needs to do is trigger an I/O error inside of file-posix
4
https://github.com/VeritasHyperScale/libqnio.git
5
(specifically raw_co_prw()). One reliable way to do this without
6
requiring special privileges is to use a FUSE export, which allows us to
7
inject any error that we want, e.g. via blkdebug.
5
8
6
Sample command line using JSON syntax:
9
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
7
./x86_64-softmmu/qemu-system-x86_64 -name instance-00000008 -S -vnc 0.0.0.0:0
10
Message-Id: <20230824155345.109765-6-hreitz@redhat.com>
8
-k en-us -vga cirrus -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5
11
[hreitz: Fixed test to be skipped when there is no FUSE support, to
9
-msg timestamp=on
12
suppress fusermount's allow_other warning, and to be skipped
10
'json:{"driver":"vxhs","vdisk-id":"c3e9095a-a5ee-4dce-afeb-2a59fb387410",
13
with $IMGOPTSSYNTAX enabled]
11
"server":{"host":"172.172.17.4","port":"9999"}}'
14
Signed-off-by: Hanna Czenczek <hreitz@redhat.com>
15
---
16
tests/qemu-iotests/tests/file-io-error | 119 +++++++++++++++++++++
17
tests/qemu-iotests/tests/file-io-error.out | 33 ++++++
18
2 files changed, 152 insertions(+)
19
create mode 100755 tests/qemu-iotests/tests/file-io-error
20
create mode 100644 tests/qemu-iotests/tests/file-io-error.out
12
21
13
Sample command line using URI syntax:
22
diff --git a/tests/qemu-iotests/tests/file-io-error b/tests/qemu-iotests/tests/file-io-error
14
qemu-img convert -f raw -O raw -n
23
new file mode 100755
15
/var/lib/nova/instances/_base/0c5eacd5ebea5ed914b6a3e7b18f1ce734c386ad
24
index XXXXXXX..XXXXXXX
16
vxhs://192.168.0.1:9999/c6718f6b-0401-441d-a8c3-1f0064d75ee0
25
--- /dev/null
17
26
+++ b/tests/qemu-iotests/tests/file-io-error
18
Sample command line using TLS credentials (run in secure mode):
27
@@ -XXX,XX +XXX,XX @@
19
./qemu-io --object
28
+#!/usr/bin/env bash
20
tls-creds-x509,id=tls0,dir=/etc/pki/qemu/vxhs,endpoint=client -c 'read
29
+# group: rw
21
-v 66000 2.5k' 'json:{"server.host": "127.0.0.1", "server.port": "9999",
30
+#
22
"vdisk-id": "/test.raw", "driver": "vxhs", "tls-creds":"tls0"}'
31
+# Produce an I/O error in file-posix, and hope that it is not catastrophic.
23
32
+# Regression test for: https://bugzilla.redhat.com/show_bug.cgi?id=2234374
24
Signed-off-by: Ashish Mittal <Ashish.Mittal@veritas.com>
33
+#
25
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
34
+# Copyright (C) 2023 Red Hat, Inc.
26
Reviewed-by: Jeff Cody <jcody@redhat.com>
35
+#
27
Signed-off-by: Jeff Cody <jcody@redhat.com>
36
+# This program is free software; you can redistribute it and/or modify
28
Message-id: 1491277689-24949-2-git-send-email-Ashish.Mittal@veritas.com
37
+# it under the terms of the GNU General Public License as published by
29
---
38
+# the Free Software Foundation; either version 2 of the License, or
30
block/Makefile.objs | 2 +
39
+# (at your option) any later version.
31
block/trace-events | 17 ++
40
+#
32
block/vxhs.c | 575 +++++++++++++++++++++++++++++++++++++++++++++++++++
41
+# This program is distributed in the hope that it will be useful,
33
configure | 39 ++++
42
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
34
qapi/block-core.json | 23 ++-
43
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35
5 files changed, 654 insertions(+), 2 deletions(-)
44
+# GNU General Public License for more details.
36
create mode 100644 block/vxhs.c
45
+#
37
46
+# You should have received a copy of the GNU General Public License
38
diff --git a/block/Makefile.objs b/block/Makefile.objs
47
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39
index XXXXXXX..XXXXXXX 100644
48
+#
40
--- a/block/Makefile.objs
41
+++ b/block/Makefile.objs
42
@@ -XXX,XX +XXX,XX @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
43
block-obj-$(CONFIG_CURL) += curl.o
44
block-obj-$(CONFIG_RBD) += rbd.o
45
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
46
+block-obj-$(CONFIG_VXHS) += vxhs.o
47
block-obj-$(CONFIG_LIBSSH2) += ssh.o
48
block-obj-y += accounting.o dirty-bitmap.o
49
block-obj-y += write-threshold.o
50
@@ -XXX,XX +XXX,XX @@ rbd.o-cflags := $(RBD_CFLAGS)
51
rbd.o-libs := $(RBD_LIBS)
52
gluster.o-cflags := $(GLUSTERFS_CFLAGS)
53
gluster.o-libs := $(GLUSTERFS_LIBS)
54
+vxhs.o-libs := $(VXHS_LIBS)
55
ssh.o-cflags := $(LIBSSH2_CFLAGS)
56
ssh.o-libs := $(LIBSSH2_LIBS)
57
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
58
diff --git a/block/trace-events b/block/trace-events
59
index XXXXXXX..XXXXXXX 100644
60
--- a/block/trace-events
61
+++ b/block/trace-events
62
@@ -XXX,XX +XXX,XX @@ qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t len) "s
63
qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
64
qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64
65
qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
66
+
49
+
67
+# block/vxhs.c
50
+seq=$(basename "$0")
68
+vxhs_iio_callback(int error) "ctx is NULL: error %d"
51
+echo "QA output created by $seq"
69
+vxhs_iio_callback_chnfail(int err, int error) "QNIO channel failed, no i/o %d, %d"
52
+
70
+vxhs_iio_callback_unknwn(int opcode, int err) "unexpected opcode %d, errno %d"
53
+status=1    # failure is the default!
71
+vxhs_aio_rw_invalid(int req) "Invalid I/O request iodir %d"
54
+
72
+vxhs_aio_rw_ioerr(char *guid, int iodir, uint64_t size, uint64_t off, void *acb, int ret, int err) "IO ERROR (vDisk %s) FOR : Read/Write = %d size = %lu offset = %lu ACB = %p. Error = %d, errno = %d"
55
+_cleanup()
73
+vxhs_get_vdisk_stat_err(char *guid, int ret, int err) "vDisk (%s) stat ioctl failed, ret = %d, errno = %d"
56
+{
74
+vxhs_get_vdisk_stat(char *vdisk_guid, uint64_t vdisk_size) "vDisk %s stat ioctl returned size %lu"
57
+ _cleanup_qemu
75
+vxhs_complete_aio(void *acb, uint64_t ret) "aio failed acb %p ret %ld"
58
+ rm -f "$TEST_DIR/fuse-export"
76
+vxhs_parse_uri_filename(const char *filename) "URI passed via bdrv_parse_filename %s"
59
+}
77
+vxhs_open_vdiskid(const char *vdisk_id) "Opening vdisk-id %s"
60
+trap "_cleanup; exit \$status" 0 1 2 3 15
78
+vxhs_open_hostinfo(char *of_vsa_addr, int port) "Adding host %s:%d to BDRVVXHSState"
61
+
79
+vxhs_open_iio_open(const char *host) "Failed to connect to storage agent on host %s"
62
+# get standard environment, filters and checks
80
+vxhs_parse_uri_hostinfo(char *host, int port) "Host: IP %s, Port %d"
63
+. ../common.rc
81
+vxhs_close(char *vdisk_guid) "Closing vdisk %s"
64
+. ../common.filter
82
+vxhs_get_creds(const char *cacert, const char *client_key, const char *client_cert) "cacert %s, client_key %s, client_cert %s"
65
+. ../common.qemu
83
diff --git a/block/vxhs.c b/block/vxhs.c
66
+
67
+# Format-agnostic (we do not use any), but we do test the file protocol
68
+_supported_proto file
69
+_require_drivers blkdebug null-co
70
+
71
+if [ "$IMGOPTSSYNTAX" = "true" ]; then
72
+ # We need `$QEMU_IO -f file` to work; IMGOPTSSYNTAX uses --image-opts,
73
+ # breaking -f.
74
+ _unsupported_fmt $IMGFMT
75
+fi
76
+
77
+# This is a regression test of a bug in which flie-posix would access zone
78
+# information in case of an I/O error even when there is no zone information,
79
+# resulting in a division by zero.
80
+# To reproduce the problem, we need to trigger an I/O error inside of
81
+# file-posix, which can be done (rootless) by providing a FUSE export that
82
+# presents only errors when accessed.
83
+
84
+_launch_qemu
85
+_send_qemu_cmd $QEMU_HANDLE \
86
+ "{'execute': 'qmp_capabilities'}" \
87
+ 'return'
88
+
89
+_send_qemu_cmd $QEMU_HANDLE \
90
+ "{'execute': 'blockdev-add',
91
+ 'arguments': {
92
+ 'driver': 'blkdebug',
93
+ 'node-name': 'node0',
94
+ 'inject-error': [{'event': 'none'}],
95
+ 'image': {
96
+ 'driver': 'null-co'
97
+ }
98
+ }}" \
99
+ 'return'
100
+
101
+# FUSE mountpoint must exist and be a regular file
102
+touch "$TEST_DIR/fuse-export"
103
+
104
+# The grep -v to filter fusermount's (benign) error when /etc/fuse.conf does
105
+# not contain user_allow_other and the subsequent check for missing FUSE support
106
+# have both been taken from iotest 308.
107
+output=$(_send_qemu_cmd $QEMU_HANDLE \
108
+ "{'execute': 'block-export-add',
109
+ 'arguments': {
110
+ 'id': 'exp0',
111
+ 'type': 'fuse',
112
+ 'node-name': 'node0',
113
+ 'mountpoint': '$TEST_DIR/fuse-export',
114
+ 'writable': true
115
+ }}" \
116
+ 'return' \
117
+ | grep -v 'option allow_other only allowed if')
118
+
119
+if echo "$output" | grep -q "Parameter 'type' does not accept value 'fuse'"; then
120
+ _notrun 'No FUSE support'
121
+fi
122
+echo "$output"
123
+
124
+echo
125
+# This should fail, but gracefully, i.e. just print an I/O error, not crash.
126
+$QEMU_IO -f file -c 'write 0 64M' "$TEST_DIR/fuse-export" | _filter_qemu_io
127
+echo
128
+
129
+_send_qemu_cmd $QEMU_HANDLE \
130
+ "{'execute': 'block-export-del',
131
+ 'arguments': {'id': 'exp0'}}" \
132
+ 'return'
133
+
134
+_send_qemu_cmd $QEMU_HANDLE \
135
+ '' \
136
+ 'BLOCK_EXPORT_DELETED'
137
+
138
+_send_qemu_cmd $QEMU_HANDLE \
139
+ "{'execute': 'blockdev-del',
140
+ 'arguments': {'node-name': 'node0'}}" \
141
+ 'return'
142
+
143
+# success, all done
144
+echo "*** done"
145
+rm -f $seq.full
146
+status=0
147
diff --git a/tests/qemu-iotests/tests/file-io-error.out b/tests/qemu-iotests/tests/file-io-error.out
84
new file mode 100644
148
new file mode 100644
85
index XXXXXXX..XXXXXXX
149
index XXXXXXX..XXXXXXX
86
--- /dev/null
150
--- /dev/null
87
+++ b/block/vxhs.c
151
+++ b/tests/qemu-iotests/tests/file-io-error.out
88
@@ -XXX,XX +XXX,XX @@
152
@@ -XXX,XX +XXX,XX @@
89
+/*
153
+QA output created by file-io-error
90
+ * QEMU Block driver for Veritas HyperScale (VxHS)
154
+{'execute': 'qmp_capabilities'}
91
+ *
155
+{"return": {}}
92
+ * Copyright (c) 2017 Veritas Technologies LLC.
156
+{'execute': 'blockdev-add',
93
+ *
157
+ 'arguments': {
94
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
158
+ 'driver': 'blkdebug',
95
+ * See the COPYING file in the top-level directory.
159
+ 'node-name': 'node0',
96
+ *
160
+ 'inject-error': [{'event': 'none'}],
97
+ */
161
+ 'image': {
162
+ 'driver': 'null-co'
163
+ }
164
+ }}
165
+{"return": {}}
166
+{'execute': 'block-export-add',
167
+ 'arguments': {
168
+ 'id': 'exp0',
169
+ 'type': 'fuse',
170
+ 'node-name': 'node0',
171
+ 'mountpoint': 'TEST_DIR/fuse-export',
172
+ 'writable': true
173
+ }}
174
+{"return": {}}
98
+
175
+
99
+#include "qemu/osdep.h"
176
+write failed: Input/output error
100
+#include <qnio/qnio_api.h>
101
+#include <sys/param.h>
102
+#include "block/block_int.h"
103
+#include "qapi/qmp/qerror.h"
104
+#include "qapi/qmp/qdict.h"
105
+#include "qapi/qmp/qstring.h"
106
+#include "trace.h"
107
+#include "qemu/uri.h"
108
+#include "qapi/error.h"
109
+#include "qemu/uuid.h"
110
+#include "crypto/tlscredsx509.h"
111
+
177
+
112
+#define VXHS_OPT_FILENAME "filename"
178
+{'execute': 'block-export-del',
113
+#define VXHS_OPT_VDISK_ID "vdisk-id"
179
+ 'arguments': {'id': 'exp0'}}
114
+#define VXHS_OPT_SERVER "server"
180
+{"return": {}}
115
+#define VXHS_OPT_HOST "host"
181
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_EXPORT_DELETED", "data": {"id": "exp0"}}
116
+#define VXHS_OPT_PORT "port"
182
+{'execute': 'blockdev-del',
117
+
183
+ 'arguments': {'node-name': 'node0'}}
118
+/* Only accessed under QEMU global mutex */
184
+{"return": {}}
119
+static uint32_t vxhs_ref;
185
+*** done
120
+
121
+typedef enum {
122
+ VDISK_AIO_READ,
123
+ VDISK_AIO_WRITE,
124
+} VDISKAIOCmd;
125
+
126
+/*
127
+ * HyperScale AIO callbacks structure
128
+ */
129
+typedef struct VXHSAIOCB {
130
+ BlockAIOCB common;
131
+ int err;
132
+} VXHSAIOCB;
133
+
134
+typedef struct VXHSvDiskHostsInfo {
135
+ void *dev_handle; /* Device handle */
136
+ char *host; /* Host name or IP */
137
+ int port; /* Host's port number */
138
+} VXHSvDiskHostsInfo;
139
+
140
+/*
141
+ * Structure per vDisk maintained for state
142
+ */
143
+typedef struct BDRVVXHSState {
144
+ VXHSvDiskHostsInfo vdisk_hostinfo; /* Per host info */
145
+ char *vdisk_guid;
146
+ char *tlscredsid; /* tlscredsid */
147
+} BDRVVXHSState;
148
+
149
+static void vxhs_complete_aio_bh(void *opaque)
150
+{
151
+ VXHSAIOCB *acb = opaque;
152
+ BlockCompletionFunc *cb = acb->common.cb;
153
+ void *cb_opaque = acb->common.opaque;
154
+ int ret = 0;
155
+
156
+ if (acb->err != 0) {
157
+ trace_vxhs_complete_aio(acb, acb->err);
158
+ ret = (-EIO);
159
+ }
160
+
161
+ qemu_aio_unref(acb);
162
+ cb(cb_opaque, ret);
163
+}
164
+
165
+/*
166
+ * Called from a libqnio thread
167
+ */
168
+static void vxhs_iio_callback(void *ctx, uint32_t opcode, uint32_t error)
169
+{
170
+ VXHSAIOCB *acb = NULL;
171
+
172
+ switch (opcode) {
173
+ case IRP_READ_REQUEST:
174
+ case IRP_WRITE_REQUEST:
175
+
176
+ /*
177
+ * ctx is VXHSAIOCB*
178
+ * ctx is NULL if error is QNIOERROR_CHANNEL_HUP
179
+ */
180
+ if (ctx) {
181
+ acb = ctx;
182
+ } else {
183
+ trace_vxhs_iio_callback(error);
184
+ goto out;
185
+ }
186
+
187
+ if (error) {
188
+ if (!acb->err) {
189
+ acb->err = error;
190
+ }
191
+ trace_vxhs_iio_callback(error);
192
+ }
193
+
194
+ aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
195
+ vxhs_complete_aio_bh, acb);
196
+ break;
197
+
198
+ default:
199
+ if (error == QNIOERROR_HUP) {
200
+ /*
201
+ * Channel failed, spontaneous notification,
202
+ * not in response to I/O
203
+ */
204
+ trace_vxhs_iio_callback_chnfail(error, errno);
205
+ } else {
206
+ trace_vxhs_iio_callback_unknwn(opcode, error);
207
+ }
208
+ break;
209
+ }
210
+out:
211
+ return;
212
+}
213
+
214
+static QemuOptsList runtime_opts = {
215
+ .name = "vxhs",
216
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_opts.head),
217
+ .desc = {
218
+ {
219
+ .name = VXHS_OPT_FILENAME,
220
+ .type = QEMU_OPT_STRING,
221
+ .help = "URI to the Veritas HyperScale image",
222
+ },
223
+ {
224
+ .name = VXHS_OPT_VDISK_ID,
225
+ .type = QEMU_OPT_STRING,
226
+ .help = "UUID of the VxHS vdisk",
227
+ },
228
+ {
229
+ .name = "tls-creds",
230
+ .type = QEMU_OPT_STRING,
231
+ .help = "ID of the TLS/SSL credentials to use",
232
+ },
233
+ { /* end of list */ }
234
+ },
235
+};
236
+
237
+static QemuOptsList runtime_tcp_opts = {
238
+ .name = "vxhs_tcp",
239
+ .head = QTAILQ_HEAD_INITIALIZER(runtime_tcp_opts.head),
240
+ .desc = {
241
+ {
242
+ .name = VXHS_OPT_HOST,
243
+ .type = QEMU_OPT_STRING,
244
+ .help = "host address (ipv4 addresses)",
245
+ },
246
+ {
247
+ .name = VXHS_OPT_PORT,
248
+ .type = QEMU_OPT_NUMBER,
249
+ .help = "port number on which VxHSD is listening (default 9999)",
250
+ .def_value_str = "9999"
251
+ },
252
+ { /* end of list */ }
253
+ },
254
+};
255
+
256
+/*
257
+ * Parse incoming URI and populate *options with the host
258
+ * and device information
259
+ */
260
+static int vxhs_parse_uri(const char *filename, QDict *options)
261
+{
262
+ URI *uri = NULL;
263
+ char *port;
264
+ int ret = 0;
265
+
266
+ trace_vxhs_parse_uri_filename(filename);
267
+ uri = uri_parse(filename);
268
+ if (!uri || !uri->server || !uri->path) {
269
+ uri_free(uri);
270
+ return -EINVAL;
271
+ }
272
+
273
+ qdict_put(options, VXHS_OPT_SERVER".host", qstring_from_str(uri->server));
274
+
275
+ if (uri->port) {
276
+ port = g_strdup_printf("%d", uri->port);
277
+ qdict_put(options, VXHS_OPT_SERVER".port", qstring_from_str(port));
278
+ g_free(port);
279
+ }
280
+
281
+ qdict_put(options, "vdisk-id", qstring_from_str(uri->path));
282
+
283
+ trace_vxhs_parse_uri_hostinfo(uri->server, uri->port);
284
+ uri_free(uri);
285
+
286
+ return ret;
287
+}
288
+
289
+static void vxhs_parse_filename(const char *filename, QDict *options,
290
+ Error **errp)
291
+{
292
+ if (qdict_haskey(options, "vdisk-id") || qdict_haskey(options, "server")) {
293
+ error_setg(errp, "vdisk-id/server and a file name may not be specified "
294
+ "at the same time");
295
+ return;
296
+ }
297
+
298
+ if (strstr(filename, "://")) {
299
+ int ret = vxhs_parse_uri(filename, options);
300
+ if (ret < 0) {
301
+ error_setg(errp, "Invalid URI. URI should be of the form "
302
+ " vxhs://<host_ip>:<port>/<vdisk-id>");
303
+ }
304
+ }
305
+}
306
+
307
+static int vxhs_init_and_ref(void)
308
+{
309
+ if (vxhs_ref++ == 0) {
310
+ if (iio_init(QNIO_VERSION, vxhs_iio_callback)) {
311
+ return -ENODEV;
312
+ }
313
+ }
314
+ return 0;
315
+}
316
+
317
+static void vxhs_unref(void)
318
+{
319
+ if (--vxhs_ref == 0) {
320
+ iio_fini();
321
+ }
322
+}
323
+
324
+static void vxhs_get_tls_creds(const char *id, char **cacert,
325
+ char **key, char **cert, Error **errp)
326
+{
327
+ Object *obj;
328
+ QCryptoTLSCreds *creds;
329
+ QCryptoTLSCredsX509 *creds_x509;
330
+
331
+ obj = object_resolve_path_component(
332
+ object_get_objects_root(), id);
333
+
334
+ if (!obj) {
335
+ error_setg(errp, "No TLS credentials with id '%s'",
336
+ id);
337
+ return;
338
+ }
339
+
340
+ creds_x509 = (QCryptoTLSCredsX509 *)
341
+ object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS_X509);
342
+
343
+ if (!creds_x509) {
344
+ error_setg(errp, "Object with id '%s' is not TLS credentials",
345
+ id);
346
+ return;
347
+ }
348
+
349
+ creds = &creds_x509->parent_obj;
350
+
351
+ if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT) {
352
+ error_setg(errp,
353
+ "Expecting TLS credentials with a client endpoint");
354
+ return;
355
+ }
356
+
357
+ /*
358
+ * Get the cacert, client_cert and client_key file names.
359
+ */
360
+ if (!creds->dir) {
361
+ error_setg(errp, "TLS object missing 'dir' property value");
362
+ return;
363
+ }
364
+
365
+ *cacert = g_strdup_printf("%s/%s", creds->dir,
366
+ QCRYPTO_TLS_CREDS_X509_CA_CERT);
367
+ *cert = g_strdup_printf("%s/%s", creds->dir,
368
+ QCRYPTO_TLS_CREDS_X509_CLIENT_CERT);
369
+ *key = g_strdup_printf("%s/%s", creds->dir,
370
+ QCRYPTO_TLS_CREDS_X509_CLIENT_KEY);
371
+}
372
+
373
+static int vxhs_open(BlockDriverState *bs, QDict *options,
374
+ int bdrv_flags, Error **errp)
375
+{
376
+ BDRVVXHSState *s = bs->opaque;
377
+ void *dev_handlep;
378
+ QDict *backing_options = NULL;
379
+ QemuOpts *opts = NULL;
380
+ QemuOpts *tcp_opts = NULL;
381
+ char *of_vsa_addr = NULL;
382
+ Error *local_err = NULL;
383
+ const char *vdisk_id_opt;
384
+ const char *server_host_opt;
385
+ int ret = 0;
386
+ char *cacert = NULL;
387
+ char *client_key = NULL;
388
+ char *client_cert = NULL;
389
+
390
+ ret = vxhs_init_and_ref();
391
+ if (ret < 0) {
392
+ ret = -EINVAL;
393
+ goto out;
394
+ }
395
+
396
+ /* Create opts info from runtime_opts and runtime_tcp_opts list */
397
+ opts = qemu_opts_create(&runtime_opts, NULL, 0, &error_abort);
398
+ tcp_opts = qemu_opts_create(&runtime_tcp_opts, NULL, 0, &error_abort);
399
+
400
+ qemu_opts_absorb_qdict(opts, options, &local_err);
401
+ if (local_err) {
402
+ ret = -EINVAL;
403
+ goto out;
404
+ }
405
+
406
+ /* vdisk-id is the disk UUID */
407
+ vdisk_id_opt = qemu_opt_get(opts, VXHS_OPT_VDISK_ID);
408
+ if (!vdisk_id_opt) {
409
+ error_setg(&local_err, QERR_MISSING_PARAMETER, VXHS_OPT_VDISK_ID);
410
+ ret = -EINVAL;
411
+ goto out;
412
+ }
413
+
414
+ /* vdisk-id may contain a leading '/' */
415
+ if (strlen(vdisk_id_opt) > UUID_FMT_LEN + 1) {
416
+ error_setg(&local_err, "vdisk-id cannot be more than %d characters",
417
+ UUID_FMT_LEN);
418
+ ret = -EINVAL;
419
+ goto out;
420
+ }
421
+
422
+ s->vdisk_guid = g_strdup(vdisk_id_opt);
423
+ trace_vxhs_open_vdiskid(vdisk_id_opt);
424
+
425
+ /* get the 'server.' arguments */
426
+ qdict_extract_subqdict(options, &backing_options, VXHS_OPT_SERVER".");
427
+
428
+ qemu_opts_absorb_qdict(tcp_opts, backing_options, &local_err);
429
+ if (local_err != NULL) {
430
+ ret = -EINVAL;
431
+ goto out;
432
+ }
433
+
434
+ server_host_opt = qemu_opt_get(tcp_opts, VXHS_OPT_HOST);
435
+ if (!server_host_opt) {
436
+ error_setg(&local_err, QERR_MISSING_PARAMETER,
437
+ VXHS_OPT_SERVER"."VXHS_OPT_HOST);
438
+ ret = -EINVAL;
439
+ goto out;
440
+ }
441
+
442
+ if (strlen(server_host_opt) > MAXHOSTNAMELEN) {
443
+ error_setg(&local_err, "server.host cannot be more than %d characters",
444
+ MAXHOSTNAMELEN);
445
+ ret = -EINVAL;
446
+ goto out;
447
+ }
448
+
449
+ /* check if we got tls-creds via the --object argument */
450
+ s->tlscredsid = g_strdup(qemu_opt_get(opts, "tls-creds"));
451
+ if (s->tlscredsid) {
452
+ vxhs_get_tls_creds(s->tlscredsid, &cacert, &client_key,
453
+ &client_cert, &local_err);
454
+ if (local_err != NULL) {
455
+ ret = -EINVAL;
456
+ goto out;
457
+ }
458
+ trace_vxhs_get_creds(cacert, client_key, client_cert);
459
+ }
460
+
461
+ s->vdisk_hostinfo.host = g_strdup(server_host_opt);
462
+ s->vdisk_hostinfo.port = g_ascii_strtoll(qemu_opt_get(tcp_opts,
463
+ VXHS_OPT_PORT),
464
+ NULL, 0);
465
+
466
+ trace_vxhs_open_hostinfo(s->vdisk_hostinfo.host,
467
+ s->vdisk_hostinfo.port);
468
+
469
+ of_vsa_addr = g_strdup_printf("of://%s:%d",
470
+ s->vdisk_hostinfo.host,
471
+ s->vdisk_hostinfo.port);
472
+
473
+ /*
474
+ * Open qnio channel to storage agent if not opened before
475
+ */
476
+ dev_handlep = iio_open(of_vsa_addr, s->vdisk_guid, 0,
477
+ cacert, client_key, client_cert);
478
+ if (dev_handlep == NULL) {
479
+ trace_vxhs_open_iio_open(of_vsa_addr);
480
+ ret = -ENODEV;
481
+ goto out;
482
+ }
483
+ s->vdisk_hostinfo.dev_handle = dev_handlep;
484
+
485
+out:
486
+ g_free(of_vsa_addr);
487
+ QDECREF(backing_options);
488
+ qemu_opts_del(tcp_opts);
489
+ qemu_opts_del(opts);
490
+ g_free(cacert);
491
+ g_free(client_key);
492
+ g_free(client_cert);
493
+
494
+ if (ret < 0) {
495
+ vxhs_unref();
496
+ error_propagate(errp, local_err);
497
+ g_free(s->vdisk_hostinfo.host);
498
+ g_free(s->vdisk_guid);
499
+ g_free(s->tlscredsid);
500
+ s->vdisk_guid = NULL;
501
+ }
502
+
503
+ return ret;
504
+}
505
+
506
+static const AIOCBInfo vxhs_aiocb_info = {
507
+ .aiocb_size = sizeof(VXHSAIOCB)
508
+};
509
+
510
+/*
511
+ * This allocates QEMU-VXHS callback for each IO
512
+ * and is passed to QNIO. When QNIO completes the work,
513
+ * it will be passed back through the callback.
514
+ */
515
+static BlockAIOCB *vxhs_aio_rw(BlockDriverState *bs, int64_t sector_num,
516
+ QEMUIOVector *qiov, int nb_sectors,
517
+ BlockCompletionFunc *cb, void *opaque,
518
+ VDISKAIOCmd iodir)
519
+{
520
+ VXHSAIOCB *acb = NULL;
521
+ BDRVVXHSState *s = bs->opaque;
522
+ size_t size;
523
+ uint64_t offset;
524
+ int iio_flags = 0;
525
+ int ret = 0;
526
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
527
+
528
+ offset = sector_num * BDRV_SECTOR_SIZE;
529
+ size = nb_sectors * BDRV_SECTOR_SIZE;
530
+ acb = qemu_aio_get(&vxhs_aiocb_info, bs, cb, opaque);
531
+
532
+ /*
533
+ * Initialize VXHSAIOCB.
534
+ */
535
+ acb->err = 0;
536
+
537
+ iio_flags = IIO_FLAG_ASYNC;
538
+
539
+ switch (iodir) {
540
+ case VDISK_AIO_WRITE:
541
+ ret = iio_writev(dev_handle, acb, qiov->iov, qiov->niov,
542
+ offset, (uint64_t)size, iio_flags);
543
+ break;
544
+ case VDISK_AIO_READ:
545
+ ret = iio_readv(dev_handle, acb, qiov->iov, qiov->niov,
546
+ offset, (uint64_t)size, iio_flags);
547
+ break;
548
+ default:
549
+ trace_vxhs_aio_rw_invalid(iodir);
550
+ goto errout;
551
+ }
552
+
553
+ if (ret != 0) {
554
+ trace_vxhs_aio_rw_ioerr(s->vdisk_guid, iodir, size, offset,
555
+ acb, ret, errno);
556
+ goto errout;
557
+ }
558
+ return &acb->common;
559
+
560
+errout:
561
+ qemu_aio_unref(acb);
562
+ return NULL;
563
+}
564
+
565
+static BlockAIOCB *vxhs_aio_readv(BlockDriverState *bs,
566
+ int64_t sector_num, QEMUIOVector *qiov,
567
+ int nb_sectors,
568
+ BlockCompletionFunc *cb, void *opaque)
569
+{
570
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
571
+ opaque, VDISK_AIO_READ);
572
+}
573
+
574
+static BlockAIOCB *vxhs_aio_writev(BlockDriverState *bs,
575
+ int64_t sector_num, QEMUIOVector *qiov,
576
+ int nb_sectors,
577
+ BlockCompletionFunc *cb, void *opaque)
578
+{
579
+ return vxhs_aio_rw(bs, sector_num, qiov, nb_sectors,
580
+ cb, opaque, VDISK_AIO_WRITE);
581
+}
582
+
583
+static void vxhs_close(BlockDriverState *bs)
584
+{
585
+ BDRVVXHSState *s = bs->opaque;
586
+
587
+ trace_vxhs_close(s->vdisk_guid);
588
+
589
+ g_free(s->vdisk_guid);
590
+ s->vdisk_guid = NULL;
591
+
592
+ /*
593
+ * Close vDisk device
594
+ */
595
+ if (s->vdisk_hostinfo.dev_handle) {
596
+ iio_close(s->vdisk_hostinfo.dev_handle);
597
+ s->vdisk_hostinfo.dev_handle = NULL;
598
+ }
599
+
600
+ vxhs_unref();
601
+
602
+ /*
603
+ * Free the dynamically allocated host string etc
604
+ */
605
+ g_free(s->vdisk_hostinfo.host);
606
+ g_free(s->tlscredsid);
607
+ s->tlscredsid = NULL;
608
+ s->vdisk_hostinfo.host = NULL;
609
+ s->vdisk_hostinfo.port = 0;
610
+}
611
+
612
+static int64_t vxhs_get_vdisk_stat(BDRVVXHSState *s)
613
+{
614
+ int64_t vdisk_size = -1;
615
+ int ret = 0;
616
+ void *dev_handle = s->vdisk_hostinfo.dev_handle;
617
+
618
+ ret = iio_ioctl(dev_handle, IOR_VDISK_STAT, &vdisk_size, 0);
619
+ if (ret < 0) {
620
+ trace_vxhs_get_vdisk_stat_err(s->vdisk_guid, ret, errno);
621
+ return -EIO;
622
+ }
623
+
624
+ trace_vxhs_get_vdisk_stat(s->vdisk_guid, vdisk_size);
625
+ return vdisk_size;
626
+}
627
+
628
+/*
629
+ * Returns the size of vDisk in bytes. This is required
630
+ * by QEMU block upper block layer so that it is visible
631
+ * to guest.
632
+ */
633
+static int64_t vxhs_getlength(BlockDriverState *bs)
634
+{
635
+ BDRVVXHSState *s = bs->opaque;
636
+ int64_t vdisk_size;
637
+
638
+ vdisk_size = vxhs_get_vdisk_stat(s);
639
+ if (vdisk_size < 0) {
640
+ return -EIO;
641
+ }
642
+
643
+ return vdisk_size;
644
+}
645
+
646
+static BlockDriver bdrv_vxhs = {
647
+ .format_name = "vxhs",
648
+ .protocol_name = "vxhs",
649
+ .instance_size = sizeof(BDRVVXHSState),
650
+ .bdrv_file_open = vxhs_open,
651
+ .bdrv_parse_filename = vxhs_parse_filename,
652
+ .bdrv_close = vxhs_close,
653
+ .bdrv_getlength = vxhs_getlength,
654
+ .bdrv_aio_readv = vxhs_aio_readv,
655
+ .bdrv_aio_writev = vxhs_aio_writev,
656
+};
657
+
658
+static void bdrv_vxhs_init(void)
659
+{
660
+ bdrv_register(&bdrv_vxhs);
661
+}
662
+
663
+block_init(bdrv_vxhs_init);
664
diff --git a/configure b/configure
665
index XXXXXXX..XXXXXXX 100755
666
--- a/configure
667
+++ b/configure
668
@@ -XXX,XX +XXX,XX @@ numa=""
669
tcmalloc="no"
670
jemalloc="no"
671
replication="yes"
672
+vxhs=""
673
674
supported_cpu="no"
675
supported_os="no"
676
@@ -XXX,XX +XXX,XX @@ for opt do
677
;;
678
--enable-replication) replication="yes"
679
;;
680
+ --disable-vxhs) vxhs="no"
681
+ ;;
682
+ --enable-vxhs) vxhs="yes"
683
+ ;;
684
*)
685
echo "ERROR: unknown option $opt"
686
echo "Try '$0 --help' for more information"
687
@@ -XXX,XX +XXX,XX @@ disabled with --disable-FEATURE, default is enabled if available:
688
xfsctl xfsctl support
689
qom-cast-debug cast debugging support
690
tools build qemu-io, qemu-nbd and qemu-image tools
691
+ vxhs Veritas HyperScale vDisk backend support
692
693
NOTE: The object files are built at the place where configure is launched
694
EOF
695
@@ -XXX,XX +XXX,XX @@ if compile_prog "" "" ; then
696
fi
697
698
##########################################
699
+# Veritas HyperScale block driver VxHS
700
+# Check if libvxhs is installed
701
+
702
+if test "$vxhs" != "no" ; then
703
+ cat > $TMPC <<EOF
704
+#include <stdint.h>
705
+#include <qnio/qnio_api.h>
706
+
707
+void *vxhs_callback;
708
+
709
+int main(void) {
710
+ iio_init(QNIO_VERSION, vxhs_callback);
711
+ return 0;
712
+}
713
+EOF
714
+ vxhs_libs="-lvxhs -lssl"
715
+ if compile_prog "" "$vxhs_libs" ; then
716
+ vxhs=yes
717
+ else
718
+ if test "$vxhs" = "yes" ; then
719
+ feature_not_found "vxhs block device" "Install libvxhs See github"
720
+ fi
721
+ vxhs=no
722
+ fi
723
+fi
724
+
725
+##########################################
726
# End of CC checks
727
# After here, no more $cc or $ld runs
728
729
@@ -XXX,XX +XXX,XX @@ echo "tcmalloc support $tcmalloc"
730
echo "jemalloc support $jemalloc"
731
echo "avx2 optimization $avx2_opt"
732
echo "replication support $replication"
733
+echo "VxHS block device $vxhs"
734
735
if test "$sdl_too_old" = "yes"; then
736
echo "-> Your SDL version is too old - please upgrade to have SDL support"
737
@@ -XXX,XX +XXX,XX @@ if test "$pthread_setname_np" = "yes" ; then
738
echo "CONFIG_PTHREAD_SETNAME_NP=y" >> $config_host_mak
739
fi
740
741
+if test "$vxhs" = "yes" ; then
742
+ echo "CONFIG_VXHS=y" >> $config_host_mak
743
+ echo "VXHS_LIBS=$vxhs_libs" >> $config_host_mak
744
+fi
745
+
746
if test "$tcg_interpreter" = "yes"; then
747
QEMU_INCLUDES="-I\$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
748
elif test "$ARCH" = "sparc64" ; then
749
diff --git a/qapi/block-core.json b/qapi/block-core.json
750
index XXXXXXX..XXXXXXX 100644
751
--- a/qapi/block-core.json
752
+++ b/qapi/block-core.json
753
@@ -XXX,XX +XXX,XX @@
754
#
755
# Drivers that are supported in block device operations.
756
#
757
+# @vxhs: Since 2.10
758
+#
759
# Since: 2.9
760
##
761
{ 'enum': 'BlockdevDriver',
762
@@ -XXX,XX +XXX,XX @@
763
'host_device', 'http', 'https', 'iscsi', 'luks', 'nbd', 'nfs',
764
'null-aio', 'null-co', 'parallels', 'qcow', 'qcow2', 'qed',
765
'quorum', 'raw', 'rbd', 'replication', 'sheepdog', 'ssh',
766
- 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat' ] }
767
+ 'vdi', 'vhdx', 'vmdk', 'vpc', 'vvfat', 'vxhs' ] }
768
769
##
770
# @BlockdevOptionsFile:
771
@@ -XXX,XX +XXX,XX @@
772
'data': { '*offset': 'int', '*size': 'int' } }
773
774
##
775
+# @BlockdevOptionsVxHS:
776
+#
777
+# Driver specific block device options for VxHS
778
+#
779
+# @vdisk-id: UUID of VxHS volume
780
+# @server: vxhs server IP, port
781
+# @tls-creds: TLS credentials ID
782
+#
783
+# Since: 2.10
784
+##
785
+{ 'struct': 'BlockdevOptionsVxHS',
786
+ 'data': { 'vdisk-id': 'str',
787
+ 'server': 'InetSocketAddressBase',
788
+ '*tls-creds': 'str' } }
789
+
790
+##
791
# @BlockdevOptions:
792
#
793
# Options for creating a block device. Many options are available for all
794
@@ -XXX,XX +XXX,XX @@
795
'vhdx': 'BlockdevOptionsGenericFormat',
796
'vmdk': 'BlockdevOptionsGenericCOWFormat',
797
'vpc': 'BlockdevOptionsGenericFormat',
798
- 'vvfat': 'BlockdevOptionsVVFAT'
799
+ 'vvfat': 'BlockdevOptionsVVFAT',
800
+ 'vxhs': 'BlockdevOptionsVxHS'
801
} }
802
803
##
804
--
186
--
805
2.9.3
187
2.41.0
806
807
diff view generated by jsdifflib