In include/qemu/coroutine.h, we have: /** * Yield the coroutine for a given duration * * Behaves similarly to co_sleep_ns(), but the sleeping coroutine will be * resumed when using aio_poll(). */ void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,
but there is no co_sleep_ns() anywhere. What should the documentation actually state? Meanwhile, I'm trying to figure out if there is an easy way to hack qemu-nbd to send two structured replies interleaved (as in A.1, B.1, A.2, B.2) to ensure the NBD client coroutines properly handle interleaved responses, but adding a plain sleep() between A.1 and A.2 does not work, and I'm not sure whether co_aio_sleep_ns() would work for the hack instead. The hack I'm currently playing with splits reads and structured errors into two parts, attempting to use sleeps to force the server to send replies out of order: diff --git c/nbd/server.c w/nbd/server.c index bcf0cdb47c..4b642127bb 100644 --- c/nbd/server.c +++ w/nbd/server.c @@ -1285,13 +1285,24 @@ static int coroutine_fn nbd_co_send_structured_read(NBDClient *client, {.iov_base = &chunk, .iov_len = sizeof(chunk)}, {.iov_base = data, .iov_len = size} }; + int ret; trace_nbd_co_send_structured_read(handle, offset, data, size); - set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_OFFSET_DATA, + set_be_chunk(&chunk.h, 0, NBD_REPLY_TYPE_OFFSET_DATA, handle, sizeof(chunk) - sizeof(chunk.h) + size); stq_be_p(&chunk.offset, offset); - return nbd_co_send_iov(client, iov, 2, errp); + ret = nbd_co_send_iov(client, iov, 2, errp); + if (ret < 0) { + return ret; + } + + sleep(2); + + set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_NONE, + handle, 0); + iov[0].iov_len = sizeof(chunk.h); + return nbd_co_send_iov(client, iov, 1, errp); } static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, @@ -1306,16 +1317,27 @@ static int coroutine_fn nbd_co_send_structured_error(NBDClient *client, {.iov_base = &chunk, .iov_len = sizeof(chunk)}, {.iov_base = (char *)msg, .iov_len = msg ? strlen(msg) : 0}, }; + int ret; assert(nbd_err); trace_nbd_co_send_structured_error(handle, nbd_err, nbd_err_lookup(nbd_err), msg ? msg : ""); - set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_ERROR, handle, + set_be_chunk(&chunk.h, 0, NBD_REPLY_TYPE_ERROR, handle, sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); stl_be_p(&chunk.error, nbd_err); stw_be_p(&chunk.message_length, iov[1].iov_len); - return nbd_co_send_iov(client, iov, 1 + !!iov[1].iov_len, errp); + ret = nbd_co_send_iov(client, iov, 1 + !!iov[1].iov_len, errp); + if (ret < 0) { + return ret; + } + + sleep(1); + + set_be_chunk(&chunk.h, NBD_REPLY_FLAG_DONE, NBD_REPLY_TYPE_NONE, + handle, 0); + iov[0].iov_len = sizeof(chunk.h); + return nbd_co_send_iov(client, iov, 1, errp); } /* nbd_co_receive_request coupled with a client that does: $ ./qemu-io -f raw nbd://localhost:10809/foo --trace='nbd_*' -c 'aio_write -P 3 1 1' -c 'aio_read -P 1 1 1' but the trace shows that the client does not receive B.1 until after it has blocked waiting for A.2, which is not what I was hoping to see. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
signature.asc
Description: OpenPGP digital signature