4 * Copyright Aporeto 2017
7 * Stefano Stabellini <stefano@aporeto.com>
11 #include "qemu/osdep.h"
14 #include "hw/9pfs/9p.h"
15 #include "hw/xen/xen_backend.h"
16 #include "hw/9pfs/xen-9pfs.h"
17 #include "qemu/config-file.h"
18 #include "fsdev/qemu-fsdev.h"
22 #define MAX_RING_ORDER 8
24 typedef struct Xen9pfsRing
{
25 struct Xen9pfsDev
*priv
;
28 xenevtchn_handle
*evtchndev
;
32 struct xen_9pfs_data_intf
*intf
;
34 struct xen_9pfs_data ring
;
39 /* local copies, so that we can read/write PDU data directly from
41 RING_IDX out_cons
, out_size
, in_cons
;
45 typedef struct Xen9pfsDev
{
46 struct XenDevice xendev
; /* must be first */
57 static void xen_9pfs_in_sg(Xen9pfsRing
*ring
,
63 RING_IDX cons
, prod
, masked_prod
, masked_cons
;
65 cons
= ring
->intf
->in_cons
;
66 prod
= ring
->intf
->in_prod
;
68 masked_prod
= xen_9pfs_mask(prod
, XEN_FLEX_RING_SIZE(ring
->ring_order
));
69 masked_cons
= xen_9pfs_mask(cons
, XEN_FLEX_RING_SIZE(ring
->ring_order
));
71 if (masked_prod
< masked_cons
) {
72 in_sg
[0].iov_base
= ring
->ring
.in
+ masked_prod
;
73 in_sg
[0].iov_len
= masked_cons
- masked_prod
;
76 in_sg
[0].iov_base
= ring
->ring
.in
+ masked_prod
;
77 in_sg
[0].iov_len
= XEN_FLEX_RING_SIZE(ring
->ring_order
) - masked_prod
;
78 in_sg
[1].iov_base
= ring
->ring
.in
;
79 in_sg
[1].iov_len
= masked_cons
;
84 static void xen_9pfs_out_sg(Xen9pfsRing
*ring
,
89 RING_IDX cons
, prod
, masked_prod
, masked_cons
;
91 cons
= ring
->intf
->out_cons
;
92 prod
= ring
->intf
->out_prod
;
94 masked_prod
= xen_9pfs_mask(prod
, XEN_FLEX_RING_SIZE(ring
->ring_order
));
95 masked_cons
= xen_9pfs_mask(cons
, XEN_FLEX_RING_SIZE(ring
->ring_order
));
97 if (masked_cons
< masked_prod
) {
98 out_sg
[0].iov_base
= ring
->ring
.out
+ masked_cons
;
99 out_sg
[0].iov_len
= ring
->out_size
;
103 (XEN_FLEX_RING_SIZE(ring
->ring_order
) - masked_cons
)) {
104 out_sg
[0].iov_base
= ring
->ring
.out
+ masked_cons
;
105 out_sg
[0].iov_len
= XEN_FLEX_RING_SIZE(ring
->ring_order
) -
107 out_sg
[1].iov_base
= ring
->ring
.out
;
108 out_sg
[1].iov_len
= ring
->out_size
-
109 (XEN_FLEX_RING_SIZE(ring
->ring_order
) -
113 out_sg
[0].iov_base
= ring
->ring
.out
+ masked_cons
;
114 out_sg
[0].iov_len
= ring
->out_size
;
120 static ssize_t
xen_9pfs_pdu_vmarshal(V9fsPDU
*pdu
,
125 Xen9pfsDev
*xen_9pfs
= container_of(pdu
->s
, Xen9pfsDev
, state
);
126 struct iovec in_sg
[2];
129 xen_9pfs_in_sg(&xen_9pfs
->rings
[pdu
->tag
% xen_9pfs
->num_rings
],
130 in_sg
, &num
, pdu
->idx
, ROUND_UP(offset
+ 128, 512));
131 return v9fs_iov_vmarshal(in_sg
, num
, offset
, 0, fmt
, ap
);
134 static ssize_t
xen_9pfs_pdu_vunmarshal(V9fsPDU
*pdu
,
139 Xen9pfsDev
*xen_9pfs
= container_of(pdu
->s
, Xen9pfsDev
, state
);
140 struct iovec out_sg
[2];
143 xen_9pfs_out_sg(&xen_9pfs
->rings
[pdu
->tag
% xen_9pfs
->num_rings
],
144 out_sg
, &num
, pdu
->idx
);
145 return v9fs_iov_vunmarshal(out_sg
, num
, offset
, 0, fmt
, ap
);
148 static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU
*pdu
,
152 Xen9pfsDev
*xen_9pfs
= container_of(pdu
->s
, Xen9pfsDev
, state
);
153 Xen9pfsRing
*ring
= &xen_9pfs
->rings
[pdu
->tag
% xen_9pfs
->num_rings
];
158 ring
->sg
= g_malloc0(sizeof(*ring
->sg
) * 2);
159 xen_9pfs_out_sg(ring
, ring
->sg
, &num
, pdu
->idx
);
164 static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU
*pdu
,
169 Xen9pfsDev
*xen_9pfs
= container_of(pdu
->s
, Xen9pfsDev
, state
);
170 Xen9pfsRing
*ring
= &xen_9pfs
->rings
[pdu
->tag
% xen_9pfs
->num_rings
];
175 ring
->sg
= g_malloc0(sizeof(*ring
->sg
) * 2);
176 xen_9pfs_in_sg(ring
, ring
->sg
, &num
, pdu
->idx
, size
);
181 static void xen_9pfs_push_and_notify(V9fsPDU
*pdu
)
184 Xen9pfsDev
*priv
= container_of(pdu
->s
, Xen9pfsDev
, state
);
185 Xen9pfsRing
*ring
= &priv
->rings
[pdu
->tag
% priv
->num_rings
];
190 ring
->intf
->out_cons
= ring
->out_cons
;
193 prod
= ring
->intf
->in_prod
;
195 ring
->intf
->in_prod
= prod
+ pdu
->size
;
198 ring
->inprogress
= false;
199 xenevtchn_notify(ring
->evtchndev
, ring
->local_port
);
201 qemu_bh_schedule(ring
->bh
);
204 static const struct V9fsTransport xen_9p_transport
= {
205 .pdu_vmarshal
= xen_9pfs_pdu_vmarshal
,
206 .pdu_vunmarshal
= xen_9pfs_pdu_vunmarshal
,
207 .init_in_iov_from_pdu
= xen_9pfs_init_in_iov_from_pdu
,
208 .init_out_iov_from_pdu
= xen_9pfs_init_out_iov_from_pdu
,
209 .push_and_notify
= xen_9pfs_push_and_notify
,
212 static int xen_9pfs_init(struct XenDevice
*xendev
)
217 static int xen_9pfs_receive(Xen9pfsRing
*ring
)
220 RING_IDX cons
, prod
, masked_prod
, masked_cons
;
223 if (ring
->inprogress
) {
227 cons
= ring
->intf
->out_cons
;
228 prod
= ring
->intf
->out_prod
;
231 if (xen_9pfs_queued(prod
, cons
, XEN_FLEX_RING_SIZE(ring
->ring_order
)) <
235 ring
->inprogress
= true;
237 masked_prod
= xen_9pfs_mask(prod
, XEN_FLEX_RING_SIZE(ring
->ring_order
));
238 masked_cons
= xen_9pfs_mask(cons
, XEN_FLEX_RING_SIZE(ring
->ring_order
));
240 xen_9pfs_read_packet((uint8_t *) &h
, ring
->ring
.out
, sizeof(h
),
241 masked_prod
, &masked_cons
,
242 XEN_FLEX_RING_SIZE(ring
->ring_order
));
244 /* cannot fail, because we only handle one request per ring at a time */
245 pdu
= pdu_alloc(&ring
->priv
->state
);
246 pdu
->size
= le32_to_cpu(h
.size_le
);
248 pdu
->tag
= le32_to_cpu(h
.tag_le
);
249 ring
->out_size
= le32_to_cpu(h
.size_le
);
250 ring
->out_cons
= cons
+ le32_to_cpu(h
.size_le
);
252 qemu_co_queue_init(&pdu
->complete
);
258 static void xen_9pfs_bh(void *opaque
)
260 Xen9pfsRing
*ring
= opaque
;
261 xen_9pfs_receive(ring
);
264 static void xen_9pfs_evtchn_event(void *opaque
)
266 Xen9pfsRing
*ring
= opaque
;
269 port
= xenevtchn_pending(ring
->evtchndev
);
270 xenevtchn_unmask(ring
->evtchndev
, port
);
272 qemu_bh_schedule(ring
->bh
);
275 static int xen_9pfs_free(struct XenDevice
*xendev
)
278 Xen9pfsDev
*xen_9pdev
= container_of(xendev
, Xen9pfsDev
, xendev
);
280 g_free(xen_9pdev
->id
);
281 g_free(xen_9pdev
->tag
);
282 g_free(xen_9pdev
->path
);
283 g_free(xen_9pdev
->security_model
);
285 for (i
= 0; i
< xen_9pdev
->num_rings
; i
++) {
286 if (xen_9pdev
->rings
[i
].data
!= NULL
) {
287 xengnttab_unmap(xen_9pdev
->xendev
.gnttabdev
,
288 xen_9pdev
->rings
[i
].data
,
289 (1 << xen_9pdev
->rings
[i
].ring_order
));
291 if (xen_9pdev
->rings
[i
].intf
!= NULL
) {
292 xengnttab_unmap(xen_9pdev
->xendev
.gnttabdev
,
293 xen_9pdev
->rings
[i
].intf
,
296 if (xen_9pdev
->rings
[i
].evtchndev
> 0) {
297 qemu_set_fd_handler(xenevtchn_fd(xen_9pdev
->rings
[i
].evtchndev
),
299 xenevtchn_unbind(xen_9pdev
->rings
[i
].evtchndev
,
300 xen_9pdev
->rings
[i
].local_port
);
302 if (xen_9pdev
->rings
[i
].bh
!= NULL
) {
303 qemu_bh_delete(xen_9pdev
->rings
[i
].bh
);
306 g_free(xen_9pdev
->rings
);
310 static int xen_9pfs_connect(struct XenDevice
*xendev
)
313 Xen9pfsDev
*xen_9pdev
= container_of(xendev
, Xen9pfsDev
, xendev
);
314 V9fsState
*s
= &xen_9pdev
->state
;
317 if (xenstore_read_fe_int(&xen_9pdev
->xendev
, "num-rings",
318 &xen_9pdev
->num_rings
) == -1 ||
319 xen_9pdev
->num_rings
> MAX_RINGS
|| xen_9pdev
->num_rings
< 1) {
323 xen_9pdev
->rings
= g_malloc0(xen_9pdev
->num_rings
* sizeof(Xen9pfsRing
));
324 for (i
= 0; i
< xen_9pdev
->num_rings
; i
++) {
328 xen_9pdev
->rings
[i
].priv
= xen_9pdev
;
329 xen_9pdev
->rings
[i
].evtchn
= -1;
330 xen_9pdev
->rings
[i
].local_port
= -1;
332 str
= g_strdup_printf("ring-ref%u", i
);
333 if (xenstore_read_fe_int(&xen_9pdev
->xendev
, str
,
334 &xen_9pdev
->rings
[i
].ref
) == -1) {
338 str
= g_strdup_printf("event-channel-%u", i
);
339 if (xenstore_read_fe_int(&xen_9pdev
->xendev
, str
,
340 &xen_9pdev
->rings
[i
].evtchn
) == -1) {
345 xen_9pdev
->rings
[i
].intf
= xengnttab_map_grant_ref(
346 xen_9pdev
->xendev
.gnttabdev
,
347 xen_9pdev
->xendev
.dom
,
348 xen_9pdev
->rings
[i
].ref
,
349 PROT_READ
| PROT_WRITE
);
350 if (!xen_9pdev
->rings
[i
].intf
) {
353 ring_order
= xen_9pdev
->rings
[i
].intf
->ring_order
;
354 if (ring_order
> MAX_RING_ORDER
) {
357 xen_9pdev
->rings
[i
].ring_order
= ring_order
;
358 xen_9pdev
->rings
[i
].data
= xengnttab_map_domain_grant_refs(
359 xen_9pdev
->xendev
.gnttabdev
,
361 xen_9pdev
->xendev
.dom
,
362 xen_9pdev
->rings
[i
].intf
->ref
,
363 PROT_READ
| PROT_WRITE
);
364 if (!xen_9pdev
->rings
[i
].data
) {
367 xen_9pdev
->rings
[i
].ring
.in
= xen_9pdev
->rings
[i
].data
;
368 xen_9pdev
->rings
[i
].ring
.out
= xen_9pdev
->rings
[i
].data
+
369 XEN_FLEX_RING_SIZE(ring_order
);
371 xen_9pdev
->rings
[i
].bh
= qemu_bh_new(xen_9pfs_bh
, &xen_9pdev
->rings
[i
]);
372 xen_9pdev
->rings
[i
].out_cons
= 0;
373 xen_9pdev
->rings
[i
].out_size
= 0;
374 xen_9pdev
->rings
[i
].inprogress
= false;
377 xen_9pdev
->rings
[i
].evtchndev
= xenevtchn_open(NULL
, 0);
378 if (xen_9pdev
->rings
[i
].evtchndev
== NULL
) {
381 fcntl(xenevtchn_fd(xen_9pdev
->rings
[i
].evtchndev
), F_SETFD
, FD_CLOEXEC
);
382 xen_9pdev
->rings
[i
].local_port
= xenevtchn_bind_interdomain
383 (xen_9pdev
->rings
[i
].evtchndev
,
385 xen_9pdev
->rings
[i
].evtchn
);
386 if (xen_9pdev
->rings
[i
].local_port
== -1) {
387 xen_pv_printf(xendev
, 0,
388 "xenevtchn_bind_interdomain failed port=%d\n",
389 xen_9pdev
->rings
[i
].evtchn
);
392 xen_pv_printf(xendev
, 2, "bind evtchn port %d\n", xendev
->local_port
);
393 qemu_set_fd_handler(xenevtchn_fd(xen_9pdev
->rings
[i
].evtchndev
),
394 xen_9pfs_evtchn_event
, NULL
, &xen_9pdev
->rings
[i
]);
397 xen_9pdev
->security_model
= xenstore_read_be_str(xendev
, "security_model");
398 xen_9pdev
->path
= xenstore_read_be_str(xendev
, "path");
399 xen_9pdev
->id
= s
->fsconf
.fsdev_id
=
400 g_strdup_printf("xen9p%d", xendev
->dev
);
401 xen_9pdev
->tag
= s
->fsconf
.tag
= xenstore_read_fe_str(xendev
, "tag");
402 v9fs_register_transport(s
, &xen_9p_transport
);
403 fsdev
= qemu_opts_create(qemu_find_opts("fsdev"),
406 qemu_opt_set(fsdev
, "fsdriver", "local", NULL
);
407 qemu_opt_set(fsdev
, "path", xen_9pdev
->path
, NULL
);
408 qemu_opt_set(fsdev
, "security_model", xen_9pdev
->security_model
, NULL
);
409 qemu_opts_set_id(fsdev
, s
->fsconf
.fsdev_id
);
410 qemu_fsdev_add(fsdev
);
411 v9fs_device_realize_common(s
, NULL
);
416 xen_9pfs_free(xendev
);
420 static void xen_9pfs_alloc(struct XenDevice
*xendev
)
422 xenstore_write_be_str(xendev
, "versions", VERSIONS
);
423 xenstore_write_be_int(xendev
, "max-rings", MAX_RINGS
);
424 xenstore_write_be_int(xendev
, "max-ring-page-order", MAX_RING_ORDER
);
427 static void xen_9pfs_disconnect(struct XenDevice
*xendev
)
429 /* Dynamic hotplug of PV filesystems at runtime is not supported. */
432 struct XenDevOps xen_9pfs_ops
= {
433 .size
= sizeof(Xen9pfsDev
),
434 .flags
= DEVOPS_FLAG_NEED_GNTDEV
,
435 .alloc
= xen_9pfs_alloc
,
436 .init
= xen_9pfs_init
,
437 .initialise
= xen_9pfs_connect
,
438 .disconnect
= xen_9pfs_disconnect
,
439 .free
= xen_9pfs_free
,