diff options
author | Stefano Stabellini <sstabellini@kernel.org> | 2017-04-05 15:04:00 -0400 |
---|---|---|
committer | Juergen Gross <jgross@suse.com> | 2017-05-02 05:11:43 -0400 |
commit | f66c72bea1293786b9916894019f96bcd729505b (patch) | |
tree | d06f34c799eb4ccc1ad50786756922c52b516a6f | |
parent | f023f18ddf41dda487241d1514075b1136eb8101 (diff) |
xen/9pfs: receive responses
Upon receiving a notification from the backend, schedule the
p9_xen_response work_struct. p9_xen_response checks if any responses are
available, if so, it reads them one by one, calling p9_client_cb to send
them up to the 9p layer (p9_client_cb completes the request). Handle the
ring following the Xen 9pfs specification.
CC: groug@kaod.org
CC: jgross@suse.com
CC: Eric Van Hensbergen <ericvh@gmail.com>
CC: Ron Minnich <rminnich@sandia.gov>
CC: Latchesar Ionkov <lucho@ionkov.net>
CC: v9fs-developer@lists.sourceforge.net
Signed-off-by: Stefano Stabellini <stefano@aporeto.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Juergen Gross <jgross@suse.com>
-rw-r--r-- | net/9p/trans_xen.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/net/9p/trans_xen.c b/net/9p/trans_xen.c index 28f30f49d5dd..47864245c0d4 100644 --- a/net/9p/trans_xen.c +++ b/net/9p/trans_xen.c | |||
@@ -189,6 +189,62 @@ again: | |||
189 | 189 | ||
190 | static void p9_xen_response(struct work_struct *work) | 190 | static void p9_xen_response(struct work_struct *work) |
191 | { | 191 | { |
192 | struct xen_9pfs_front_priv *priv; | ||
193 | struct xen_9pfs_dataring *ring; | ||
194 | RING_IDX cons, prod, masked_cons, masked_prod; | ||
195 | struct xen_9pfs_header h; | ||
196 | struct p9_req_t *req; | ||
197 | int status; | ||
198 | |||
199 | ring = container_of(work, struct xen_9pfs_dataring, work); | ||
200 | priv = ring->priv; | ||
201 | |||
202 | while (1) { | ||
203 | cons = ring->intf->in_cons; | ||
204 | prod = ring->intf->in_prod; | ||
205 | virt_rmb(); | ||
206 | |||
207 | if (xen_9pfs_queued(prod, cons, XEN_9PFS_RING_SIZE) < | ||
208 | sizeof(h)) { | ||
209 | notify_remote_via_irq(ring->irq); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | masked_prod = xen_9pfs_mask(prod, XEN_9PFS_RING_SIZE); | ||
214 | masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE); | ||
215 | |||
216 | /* First, read just the header */ | ||
217 | xen_9pfs_read_packet(&h, ring->data.in, sizeof(h), | ||
218 | masked_prod, &masked_cons, | ||
219 | XEN_9PFS_RING_SIZE); | ||
220 | |||
221 | req = p9_tag_lookup(priv->client, h.tag); | ||
222 | if (!req || req->status != REQ_STATUS_SENT) { | ||
223 | dev_warn(&priv->dev->dev, "Wrong req tag=%x\n", h.tag); | ||
224 | cons += h.size; | ||
225 | virt_mb(); | ||
226 | ring->intf->in_cons = cons; | ||
227 | continue; | ||
228 | } | ||
229 | |||
230 | memcpy(req->rc, &h, sizeof(h)); | ||
231 | req->rc->offset = 0; | ||
232 | |||
233 | masked_cons = xen_9pfs_mask(cons, XEN_9PFS_RING_SIZE); | ||
234 | /* Then, read the whole packet (including the header) */ | ||
235 | xen_9pfs_read_packet(req->rc->sdata, ring->data.in, h.size, | ||
236 | masked_prod, &masked_cons, | ||
237 | XEN_9PFS_RING_SIZE); | ||
238 | |||
239 | virt_mb(); | ||
240 | cons += h.size; | ||
241 | ring->intf->in_cons = cons; | ||
242 | |||
243 | status = (req->status != REQ_STATUS_ERROR) ? | ||
244 | REQ_STATUS_RCVD : REQ_STATUS_ERROR; | ||
245 | |||
246 | p9_client_cb(priv->client, req, status); | ||
247 | } | ||
192 | } | 248 | } |
193 | 249 | ||
194 | static irqreturn_t xen_9pfs_front_event_handler(int irq, void *r) | 250 | static irqreturn_t xen_9pfs_front_event_handler(int irq, void *r) |