]> git.proxmox.com Git - mirror_qemu.git/blame - hw/9pfs/virtio-9p-device.c
9pfs: suppress performance warnings on qtest runs
[mirror_qemu.git] / hw / 9pfs / virtio-9p-device.c
CommitLineData
f4f61d27
AK
1/*
2 * Virtio 9p backend
3 *
4 * Copyright IBM, Corp. 2010
5 *
6 * Authors:
7 * Anthony Liguori <aliguori@us.ibm.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
11 *
12 */
13
9b8bfe21 14#include "qemu/osdep.h"
0d09e41a 15#include "hw/virtio/virtio.h"
1de7afc9 16#include "qemu/sockets.h"
f4f61d27
AK
17#include "virtio-9p.h"
18#include "fsdev/qemu-fsdev.h"
fe52840c 19#include "coth.h"
a27bd6c7 20#include "hw/qdev-properties.h"
d64ccb91 21#include "hw/virtio/virtio-access.h"
0192cc5d 22#include "qemu/iov.h"
0b8fa32f 23#include "qemu/module.h"
b036d9ac 24#include "sysemu/qtest.h"
f4f61d27 25
ea83441c 26static void virtio_9p_push_and_notify(V9fsPDU *pdu)
0d3716b4
WL
27{
28 V9fsState *s = pdu->s;
00588a0a 29 V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
51b19ebe 30 VirtQueueElement *elem = v->elems[pdu->idx];
0d3716b4
WL
31
32 /* push onto queue and notify */
00588a0a 33 virtqueue_push(v->vq, elem, pdu->size);
51b19ebe
PB
34 g_free(elem);
35 v->elems[pdu->idx] = NULL;
0d3716b4
WL
36
37 /* FIXME: we should batch these completions */
00588a0a 38 virtio_notify(VIRTIO_DEVICE(v), v->vq);
0d3716b4
WL
39}
40
0192cc5d
WL
41static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
42{
00588a0a
WL
43 V9fsVirtioState *v = (V9fsVirtioState *)vdev;
44 V9fsState *s = &v->state;
0192cc5d
WL
45 V9fsPDU *pdu;
46 ssize_t len;
d3d74d6f 47 VirtQueueElement *elem;
0192cc5d 48
00588a0a 49 while ((pdu = pdu_alloc(s))) {
c9fb47e7 50 P9MsgHeader out;
0192cc5d 51
51b19ebe
PB
52 elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
53 if (!elem) {
d3d74d6f 54 goto out_free_pdu;
00588a0a
WL
55 }
56
a4d99854 57 if (iov_size(elem->in_sg, elem->in_num) < 7) {
d3d74d6f
GK
58 virtio_error(vdev,
59 "The guest sent a VirtFS request without space for "
60 "the reply");
61 goto out_free_req;
62 }
0192cc5d 63
a4d99854
GK
64 len = iov_to_buf(elem->out_sg, elem->out_num, 0, &out, 7);
65 if (len != 7) {
d3d74d6f
GK
66 virtio_error(vdev, "The guest sent a malformed VirtFS request: "
67 "header size is %zd, should be 7", len);
68 goto out_free_req;
69 }
0192cc5d 70
3a21fb2a
GK
71 v->elems[pdu->idx] = elem;
72
506f3275 73 pdu_submit(pdu, &out);
0192cc5d 74 }
d3d74d6f
GK
75
76 return;
77
78out_free_req:
79 virtqueue_detach_element(vq, elem, 0);
80 g_free(elem);
81out_free_pdu:
82 pdu_free(pdu);
0192cc5d
WL
83}
84
9d5b731d
JW
85static uint64_t virtio_9p_get_features(VirtIODevice *vdev, uint64_t features,
86 Error **errp)
f4f61d27 87{
0cd09c3a 88 virtio_add_feature(&features, VIRTIO_9P_MOUNT_TAG);
f4f61d27
AK
89 return features;
90}
91
f4f61d27
AK
92static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
93{
e9a0152b 94 int len;
f4f61d27 95 struct virtio_9p_config *cfg;
00588a0a
WL
96 V9fsVirtioState *v = VIRTIO_9P(vdev);
97 V9fsState *s = &v->state;
f4f61d27 98
e9a0152b
AK
99 len = strlen(s->tag);
100 cfg = g_malloc0(sizeof(struct virtio_9p_config) + len);
d64ccb91 101 virtio_stw_p(vdev, &cfg->tag_len, len);
e9a0152b
AK
102 /* We don't copy the terminating null to config space */
103 memcpy(cfg->tag, s->tag, len);
00588a0a 104 memcpy(config, cfg, v->config_size);
7267c094 105 g_free(cfg);
f4f61d27
AK
106}
107
0e44a0fd
GK
108static void virtio_9p_reset(VirtIODevice *vdev)
109{
110 V9fsVirtioState *v = (V9fsVirtioState *)vdev;
111
112 v9fs_reset(&v->state);
113}
114
ea83441c
SS
115static ssize_t virtio_pdu_vmarshal(V9fsPDU *pdu, size_t offset,
116 const char *fmt, va_list ap)
fe9fa96d 117{
00588a0a
WL
118 V9fsState *s = pdu->s;
119 V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
51b19ebe 120 VirtQueueElement *elem = v->elems[pdu->idx];
8d37de41 121 ssize_t ret;
00588a0a 122
8d37de41
GK
123 ret = v9fs_iov_vmarshal(elem->in_sg, elem->in_num, offset, 1, fmt, ap);
124 if (ret < 0) {
125 VirtIODevice *vdev = VIRTIO_DEVICE(v);
126
127 virtio_error(vdev, "Failed to encode VirtFS reply type %d",
128 pdu->id + 1);
129 }
130 return ret;
fe9fa96d
WL
131}
132
ea83441c
SS
133static ssize_t virtio_pdu_vunmarshal(V9fsPDU *pdu, size_t offset,
134 const char *fmt, va_list ap)
fe9fa96d 135{
00588a0a
WL
136 V9fsState *s = pdu->s;
137 V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
51b19ebe 138 VirtQueueElement *elem = v->elems[pdu->idx];
8d37de41
GK
139 ssize_t ret;
140
141 ret = v9fs_iov_vunmarshal(elem->out_sg, elem->out_num, offset, 1, fmt, ap);
142 if (ret < 0) {
143 VirtIODevice *vdev = VIRTIO_DEVICE(v);
00588a0a 144
8d37de41
GK
145 virtio_error(vdev, "Failed to decode VirtFS request type %d", pdu->id);
146 }
147 return ret;
fe9fa96d
WL
148}
149
88da0b03 150static void virtio_init_in_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
cf45183b 151 unsigned int *pniov, size_t size)
592707af 152{
00588a0a
WL
153 V9fsState *s = pdu->s;
154 V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
51b19ebe 155 VirtQueueElement *elem = v->elems[pdu->idx];
8d37de41
GK
156 size_t buf_size = iov_size(elem->in_sg, elem->in_num);
157
cf45183b 158 if (buf_size < size) {
8d37de41
GK
159 VirtIODevice *vdev = VIRTIO_DEVICE(v);
160
161 virtio_error(vdev,
cf45183b
SS
162 "VirtFS reply type %d needs %zu bytes, buffer has %zu",
163 pdu->id + 1, size, buf_size);
8d37de41 164 }
00588a0a 165
88da0b03
SS
166 *piov = elem->in_sg;
167 *pniov = elem->in_num;
168}
169
170static void virtio_init_out_iov_from_pdu(V9fsPDU *pdu, struct iovec **piov,
8d37de41 171 unsigned int *pniov, size_t size)
88da0b03
SS
172{
173 V9fsState *s = pdu->s;
174 V9fsVirtioState *v = container_of(s, V9fsVirtioState, state);
175 VirtQueueElement *elem = v->elems[pdu->idx];
8d37de41
GK
176 size_t buf_size = iov_size(elem->out_sg, elem->out_num);
177
178 if (buf_size < size) {
179 VirtIODevice *vdev = VIRTIO_DEVICE(v);
180
181 virtio_error(vdev,
182 "VirtFS request type %d needs %zu bytes, buffer has %zu",
183 pdu->id, size, buf_size);
184 }
88da0b03
SS
185
186 *piov = elem->out_sg;
187 *pniov = elem->out_num;
592707af
WL
188}
189
8e71b96c 190static const V9fsTransport virtio_9p_transport = {
ea83441c
SS
191 .pdu_vmarshal = virtio_pdu_vmarshal,
192 .pdu_vunmarshal = virtio_pdu_vunmarshal,
88da0b03
SS
193 .init_in_iov_from_pdu = virtio_init_in_iov_from_pdu,
194 .init_out_iov_from_pdu = virtio_init_out_iov_from_pdu,
ea83441c
SS
195 .push_and_notify = virtio_9p_push_and_notify,
196};
197
bd3be4db
GK
198static void virtio_9p_device_realize(DeviceState *dev, Error **errp)
199{
200 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
201 V9fsVirtioState *v = VIRTIO_9P(dev);
202 V9fsState *s = &v->state;
b036d9ac
CS
203 FsDriverEntry *fse = get_fsdev_fsentry(s->fsconf.fsdev_id);
204
205 if (qtest_enabled() && fse) {
206 fse->export_flags |= V9FS_NO_PERF_WARN;
207 }
bd3be4db 208
066eb006
GK
209 if (v9fs_device_realize_common(s, &virtio_9p_transport, errp)) {
210 return;
bd3be4db
GK
211 }
212
213 v->config_size = sizeof(struct virtio_9p_config) + strlen(s->fsconf.tag);
214 virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, v->config_size);
215 v->vq = virtio_add_queue(vdev, MAX_REQ, handle_9p_output);
bd3be4db
GK
216}
217
b69c3c21 218static void virtio_9p_device_unrealize(DeviceState *dev)
bd3be4db
GK
219{
220 VirtIODevice *vdev = VIRTIO_DEVICE(dev);
221 V9fsVirtioState *v = VIRTIO_9P(dev);
222 V9fsState *s = &v->state;
223
ad30a9e9 224 virtio_delete_queue(v->vq);
bd3be4db 225 virtio_cleanup(vdev);
b69c3c21 226 v9fs_device_unrealize_common(s);
bd3be4db
GK
227}
228
e7303c43
FK
229/* virtio-9p device */
230
dcaf8dda
HP
231static const VMStateDescription vmstate_virtio_9p = {
232 .name = "virtio-9p",
233 .minimum_version_id = 1,
234 .version_id = 1,
235 .fields = (VMStateField[]) {
236 VMSTATE_VIRTIO_DEVICE,
237 VMSTATE_END_OF_LIST()
238 },
239};
18e0e5b2 240
e7303c43 241static Property virtio_9p_properties[] = {
00588a0a
WL
242 DEFINE_PROP_STRING("mount_tag", V9fsVirtioState, state.fsconf.tag),
243 DEFINE_PROP_STRING("fsdev", V9fsVirtioState, state.fsconf.fsdev_id),
e7303c43
FK
244 DEFINE_PROP_END_OF_LIST(),
245};
246
247static void virtio_9p_class_init(ObjectClass *klass, void *data)
248{
249 DeviceClass *dc = DEVICE_CLASS(klass);
250 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
59be7522 251
4f67d30b 252 device_class_set_props(dc, virtio_9p_properties);
18e0e5b2 253 dc->vmsd = &vmstate_virtio_9p;
125ee0ed 254 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
59be7522 255 vdc->realize = virtio_9p_device_realize;
6cecf093 256 vdc->unrealize = virtio_9p_device_unrealize;
e7303c43
FK
257 vdc->get_features = virtio_9p_get_features;
258 vdc->get_config = virtio_9p_get_config;
0e44a0fd 259 vdc->reset = virtio_9p_reset;
e7303c43
FK
260}
261
262static const TypeInfo virtio_device_info = {
263 .name = TYPE_VIRTIO_9P,
264 .parent = TYPE_VIRTIO_DEVICE,
00588a0a 265 .instance_size = sizeof(V9fsVirtioState),
e7303c43
FK
266 .class_init = virtio_9p_class_init,
267};
268
269static void virtio_9p_register_types(void)
270{
271 type_register_static(&virtio_device_info);
272}
273
274type_init(virtio_9p_register_types)