From: David Vrabel <david.vrabel@citrix.com>
To: xen-devel@lists.xen.org
Cc: Keir Fraser <keir@xen.org>,
David Vrabel <david.vrabel@citrix.com>,
Jan Beulich <jbeulich@suse.com>
Subject: [PATCH 2/2] evtchn/fifo: don't corrupt queues if an old tail moves queues
Date: Tue, 12 Nov 2013 11:38:48 +0000 [thread overview]
Message-ID: <1384256328-20223-3-git-send-email-david.vrabel@citrix.com> (raw)
In-Reply-To: <1384256328-20223-1-git-send-email-david.vrabel@citrix.com>
From: David Vrabel <david.vrabel@citrix.com>
An event may still be the tail of a queue even if the queue is now
empty (an 'old tail' event). There is logic to handle the case when
this old tail event needs to be added to the now empty queue (by
checking for q->tail == port).
However, if the old tail event on queue A is moved to a different
queue B (by changing its VCPU or priority), the event may then be
linked onto queue B. When another event is linked onto queue A it
will check the old tail, see that it is linked (but on queue B) and
overwrite the LINK field, corrupting both queues.
When an event is linked, save the vcpu id and priority of thee queue
it is being linked onto. Use this when linking an event to check if
it is an unlinked old tail event. i.e., a) it has moved queues; b) it
is currently unlinked; and c) it's the tail of the old queue. If it
is an unlinked, old tail event, the old queue is empty and old_q->tail
is invalidated to ensure adding another event to old_q will update
HEAD. The tail is invalidated by setting it to 0 since the event 0 is
never linked.
The old_q->lock is held while setting LINKED to avoid a race with the
test of LINKED in evtchn_fifo_set_link().
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
---
xen/common/event_fifo.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
xen/include/xen/sched.h | 2 ++
2 files changed, 44 insertions(+), 1 deletions(-)
diff --git a/xen/common/event_fifo.c b/xen/common/event_fifo.c
index 9106c55..8e126d6 100644
--- a/xen/common/event_fifo.c
+++ b/xen/common/event_fifo.c
@@ -98,6 +98,47 @@ static bool_t evtchn_fifo_set_link(const struct domain *d, event_word_t *word,
return 1;
}
+static bool_t test_and_set_linked(const struct domain *d,
+ struct evtchn *evtchn,
+ struct evtchn_fifo_queue *q,
+ event_word_t *word)
+{
+ struct vcpu *old_v;
+ struct evtchn_fifo_queue *old_q;
+ bool_t was_linked;
+ unsigned long flags;
+
+ old_v = d->vcpu[evtchn->last_vcpu_id];
+ old_q = &old_v->evtchn_fifo->queue[evtchn->last_priority];
+
+ evtchn->last_vcpu_id = evtchn->notify_vcpu_id;
+ evtchn->last_priority = evtchn->priority;
+
+ if ( q == old_q )
+ return test_and_set_bit(EVTCHN_FIFO_LINKED, word);
+
+ /*
+ * This event is now on a different queue.
+ *
+ * If the event is still linked in the old queue it won't be moved
+ * yet.
+ *
+ * If this event is unlinked /and/ it's the old queue's tail, the
+ * old queue is empty and its tail must be invalidated to prevent
+ * adding an event to the old queue from corrupting the new queue.
+ */
+ spin_lock_irqsave(&old_q->lock, flags);
+
+ was_linked = test_and_set_bit(EVTCHN_FIFO_LINKED, word);
+
+ if ( !was_linked && old_q->tail == evtchn->port )
+ old_q->tail = 0;
+
+ spin_unlock_irqrestore(&old_q->lock, flags);
+
+ return was_linked;
+}
+
static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
{
struct domain *d = v->domain;
@@ -133,7 +174,7 @@ static void evtchn_fifo_set_pending(struct vcpu *v, struct evtchn *evtchn)
* Link the event if it unmasked and not already linked.
*/
if ( !test_bit(EVTCHN_FIFO_MASKED, word)
- && !test_and_set_bit(EVTCHN_FIFO_LINKED, word) )
+ && !test_and_set_linked(d, evtchn, q, word) )
{
event_word_t *tail_word;
bool_t linked = 0;
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 2397537..3714c37 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -98,6 +98,8 @@ struct evtchn
} u;
u8 priority;
u8 pending:1;
+ u16 last_vcpu_id;
+ u8 last_priority;
#ifdef FLASK_ENABLE
void *ssid;
#endif
--
1.7.2.5
next prev parent reply other threads:[~2013-11-12 11:38 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-11-12 11:38 [PATCHv4 0/2] Xen: FIFO-based event channel ABI fixes David Vrabel
2013-11-12 11:38 ` [PATCH 1/2] evtchn/fifo: don't spin indefinitely when setting LINK David Vrabel
2013-11-20 15:19 ` David Vrabel
2013-11-22 12:08 ` Jan Beulich
2013-11-12 11:38 ` David Vrabel [this message]
2013-11-15 13:15 ` [PATCH 2/2] evtchn/fifo: don't corrupt queues if an old tail moves queues David Vrabel
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=1384256328-20223-3-git-send-email-david.vrabel@citrix.com \
--to=david.vrabel@citrix.com \
--cc=jbeulich@suse.com \
--cc=keir@xen.org \
--cc=xen-devel@lists.xen.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).