From: Laszlo Ersek <lersek@redhat.com>
To: Rusty Russell <rusty@rustcorp.com.au>,
Stefan Hajnoczi <stefanha@redhat.com>,
virtualization@lists.linux-foundation.org,
Jordan Justen <jordan.l.justen@intel.com>,
Laszlo Ersek <lersek@redhat.com>
Subject: [virtio-spec PATCH 5/5] Receiving Used Buffers: prevent speculative load when not sequentially consistent
Date: Sat, 8 Jun 2013 19:39:28 +0200 [thread overview]
Message-ID: <1370713168-20624-6-git-send-email-lersek@redhat.com> (raw)
In-Reply-To: <1370713168-20624-1-git-send-email-lersek@redhat.com>
The example code in "Receiving Used Buffers From The Device" goes as
follows:
vring_disable_interrupts(vq);
for (;;) {
if (vq->last_seen_used == vring->used.idx) {
vring_enable_interrupts(vq);
mb();
if (vq->last_seen_used == vring->used.idx)
break;
vring_disable_interrupts(vq);
}
struct vring_used_elem *e =
&vring->used.ring[vq->last_seen_used % qsz];
process_buffer(e);
vq->last_seen_used++;
}
Suppose that process_buffer() does something like this:
process_buffer(struct vring_used_elem *e)
{
u32 id;
u32 len;
id = e->id;
len = e->len;
/* go on to process the descriptor chain starting at "id" */
process_desc_chain(id, len);
}
On an architecture that is not sequentially consistent, the "e->id"
load could be executed out of order, speculatively; for example:
vring_disable_interrupts(vq);
for (;;) {
struct vring_used_elem *e =
&vring->used.ring[vq->last_seen_used % qsz];
u32 id = e->id;
u32 len = e->len;
if (vq->last_seen_used == vring->used.idx) {
vring_enable_interrupts(vq);
mb();
if (vq->last_seen_used == vring->used.idx)
break;
vring_disable_interrupts(vq);
}
process_desc_chain(id, len);
vq->last_seen_used++;
}
The (*e) pointer dereferences are OK, but the pointer targets could be
stale at the time of the speculative load (just adding comments):
vring_disable_interrupts(vq);
for (;;) {
/* ring is empty, load stale data into "id" and "len" */
struct vring_used_elem *e =
&vring->used.ring[vq->last_seen_used % qsz];
u32 id = e->id;
u32 len = e->len;
/* at this point the host goes through all of the following:
* - fill in a descriptor chain
* - place the index of its head descriptor on the used ring
* - store the number of processed bytes too
* - mb()
* - bump used index
* - mb()
*
* and the used index happens to become visible to the guest,
* enabling it to move past the next check:
*/
if (vq->last_seen_used == vring->used.idx) {
vring_enable_interrupts(vq);
mb();
if (vq->last_seen_used == vring->used.idx)
break;
vring_disable_interrupts(vq);
}
/* use stale "id" and "len" */
process_desc_chain(id, len);
vq->last_seen_used++;
}
Prevent this by adding a barrier between the ring emptiness check and the
access to the used element.
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
virtio-spec.lyx | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/virtio-spec.lyx b/virtio-spec.lyx
index 51f41dc..2186d35 100644
--- a/virtio-spec.lyx
+++ b/virtio-spec.lyx
@@ -2982,6 +2982,11 @@ for (;;) {
\begin_layout Plain Layout
+ mb();
+\end_layout
+
+\begin_layout Plain Layout
+
process_buffer(e);
\end_layout
--
1.7.1
next prev parent reply other threads:[~2013-06-08 17:39 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-06-08 17:39 [virtio-spec PATCH 0/5] Receiving Used Buffers example code: cleanups and an extra mb() Laszlo Ersek
2013-06-08 17:39 ` [virtio-spec PATCH 1/5] Receiving Used Buffers: fix typo in "ring empty" condition in example code Laszlo Ersek
2013-06-08 17:39 ` [virtio-spec PATCH 2/5] Receiving Used Buffers: re-disable interrupts when staying in the loop Laszlo Ersek
2013-06-08 17:39 ` [virtio-spec PATCH 3/5] Receiving Used Buffers: variable for Queue Size is called "qsz" elsewhere Laszlo Ersek
2013-06-08 17:39 ` [virtio-spec PATCH 4/5] Receiving Used Buffers: switch . and -> operators, add missing & Laszlo Ersek
2013-06-08 17:39 ` Laszlo Ersek [this message]
2013-06-10 8:15 ` [virtio-spec PATCH 0/5] Receiving Used Buffers example code: cleanups and an extra mb() Stefan Hajnoczi
2013-06-17 2:17 ` Rusty Russell
2013-06-17 7:29 ` Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1370713168-20624-6-git-send-email-lersek@redhat.com \
--to=lersek@redhat.com \
--cc=jordan.l.justen@intel.com \
--cc=rusty@rustcorp.com.au \
--cc=stefanha@redhat.com \
--cc=virtualization@lists.linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).