Revision d28a1b6e hw/virtio-blk.c
b/hw/virtio-blk.c | ||
---|---|---|
35 | 35 |
VirtQueueElement elem; |
36 | 36 |
struct virtio_blk_inhdr *in; |
37 | 37 |
struct virtio_blk_outhdr *out; |
38 |
size_t size; |
|
39 |
uint8_t *buffer; |
|
38 |
QEMUIOVector qiov; |
|
40 | 39 |
struct VirtIOBlockReq *next; |
41 | 40 |
} VirtIOBlockReq; |
42 | 41 |
|
... | ... | |
45 | 44 |
VirtIOBlock *s = req->dev; |
46 | 45 |
|
47 | 46 |
req->in->status = status; |
48 |
virtqueue_push(s->vq, &req->elem, req->size + sizeof(*req->in)); |
|
47 |
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
|
|
49 | 48 |
virtio_notify(&s->vdev, s->vq); |
50 | 49 |
|
51 |
qemu_free(req->buffer); |
|
52 | 50 |
qemu_free(req); |
53 | 51 |
} |
54 | 52 |
|
... | ... | |
76 | 74 |
{ |
77 | 75 |
VirtIOBlockReq *req = opaque; |
78 | 76 |
|
79 |
/* Copy read data to the guest */ |
|
80 |
if (!ret && !(req->out->type & VIRTIO_BLK_T_OUT)) { |
|
81 |
size_t offset = 0; |
|
82 |
int i; |
|
83 |
|
|
84 |
for (i = 0; i < req->elem.in_num - 1; i++) { |
|
85 |
size_t len; |
|
86 |
|
|
87 |
/* Be pretty defensive wrt malicious guests */ |
|
88 |
len = MIN(req->elem.in_sg[i].iov_len, |
|
89 |
req->size - offset); |
|
90 |
|
|
91 |
memcpy(req->elem.in_sg[i].iov_base, |
|
92 |
req->buffer + offset, |
|
93 |
len); |
|
94 |
offset += len; |
|
95 |
} |
|
96 |
} else if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) { |
|
77 |
if (ret && (req->out->type & VIRTIO_BLK_T_OUT)) { |
|
97 | 78 |
if (virtio_blk_handle_write_error(req, -ret)) |
98 | 79 |
return; |
99 | 80 |
} |
... | ... | |
122 | 103 |
return req; |
123 | 104 |
} |
124 | 105 |
|
125 |
static int virtio_blk_handle_write(VirtIOBlockReq *req)
|
|
106 |
static void virtio_blk_handle_write(VirtIOBlockReq *req)
|
|
126 | 107 |
{ |
127 |
if (!req->buffer) { |
|
128 |
size_t offset = 0; |
|
129 |
int i; |
|
130 |
|
|
131 |
for (i = 1; i < req->elem.out_num; i++) |
|
132 |
req->size += req->elem.out_sg[i].iov_len; |
|
133 |
|
|
134 |
req->buffer = qemu_memalign(512, req->size); |
|
135 |
if (req->buffer == NULL) { |
|
136 |
qemu_free(req); |
|
137 |
return -1; |
|
138 |
} |
|
139 |
|
|
140 |
/* We copy the data from the SG list to avoid splitting up the request. |
|
141 |
This helps performance a lot until we can pass full sg lists as AIO |
|
142 |
operations */ |
|
143 |
for (i = 1; i < req->elem.out_num; i++) { |
|
144 |
size_t len; |
|
145 |
|
|
146 |
len = MIN(req->elem.out_sg[i].iov_len, |
|
147 |
req->size - offset); |
|
148 |
memcpy(req->buffer + offset, |
|
149 |
req->elem.out_sg[i].iov_base, |
|
150 |
len); |
|
151 |
offset += len; |
|
152 |
} |
|
153 |
} |
|
108 |
bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov, |
|
109 |
req->qiov.size / 512, virtio_blk_rw_complete, req); |
|
110 |
} |
|
154 | 111 |
|
155 |
bdrv_aio_write(req->dev->bs, req->out->sector, req->buffer, req->size / 512, |
|
156 |
virtio_blk_rw_complete, req); |
|
157 |
return 0; |
|
112 |
static void virtio_blk_handle_read(VirtIOBlockReq *req) |
|
113 |
{ |
|
114 |
bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov, |
|
115 |
req->qiov.size / 512, virtio_blk_rw_complete, req); |
|
158 | 116 |
} |
159 | 117 |
|
160 | 118 |
static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) |
... | ... | |
163 | 121 |
VirtIOBlockReq *req; |
164 | 122 |
|
165 | 123 |
while ((req = virtio_blk_get_request(s))) { |
166 |
int i; |
|
167 |
|
|
168 | 124 |
if (req->elem.out_num < 1 || req->elem.in_num < 1) { |
169 | 125 |
fprintf(stderr, "virtio-blk missing headers\n"); |
170 | 126 |
exit(1); |
... | ... | |
187 | 143 |
virtio_notify(vdev, vq); |
188 | 144 |
qemu_free(req); |
189 | 145 |
} else if (req->out->type & VIRTIO_BLK_T_OUT) { |
190 |
if (virtio_blk_handle_write(req) < 0) |
|
191 |
break; |
|
146 |
qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1], |
|
147 |
req->elem.out_num - 1); |
|
148 |
virtio_blk_handle_write(req); |
|
192 | 149 |
} else { |
193 |
for (i = 0; i < req->elem.in_num - 1; i++) |
|
194 |
req->size += req->elem.in_sg[i].iov_len; |
|
195 |
|
|
196 |
req->buffer = qemu_memalign(512, req->size); |
|
197 |
if (req->buffer == NULL) { |
|
198 |
qemu_free(req); |
|
199 |
break; |
|
200 |
} |
|
201 |
|
|
202 |
bdrv_aio_read(s->bs, req->out->sector, |
|
203 |
req->buffer, |
|
204 |
req->size / 512, |
|
205 |
virtio_blk_rw_complete, |
|
206 |
req); |
|
150 |
qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0], |
|
151 |
req->elem.in_num - 1); |
|
152 |
virtio_blk_handle_read(req); |
|
207 | 153 |
} |
208 | 154 |
} |
209 | 155 |
/* |
Also available in: Unified diff