1
The following changes since commit d992f2f1368ceb92e6bfd8efece174110f4236ff:
1
The following changes since commit e47f81b617684c4546af286d307b69014a83538a:
2
2
3
Merge remote-tracking branch 'remotes/artyom/tags/pull-sun4v-20170226' into staging (2017-02-26 22:40:23 +0000)
3
Merge remote-tracking branch 'remotes/thibault/tags/samuel-thibault' into staging (2019-02-07 18:53:25 +0000)
4
4
5
are available in the git repository at:
5
are available in the Git repository at:
6
6
7
git://github.com/stefanha/qemu.git tags/block-pull-request
7
git://github.com/stefanha/qemu.git tags/block-pull-request
8
8
9
for you to fetch changes up to 1ab17f9f5c63c2798d707aeb22588e4fcc17b2cd:
9
for you to fetch changes up to 55140166667bb555c5d05165b93b25557d2e6397:
10
10
11
tests-aio-multithread: use atomic_read properly (2017-02-27 14:00:53 +0000)
11
tests/virtio-blk: add test for WRITE_ZEROES command (2019-02-11 11:58:17 +0800)
12
13
----------------------------------------------------------------
14
Pull request
15
16
User-visible changes:
17
18
* virtio-blk: DISCARD and WRITE_ZEROES support
12
19
13
----------------------------------------------------------------
20
----------------------------------------------------------------
14
21
15
----------------------------------------------------------------
22
Peter Xu (1):
23
iothread: fix iothread hang when stop too soon
16
24
17
Paolo Bonzini (4):
25
Stefano Garzarella (7):
18
curl: do not use aio_context_acquire/release
26
virtio-blk: cleanup using VirtIOBlock *s and VirtIODevice *vdev
19
nfs: do not use aio_context_acquire/release
27
virtio-blk: add acct_failed param to virtio_blk_handle_rw_error()
20
iscsi: do not use aio_context_acquire/release
28
virtio-blk: add host_features field in VirtIOBlock
21
tests-aio-multithread: use atomic_read properly
29
virtio-blk: add "discard" and "write-zeroes" properties
30
virtio-blk: add DISCARD and WRITE_ZEROES features
31
tests/virtio-blk: change assert on data_size in virtio_blk_request()
32
tests/virtio-blk: add test for WRITE_ZEROES command
22
33
23
block/curl.c | 24 ++++++++-----
34
Vladimir Sementsov-Ogievskiy (1):
24
block/iscsi.c | 83 ++++++++++++++++++++++++++++++++++----------
35
qemugdb/coroutine: fix arch_prctl has unknown return type
25
block/nfs.c | 23 +++++++++---
36
26
tests/test-aio-multithread.c | 4 +--
37
include/hw/virtio/virtio-blk.h | 5 +-
27
4 files changed, 100 insertions(+), 34 deletions(-)
38
hw/block/virtio-blk.c | 236 +++++++++++++++++++++++++++++----
39
hw/core/machine.c | 2 +
40
iothread.c | 6 +-
41
tests/virtio-blk-test.c | 75 ++++++++++-
42
scripts/qemugdb/coroutine.py | 2 +-
43
6 files changed, 297 insertions(+), 29 deletions(-)
28
44
29
--
45
--
30
2.9.3
46
2.20.1
31
47
32
48
diff view generated by jsdifflib
New patch
1
From: Peter Xu <peterx@redhat.com>
1
2
3
Lukas reported an hard to reproduce QMP iothread hang on s390 that
4
QEMU might hang at pthread_join() of the QMP monitor iothread before
5
quitting:
6
7
Thread 1
8
#0 0x000003ffad10932c in pthread_join
9
#1 0x0000000109e95750 in qemu_thread_join
10
at /home/thuth/devel/qemu/util/qemu-thread-posix.c:570
11
#2 0x0000000109c95a1c in iothread_stop
12
#3 0x0000000109bb0874 in monitor_cleanup
13
#4 0x0000000109b55042 in main
14
15
While the iothread is still in the main loop:
16
17
Thread 4
18
#0 0x000003ffad0010e4 in ??
19
#1 0x000003ffad553958 in g_main_context_iterate.isra.19
20
#2 0x000003ffad553d90 in g_main_loop_run
21
#3 0x0000000109c9585a in iothread_run
22
at /home/thuth/devel/qemu/iothread.c:74
23
#4 0x0000000109e94752 in qemu_thread_start
24
at /home/thuth/devel/qemu/util/qemu-thread-posix.c:502
25
#5 0x000003ffad10825a in start_thread
26
#6 0x000003ffad00dcf2 in thread_start
27
28
IMHO it's because there's a race between the main thread and iothread
29
when stopping the thread in following sequence:
30
31
main thread iothread
32
=========== ==============
33
aio_poll()
34
iothread_get_g_main_context
35
set iothread->worker_context
36
iothread_stop
37
schedule iothread_stop_bh
38
execute iothread_stop_bh [1]
39
set iothread->running=false
40
(since main_loop==NULL so
41
skip to quit main loop.
42
Note: although main_loop is
43
NULL but worker_context is
44
not!)
45
atomic_read(&iothread->worker_context) [2]
46
create main_loop object
47
g_main_loop_run() [3]
48
pthread_join() [4]
49
50
We can see that when execute iothread_stop_bh() at [1] it's possible
51
that main_loop is still NULL because it's only created until the first
52
check of the worker_context later at [2]. Then the iothread will hang
53
in the main loop [3] and it'll starve the main thread too [4].
54
55
Here the simple solution should be that we check again the "running"
56
variable before check against worker_context.
57
58
CC: Thomas Huth <thuth@redhat.com>
59
CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
60
CC: Stefan Hajnoczi <stefanha@redhat.com>
61
CC: Lukáš Doktor <ldoktor@redhat.com>
62
CC: Markus Armbruster <armbru@redhat.com>
63
CC: Eric Blake <eblake@redhat.com>
64
CC: Paolo Bonzini <pbonzini@redhat.com>
65
Reported-by: Lukáš Doktor <ldoktor@redhat.com>
66
Signed-off-by: Peter Xu <peterx@redhat.com>
67
Tested-by: Thomas Huth <thuth@redhat.com>
68
Message-id: 20190129051432.22023-1-peterx@redhat.com
69
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
70
---
71
iothread.c | 6 +++++-
72
1 file changed, 5 insertions(+), 1 deletion(-)
73
74
diff --git a/iothread.c b/iothread.c
75
index XXXXXXX..XXXXXXX 100644
76
--- a/iothread.c
77
+++ b/iothread.c
78
@@ -XXX,XX +XXX,XX @@ static void *iothread_run(void *opaque)
79
while (iothread->running) {
80
aio_poll(iothread->ctx, true);
81
82
- if (atomic_read(&iothread->worker_context)) {
83
+ /*
84
+ * We must check the running state again in case it was
85
+ * changed in previous aio_poll()
86
+ */
87
+ if (iothread->running && atomic_read(&iothread->worker_context)) {
88
GMainLoop *loop;
89
90
g_main_context_push_thread_default(iothread->worker_context);
91
--
92
2.20.1
93
94
diff view generated by jsdifflib
New patch
1
From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
1
2
3
qemu coroutine command results in following error output:
4
5
Python Exception <class 'gdb.error'> 'arch_prctl' has unknown return
6
type; cast the call to its declared return type: Error occurred in
7
Python command: 'arch_prctl' has unknown return type; cast the call to
8
its declared return type
9
10
Fix it by giving it what it wants: arch_prctl return type.
11
12
Information on the topic:
13
https://sourceware.org/gdb/onlinedocs/gdb/Calling.html
14
15
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
16
Message-id: 20190206151425.105871-1-vsementsov@virtuozzo.com
17
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
18
---
19
scripts/qemugdb/coroutine.py | 2 +-
20
1 file changed, 1 insertion(+), 1 deletion(-)
21
22
diff --git a/scripts/qemugdb/coroutine.py b/scripts/qemugdb/coroutine.py
23
index XXXXXXX..XXXXXXX 100644
24
--- a/scripts/qemugdb/coroutine.py
25
+++ b/scripts/qemugdb/coroutine.py
26
@@ -XXX,XX +XXX,XX @@ def get_fs_base():
27
pthread_self().'''
28
# %rsp - 120 is scratch space according to the SystemV ABI
29
old = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
30
- gdb.execute('call arch_prctl(0x1003, $rsp - 120)', False, True)
31
+ gdb.execute('call (int)arch_prctl(0x1003, $rsp - 120)', False, True)
32
fs_base = gdb.parse_and_eval('*(uint64_t*)($rsp - 120)')
33
gdb.execute('set *(uint64_t*)($rsp - 120) = %s' % old, False, True)
34
return fs_base
35
--
36
2.20.1
37
38
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
nodes[id].next is written by other threads. If atomic_read is not used
3
In several part we still using req->dev or VIRTIO_DEVICE(req->dev)
4
(matching atomic_set in mcs_mutex_lock!) the compiler can optimize the
4
when we have already defined s and vdev pointers:
5
whole "if" away!
5
VirtIOBlock *s = req->dev;
6
VirtIODevice *vdev = VIRTIO_DEVICE(s);
6
7
7
Reported-by: Alex Bennée <alex.bennee@linaro.org>
8
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
8
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Reviewed-by: Liam Merwick <liam.merwick@oracle.com>
9
Tested-by: Greg Kurz <groug@kaod.org>
10
Message-id: 20190208142347.214815-1-sgarzare@redhat.com
10
Message-id: 20170227111726.9237-1-pbonzini@redhat.com
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
11
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
---
12
---
13
tests/test-aio-multithread.c | 4 ++--
13
hw/block/virtio-blk.c | 22 +++++++++-------------
14
1 file changed, 2 insertions(+), 2 deletions(-)
14
1 file changed, 9 insertions(+), 13 deletions(-)
15
15
16
diff --git a/tests/test-aio-multithread.c b/tests/test-aio-multithread.c
16
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
17
index XXXXXXX..XXXXXXX 100644
17
index XXXXXXX..XXXXXXX 100644
18
--- a/tests/test-aio-multithread.c
18
--- a/hw/block/virtio-blk.c
19
+++ b/tests/test-aio-multithread.c
19
+++ b/hw/block/virtio-blk.c
20
@@ -XXX,XX +XXX,XX @@ static void mcs_mutex_lock(void)
20
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
21
static void mcs_mutex_unlock(void)
21
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
22
bool is_read)
22
{
23
{
23
int next;
24
- BlockErrorAction action = blk_get_error_action(req->dev->blk,
24
- if (nodes[id].next == -1) {
25
- is_read, error);
25
+ if (atomic_read(&nodes[id].next) == -1) {
26
VirtIOBlock *s = req->dev;
26
if (atomic_read(&mutex_head) == id &&
27
+ BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
27
atomic_cmpxchg(&mutex_head, id, -1) == id) {
28
28
/* Last item in the list, exit. */
29
if (action == BLOCK_ERROR_ACTION_STOP) {
29
@@ -XXX,XX +XXX,XX @@ static void mcs_mutex_unlock(void)
30
/* Break the link as the next request is going to be parsed from the
31
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_flush_complete(void *opaque, int ret)
30
}
32
}
31
33
32
/* Wake up the next in line. */
34
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
33
- next = nodes[id].next;
35
- block_acct_done(blk_get_stats(req->dev->blk), &req->acct);
34
+ next = atomic_read(&nodes[id].next);
36
+ block_acct_done(blk_get_stats(s->blk), &req->acct);
35
nodes[next].locked = 0;
37
virtio_blk_free_request(req);
36
qemu_futex_wake(&nodes[next].locked, 1);
38
37
}
39
out:
40
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
41
- sizeof(struct virtio_blk_inhdr);
42
iov_discard_back(in_iov, &in_num, sizeof(struct virtio_blk_inhdr));
43
44
- type = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
45
+ type = virtio_ldl_p(vdev, &req->out.type);
46
47
/* VIRTIO_BLK_T_OUT defines the command direction. VIRTIO_BLK_T_BARRIER
48
* is an optional flag. Although a guest should not send this flag if
49
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
50
case VIRTIO_BLK_T_IN:
51
{
52
bool is_write = type & VIRTIO_BLK_T_OUT;
53
- req->sector_num = virtio_ldq_p(VIRTIO_DEVICE(req->dev),
54
- &req->out.sector);
55
+ req->sector_num = virtio_ldq_p(vdev, &req->out.sector);
56
57
if (is_write) {
58
qemu_iovec_init_external(&req->qiov, out_iov, out_num);
59
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
60
req->qiov.size / BDRV_SECTOR_SIZE);
61
}
62
63
- if (!virtio_blk_sect_range_ok(req->dev, req->sector_num,
64
- req->qiov.size)) {
65
+ if (!virtio_blk_sect_range_ok(s, req->sector_num, req->qiov.size)) {
66
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
67
- block_acct_invalid(blk_get_stats(req->dev->blk),
68
+ block_acct_invalid(blk_get_stats(s->blk),
69
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
70
virtio_blk_free_request(req);
71
return 0;
72
}
73
74
- block_acct_start(blk_get_stats(req->dev->blk),
75
- &req->acct, req->qiov.size,
76
+ block_acct_start(blk_get_stats(s->blk), &req->acct, req->qiov.size,
77
is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ);
78
79
/* merge would exceed maximum number of requests or IO direction
80
* changes */
81
if (mrb->num_reqs > 0 && (mrb->num_reqs == VIRTIO_BLK_MAX_MERGE_REQS ||
82
is_write != mrb->is_write ||
83
- !req->dev->conf.request_merging)) {
84
- virtio_blk_submit_multireq(req->dev->blk, mrb);
85
+ !s->conf.request_merging)) {
86
+ virtio_blk_submit_multireq(s->blk, mrb);
87
}
88
89
assert(mrb->num_reqs < VIRTIO_BLK_MAX_MERGE_REQS);
38
--
90
--
39
2.9.3
91
2.20.1
40
92
41
93
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Now that all bottom halves and callbacks take care of taking the
3
We add acct_failed param in order to use virtio_blk_handle_rw_error()
4
AioContext lock, we can migrate some users away from it and to a
4
also when is not required to call block_acct_failed(). (eg. a discard
5
specific QemuMutex or CoMutex.
5
operation is failed)
6
6
7
Protect libiscsi calls with a QemuMutex. Callbacks are invoked
7
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
8
using bottom halves, so we don't even have to drop it around
9
callback invocations.
10
11
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
13
Message-id: 20170222180725.28611-4-pbonzini@redhat.com
10
Acked-by: Pankaj Gupta <pagupta@redhat.com>
11
Message-id: 20190208134950.187665-2-sgarzare@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
13
---
16
block/iscsi.c | 83 +++++++++++++++++++++++++++++++++++++++++++++--------------
14
hw/block/virtio-blk.c | 10 ++++++----
17
1 file changed, 64 insertions(+), 19 deletions(-)
15
1 file changed, 6 insertions(+), 4 deletions(-)
18
16
19
diff --git a/block/iscsi.c b/block/iscsi.c
17
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
20
index XXXXXXX..XXXXXXX 100644
18
index XXXXXXX..XXXXXXX 100644
21
--- a/block/iscsi.c
19
--- a/hw/block/virtio-blk.c
22
+++ b/block/iscsi.c
20
+++ b/hw/block/virtio-blk.c
23
@@ -XXX,XX +XXX,XX @@ typedef struct IscsiLun {
21
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_req_complete(VirtIOBlockReq *req, unsigned char status)
24
int events;
25
QEMUTimer *nop_timer;
26
QEMUTimer *event_timer;
27
+ QemuMutex mutex;
28
struct scsi_inquiry_logical_block_provisioning lbp;
29
struct scsi_inquiry_block_limits bl;
30
unsigned char *zeroblock;
31
@@ -XXX,XX +XXX,XX @@ static int iscsi_translate_sense(struct scsi_sense *sense)
32
return ret;
33
}
22
}
34
23
35
+/* Called (via iscsi_service) with QemuMutex held. */
24
static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
36
static void
25
- bool is_read)
37
iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
26
+ bool is_read, bool acct_failed)
38
void *command_data, void *opaque)
39
@@ -XXX,XX +XXX,XX @@ static const AIOCBInfo iscsi_aiocb_info = {
40
static void iscsi_process_read(void *arg);
41
static void iscsi_process_write(void *arg);
42
43
+/* Called with QemuMutex held. */
44
static void
45
iscsi_set_events(IscsiLun *iscsilun)
46
{
27
{
47
@@ -XXX,XX +XXX,XX @@ iscsi_process_read(void *arg)
28
VirtIOBlock *s = req->dev;
48
IscsiLun *iscsilun = arg;
29
BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
49
struct iscsi_context *iscsi = iscsilun->iscsi;
30
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
50
31
s->rq = req;
51
- aio_context_acquire(iscsilun->aio_context);
32
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
52
+ qemu_mutex_lock(&iscsilun->mutex);
33
virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
53
iscsi_service(iscsi, POLLIN);
34
- block_acct_failed(blk_get_stats(s->blk), &req->acct);
54
iscsi_set_events(iscsilun);
35
+ if (acct_failed) {
55
- aio_context_release(iscsilun->aio_context);
36
+ block_acct_failed(blk_get_stats(s->blk), &req->acct);
56
+ qemu_mutex_unlock(&iscsilun->mutex);
37
+ }
57
}
38
virtio_blk_free_request(req);
58
59
static void
60
@@ -XXX,XX +XXX,XX @@ iscsi_process_write(void *arg)
61
IscsiLun *iscsilun = arg;
62
struct iscsi_context *iscsi = iscsilun->iscsi;
63
64
- aio_context_acquire(iscsilun->aio_context);
65
+ qemu_mutex_lock(&iscsilun->mutex);
66
iscsi_service(iscsi, POLLOUT);
67
iscsi_set_events(iscsilun);
68
- aio_context_release(iscsilun->aio_context);
69
+ qemu_mutex_unlock(&iscsilun->mutex);
70
}
71
72
static int64_t sector_lun2qemu(int64_t sector, IscsiLun *iscsilun)
73
@@ -XXX,XX +XXX,XX @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
74
uint64_t lba;
75
uint32_t num_sectors;
76
bool fua = flags & BDRV_REQ_FUA;
77
+ int r = 0;
78
79
if (fua) {
80
assert(iscsilun->dpofua);
81
@@ -XXX,XX +XXX,XX @@ iscsi_co_writev_flags(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
82
lba = sector_qemu2lun(sector_num, iscsilun);
83
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
84
iscsi_co_init_iscsitask(iscsilun, &iTask);
85
+ qemu_mutex_lock(&iscsilun->mutex);
86
retry:
87
if (iscsilun->use_16_for_rw) {
88
#if LIBISCSI_API_VERSION >= (20160603)
89
@@ -XXX,XX +XXX,XX @@ retry:
90
#endif
91
while (!iTask.complete) {
92
iscsi_set_events(iscsilun);
93
+ qemu_mutex_unlock(&iscsilun->mutex);
94
qemu_coroutine_yield();
95
+ qemu_mutex_lock(&iscsilun->mutex);
96
}
39
}
97
40
98
if (iTask.task != NULL) {
41
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_rw_complete(void *opaque, int ret)
99
@@ -XXX,XX +XXX,XX @@ retry:
42
* the memory until the request is completed (which will
100
43
* happen on the other side of the migration).
101
if (iTask.status != SCSI_STATUS_GOOD) {
44
*/
102
iscsi_allocmap_set_invalid(iscsilun, sector_num, nb_sectors);
45
- if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
103
- return iTask.err_code;
46
+ if (virtio_blk_handle_rw_error(req, -ret, is_read, true)) {
104
+ r = iTask.err_code;
47
continue;
105
+ goto out_unlock;
48
}
106
}
49
}
107
50
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_flush_complete(void *opaque, int ret)
108
iscsi_allocmap_set_allocated(iscsilun, sector_num, nb_sectors);
51
109
52
aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
110
- return 0;
53
if (ret) {
111
+out_unlock:
54
- if (virtio_blk_handle_rw_error(req, -ret, 0)) {
112
+ qemu_mutex_unlock(&iscsilun->mutex);
55
+ if (virtio_blk_handle_rw_error(req, -ret, 0, true)) {
113
+ return r;
56
goto out;
114
}
115
116
117
@@ -XXX,XX +XXX,XX @@ static int64_t coroutine_fn iscsi_co_get_block_status(BlockDriverState *bs,
118
goto out;
119
}
120
121
+ qemu_mutex_lock(&iscsilun->mutex);
122
retry:
123
if (iscsi_get_lba_status_task(iscsilun->iscsi, iscsilun->lun,
124
sector_qemu2lun(sector_num, iscsilun),
125
8 + 16, iscsi_co_generic_cb,
126
&iTask) == NULL) {
127
ret = -ENOMEM;
128
- goto out;
129
+ goto out_unlock;
130
}
131
132
while (!iTask.complete) {
133
iscsi_set_events(iscsilun);
134
+ qemu_mutex_unlock(&iscsilun->mutex);
135
qemu_coroutine_yield();
136
+ qemu_mutex_lock(&iscsilun->mutex);
137
}
138
139
if (iTask.do_retry) {
140
@@ -XXX,XX +XXX,XX @@ retry:
141
* because the device is busy or the cmd is not
142
* supported) we pretend all blocks are allocated
143
* for backwards compatibility */
144
- goto out;
145
+ goto out_unlock;
146
}
147
148
lbas = scsi_datain_unmarshall(iTask.task);
149
if (lbas == NULL) {
150
ret = -EIO;
151
- goto out;
152
+ goto out_unlock;
153
}
154
155
lbasd = &lbas->descriptors[0];
156
157
if (sector_qemu2lun(sector_num, iscsilun) != lbasd->lba) {
158
ret = -EIO;
159
- goto out;
160
+ goto out_unlock;
161
}
162
163
*pnum = sector_lun2qemu(lbasd->num_blocks, iscsilun);
164
@@ -XXX,XX +XXX,XX @@ retry:
165
if (*pnum > nb_sectors) {
166
*pnum = nb_sectors;
167
}
168
+out_unlock:
169
+ qemu_mutex_unlock(&iscsilun->mutex);
170
out:
171
if (iTask.task != NULL) {
172
scsi_free_scsi_task(iTask.task);
173
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn iscsi_co_readv(BlockDriverState *bs,
174
num_sectors = sector_qemu2lun(nb_sectors, iscsilun);
175
176
iscsi_co_init_iscsitask(iscsilun, &iTask);
177
+ qemu_mutex_lock(&iscsilun->mutex);
178
retry:
179
if (iscsilun->use_16_for_rw) {
180
#if LIBISCSI_API_VERSION >= (20160603)
181
@@ -XXX,XX +XXX,XX @@ retry:
182
#endif
183
while (!iTask.complete) {
184
iscsi_set_events(iscsilun);
185
+ qemu_mutex_unlock(&iscsilun->mutex);
186
qemu_coroutine_yield();
187
+ qemu_mutex_lock(&iscsilun->mutex);
188
}
189
190
if (iTask.task != NULL) {
191
@@ -XXX,XX +XXX,XX @@ retry:
192
iTask.complete = 0;
193
goto retry;
194
}
195
+ qemu_mutex_unlock(&iscsilun->mutex);
196
197
if (iTask.status != SCSI_STATUS_GOOD) {
198
return iTask.err_code;
199
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn iscsi_co_flush(BlockDriverState *bs)
200
struct IscsiTask iTask;
201
202
iscsi_co_init_iscsitask(iscsilun, &iTask);
203
+ qemu_mutex_lock(&iscsilun->mutex);
204
retry:
205
if (iscsi_synchronizecache10_task(iscsilun->iscsi, iscsilun->lun, 0, 0, 0,
206
0, iscsi_co_generic_cb, &iTask) == NULL) {
207
@@ -XXX,XX +XXX,XX @@ retry:
208
209
while (!iTask.complete) {
210
iscsi_set_events(iscsilun);
211
+ qemu_mutex_unlock(&iscsilun->mutex);
212
qemu_coroutine_yield();
213
+ qemu_mutex_lock(&iscsilun->mutex);
214
}
215
216
if (iTask.task != NULL) {
217
@@ -XXX,XX +XXX,XX @@ retry:
218
iTask.complete = 0;
219
goto retry;
220
}
221
+ qemu_mutex_unlock(&iscsilun->mutex);
222
223
if (iTask.status != SCSI_STATUS_GOOD) {
224
return iTask.err_code;
225
@@ -XXX,XX +XXX,XX @@ retry:
226
}
227
228
#ifdef __linux__
229
+/* Called (via iscsi_service) with QemuMutex held. */
230
static void
231
iscsi_aio_ioctl_cb(struct iscsi_context *iscsi, int status,
232
void *command_data, void *opaque)
233
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
234
acb->task->expxferlen = acb->ioh->dxfer_len;
235
236
data.size = 0;
237
+ qemu_mutex_lock(&iscsilun->mutex);
238
if (acb->task->xfer_dir == SCSI_XFER_WRITE) {
239
if (acb->ioh->iovec_count == 0) {
240
data.data = acb->ioh->dxferp;
241
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
242
iscsi_aio_ioctl_cb,
243
(data.size > 0) ? &data : NULL,
244
acb) != 0) {
245
+ qemu_mutex_unlock(&iscsilun->mutex);
246
scsi_free_scsi_task(acb->task);
247
qemu_aio_unref(acb);
248
return NULL;
249
@@ -XXX,XX +XXX,XX @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs,
250
}
251
252
iscsi_set_events(iscsilun);
253
+ qemu_mutex_unlock(&iscsilun->mutex);
254
255
return &acb->common;
256
}
257
@@ -XXX,XX +XXX,XX @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
258
IscsiLun *iscsilun = bs->opaque;
259
struct IscsiTask iTask;
260
struct unmap_list list;
261
+ int r = 0;
262
263
if (!is_byte_request_lun_aligned(offset, count, iscsilun)) {
264
return -ENOTSUP;
265
@@ -XXX,XX +XXX,XX @@ coroutine_fn iscsi_co_pdiscard(BlockDriverState *bs, int64_t offset, int count)
266
list.num = count / iscsilun->block_size;
267
268
iscsi_co_init_iscsitask(iscsilun, &iTask);
269
+ qemu_mutex_lock(&iscsilun->mutex);
270
retry:
271
if (iscsi_unmap_task(iscsilun->iscsi, iscsilun->lun, 0, 0, &list, 1,
272
iscsi_co_generic_cb, &iTask) == NULL) {
273
- return -ENOMEM;
274
+ r = -ENOMEM;
275
+ goto out_unlock;
276
}
277
278
while (!iTask.complete) {
279
iscsi_set_events(iscsilun);
280
+ qemu_mutex_unlock(&iscsilun->mutex);
281
qemu_coroutine_yield();
282
+ qemu_mutex_lock(&iscsilun->mutex);
283
}
284
285
if (iTask.task != NULL) {
286
@@ -XXX,XX +XXX,XX @@ retry:
287
/* the target might fail with a check condition if it
288
is not happy with the alignment of the UNMAP request
289
we silently fail in this case */
290
- return 0;
291
+ goto out_unlock;
292
}
293
294
if (iTask.status != SCSI_STATUS_GOOD) {
295
- return iTask.err_code;
296
+ r = iTask.err_code;
297
+ goto out_unlock;
298
}
299
300
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
301
count >> BDRV_SECTOR_BITS);
302
303
- return 0;
304
+out_unlock:
305
+ qemu_mutex_unlock(&iscsilun->mutex);
306
+ return r;
307
}
308
309
static int
310
@@ -XXX,XX +XXX,XX @@ coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
311
uint64_t lba;
312
uint32_t nb_blocks;
313
bool use_16_for_ws = iscsilun->use_16_for_rw;
314
+ int r = 0;
315
316
if (!is_byte_request_lun_aligned(offset, count, iscsilun)) {
317
return -ENOTSUP;
318
@@ -XXX,XX +XXX,XX @@ coroutine_fn iscsi_co_pwrite_zeroes(BlockDriverState *bs, int64_t offset,
319
}
57
}
320
}
58
}
321
322
+ qemu_mutex_lock(&iscsilun->mutex);
323
iscsi_co_init_iscsitask(iscsilun, &iTask);
324
retry:
325
if (use_16_for_ws) {
326
@@ -XXX,XX +XXX,XX @@ retry:
327
328
while (!iTask.complete) {
329
iscsi_set_events(iscsilun);
330
+ qemu_mutex_unlock(&iscsilun->mutex);
331
qemu_coroutine_yield();
332
+ qemu_mutex_lock(&iscsilun->mutex);
333
}
334
335
if (iTask.status == SCSI_STATUS_CHECK_CONDITION &&
336
@@ -XXX,XX +XXX,XX @@ retry:
337
/* WRITE SAME is not supported by the target */
338
iscsilun->has_write_same = false;
339
scsi_free_scsi_task(iTask.task);
340
- return -ENOTSUP;
341
+ r = -ENOTSUP;
342
+ goto out_unlock;
343
}
344
345
if (iTask.task != NULL) {
346
@@ -XXX,XX +XXX,XX @@ retry:
347
if (iTask.status != SCSI_STATUS_GOOD) {
348
iscsi_allocmap_set_invalid(iscsilun, offset >> BDRV_SECTOR_BITS,
349
count >> BDRV_SECTOR_BITS);
350
- return iTask.err_code;
351
+ r = iTask.err_code;
352
+ goto out_unlock;
353
}
354
355
if (flags & BDRV_REQ_MAY_UNMAP) {
356
@@ -XXX,XX +XXX,XX @@ retry:
357
count >> BDRV_SECTOR_BITS);
358
}
359
360
- return 0;
361
+out_unlock:
362
+ qemu_mutex_unlock(&iscsilun->mutex);
363
+ return r;
364
}
365
366
static void apply_chap(struct iscsi_context *iscsi, QemuOpts *opts,
367
@@ -XXX,XX +XXX,XX @@ static void iscsi_nop_timed_event(void *opaque)
368
{
369
IscsiLun *iscsilun = opaque;
370
371
- aio_context_acquire(iscsilun->aio_context);
372
+ qemu_mutex_lock(&iscsilun->mutex);
373
if (iscsi_get_nops_in_flight(iscsilun->iscsi) >= MAX_NOP_FAILURES) {
374
error_report("iSCSI: NOP timeout. Reconnecting...");
375
iscsilun->request_timed_out = true;
376
@@ -XXX,XX +XXX,XX @@ static void iscsi_nop_timed_event(void *opaque)
377
iscsi_set_events(iscsilun);
378
379
out:
380
- aio_context_release(iscsilun->aio_context);
381
+ qemu_mutex_unlock(&iscsilun->mutex);
382
}
383
384
static void iscsi_readcapacity_sync(IscsiLun *iscsilun, Error **errp)
385
@@ -XXX,XX +XXX,XX @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
386
scsi_free_scsi_task(task);
387
task = NULL;
388
389
+ qemu_mutex_init(&iscsilun->mutex);
390
iscsi_attach_aio_context(bs, iscsilun->aio_context);
391
392
/* Guess the internal cluster (page) size of the iscsi target by the means
393
@@ -XXX,XX +XXX,XX @@ static void iscsi_close(BlockDriverState *bs)
394
iscsi_destroy_context(iscsi);
395
g_free(iscsilun->zeroblock);
396
iscsi_allocmap_free(iscsilun);
397
+ qemu_mutex_destroy(&iscsilun->mutex);
398
memset(iscsilun, 0, sizeof(IscsiLun));
399
}
400
401
--
59
--
402
2.9.3
60
2.20.1
403
61
404
62
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Now that all bottom halves and callbacks take care of taking the
3
Since configurable features for virtio-blk are growing, this patch
4
AioContext lock, we can migrate some users away from it and to a
4
adds host_features field in the struct VirtIOBlock. (as in virtio-net)
5
specific QemuMutex or CoMutex.
5
In this way, we can avoid to add new fields for new properties and
6
we can directly set VIRTIO_BLK_F* flags in the host_features.
6
7
7
Protect libnfs calls with a QemuMutex. Callbacks are invoked
8
We update "config-wce" and "scsi" property definition to use the new
8
using bottom halves, so we don't even have to drop it around
9
host_features field without change the behaviour.
9
callback invocations.
10
10
11
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
11
Suggested-by: Michael S. Tsirkin <mst@redhat.com>
12
Message-id: 20170222180725.28611-3-pbonzini@redhat.com
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
13
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
14
Acked-by: Pankaj Gupta <pagupta@redhat.com>
15
Message-id: 20190208134950.187665-3-sgarzare@redhat.com
13
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
14
---
17
---
15
block/nfs.c | 23 +++++++++++++++++++----
18
include/hw/virtio/virtio-blk.h | 3 +--
16
1 file changed, 19 insertions(+), 4 deletions(-)
19
hw/block/virtio-blk.c | 16 +++++++++-------
20
2 files changed, 10 insertions(+), 9 deletions(-)
17
21
18
diff --git a/block/nfs.c b/block/nfs.c
22
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
19
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
20
--- a/block/nfs.c
24
--- a/include/hw/virtio/virtio-blk.h
21
+++ b/block/nfs.c
25
+++ b/include/hw/virtio/virtio-blk.h
22
@@ -XXX,XX +XXX,XX @@ typedef struct NFSClient {
26
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
23
int events;
27
BlockConf conf;
24
bool has_zero_init;
28
IOThread *iothread;
25
AioContext *aio_context;
29
char *serial;
26
+ QemuMutex mutex;
30
- uint32_t scsi;
27
blkcnt_t st_blocks;
31
- uint32_t config_wce;
28
bool cache_used;
32
uint32_t request_merging;
29
NFSServer *server;
33
uint16_t num_queues;
30
@@ -XXX,XX +XXX,XX @@ static void nfs_parse_filename(const char *filename, QDict *options,
34
uint16_t queue_size;
31
static void nfs_process_read(void *arg);
35
@@ -XXX,XX +XXX,XX @@ typedef struct VirtIOBlock {
32
static void nfs_process_write(void *arg);
36
bool dataplane_disabled;
33
37
bool dataplane_started;
34
+/* Called with QemuMutex held. */
38
struct VirtIOBlockDataPlane *dataplane;
35
static void nfs_set_events(NFSClient *client)
39
+ uint64_t host_features;
40
} VirtIOBlock;
41
42
typedef struct VirtIOBlockReq {
43
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
44
index XXXXXXX..XXXXXXX 100644
45
--- a/hw/block/virtio-blk.c
46
+++ b/hw/block/virtio-blk.c
47
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
48
*/
49
scsi = (void *)elem->in_sg[elem->in_num - 2].iov_base;
50
51
- if (!blk->conf.scsi) {
52
+ if (!virtio_has_feature(blk->host_features, VIRTIO_BLK_F_SCSI)) {
53
status = VIRTIO_BLK_S_UNSUPP;
54
goto fail;
55
}
56
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
36
{
57
{
37
int ev = nfs_which_events(client->context);
58
VirtIOBlock *s = VIRTIO_BLK(vdev);
38
@@ -XXX,XX +XXX,XX @@ static void nfs_process_read(void *arg)
59
39
{
60
+ /* Firstly sync all virtio-blk possible supported features */
40
NFSClient *client = arg;
61
+ features |= s->host_features;
41
62
+
42
- aio_context_acquire(client->aio_context);
63
virtio_add_feature(&features, VIRTIO_BLK_F_SEG_MAX);
43
+ qemu_mutex_lock(&client->mutex);
64
virtio_add_feature(&features, VIRTIO_BLK_F_GEOMETRY);
44
nfs_service(client->context, POLLIN);
65
virtio_add_feature(&features, VIRTIO_BLK_F_TOPOLOGY);
45
nfs_set_events(client);
66
virtio_add_feature(&features, VIRTIO_BLK_F_BLK_SIZE);
46
- aio_context_release(client->aio_context);
67
if (virtio_has_feature(features, VIRTIO_F_VERSION_1)) {
47
+ qemu_mutex_unlock(&client->mutex);
68
- if (s->conf.scsi) {
48
}
69
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_SCSI)) {
49
70
error_setg(errp, "Please set scsi=off for virtio-blk devices in order to use virtio 1.0");
50
static void nfs_process_write(void *arg)
71
return 0;
51
{
72
}
52
NFSClient *client = arg;
73
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_get_features(VirtIODevice *vdev, uint64_t features,
53
74
virtio_add_feature(&features, VIRTIO_BLK_F_SCSI);
54
- aio_context_acquire(client->aio_context);
55
+ qemu_mutex_lock(&client->mutex);
56
nfs_service(client->context, POLLOUT);
57
nfs_set_events(client);
58
- aio_context_release(client->aio_context);
59
+ qemu_mutex_unlock(&client->mutex);
60
}
61
62
static void nfs_co_init_task(BlockDriverState *bs, NFSRPC *task)
63
@@ -XXX,XX +XXX,XX @@ static void nfs_co_generic_bh_cb(void *opaque)
64
aio_co_wake(task->co);
65
}
66
67
+/* Called (via nfs_service) with QemuMutex held. */
68
static void
69
nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
70
void *private_data)
71
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_preadv(BlockDriverState *bs, uint64_t offset,
72
nfs_co_init_task(bs, &task);
73
task.iov = iov;
74
75
+ qemu_mutex_lock(&client->mutex);
76
if (nfs_pread_async(client->context, client->fh,
77
offset, bytes, nfs_co_generic_cb, &task) != 0) {
78
+ qemu_mutex_unlock(&client->mutex);
79
return -ENOMEM;
80
}
75
}
81
76
82
nfs_set_events(client);
77
- if (s->conf.config_wce) {
83
+ qemu_mutex_unlock(&client->mutex);
78
- virtio_add_feature(&features, VIRTIO_BLK_F_CONFIG_WCE);
84
while (!task.complete) {
79
- }
85
qemu_coroutine_yield();
80
if (blk_enable_write_cache(s->blk)) {
81
virtio_add_feature(&features, VIRTIO_BLK_F_WCE);
86
}
82
}
87
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
83
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
88
buf = iov->iov[0].iov_base;
84
DEFINE_BLOCK_ERROR_PROPERTIES(VirtIOBlock, conf.conf),
89
}
85
DEFINE_BLOCK_CHS_PROPERTIES(VirtIOBlock, conf.conf),
90
86
DEFINE_PROP_STRING("serial", VirtIOBlock, conf.serial),
91
+ qemu_mutex_lock(&client->mutex);
87
- DEFINE_PROP_BIT("config-wce", VirtIOBlock, conf.config_wce, 0, true),
92
if (nfs_pwrite_async(client->context, client->fh,
88
+ DEFINE_PROP_BIT64("config-wce", VirtIOBlock, host_features,
93
offset, bytes, buf,
89
+ VIRTIO_BLK_F_CONFIG_WCE, true),
94
nfs_co_generic_cb, &task) != 0) {
90
#ifdef __linux__
95
+ qemu_mutex_unlock(&client->mutex);
91
- DEFINE_PROP_BIT("scsi", VirtIOBlock, conf.scsi, 0, false),
96
if (my_buffer) {
92
+ DEFINE_PROP_BIT64("scsi", VirtIOBlock, host_features,
97
g_free(buf);
93
+ VIRTIO_BLK_F_SCSI, false),
98
}
94
#endif
99
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_pwritev(BlockDriverState *bs, uint64_t offset,
95
DEFINE_PROP_BIT("request-merging", VirtIOBlock, conf.request_merging, 0,
100
}
96
true),
101
102
nfs_set_events(client);
103
+ qemu_mutex_unlock(&client->mutex);
104
while (!task.complete) {
105
qemu_coroutine_yield();
106
}
107
@@ -XXX,XX +XXX,XX @@ static int coroutine_fn nfs_co_flush(BlockDriverState *bs)
108
109
nfs_co_init_task(bs, &task);
110
111
+ qemu_mutex_lock(&client->mutex);
112
if (nfs_fsync_async(client->context, client->fh, nfs_co_generic_cb,
113
&task) != 0) {
114
+ qemu_mutex_unlock(&client->mutex);
115
return -ENOMEM;
116
}
117
118
nfs_set_events(client);
119
+ qemu_mutex_unlock(&client->mutex);
120
while (!task.complete) {
121
qemu_coroutine_yield();
122
}
123
@@ -XXX,XX +XXX,XX @@ static void nfs_file_close(BlockDriverState *bs)
124
{
125
NFSClient *client = bs->opaque;
126
nfs_client_close(client);
127
+ qemu_mutex_destroy(&client->mutex);
128
}
129
130
static NFSServer *nfs_config(QDict *options, Error **errp)
131
@@ -XXX,XX +XXX,XX @@ static int nfs_file_open(BlockDriverState *bs, QDict *options, int flags,
132
if (ret < 0) {
133
return ret;
134
}
135
+ qemu_mutex_init(&client->mutex);
136
bs->total_sectors = ret;
137
ret = 0;
138
return ret;
139
@@ -XXX,XX +XXX,XX @@ static int nfs_has_zero_init(BlockDriverState *bs)
140
return client->has_zero_init;
141
}
142
143
+/* Called (via nfs_service) with QemuMutex held. */
144
static void
145
nfs_get_allocated_file_size_cb(int ret, struct nfs_context *nfs, void *data,
146
void *private_data)
147
--
97
--
148
2.9.3
98
2.20.1
149
99
150
100
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
In order to avoid migration issues, we enable DISCARD and
4
WRITE_ZEROES features only for machine type >= 4.0
5
6
As discussed with Michael S. Tsirkin and Stefan Hajnoczi on the
7
list [1], DISCARD operation should not have security implications
8
(eg. page cache attacks), so we can enable it by default.
9
10
[1] https://lists.gnu.org/archive/html/qemu-devel/2019-02/msg00504.html
11
12
Suggested-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
13
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
14
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
15
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
16
Acked-by: Pankaj Gupta <pagupta@redhat.com>
17
Message-id: 20190208134950.187665-4-sgarzare@redhat.com
18
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
19
---
20
hw/block/virtio-blk.c | 4 ++++
21
hw/core/machine.c | 2 ++
22
2 files changed, 6 insertions(+)
23
24
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
25
index XXXXXXX..XXXXXXX 100644
26
--- a/hw/block/virtio-blk.c
27
+++ b/hw/block/virtio-blk.c
28
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
29
DEFINE_PROP_UINT16("queue-size", VirtIOBlock, conf.queue_size, 128),
30
DEFINE_PROP_LINK("iothread", VirtIOBlock, conf.iothread, TYPE_IOTHREAD,
31
IOThread *),
32
+ DEFINE_PROP_BIT64("discard", VirtIOBlock, host_features,
33
+ VIRTIO_BLK_F_DISCARD, true),
34
+ DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
35
+ VIRTIO_BLK_F_WRITE_ZEROES, true),
36
DEFINE_PROP_END_OF_LIST(),
37
};
38
39
diff --git a/hw/core/machine.c b/hw/core/machine.c
40
index XXXXXXX..XXXXXXX 100644
41
--- a/hw/core/machine.c
42
+++ b/hw/core/machine.c
43
@@ -XXX,XX +XXX,XX @@ GlobalProperty hw_compat_3_1[] = {
44
{ "usb-kbd", "serial", "42" },
45
{ "usb-mouse", "serial", "42" },
46
{ "usb-kbd", "serial", "42" },
47
+ { "virtio-blk-device", "discard", "false" },
48
+ { "virtio-blk-device", "write-zeroes", "false" },
49
};
50
const size_t hw_compat_3_1_len = G_N_ELEMENTS(hw_compat_3_1);
51
52
--
53
2.20.1
54
55
diff view generated by jsdifflib
1
From: Paolo Bonzini <pbonzini@redhat.com>
1
From: Stefano Garzarella <sgarzare@redhat.com>
2
2
3
Now that all bottom halves and callbacks take care of taking the
3
This patch adds the support of DISCARD and WRITE_ZEROES commands,
4
AioContext lock, we can migrate some users away from it and to a
4
that have been introduced in the virtio-blk protocol to have
5
specific QemuMutex or CoMutex.
5
better performance when using SSD backend.
6
6
7
Protect BDRVCURLState access with a QemuMutex.
7
We support only one segment per request since multiple segments
8
8
are not widely used and there are no userspace APIs that allow
9
applications to submit multiple segments in a single call.
10
11
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
12
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
13
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
11
Message-id: 20170222180725.28611-2-pbonzini@redhat.com
14
Acked-by: Pankaj Gupta <pagupta@redhat.com>
15
Message-id: 20190208134950.187665-5-sgarzare@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
16
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
17
---
14
block/curl.c | 24 +++++++++++++++---------
18
include/hw/virtio/virtio-blk.h | 2 +
15
1 file changed, 15 insertions(+), 9 deletions(-)
19
hw/block/virtio-blk.c | 184 +++++++++++++++++++++++++++++++++
16
20
2 files changed, 186 insertions(+)
17
diff --git a/block/curl.c b/block/curl.c
21
22
diff --git a/include/hw/virtio/virtio-blk.h b/include/hw/virtio/virtio-blk.h
18
index XXXXXXX..XXXXXXX 100644
23
index XXXXXXX..XXXXXXX 100644
19
--- a/block/curl.c
24
--- a/include/hw/virtio/virtio-blk.h
20
+++ b/block/curl.c
25
+++ b/include/hw/virtio/virtio-blk.h
21
@@ -XXX,XX +XXX,XX @@ typedef struct BDRVCURLState {
26
@@ -XXX,XX +XXX,XX @@ struct VirtIOBlkConf
22
char *cookie;
27
uint32_t request_merging;
23
bool accept_range;
28
uint16_t num_queues;
24
AioContext *aio_context;
29
uint16_t queue_size;
25
+ QemuMutex mutex;
30
+ uint32_t max_discard_sectors;
26
char *username;
31
+ uint32_t max_write_zeroes_sectors;
27
char *password;
32
};
28
char *proxyusername;
33
29
@@ -XXX,XX +XXX,XX @@ static int curl_find_buf(BDRVCURLState *s, size_t start, size_t len,
34
struct VirtIOBlockDataPlane;
30
return FIND_RET_NONE;
35
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
36
index XXXXXXX..XXXXXXX 100644
37
--- a/hw/block/virtio-blk.c
38
+++ b/hw/block/virtio-blk.c
39
@@ -XXX,XX +XXX,XX @@ out:
40
aio_context_release(blk_get_aio_context(s->conf.conf.blk));
31
}
41
}
32
42
33
+/* Called with s->mutex held. */
43
+static void virtio_blk_discard_write_zeroes_complete(void *opaque, int ret)
34
static void curl_multi_check_completion(BDRVCURLState *s)
44
+{
45
+ VirtIOBlockReq *req = opaque;
46
+ VirtIOBlock *s = req->dev;
47
+ bool is_write_zeroes = (virtio_ldl_p(VIRTIO_DEVICE(s), &req->out.type) &
48
+ ~VIRTIO_BLK_T_BARRIER) == VIRTIO_BLK_T_WRITE_ZEROES;
49
+
50
+ aio_context_acquire(blk_get_aio_context(s->conf.conf.blk));
51
+ if (ret) {
52
+ if (virtio_blk_handle_rw_error(req, -ret, false, is_write_zeroes)) {
53
+ goto out;
54
+ }
55
+ }
56
+
57
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
58
+ if (is_write_zeroes) {
59
+ block_acct_done(blk_get_stats(s->blk), &req->acct);
60
+ }
61
+ virtio_blk_free_request(req);
62
+
63
+out:
64
+ aio_context_release(blk_get_aio_context(s->conf.conf.blk));
65
+}
66
+
67
#ifdef __linux__
68
69
typedef struct {
70
@@ -XXX,XX +XXX,XX @@ static bool virtio_blk_sect_range_ok(VirtIOBlock *dev,
71
return true;
72
}
73
74
+static uint8_t virtio_blk_handle_discard_write_zeroes(VirtIOBlockReq *req,
75
+ struct virtio_blk_discard_write_zeroes *dwz_hdr, bool is_write_zeroes)
76
+{
77
+ VirtIOBlock *s = req->dev;
78
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
79
+ uint64_t sector;
80
+ uint32_t num_sectors, flags, max_sectors;
81
+ uint8_t err_status;
82
+ int bytes;
83
+
84
+ sector = virtio_ldq_p(vdev, &dwz_hdr->sector);
85
+ num_sectors = virtio_ldl_p(vdev, &dwz_hdr->num_sectors);
86
+ flags = virtio_ldl_p(vdev, &dwz_hdr->flags);
87
+ max_sectors = is_write_zeroes ? s->conf.max_write_zeroes_sectors :
88
+ s->conf.max_discard_sectors;
89
+
90
+ /*
91
+ * max_sectors is at most BDRV_REQUEST_MAX_SECTORS, this check
92
+ * make us sure that "num_sectors << BDRV_SECTOR_BITS" can fit in
93
+ * the integer variable.
94
+ */
95
+ if (unlikely(num_sectors > max_sectors)) {
96
+ err_status = VIRTIO_BLK_S_IOERR;
97
+ goto err;
98
+ }
99
+
100
+ bytes = num_sectors << BDRV_SECTOR_BITS;
101
+
102
+ if (unlikely(!virtio_blk_sect_range_ok(s, sector, bytes))) {
103
+ err_status = VIRTIO_BLK_S_IOERR;
104
+ goto err;
105
+ }
106
+
107
+ /*
108
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for discard
109
+ * and write zeroes commands if any unknown flag is set.
110
+ */
111
+ if (unlikely(flags & ~VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
112
+ err_status = VIRTIO_BLK_S_UNSUPP;
113
+ goto err;
114
+ }
115
+
116
+ if (is_write_zeroes) { /* VIRTIO_BLK_T_WRITE_ZEROES */
117
+ int blk_aio_flags = 0;
118
+
119
+ if (flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP) {
120
+ blk_aio_flags |= BDRV_REQ_MAY_UNMAP;
121
+ }
122
+
123
+ block_acct_start(blk_get_stats(s->blk), &req->acct, bytes,
124
+ BLOCK_ACCT_WRITE);
125
+
126
+ blk_aio_pwrite_zeroes(s->blk, sector << BDRV_SECTOR_BITS,
127
+ bytes, blk_aio_flags,
128
+ virtio_blk_discard_write_zeroes_complete, req);
129
+ } else { /* VIRTIO_BLK_T_DISCARD */
130
+ /*
131
+ * The device MUST set the status byte to VIRTIO_BLK_S_UNSUPP for
132
+ * discard commands if the unmap flag is set.
133
+ */
134
+ if (unlikely(flags & VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP)) {
135
+ err_status = VIRTIO_BLK_S_UNSUPP;
136
+ goto err;
137
+ }
138
+
139
+ blk_aio_pdiscard(s->blk, sector << BDRV_SECTOR_BITS, bytes,
140
+ virtio_blk_discard_write_zeroes_complete, req);
141
+ }
142
+
143
+ return VIRTIO_BLK_S_OK;
144
+
145
+err:
146
+ if (is_write_zeroes) {
147
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_WRITE);
148
+ }
149
+ return err_status;
150
+}
151
+
152
static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
35
{
153
{
36
int msgs_in_queue;
154
uint32_t type;
37
@@ -XXX,XX +XXX,XX @@ static void curl_multi_check_completion(BDRVCURLState *s)
155
@@ -XXX,XX +XXX,XX @@ static int virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
38
continue;
156
virtio_blk_free_request(req);
39
}
157
break;
40
41
+ qemu_mutex_unlock(&s->mutex);
42
acb->common.cb(acb->common.opaque, -EPROTO);
43
+ qemu_mutex_lock(&s->mutex);
44
qemu_aio_unref(acb);
45
state->acb[i] = NULL;
46
}
47
@@ -XXX,XX +XXX,XX @@ static void curl_multi_check_completion(BDRVCURLState *s)
48
}
158
}
159
+ /*
160
+ * VIRTIO_BLK_T_DISCARD and VIRTIO_BLK_T_WRITE_ZEROES are defined with
161
+ * VIRTIO_BLK_T_OUT flag set. We masked this flag in the switch statement,
162
+ * so we must mask it for these requests, then we will check if it is set.
163
+ */
164
+ case VIRTIO_BLK_T_DISCARD & ~VIRTIO_BLK_T_OUT:
165
+ case VIRTIO_BLK_T_WRITE_ZEROES & ~VIRTIO_BLK_T_OUT:
166
+ {
167
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
168
+ size_t out_len = iov_size(out_iov, out_num);
169
+ bool is_write_zeroes = (type & ~VIRTIO_BLK_T_BARRIER) ==
170
+ VIRTIO_BLK_T_WRITE_ZEROES;
171
+ uint8_t err_status;
172
+
173
+ /*
174
+ * Unsupported if VIRTIO_BLK_T_OUT is not set or the request contains
175
+ * more than one segment.
176
+ */
177
+ if (unlikely(!(type & VIRTIO_BLK_T_OUT) ||
178
+ out_len > sizeof(dwz_hdr))) {
179
+ virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
180
+ virtio_blk_free_request(req);
181
+ return 0;
182
+ }
183
+
184
+ if (unlikely(iov_to_buf(out_iov, out_num, 0, &dwz_hdr,
185
+ sizeof(dwz_hdr)) != sizeof(dwz_hdr))) {
186
+ virtio_error(vdev, "virtio-blk discard/write_zeroes header"
187
+ " too short");
188
+ return -1;
189
+ }
190
+
191
+ err_status = virtio_blk_handle_discard_write_zeroes(req, &dwz_hdr,
192
+ is_write_zeroes);
193
+ if (err_status != VIRTIO_BLK_S_OK) {
194
+ virtio_blk_req_complete(req, err_status);
195
+ virtio_blk_free_request(req);
196
+ }
197
+
198
+ break;
199
+ }
200
default:
201
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
202
virtio_blk_free_request(req);
203
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
204
blkcfg.alignment_offset = 0;
205
blkcfg.wce = blk_enable_write_cache(s->blk);
206
virtio_stw_p(vdev, &blkcfg.num_queues, s->conf.num_queues);
207
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD)) {
208
+ virtio_stl_p(vdev, &blkcfg.max_discard_sectors,
209
+ s->conf.max_discard_sectors);
210
+ virtio_stl_p(vdev, &blkcfg.discard_sector_alignment,
211
+ blk_size >> BDRV_SECTOR_BITS);
212
+ /*
213
+ * We support only one segment per request since multiple segments
214
+ * are not widely used and there are no userspace APIs that allow
215
+ * applications to submit multiple segments in a single call.
216
+ */
217
+ virtio_stl_p(vdev, &blkcfg.max_discard_seg, 1);
218
+ }
219
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES)) {
220
+ virtio_stl_p(vdev, &blkcfg.max_write_zeroes_sectors,
221
+ s->conf.max_write_zeroes_sectors);
222
+ blkcfg.write_zeroes_may_unmap = 1;
223
+ virtio_stl_p(vdev, &blkcfg.max_write_zeroes_seg, 1);
224
+ }
225
memcpy(config, &blkcfg, sizeof(struct virtio_blk_config));
49
}
226
}
50
227
51
+/* Called with s->mutex held. */
228
@@ -XXX,XX +XXX,XX @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
52
static void curl_multi_do_locked(CURLState *s)
53
{
54
CURLSocket *socket, *next_socket;
55
@@ -XXX,XX +XXX,XX @@ static void curl_multi_do(void *arg)
56
{
57
CURLState *s = (CURLState *)arg;
58
59
- aio_context_acquire(s->s->aio_context);
60
+ qemu_mutex_lock(&s->s->mutex);
61
curl_multi_do_locked(s);
62
- aio_context_release(s->s->aio_context);
63
+ qemu_mutex_unlock(&s->s->mutex);
64
}
65
66
static void curl_multi_read(void *arg)
67
{
68
CURLState *s = (CURLState *)arg;
69
70
- aio_context_acquire(s->s->aio_context);
71
+ qemu_mutex_lock(&s->s->mutex);
72
curl_multi_do_locked(s);
73
curl_multi_check_completion(s->s);
74
- aio_context_release(s->s->aio_context);
75
+ qemu_mutex_unlock(&s->s->mutex);
76
}
77
78
static void curl_multi_timeout_do(void *arg)
79
@@ -XXX,XX +XXX,XX @@ static void curl_multi_timeout_do(void *arg)
80
return;
229
return;
81
}
230
}
82
231
83
- aio_context_acquire(s->aio_context);
232
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_DISCARD) &&
84
+ qemu_mutex_lock(&s->mutex);
233
+ (!conf->max_discard_sectors ||
85
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
234
+ conf->max_discard_sectors > BDRV_REQUEST_MAX_SECTORS)) {
86
235
+ error_setg(errp, "invalid max-discard-sectors property (%" PRIu32 ")"
87
curl_multi_check_completion(s);
236
+ ", must be between 1 and %d",
88
- aio_context_release(s->aio_context);
237
+ conf->max_discard_sectors, (int)BDRV_REQUEST_MAX_SECTORS);
89
+ qemu_mutex_unlock(&s->mutex);
238
+ return;
90
#else
239
+ }
91
abort();
240
+
92
#endif
241
+ if (virtio_has_feature(s->host_features, VIRTIO_BLK_F_WRITE_ZEROES) &&
93
@@ -XXX,XX +XXX,XX @@ static int curl_open(BlockDriverState *bs, QDict *options, int flags,
242
+ (!conf->max_write_zeroes_sectors ||
94
curl_easy_cleanup(state->curl);
243
+ conf->max_write_zeroes_sectors > BDRV_REQUEST_MAX_SECTORS)) {
95
state->curl = NULL;
244
+ error_setg(errp, "invalid max-write-zeroes-sectors property (%" PRIu32
96
245
+ "), must be between 1 and %d",
97
+ qemu_mutex_init(&s->mutex);
246
+ conf->max_write_zeroes_sectors,
98
curl_attach_aio_context(bs, bdrv_get_aio_context(bs));
247
+ (int)BDRV_REQUEST_MAX_SECTORS);
99
248
+ return;
100
qemu_opts_del(opts);
249
+ }
101
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
250
+
102
CURLAIOCB *acb = p;
251
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
103
BlockDriverState *bs = acb->common.bs;
252
sizeof(struct virtio_blk_config));
104
BDRVCURLState *s = bs->opaque;
253
105
- AioContext *ctx = bdrv_get_aio_context(bs);
254
@@ -XXX,XX +XXX,XX @@ static Property virtio_blk_properties[] = {
106
255
VIRTIO_BLK_F_DISCARD, true),
107
size_t start = acb->sector_num * BDRV_SECTOR_SIZE;
256
DEFINE_PROP_BIT64("write-zeroes", VirtIOBlock, host_features,
108
size_t end;
257
VIRTIO_BLK_F_WRITE_ZEROES, true),
109
258
+ DEFINE_PROP_UINT32("max-discard-sectors", VirtIOBlock,
110
- aio_context_acquire(ctx);
259
+ conf.max_discard_sectors, BDRV_REQUEST_MAX_SECTORS),
111
+ qemu_mutex_lock(&s->mutex);
260
+ DEFINE_PROP_UINT32("max-write-zeroes-sectors", VirtIOBlock,
112
261
+ conf.max_write_zeroes_sectors, BDRV_REQUEST_MAX_SECTORS),
113
// In case we have the requested data already (e.g. read-ahead),
262
DEFINE_PROP_END_OF_LIST(),
114
// we can just call the callback and be done.
263
};
115
@@ -XXX,XX +XXX,XX @@ static void curl_readv_bh_cb(void *p)
264
116
curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0, &running);
117
118
out:
119
- aio_context_release(ctx);
120
+ qemu_mutex_unlock(&s->mutex);
121
if (ret != -EINPROGRESS) {
122
acb->common.cb(acb->common.opaque, ret);
123
qemu_aio_unref(acb);
124
@@ -XXX,XX +XXX,XX @@ static void curl_close(BlockDriverState *bs)
125
126
DPRINTF("CURL: Close\n");
127
curl_detach_aio_context(bs);
128
+ qemu_mutex_destroy(&s->mutex);
129
130
g_free(s->cookie);
131
g_free(s->url);
132
--
265
--
133
2.9.3
266
2.20.1
134
267
135
268
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
The size of data in the virtio_blk_request must be a multiple
4
of 512 bytes for IN and OUT requests, or a multiple of the size
5
of struct virtio_blk_discard_write_zeroes for DISCARD and
6
WRITE_ZEROES requests.
7
8
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
9
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
10
Reviewed-by: Thomas Huth <thuth@redhat.com>
11
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
12
Acked-by: Pankaj Gupta <pagupta@redhat.com>
13
Message-id: 20190208134950.187665-6-sgarzare@redhat.com
14
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
15
---
16
tests/virtio-blk-test.c | 15 ++++++++++++++-
17
1 file changed, 14 insertions(+), 1 deletion(-)
18
19
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
20
index XXXXXXX..XXXXXXX 100644
21
--- a/tests/virtio-blk-test.c
22
+++ b/tests/virtio-blk-test.c
23
@@ -XXX,XX +XXX,XX @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioDevice *d,
24
uint64_t addr;
25
uint8_t status = 0xFF;
26
27
- g_assert_cmpuint(data_size % 512, ==, 0);
28
+ switch (req->type) {
29
+ case VIRTIO_BLK_T_IN:
30
+ case VIRTIO_BLK_T_OUT:
31
+ g_assert_cmpuint(data_size % 512, ==, 0);
32
+ break;
33
+ case VIRTIO_BLK_T_DISCARD:
34
+ case VIRTIO_BLK_T_WRITE_ZEROES:
35
+ g_assert_cmpuint(data_size %
36
+ sizeof(struct virtio_blk_discard_write_zeroes), ==, 0);
37
+ break;
38
+ default:
39
+ g_assert_cmpuint(data_size, ==, 0);
40
+ }
41
+
42
addr = guest_alloc(alloc, sizeof(*req) + data_size);
43
44
virtio_blk_fix_request(d, req);
45
--
46
2.20.1
47
48
diff view generated by jsdifflib
New patch
1
From: Stefano Garzarella <sgarzare@redhat.com>
1
2
3
If the WRITE_ZEROES feature is enabled, we check this command
4
in the test_basic().
5
6
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
7
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
8
Acked-by: Thomas Huth <thuth@redhat.com>
9
Signed-off-by: Stefano Garzarella <sgarzare@redhat.com>
10
Acked-by: Pankaj Gupta <pagupta@redhat.com>
11
Message-id: 20190208134950.187665-7-sgarzare@redhat.com
12
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
13
---
14
tests/virtio-blk-test.c | 60 +++++++++++++++++++++++++++++++++++++++++
15
1 file changed, 60 insertions(+)
16
17
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
18
index XXXXXXX..XXXXXXX 100644
19
--- a/tests/virtio-blk-test.c
20
+++ b/tests/virtio-blk-test.c
21
@@ -XXX,XX +XXX,XX @@ static void test_basic(QVirtioDevice *dev, QGuestAllocator *alloc,
22
23
guest_free(alloc, req_addr);
24
25
+ if (features & (1u << VIRTIO_BLK_F_WRITE_ZEROES)) {
26
+ struct virtio_blk_discard_write_zeroes dwz_hdr;
27
+ void *expected;
28
+
29
+ /*
30
+ * WRITE_ZEROES request on the same sector of previous test where
31
+ * we wrote "TEST".
32
+ */
33
+ req.type = VIRTIO_BLK_T_WRITE_ZEROES;
34
+ req.data = (char *) &dwz_hdr;
35
+ dwz_hdr.sector = 0;
36
+ dwz_hdr.num_sectors = 1;
37
+ dwz_hdr.flags = 0;
38
+
39
+ req_addr = virtio_blk_request(alloc, dev, &req, sizeof(dwz_hdr));
40
+
41
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
42
+ qvirtqueue_add(vq, req_addr + 16, sizeof(dwz_hdr), false, true);
43
+ qvirtqueue_add(vq, req_addr + 16 + sizeof(dwz_hdr), 1, true, false);
44
+
45
+ qvirtqueue_kick(dev, vq, free_head);
46
+
47
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
48
+ QVIRTIO_BLK_TIMEOUT_US);
49
+ status = readb(req_addr + 16 + sizeof(dwz_hdr));
50
+ g_assert_cmpint(status, ==, 0);
51
+
52
+ guest_free(alloc, req_addr);
53
+
54
+ /* Read request to check if the sector contains all zeroes */
55
+ req.type = VIRTIO_BLK_T_IN;
56
+ req.ioprio = 1;
57
+ req.sector = 0;
58
+ req.data = g_malloc0(512);
59
+
60
+ req_addr = virtio_blk_request(alloc, dev, &req, 512);
61
+
62
+ g_free(req.data);
63
+
64
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
65
+ qvirtqueue_add(vq, req_addr + 16, 512, true, true);
66
+ qvirtqueue_add(vq, req_addr + 528, 1, true, false);
67
+
68
+ qvirtqueue_kick(dev, vq, free_head);
69
+
70
+ qvirtio_wait_used_elem(dev, vq, free_head, NULL,
71
+ QVIRTIO_BLK_TIMEOUT_US);
72
+ status = readb(req_addr + 528);
73
+ g_assert_cmpint(status, ==, 0);
74
+
75
+ data = g_malloc(512);
76
+ expected = g_malloc0(512);
77
+ memread(req_addr + 16, data, 512);
78
+ g_assert_cmpmem(data, 512, expected, 512);
79
+ g_free(expected);
80
+ g_free(data);
81
+
82
+ guest_free(alloc, req_addr);
83
+ }
84
+
85
if (features & (1u << VIRTIO_F_ANY_LAYOUT)) {
86
/* Write and read with 2 descriptor layout */
87
/* Write request */
88
--
89
2.20.1
90
91
diff view generated by jsdifflib