aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/9pfs/9p.c18
-rw-r--r--hw/9pfs/trace-events1
2 files changed, 19 insertions, 0 deletions
diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
index 364c7cb..e88bb50 100644
--- a/hw/9pfs/9p.c
+++ b/hw/9pfs/9p.c
@@ -630,6 +630,24 @@ static void coroutine_fn pdu_complete(V9fsPDU *pdu, ssize_t len)
V9fsState *s = pdu->s;
int ret;
+ /*
+ * The 9p spec requires that successfully cancelled pdus receive no reply.
+ * Sending a reply would confuse clients because they would
+ * assume that any EINTR is the actual result of the operation,
+ * rather than a consequence of the cancellation. However, if
+ * the operation completed (succesfully or with an error other
+ * than caused be cancellation), we do send out that reply, both
+ * for efficiency and to avoid confusing the rest of the state machine
+ * that assumes passing a non-error here will mean a successful
+ * transmission of the reply.
+ */
+ bool discard = pdu->cancelled && len == -EINTR;
+ if (discard) {
+ trace_v9fs_rcancel(pdu->tag, pdu->id);
+ pdu->size = 0;
+ goto out_notify;
+ }
+
if (len < 0) {
int err = -len;
len = 7;
diff --git a/hw/9pfs/trace-events b/hw/9pfs/trace-events
index 08a4abf..1aee350 100644
--- a/hw/9pfs/trace-events
+++ b/hw/9pfs/trace-events
@@ -1,6 +1,7 @@
# See docs/devel/tracing.txt for syntax documentation.
# hw/9pfs/virtio-9p.c
+v9fs_rcancel(uint16_t tag, uint8_t id) "tag %d id %d"
v9fs_rerror(uint16_t tag, uint8_t id, int err) "tag %d id %d err %d"
v9fs_version(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"
v9fs_version_return(uint16_t tag, uint8_t id, int32_t msize, char* version) "tag %d id %d msize %d version %s"