summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '0017-xen-io-Fix-race-between-sending-an-I-O-and-domain-sh.patch')
-rw-r--r--0017-xen-io-Fix-race-between-sending-an-I-O-and-domain-sh.patch142
1 files changed, 142 insertions, 0 deletions
diff --git a/0017-xen-io-Fix-race-between-sending-an-I-O-and-domain-sh.patch b/0017-xen-io-Fix-race-between-sending-an-I-O-and-domain-sh.patch
new file mode 100644
index 0000000..d226e97
--- /dev/null
+++ b/0017-xen-io-Fix-race-between-sending-an-I-O-and-domain-sh.patch
@@ -0,0 +1,142 @@
+From 982a314bd3000a16c3128afadb36a8ff41029adc Mon Sep 17 00:00:00 2001
+From: Julien Grall <jgrall@amazon.com>
+Date: Tue, 7 Jun 2022 14:06:11 +0200
+Subject: [PATCH 17/32] xen: io: Fix race between sending an I/O and domain
+ shutdown
+
+Xen provides hypercalls to shutdown (SCHEDOP_shutdown{,_code}) and
+resume a domain (XEN_DOMCTL_resumedomain). They can be used for checkpoint
+where the expectation is the domain should continue as nothing happened
+afterwards.
+
+hvmemul_do_io() and handle_pio() will act differently if the return
+code of hvm_send_ioreq() (resp. hvmemul_do_pio_buffer()) is X86EMUL_RETRY.
+
+In this case, the I/O state will be reset to STATE_IOREQ_NONE (i.e
+no I/O is pending) and/or the PC will not be advanced.
+
+If the shutdown request happens right after the I/O was sent to the
+IOREQ, then emulation code will end up to re-execute the instruction
+and therefore forward again the same I/O (at least when reading IO port).
+
+This would be problem if the access has a side-effect. A dumb example,
+is a device implementing a counter which is incremented by one for every
+access. When running shutdown/resume in a loop, the value read by the
+OS may not be the old value + 1.
+
+Add an extra boolean in the structure hvm_vcpu_io to indicate whether
+the I/O was suspended. This is then used in place of checking the domain
+is shutting down in hvmemul_do_io() and handle_pio() as they should
+act on suspend (i.e. vcpu_start_shutdown_deferral() returns false) rather
+than shutdown.
+
+Signed-off-by: Julien Grall <jgrall@amazon.com>
+Reviewed-by: Paul Durrant <paul@xen.org>
+master commit: b7e0d8978810b534725e94a321736496928f00a5
+master date: 2022-05-06 17:16:22 +0100
+---
+ xen/arch/arm/ioreq.c | 3 ++-
+ xen/arch/x86/hvm/emulate.c | 3 ++-
+ xen/arch/x86/hvm/io.c | 7 ++++---
+ xen/common/ioreq.c | 4 ++++
+ xen/include/xen/sched.h | 5 +++++
+ 5 files changed, 17 insertions(+), 5 deletions(-)
+
+diff --git a/xen/arch/arm/ioreq.c b/xen/arch/arm/ioreq.c
+index 308650b40051..fbccef212bf1 100644
+--- a/xen/arch/arm/ioreq.c
++++ b/xen/arch/arm/ioreq.c
+@@ -80,9 +80,10 @@ enum io_state try_fwd_ioserv(struct cpu_user_regs *regs,
+ return IO_ABORT;
+
+ vio->req = p;
++ vio->suspended = false;
+
+ rc = ioreq_send(s, &p, 0);
+- if ( rc != IO_RETRY || v->domain->is_shutting_down )
++ if ( rc != IO_RETRY || vio->suspended )
+ vio->req.state = STATE_IOREQ_NONE;
+ else if ( !ioreq_needs_completion(&vio->req) )
+ rc = IO_HANDLED;
+diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c
+index 76a2ccfafe23..7da348b5d486 100644
+--- a/xen/arch/x86/hvm/emulate.c
++++ b/xen/arch/x86/hvm/emulate.c
+@@ -239,6 +239,7 @@ static int hvmemul_do_io(
+ ASSERT(p.count);
+
+ vio->req = p;
++ vio->suspended = false;
+
+ rc = hvm_io_intercept(&p);
+
+@@ -334,7 +335,7 @@ static int hvmemul_do_io(
+ else
+ {
+ rc = ioreq_send(s, &p, 0);
+- if ( rc != X86EMUL_RETRY || currd->is_shutting_down )
++ if ( rc != X86EMUL_RETRY || vio->suspended )
+ vio->req.state = STATE_IOREQ_NONE;
+ else if ( !ioreq_needs_completion(&vio->req) )
+ rc = X86EMUL_OKAY;
+diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c
+index 93f1d1503fa6..80915f27e488 100644
+--- a/xen/arch/x86/hvm/io.c
++++ b/xen/arch/x86/hvm/io.c
+@@ -138,10 +138,11 @@ bool handle_pio(uint16_t port, unsigned int size, int dir)
+
+ case X86EMUL_RETRY:
+ /*
+- * We should not advance RIP/EIP if the domain is shutting down or
+- * if X86EMUL_RETRY has been returned by an internal handler.
++ * We should not advance RIP/EIP if the vio was suspended (e.g.
++ * because the domain is shutting down) or if X86EMUL_RETRY has
++ * been returned by an internal handler.
+ */
+- if ( curr->domain->is_shutting_down || !vcpu_ioreq_pending(curr) )
++ if ( vio->suspended || !vcpu_ioreq_pending(curr) )
+ return false;
+ break;
+
+diff --git a/xen/common/ioreq.c b/xen/common/ioreq.c
+index d732dc045df9..42414b750bef 100644
+--- a/xen/common/ioreq.c
++++ b/xen/common/ioreq.c
+@@ -1256,6 +1256,7 @@ int ioreq_send(struct ioreq_server *s, ioreq_t *proto_p,
+ struct vcpu *curr = current;
+ struct domain *d = curr->domain;
+ struct ioreq_vcpu *sv;
++ struct vcpu_io *vio = &curr->io;
+
+ ASSERT(s);
+
+@@ -1263,7 +1264,10 @@ int ioreq_send(struct ioreq_server *s, ioreq_t *proto_p,
+ return ioreq_send_buffered(s, proto_p);
+
+ if ( unlikely(!vcpu_start_shutdown_deferral(curr)) )
++ {
++ vio->suspended = true;
+ return IOREQ_STATUS_RETRY;
++ }
+
+ list_for_each_entry ( sv,
+ &s->ioreq_vcpu_list,
+diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
+index 28146ee404e6..9671062360ac 100644
+--- a/xen/include/xen/sched.h
++++ b/xen/include/xen/sched.h
+@@ -159,6 +159,11 @@ enum vio_completion {
+ struct vcpu_io {
+ /* I/O request in flight to device model. */
+ enum vio_completion completion;
++ /*
++ * Indicate whether the I/O was not handled because the domain
++ * is about to be paused.
++ */
++ bool suspended;
+ ioreq_t req;
+ };
+
+--
+2.35.1
+