mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
xen/9pfs: yield when there isn't enough room on the ring
Instead of truncating replies, which is problematic, wait until the client reads more data and frees bytes on the reply ring. Do that by calling qemu_coroutine_yield(). The corresponding qemu_coroutine_enter_if_inactive() is called from xen_9pfs_bh upon receiving the next notification from the client. We need to be careful to avoid races in case xen_9pfs_bh and the coroutine are both active at the same time. In xen_9pfs_bh, wait until either the critical section is over (ring->co == NULL) or until the coroutine becomes inactive (qemu_coroutine_yield() was called) before continuing. Then, simply wake up the coroutine if it is inactive. Signed-off-by: Stefano Stabellini <stefano.stabellini@xilinx.com> Reviewed-by: Christian Schoenebeck <qemu_oss@crudebyte.com> Message-Id: <20200521192627.15259-2-sstabellini@kernel.org> Signed-off-by: Greg Kurz <groug@kaod.org>
This commit is contained in:
parent
cf45183b71
commit
a4c4d46272
1 changed files with 25 additions and 6 deletions
|
@ -37,6 +37,7 @@ typedef struct Xen9pfsRing {
|
|||
|
||||
struct iovec *sg;
|
||||
QEMUBH *bh;
|
||||
Coroutine *co;
|
||||
|
||||
/* local copies, so that we can read/write PDU data directly from
|
||||
* the ring */
|
||||
|
@ -198,16 +199,20 @@ static void xen_9pfs_init_in_iov_from_pdu(V9fsPDU *pdu,
|
|||
g_free(ring->sg);
|
||||
|
||||
ring->sg = g_new0(struct iovec, 2);
|
||||
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
|
||||
ring->co = qemu_coroutine_self();
|
||||
/* make sure other threads see ring->co changes before continuing */
|
||||
smp_wmb();
|
||||
|
||||
again:
|
||||
xen_9pfs_in_sg(ring, ring->sg, &num, pdu->idx, size);
|
||||
buf_size = iov_size(ring->sg, num);
|
||||
if (buf_size < size) {
|
||||
xen_pv_printf(&xen_9pfs->xendev, 0, "Xen 9pfs request type %d"
|
||||
"needs %zu bytes, buffer has %zu\n", pdu->id, size,
|
||||
buf_size);
|
||||
xen_be_set_state(&xen_9pfs->xendev, XenbusStateClosing);
|
||||
xen_9pfs_disconnect(&xen_9pfs->xendev);
|
||||
qemu_coroutine_yield();
|
||||
goto again;
|
||||
}
|
||||
ring->co = NULL;
|
||||
/* make sure other threads see ring->co changes before continuing */
|
||||
smp_wmb();
|
||||
|
||||
*piov = ring->sg;
|
||||
*pniov = num;
|
||||
|
@ -292,6 +297,20 @@ static int xen_9pfs_receive(Xen9pfsRing *ring)
|
|||
static void xen_9pfs_bh(void *opaque)
|
||||
{
|
||||
Xen9pfsRing *ring = opaque;
|
||||
bool wait;
|
||||
|
||||
again:
|
||||
wait = ring->co != NULL && qemu_coroutine_entered(ring->co);
|
||||
/* paired with the smb_wmb barriers in xen_9pfs_init_in_iov_from_pdu */
|
||||
smp_rmb();
|
||||
if (wait) {
|
||||
cpu_relax();
|
||||
goto again;
|
||||
}
|
||||
|
||||
if (ring->co != NULL) {
|
||||
qemu_coroutine_enter_if_inactive(ring->co);
|
||||
}
|
||||
xen_9pfs_receive(ring);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue