xref: /openbmc/qemu/hw/9pfs/xen-9p-backend.c (revision 92e667f6)
1b37eeb02SStefano Stabellini /*
2b37eeb02SStefano Stabellini  * Xen 9p backend
3b37eeb02SStefano Stabellini  *
4b37eeb02SStefano Stabellini  * Copyright Aporeto 2017
5b37eeb02SStefano Stabellini  *
6b37eeb02SStefano Stabellini  * Authors:
7b37eeb02SStefano Stabellini  *  Stefano Stabellini <stefano@aporeto.com>
8b37eeb02SStefano Stabellini  *
9b37eeb02SStefano Stabellini  */
10b37eeb02SStefano Stabellini 
116f569084SChristian Schoenebeck /*
126f569084SChristian Schoenebeck  * Not so fast! You might want to read the 9p developer docs first:
136f569084SChristian Schoenebeck  * https://wiki.qemu.org/Documentation/9p
146f569084SChristian Schoenebeck  */
156f569084SChristian Schoenebeck 
16b37eeb02SStefano Stabellini #include "qemu/osdep.h"
17b37eeb02SStefano Stabellini 
18b37eeb02SStefano Stabellini #include "hw/9pfs/9p.h"
192d0ed5e6SPaul Durrant #include "hw/xen/xen-legacy-backend.h"
20b37eeb02SStefano Stabellini #include "hw/9pfs/xen-9pfs.h"
21b836723dSMarkus Armbruster #include "qapi/error.h"
22b37eeb02SStefano Stabellini #include "qemu/config-file.h"
23db725815SMarkus Armbruster #include "qemu/main-loop.h"
24922a01a0SMarkus Armbruster #include "qemu/option.h"
25e2abfe5eSDavid Woodhouse #include "qemu/iov.h"
26b37eeb02SStefano Stabellini #include "fsdev/qemu-fsdev.h"
27b37eeb02SStefano Stabellini 
28*92e667f6SJason Andryuk #include "trace.h"
29*92e667f6SJason Andryuk 
30f23ef34aSStefano Stabellini #define VERSIONS "1"
31f23ef34aSStefano Stabellini #define MAX_RINGS 8
3284af7557SStefano Stabellini #define MAX_RING_ORDER 9
33f23ef34aSStefano Stabellini 
34f23ef34aSStefano Stabellini typedef struct Xen9pfsRing {
35f23ef34aSStefano Stabellini     struct Xen9pfsDev *priv;
36f23ef34aSStefano Stabellini 
37f23ef34aSStefano Stabellini     int ref;
38f23ef34aSStefano Stabellini     xenevtchn_handle   *evtchndev;
39f23ef34aSStefano Stabellini     int evtchn;
40f23ef34aSStefano Stabellini     int local_port;
41f23ef34aSStefano Stabellini     int ring_order;
42f23ef34aSStefano Stabellini     struct xen_9pfs_data_intf *intf;
43f23ef34aSStefano Stabellini     unsigned char *data;
44f23ef34aSStefano Stabellini     struct xen_9pfs_data ring;
45f23ef34aSStefano Stabellini 
46f23ef34aSStefano Stabellini     struct iovec *sg;
47f23ef34aSStefano Stabellini     QEMUBH *bh;
48a4c4d462SStefano Stabellini     Coroutine *co;
49f23ef34aSStefano Stabellini 
50f23ef34aSStefano Stabellini     /* local copies, so that we can read/write PDU data directly from
51f23ef34aSStefano Stabellini      * the ring */
52f23ef34aSStefano Stabellini     RING_IDX out_cons, out_size, in_cons;
53f23ef34aSStefano Stabellini     bool inprogress;
54f23ef34aSStefano Stabellini } Xen9pfsRing;
55f23ef34aSStefano Stabellini 
56b37eeb02SStefano Stabellini typedef struct Xen9pfsDev {
572d0ed5e6SPaul Durrant     struct XenLegacyDevice xendev;  /* must be first */
58f23ef34aSStefano Stabellini     V9fsState state;
59f23ef34aSStefano Stabellini     char *path;
60f23ef34aSStefano Stabellini     char *security_model;
61f23ef34aSStefano Stabellini     char *tag;
62f23ef34aSStefano Stabellini     char *id;
63f23ef34aSStefano Stabellini 
64f23ef34aSStefano Stabellini     int num_rings;
65f23ef34aSStefano Stabellini     Xen9pfsRing *rings;
66f63192b0SAlexander Bulekov     MemReentrancyGuard mem_reentrancy_guard;
67b37eeb02SStefano Stabellini } Xen9pfsDev;
68b37eeb02SStefano Stabellini 
692d0ed5e6SPaul Durrant static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev);
70e08d1e11SStefano Stabellini 
xen_9pfs_in_sg(Xen9pfsRing * ring,struct iovec * in_sg,int * num,uint32_t idx,uint32_t size)7140a23892SStefano Stabellini static void xen_9pfs_in_sg(Xen9pfsRing *ring,
7240a23892SStefano Stabellini                            struct iovec *in_sg,
7340a23892SStefano Stabellini                            int *num,
7440a23892SStefano Stabellini                            uint32_t idx,
7540a23892SStefano Stabellini                            uint32_t size)
7640a23892SStefano Stabellini {
7740a23892SStefano Stabellini     RING_IDX cons, prod, masked_prod, masked_cons;
7840a23892SStefano Stabellini 
7940a23892SStefano Stabellini     cons = ring->intf->in_cons;
8040a23892SStefano Stabellini     prod = ring->intf->in_prod;
8140a23892SStefano Stabellini     xen_rmb();
8240a23892SStefano Stabellini     masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
8340a23892SStefano Stabellini     masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
8440a23892SStefano Stabellini 
8540a23892SStefano Stabellini     if (masked_prod < masked_cons) {
8640a23892SStefano Stabellini         in_sg[0].iov_base = ring->ring.in + masked_prod;
8740a23892SStefano Stabellini         in_sg[0].iov_len = masked_cons - masked_prod;
8840a23892SStefano Stabellini         *num = 1;
8940a23892SStefano Stabellini     } else {
9040a23892SStefano Stabellini         in_sg[0].iov_base = ring->ring.in + masked_prod;
9140a23892SStefano Stabellini         in_sg[0].iov_len = XEN_FLEX_RING_SIZE(ring->ring_order) - masked_prod;
9240a23892SStefano Stabellini         in_sg[1].iov_base = ring->ring.in;
9340a23892SStefano Stabellini         in_sg[1].iov_len = masked_cons;
9440a23892SStefano Stabellini         *num = 2;
9540a23892SStefano Stabellini     }
9640a23892SStefano Stabellini }
9740a23892SStefano Stabellini 
xen_9pfs_out_sg(Xen9pfsRing * ring,struct iovec * out_sg,int * num,uint32_t idx)9840a23892SStefano Stabellini static void xen_9pfs_out_sg(Xen9pfsRing *ring,
9940a23892SStefano Stabellini                             struct iovec *out_sg,
10040a23892SStefano Stabellini                             int *num,
10140a23892SStefano Stabellini                             uint32_t idx)
10240a23892SStefano Stabellini {
10340a23892SStefano Stabellini     RING_IDX cons, prod, masked_prod, masked_cons;
10440a23892SStefano Stabellini 
10540a23892SStefano Stabellini     cons = ring->intf->out_cons;
10640a23892SStefano Stabellini     prod = ring->intf->out_prod;
10740a23892SStefano Stabellini     xen_rmb();
10840a23892SStefano Stabellini     masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
10940a23892SStefano Stabellini     masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
11040a23892SStefano Stabellini 
11140a23892SStefano Stabellini     if (masked_cons < masked_prod) {
11240a23892SStefano Stabellini         out_sg[0].iov_base = ring->ring.out + masked_cons;
11340a23892SStefano Stabellini         out_sg[0].iov_len = ring->out_size;
11440a23892SStefano Stabellini         *num = 1;
11540a23892SStefano Stabellini     } else {
11640a23892SStefano Stabellini         if (ring->out_size >
11740a23892SStefano Stabellini             (XEN_FLEX_RING_SIZE(ring->ring_order) - masked_cons)) {
11840a23892SStefano Stabellini             out_sg[0].iov_base = ring->ring.out + masked_cons;
11940a23892SStefano Stabellini             out_sg[0].iov_len = XEN_FLEX_RING_SIZE(ring->ring_order) -
12040a23892SStefano Stabellini                                 masked_cons;
12140a23892SStefano Stabellini             out_sg[1].iov_base = ring->ring.out;
12240a23892SStefano Stabellini             out_sg[1].iov_len = ring->out_size -
12340a23892SStefano Stabellini                                 (XEN_FLEX_RING_SIZE(ring->ring_order) -
12440a23892SStefano Stabellini                                  masked_cons);
12540a23892SStefano Stabellini             *num = 2;
12640a23892SStefano Stabellini         } else {
12740a23892SStefano Stabellini             out_sg[0].iov_base = ring->ring.out + masked_cons;
12840a23892SStefano Stabellini             out_sg[0].iov_len = ring->out_size;
12940a23892SStefano Stabellini             *num = 1;
13040a23892SStefano Stabellini         }
13140a23892SStefano Stabellini     }
13240a23892SStefano Stabellini }
13340a23892SStefano Stabellini 
xen_9pfs_pdu_vmarshal(V9fsPDU * pdu,size_t offset,const char * fmt,va_list ap)134b37eeb02SStefano Stabellini static ssize_t xen_9pfs_pdu_vmarshal(V9fsPDU *pdu,
135b37eeb02SStefano Stabellini                                      size_t offset,
136b37eeb02SStefano Stabellini                                      const char *fmt,
137b37eeb02SStefano Stabellini                                      va_list ap)
138b37eeb02SStefano Stabellini {
13940a23892SStefano Stabellini     Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
14040a23892SStefano Stabellini     struct iovec in_sg[2];
14140a23892SStefano Stabellini     int num;
142e08d1e11SStefano Stabellini     ssize_t ret;
14340a23892SStefano Stabellini 
14440a23892SStefano Stabellini     xen_9pfs_in_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
14540a23892SStefano Stabellini                    in_sg, &num, pdu->idx, ROUND_UP(offset + 128, 512));
146e08d1e11SStefano Stabellini 
147e08d1e11SStefano Stabellini     ret = v9fs_iov_vmarshal(in_sg, num, offset, 0, fmt, ap);
148e08d1e11SStefano Stabellini     if (ret < 0) {
149e08d1e11SStefano Stabellini         xen_pv_printf(&xen_9pfs->xendev, 0,
1509bbb7e0fSChristian Schoenebeck                       "Failed to encode VirtFS reply type %d\n",
1519bbb7e0fSChristian Schoenebeck                       pdu->id + 1);
152e08d1e11SStefano Stabellini         xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
153e08d1e11SStefano Stabellini         xen_9pfs_disconnect(&xen_9pfs->xendev);
154e08d1e11SStefano Stabellini     }
155e08d1e11SStefano Stabellini     return ret;
156b37eeb02SStefano Stabellini }
157b37eeb02SStefano Stabellini 
xen_9pfs_pdu_vunmarshal(V9fsPDU * pdu,size_t offset,const char * fmt,va_list ap)158b37eeb02SStefano Stabellini static ssize_t xen_9pfs_pdu_vunmarshal(V9fsPDU *pdu,
159b37eeb02SStefano Stabellini                                        size_t offset,
160b37eeb02SStefano Stabellini                                        const char *fmt,
161b37eeb02SStefano Stabellini                                        va_list ap)
162b37eeb02SStefano Stabellini {
16340a23892SStefano Stabellini     Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
16440a23892SStefano Stabellini     struct iovec out_sg[2];
16540a23892SStefano Stabellini     int num;
166e08d1e11SStefano Stabellini     ssize_t ret;
16740a23892SStefano Stabellini 
16840a23892SStefano Stabellini     xen_9pfs_out_sg(&xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings],
16940a23892SStefano Stabellini                     out_sg, &num, pdu->idx);
170e08d1e11SStefano Stabellini 
171e08d1e11SStefano Stabellini     ret = v9fs_iov_vunmarshal(out_sg, num, offset, 0, fmt, ap);
172e08d1e11SStefano Stabellini     if (ret < 0) {
173e08d1e11SStefano Stabellini         xen_pv_printf(&xen_9pfs->xendev, 0,
174e08d1e11SStefano Stabellini                       "Failed to decode VirtFS request type %d\n", pdu->id);
175e08d1e11SStefano Stabellini         xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
176e08d1e11SStefano Stabellini         xen_9pfs_disconnect(&xen_9pfs->xendev);
177e08d1e11SStefano Stabellini     }
178e08d1e11SStefano Stabellini     return ret;
179b37eeb02SStefano Stabellini }
180b37eeb02SStefano Stabellini 
xen_9pfs_init_out_iov_from_pdu(V9fsPDU * pdu,struct iovec ** piov,unsigned int * pniov,size_t size)181b37eeb02SStefano Stabellini static void xen_9pfs_init_out_iov_from_pdu(V9fsPDU *pdu,
182b37eeb02SStefano Stabellini                                            struct iovec **piov,
1838d37de41SGreg Kurz                                            unsigned int *pniov,
1848d37de41SGreg Kurz                                            size_t size)
185b37eeb02SStefano Stabellini {
18640a23892SStefano Stabellini     Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
18740a23892SStefano Stabellini     Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
18840a23892SStefano Stabellini     int num;
18940a23892SStefano Stabellini 
19040a23892SStefano Stabellini     g_free(ring->sg);
19140a23892SStefano Stabellini 
19275607e0dSGreg Kurz     ring->sg = g_new0(struct iovec, 2);
19340a23892SStefano Stabellini     xen_9pfs_out_sg(ring, ring->sg, &num, pdu->idx);
19440a23892SStefano Stabellini     *piov = ring->sg;
19540a23892SStefano Stabellini     *pniov = num;
196b37eeb02SStefano Stabellini }
197b37eeb02SStefano Stabellini 
xen_9pfs_init_in_iov_from_pdu(V9fsPDU * pdu,struct iovec ** piov,unsigned int * pniov,size_t size)198b37eeb02SStefano Stabellini static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
199b37eeb02SStefano Stabellini                                           struct iovec **piov,
200b37eeb02SStefano Stabellini                                           unsigned int *pniov,
201cf45183bSStefano Stabellini                                           size_t size)
202b37eeb02SStefano Stabellini {
20340a23892SStefano Stabellini     Xen9pfsDev *xen_9pfs = container_of(pdu->s, Xen9pfsDev, state);
20440a23892SStefano Stabellini     Xen9pfsRing *ring = &xen_9pfs->rings[pdu->tag % xen_9pfs->num_rings];
20540a23892SStefano Stabellini     int num;
206e08d1e11SStefano Stabellini     size_t buf_size;
20740a23892SStefano Stabellini 
20840a23892SStefano Stabellini     g_free(ring->sg);
20940a23892SStefano Stabellini 
21075607e0dSGreg Kurz     ring->sg = g_new0(struct iovec, 2);
211a4c4d462SStefano Stabellini     ring->co = qemu_coroutine_self();
212a4c4d462SStefano Stabellini     /* make sure other threads see ring->co changes before continuing */
213a4c4d462SStefano Stabellini     smp_wmb();
214e08d1e11SStefano Stabellini 
215a4c4d462SStefano Stabellini again:
216a4c4d462SStefano Stabellini     xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
217e08d1e11SStefano Stabellini     buf_size = iov_size(ring->sg, num);
218cf45183bSStefano Stabellini     if (buf_size  < size) {
219a4c4d462SStefano Stabellini         qemu_coroutine_yield();
220a4c4d462SStefano Stabellini         goto again;
221e08d1e11SStefano Stabellini     }
222a4c4d462SStefano Stabellini     ring->co = NULL;
223a4c4d462SStefano Stabellini     /* make sure other threads see ring->co changes before continuing */
224a4c4d462SStefano Stabellini     smp_wmb();
225e08d1e11SStefano Stabellini 
22640a23892SStefano Stabellini     *piov = ring->sg;
22740a23892SStefano Stabellini     *pniov = num;
228b37eeb02SStefano Stabellini }
229b37eeb02SStefano Stabellini 
xen_9pfs_push_and_notify(V9fsPDU * pdu)230b37eeb02SStefano Stabellini static void xen_9pfs_push_and_notify(V9fsPDU *pdu)
231b37eeb02SStefano Stabellini {
2324476e09eSStefano Stabellini     RING_IDX prod;
2334476e09eSStefano Stabellini     Xen9pfsDev *priv = container_of(pdu->s, Xen9pfsDev, state);
2344476e09eSStefano Stabellini     Xen9pfsRing *ring = &priv->rings[pdu->tag % priv->num_rings];
2354476e09eSStefano Stabellini 
2364476e09eSStefano Stabellini     g_free(ring->sg);
2374476e09eSStefano Stabellini     ring->sg = NULL;
2384476e09eSStefano Stabellini 
2394476e09eSStefano Stabellini     ring->intf->out_cons = ring->out_cons;
2404476e09eSStefano Stabellini     xen_wmb();
2414476e09eSStefano Stabellini 
2424476e09eSStefano Stabellini     prod = ring->intf->in_prod;
2434476e09eSStefano Stabellini     xen_rmb();
2444476e09eSStefano Stabellini     ring->intf->in_prod = prod + pdu->size;
2454476e09eSStefano Stabellini     xen_wmb();
2464476e09eSStefano Stabellini 
2474476e09eSStefano Stabellini     ring->inprogress = false;
248b6cacfeaSDavid Woodhouse     qemu_xen_evtchn_notify(ring->evtchndev, ring->local_port);
2494476e09eSStefano Stabellini 
2504476e09eSStefano Stabellini     qemu_bh_schedule(ring->bh);
251b37eeb02SStefano Stabellini }
252b37eeb02SStefano Stabellini 
2538e71b96cSGreg Kurz static const V9fsTransport xen_9p_transport = {
254b37eeb02SStefano Stabellini     .pdu_vmarshal = xen_9pfs_pdu_vmarshal,
255b37eeb02SStefano Stabellini     .pdu_vunmarshal = xen_9pfs_pdu_vunmarshal,
256b37eeb02SStefano Stabellini     .init_in_iov_from_pdu = xen_9pfs_init_in_iov_from_pdu,
257b37eeb02SStefano Stabellini     .init_out_iov_from_pdu = xen_9pfs_init_out_iov_from_pdu,
258b37eeb02SStefano Stabellini     .push_and_notify = xen_9pfs_push_and_notify,
259b37eeb02SStefano Stabellini };
260b37eeb02SStefano Stabellini 
xen_9pfs_init(struct XenLegacyDevice * xendev)2612d0ed5e6SPaul Durrant static int xen_9pfs_init(struct XenLegacyDevice *xendev)
262b37eeb02SStefano Stabellini {
263b37eeb02SStefano Stabellini     return 0;
264b37eeb02SStefano Stabellini }
265b37eeb02SStefano Stabellini 
xen_9pfs_receive(Xen9pfsRing * ring)26647b70fb1SStefano Stabellini static int xen_9pfs_receive(Xen9pfsRing *ring)
26747b70fb1SStefano Stabellini {
26847b70fb1SStefano Stabellini     P9MsgHeader h;
269e08d1e11SStefano Stabellini     RING_IDX cons, prod, masked_prod, masked_cons, queued;
27047b70fb1SStefano Stabellini     V9fsPDU *pdu;
27147b70fb1SStefano Stabellini 
27247b70fb1SStefano Stabellini     if (ring->inprogress) {
27347b70fb1SStefano Stabellini         return 0;
27447b70fb1SStefano Stabellini     }
27547b70fb1SStefano Stabellini 
27647b70fb1SStefano Stabellini     cons = ring->intf->out_cons;
27747b70fb1SStefano Stabellini     prod = ring->intf->out_prod;
27847b70fb1SStefano Stabellini     xen_rmb();
27947b70fb1SStefano Stabellini 
280e08d1e11SStefano Stabellini     queued = xen_9pfs_queued(prod, cons, XEN_FLEX_RING_SIZE(ring->ring_order));
281e08d1e11SStefano Stabellini     if (queued < sizeof(h)) {
28247b70fb1SStefano Stabellini         return 0;
28347b70fb1SStefano Stabellini     }
28447b70fb1SStefano Stabellini     ring->inprogress = true;
28547b70fb1SStefano Stabellini 
28647b70fb1SStefano Stabellini     masked_prod = xen_9pfs_mask(prod, XEN_FLEX_RING_SIZE(ring->ring_order));
28747b70fb1SStefano Stabellini     masked_cons = xen_9pfs_mask(cons, XEN_FLEX_RING_SIZE(ring->ring_order));
28847b70fb1SStefano Stabellini 
28947b70fb1SStefano Stabellini     xen_9pfs_read_packet((uint8_t *) &h, ring->ring.out, sizeof(h),
29047b70fb1SStefano Stabellini                          masked_prod, &masked_cons,
29147b70fb1SStefano Stabellini                          XEN_FLEX_RING_SIZE(ring->ring_order));
292e08d1e11SStefano Stabellini     if (queued < le32_to_cpu(h.size_le)) {
293e08d1e11SStefano Stabellini         return 0;
294e08d1e11SStefano Stabellini     }
29547b70fb1SStefano Stabellini 
29647b70fb1SStefano Stabellini     /* cannot fail, because we only handle one request per ring at a time */
29747b70fb1SStefano Stabellini     pdu = pdu_alloc(&ring->priv->state);
29847b70fb1SStefano Stabellini     ring->out_size = le32_to_cpu(h.size_le);
29947b70fb1SStefano Stabellini     ring->out_cons = cons + le32_to_cpu(h.size_le);
30047b70fb1SStefano Stabellini 
301506f3275SGreg Kurz     pdu_submit(pdu, &h);
30247b70fb1SStefano Stabellini 
30347b70fb1SStefano Stabellini     return 0;
30447b70fb1SStefano Stabellini }
30547b70fb1SStefano Stabellini 
xen_9pfs_bh(void * opaque)306f23ef34aSStefano Stabellini static void xen_9pfs_bh(void *opaque)
307f23ef34aSStefano Stabellini {
30847b70fb1SStefano Stabellini     Xen9pfsRing *ring = opaque;
309a4c4d462SStefano Stabellini     bool wait;
310a4c4d462SStefano Stabellini 
311a4c4d462SStefano Stabellini again:
312a4c4d462SStefano Stabellini     wait = ring->co != NULL && qemu_coroutine_entered(ring->co);
313a4c4d462SStefano Stabellini     /* paired with the smb_wmb barriers in xen_9pfs_init_in_iov_from_pdu */
314a4c4d462SStefano Stabellini     smp_rmb();
315a4c4d462SStefano Stabellini     if (wait) {
316a4c4d462SStefano Stabellini         cpu_relax();
317a4c4d462SStefano Stabellini         goto again;
318a4c4d462SStefano Stabellini     }
319a4c4d462SStefano Stabellini 
320a4c4d462SStefano Stabellini     if (ring->co != NULL) {
321a4c4d462SStefano Stabellini         qemu_coroutine_enter_if_inactive(ring->co);
322a4c4d462SStefano Stabellini     }
32347b70fb1SStefano Stabellini     xen_9pfs_receive(ring);
324f23ef34aSStefano Stabellini }
325f23ef34aSStefano Stabellini 
xen_9pfs_evtchn_event(void * opaque)326f23ef34aSStefano Stabellini static void xen_9pfs_evtchn_event(void *opaque)
327f23ef34aSStefano Stabellini {
32847b70fb1SStefano Stabellini     Xen9pfsRing *ring = opaque;
32947b70fb1SStefano Stabellini     evtchn_port_t port;
33047b70fb1SStefano Stabellini 
331b6cacfeaSDavid Woodhouse     port = qemu_xen_evtchn_pending(ring->evtchndev);
332b6cacfeaSDavid Woodhouse     qemu_xen_evtchn_unmask(ring->evtchndev, port);
33347b70fb1SStefano Stabellini 
33447b70fb1SStefano Stabellini     qemu_bh_schedule(ring->bh);
335f23ef34aSStefano Stabellini }
336f23ef34aSStefano Stabellini 
xen_9pfs_disconnect(struct XenLegacyDevice * xendev)3372d0ed5e6SPaul Durrant static void xen_9pfs_disconnect(struct XenLegacyDevice *xendev)
338e08d1e11SStefano Stabellini {
339e08d1e11SStefano Stabellini     Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
340e08d1e11SStefano Stabellini     int i;
341e08d1e11SStefano Stabellini 
342*92e667f6SJason Andryuk     trace_xen_9pfs_disconnect(xendev->name);
343*92e667f6SJason Andryuk 
344e08d1e11SStefano Stabellini     for (i = 0; i < xen_9pdev->num_rings; i++) {
345e08d1e11SStefano Stabellini         if (xen_9pdev->rings[i].evtchndev != NULL) {
346b6cacfeaSDavid Woodhouse             qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
347e08d1e11SStefano Stabellini                                 NULL, NULL, NULL);
348b6cacfeaSDavid Woodhouse             qemu_xen_evtchn_unbind(xen_9pdev->rings[i].evtchndev,
349e08d1e11SStefano Stabellini                                    xen_9pdev->rings[i].local_port);
350e08d1e11SStefano Stabellini             xen_9pdev->rings[i].evtchndev = NULL;
351e08d1e11SStefano Stabellini         }
352f23ef34aSStefano Stabellini         if (xen_9pdev->rings[i].data != NULL) {
35358560f2aSPaul Durrant             xen_be_unmap_grant_refs(&xen_9pdev->xendev,
354f23ef34aSStefano Stabellini                                     xen_9pdev->rings[i].data,
355f80fad16SDavid Woodhouse                                     xen_9pdev->rings[i].intf->ref,
356f23ef34aSStefano Stabellini                                     (1 << xen_9pdev->rings[i].ring_order));
357*92e667f6SJason Andryuk             xen_9pdev->rings[i].data = NULL;
358f23ef34aSStefano Stabellini         }
359f23ef34aSStefano Stabellini         if (xen_9pdev->rings[i].intf != NULL) {
360f80fad16SDavid Woodhouse             xen_be_unmap_grant_ref(&xen_9pdev->xendev,
361f23ef34aSStefano Stabellini                                    xen_9pdev->rings[i].intf,
362f80fad16SDavid Woodhouse                                    xen_9pdev->rings[i].ref);
363*92e667f6SJason Andryuk             xen_9pdev->rings[i].intf = NULL;
364f23ef34aSStefano Stabellini         }
365f23ef34aSStefano Stabellini         if (xen_9pdev->rings[i].bh != NULL) {
366f23ef34aSStefano Stabellini             qemu_bh_delete(xen_9pdev->rings[i].bh);
367*92e667f6SJason Andryuk             xen_9pdev->rings[i].bh = NULL;
368f23ef34aSStefano Stabellini         }
369f23ef34aSStefano Stabellini     }
370e08d1e11SStefano Stabellini 
371e08d1e11SStefano Stabellini     g_free(xen_9pdev->id);
372*92e667f6SJason Andryuk     xen_9pdev->id = NULL;
373e08d1e11SStefano Stabellini     g_free(xen_9pdev->tag);
374*92e667f6SJason Andryuk     xen_9pdev->tag = NULL;
375e08d1e11SStefano Stabellini     g_free(xen_9pdev->path);
376*92e667f6SJason Andryuk     xen_9pdev->path = NULL;
377e08d1e11SStefano Stabellini     g_free(xen_9pdev->security_model);
378*92e667f6SJason Andryuk     xen_9pdev->security_model = NULL;
379f23ef34aSStefano Stabellini     g_free(xen_9pdev->rings);
380*92e667f6SJason Andryuk     xen_9pdev->rings = NULL;
381*92e667f6SJason Andryuk }
382*92e667f6SJason Andryuk 
xen_9pfs_free(struct XenLegacyDevice * xendev)383*92e667f6SJason Andryuk static int xen_9pfs_free(struct XenLegacyDevice *xendev)
384*92e667f6SJason Andryuk {
385*92e667f6SJason Andryuk     trace_xen_9pfs_free(xendev->name);
386*92e667f6SJason Andryuk 
387f23ef34aSStefano Stabellini     return 0;
388b37eeb02SStefano Stabellini }
389b37eeb02SStefano Stabellini 
xen_9pfs_connect(struct XenLegacyDevice * xendev)3902d0ed5e6SPaul Durrant static int xen_9pfs_connect(struct XenLegacyDevice *xendev)
391b37eeb02SStefano Stabellini {
392b836723dSMarkus Armbruster     Error *err = NULL;
393f23ef34aSStefano Stabellini     int i;
394f23ef34aSStefano Stabellini     Xen9pfsDev *xen_9pdev = container_of(xendev, Xen9pfsDev, xendev);
395f23ef34aSStefano Stabellini     V9fsState *s = &xen_9pdev->state;
396f23ef34aSStefano Stabellini     QemuOpts *fsdev;
397f23ef34aSStefano Stabellini 
398*92e667f6SJason Andryuk     trace_xen_9pfs_connect(xendev->name);
399*92e667f6SJason Andryuk 
400f23ef34aSStefano Stabellini     if (xenstore_read_fe_int(&xen_9pdev->xendev, "num-rings",
401f23ef34aSStefano Stabellini                              &xen_9pdev->num_rings) == -1 ||
402f23ef34aSStefano Stabellini         xen_9pdev->num_rings > MAX_RINGS || xen_9pdev->num_rings < 1) {
403f23ef34aSStefano Stabellini         return -1;
404f23ef34aSStefano Stabellini     }
405f23ef34aSStefano Stabellini 
40675607e0dSGreg Kurz     xen_9pdev->rings = g_new0(Xen9pfsRing, xen_9pdev->num_rings);
407f23ef34aSStefano Stabellini     for (i = 0; i < xen_9pdev->num_rings; i++) {
408f23ef34aSStefano Stabellini         char *str;
409f23ef34aSStefano Stabellini         int ring_order;
410f23ef34aSStefano Stabellini 
411f23ef34aSStefano Stabellini         xen_9pdev->rings[i].priv = xen_9pdev;
412f23ef34aSStefano Stabellini         xen_9pdev->rings[i].evtchn = -1;
413f23ef34aSStefano Stabellini         xen_9pdev->rings[i].local_port = -1;
414f23ef34aSStefano Stabellini 
415f23ef34aSStefano Stabellini         str = g_strdup_printf("ring-ref%u", i);
416f23ef34aSStefano Stabellini         if (xenstore_read_fe_int(&xen_9pdev->xendev, str,
417f23ef34aSStefano Stabellini                                  &xen_9pdev->rings[i].ref) == -1) {
418c0c24b95SStefano Stabellini             g_free(str);
419f23ef34aSStefano Stabellini             goto out;
420f23ef34aSStefano Stabellini         }
421f23ef34aSStefano Stabellini         g_free(str);
422f23ef34aSStefano Stabellini         str = g_strdup_printf("event-channel-%u", i);
423f23ef34aSStefano Stabellini         if (xenstore_read_fe_int(&xen_9pdev->xendev, str,
424f23ef34aSStefano Stabellini                                  &xen_9pdev->rings[i].evtchn) == -1) {
425c0c24b95SStefano Stabellini             g_free(str);
426f23ef34aSStefano Stabellini             goto out;
427f23ef34aSStefano Stabellini         }
428f23ef34aSStefano Stabellini         g_free(str);
429f23ef34aSStefano Stabellini 
43058560f2aSPaul Durrant         xen_9pdev->rings[i].intf =
43158560f2aSPaul Durrant             xen_be_map_grant_ref(&xen_9pdev->xendev,
432f23ef34aSStefano Stabellini                                  xen_9pdev->rings[i].ref,
433f23ef34aSStefano Stabellini                                  PROT_READ | PROT_WRITE);
434f23ef34aSStefano Stabellini         if (!xen_9pdev->rings[i].intf) {
435f23ef34aSStefano Stabellini             goto out;
436f23ef34aSStefano Stabellini         }
437f23ef34aSStefano Stabellini         ring_order = xen_9pdev->rings[i].intf->ring_order;
438f23ef34aSStefano Stabellini         if (ring_order > MAX_RING_ORDER) {
439f23ef34aSStefano Stabellini             goto out;
440f23ef34aSStefano Stabellini         }
441f23ef34aSStefano Stabellini         xen_9pdev->rings[i].ring_order = ring_order;
44258560f2aSPaul Durrant         xen_9pdev->rings[i].data =
44358560f2aSPaul Durrant             xen_be_map_grant_refs(&xen_9pdev->xendev,
444f23ef34aSStefano Stabellini                                   xen_9pdev->rings[i].intf->ref,
44558560f2aSPaul Durrant                                   (1 << ring_order),
446f23ef34aSStefano Stabellini                                   PROT_READ | PROT_WRITE);
447f23ef34aSStefano Stabellini         if (!xen_9pdev->rings[i].data) {
448f23ef34aSStefano Stabellini             goto out;
449f23ef34aSStefano Stabellini         }
450f23ef34aSStefano Stabellini         xen_9pdev->rings[i].ring.in = xen_9pdev->rings[i].data;
451f23ef34aSStefano Stabellini         xen_9pdev->rings[i].ring.out = xen_9pdev->rings[i].data +
452f23ef34aSStefano Stabellini                                        XEN_FLEX_RING_SIZE(ring_order);
453f23ef34aSStefano Stabellini 
454f63192b0SAlexander Bulekov         xen_9pdev->rings[i].bh = qemu_bh_new_guarded(xen_9pfs_bh,
455f63192b0SAlexander Bulekov                                                      &xen_9pdev->rings[i],
456f63192b0SAlexander Bulekov                                                      &xen_9pdev->mem_reentrancy_guard);
457f23ef34aSStefano Stabellini         xen_9pdev->rings[i].out_cons = 0;
458f23ef34aSStefano Stabellini         xen_9pdev->rings[i].out_size = 0;
459f23ef34aSStefano Stabellini         xen_9pdev->rings[i].inprogress = false;
460f23ef34aSStefano Stabellini 
461f23ef34aSStefano Stabellini 
462b6cacfeaSDavid Woodhouse         xen_9pdev->rings[i].evtchndev = qemu_xen_evtchn_open();
463f23ef34aSStefano Stabellini         if (xen_9pdev->rings[i].evtchndev == NULL) {
464f23ef34aSStefano Stabellini             goto out;
465f23ef34aSStefano Stabellini         }
466b6cacfeaSDavid Woodhouse         qemu_set_cloexec(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev));
467b6cacfeaSDavid Woodhouse         xen_9pdev->rings[i].local_port = qemu_xen_evtchn_bind_interdomain
468f23ef34aSStefano Stabellini                                             (xen_9pdev->rings[i].evtchndev,
469f23ef34aSStefano Stabellini                                              xendev->dom,
470f23ef34aSStefano Stabellini                                              xen_9pdev->rings[i].evtchn);
471f23ef34aSStefano Stabellini         if (xen_9pdev->rings[i].local_port == -1) {
472f23ef34aSStefano Stabellini             xen_pv_printf(xendev, 0,
473f23ef34aSStefano Stabellini                           "xenevtchn_bind_interdomain failed port=%d\n",
474f23ef34aSStefano Stabellini                           xen_9pdev->rings[i].evtchn);
475f23ef34aSStefano Stabellini             goto out;
476f23ef34aSStefano Stabellini         }
477f23ef34aSStefano Stabellini         xen_pv_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
478b6cacfeaSDavid Woodhouse         qemu_set_fd_handler(qemu_xen_evtchn_fd(xen_9pdev->rings[i].evtchndev),
479f23ef34aSStefano Stabellini                             xen_9pfs_evtchn_event, NULL, &xen_9pdev->rings[i]);
480f23ef34aSStefano Stabellini     }
481f23ef34aSStefano Stabellini 
482f23ef34aSStefano Stabellini     xen_9pdev->security_model = xenstore_read_be_str(xendev, "security_model");
483f23ef34aSStefano Stabellini     xen_9pdev->path = xenstore_read_be_str(xendev, "path");
484f23ef34aSStefano Stabellini     xen_9pdev->id = s->fsconf.fsdev_id =
485f23ef34aSStefano Stabellini         g_strdup_printf("xen9p%d", xendev->dev);
486f23ef34aSStefano Stabellini     xen_9pdev->tag = s->fsconf.tag = xenstore_read_fe_str(xendev, "tag");
487f23ef34aSStefano Stabellini     fsdev = qemu_opts_create(qemu_find_opts("fsdev"),
488f23ef34aSStefano Stabellini             s->fsconf.tag,
489f23ef34aSStefano Stabellini             1, NULL);
490f23ef34aSStefano Stabellini     qemu_opt_set(fsdev, "fsdriver", "local", NULL);
491f23ef34aSStefano Stabellini     qemu_opt_set(fsdev, "path", xen_9pdev->path, NULL);
492f23ef34aSStefano Stabellini     qemu_opt_set(fsdev, "security_model", xen_9pdev->security_model, NULL);
493f23ef34aSStefano Stabellini     qemu_opts_set_id(fsdev, s->fsconf.fsdev_id);
494b836723dSMarkus Armbruster     qemu_fsdev_add(fsdev, &err);
495b836723dSMarkus Armbruster     if (err) {
496b836723dSMarkus Armbruster         error_report_err(err);
497b836723dSMarkus Armbruster     }
498066eb006SGreg Kurz     v9fs_device_realize_common(s, &xen_9p_transport, NULL);
499f23ef34aSStefano Stabellini 
500b37eeb02SStefano Stabellini     return 0;
501f23ef34aSStefano Stabellini 
502f23ef34aSStefano Stabellini out:
503f23ef34aSStefano Stabellini     xen_9pfs_free(xendev);
504f23ef34aSStefano Stabellini     return -1;
505b37eeb02SStefano Stabellini }
506b37eeb02SStefano Stabellini 
xen_9pfs_alloc(struct XenLegacyDevice * xendev)5072d0ed5e6SPaul Durrant static void xen_9pfs_alloc(struct XenLegacyDevice *xendev)
508b37eeb02SStefano Stabellini {
509*92e667f6SJason Andryuk     trace_xen_9pfs_alloc(xendev->name);
510*92e667f6SJason Andryuk 
511f23ef34aSStefano Stabellini     xenstore_write_be_str(xendev, "versions", VERSIONS);
512f23ef34aSStefano Stabellini     xenstore_write_be_int(xendev, "max-rings", MAX_RINGS);
513f23ef34aSStefano Stabellini     xenstore_write_be_int(xendev, "max-ring-page-order", MAX_RING_ORDER);
514b37eeb02SStefano Stabellini }
515b37eeb02SStefano Stabellini 
516b37eeb02SStefano Stabellini struct XenDevOps xen_9pfs_ops = {
517b37eeb02SStefano Stabellini     .size       = sizeof(Xen9pfsDev),
518b37eeb02SStefano Stabellini     .flags      = DEVOPS_FLAG_NEED_GNTDEV,
519b37eeb02SStefano Stabellini     .alloc      = xen_9pfs_alloc,
520b37eeb02SStefano Stabellini     .init       = xen_9pfs_init,
521b37eeb02SStefano Stabellini     .initialise = xen_9pfs_connect,
522b37eeb02SStefano Stabellini     .disconnect = xen_9pfs_disconnect,
523b37eeb02SStefano Stabellini     .free       = xen_9pfs_free,
524b37eeb02SStefano Stabellini };
525