From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: "Michael S. Tsirkin" <mst@redhat.com>
Cc: Alexey Kardashevskiy <aik@ozlabs.ru>,
Alex Williamson <alex.williamson@redhat.com>,
qemu-devel@nongnu.org, David Gibson <david@gibson.dropbear.id.au>
Subject: Re: [Qemu-devel] QEMU question: is eventfd not thread safe?
Date: Mon, 02 Jul 2012 08:30:37 +1000 [thread overview]
Message-ID: <1341181837.2588.6.camel@pasglop> (raw)
In-Reply-To: <20120701124314.GB4782@redhat.com>
> Doesn't qemu remove an fd handler before closing the fd?
> If not that's the bug right there.
No, it's just marked deleted, removal is deferred. But that doesn't
change the fact that you need to wake up select. Ie. What happens is:
- eventfd gets you fd #x
- thread 1 selects() on it which sleeps
- thread 2 closes (x)
- thread 2 does eventfd and gets fd #x (same number)
- new eventfd gets signalled, but doesn't wake up select which
internally is still waiting on the old file descriptor.
The reason for that is that select() (and poll()) internally in
the kernel do a get_file() on the fd (as a result of eventfd->poll
calling poll_wait()) and keeps a reference to the struct file.
So the fd itself can be freed from the table by close, but the
struct file remains around (f_count is elevated), thus the close
does not calls eventfd->release (that only happens on the last
close, ie, after select times out or returns for another reason).
I think this was even overlooked in the design of eventfd itself,
ie, it tries to wakeup all waiters in its release() function but that
will not be called as long as either select or poll is waiting due
to the elevated refcount.
The right solution at this stage if for qemu to kick select() out of its
slumber when it closes the fd, a signal does the job.
Cheers,
Ben.
> > eventfd_release() could wake it up but it is called when its refcounter becomes 0 and this won't happen till select() interrupts.
> >
> > Doing MSI init stuff, QEMU-VFIO calls the same event_notifier_init() (returns recycled fd=XX what is correct but confuses) and qemu_set_fd_handler() which adds a handler but select() does not pick it up.
> > The eventfd() (called by event_notifier_init()) allocates new struct file *P2 in the kernel, QEMU-VFIO passes this fd=XX to the kernel's VFIO. When MSI interrupt comes to the host kernel, the VFIO interrupt handler calls eventfd_signal() on the correct file* P2. However do_select() in the kernel does not interrupt to deliver eventfd event as it is still waiting on P1 - nobody interrupted select(). It can only interrupt on stdin events (like typing keys) and INTx interrupt (which does not happen as MSI is enabled).
> >
> > So we need to sync eventfd()/close() calls in one thread with select() in another. Below is the patch which simply sends SIGUSR2 to the main thread (the sample patch is below). Another solution could be adding new IO handler to wake select() up. Or to do something with the kernel but I am not sure what - implementing file_operations::flush for eventfd to do wakeup did not help and I did not dig any further.
> >
> >
> > Does it make sense? What do I miss? What would be the right solution?
> >
> >
> > ---
> > iohandler.c | 1 +
> > main-loop.c | 17 +++++++++++++++++
> > 2 files changed, 18 insertions(+)
> >
> > diff --git a/iohandler.c b/iohandler.c
> > index 3c74de6..54f4c48 100644
> > --- a/iohandler.c
> > +++ b/iohandler.c
> > @@ -77,6 +77,7 @@ int qemu_set_fd_handler2(int fd,
> > ioh->fd_write = fd_write;
> > ioh->opaque = opaque;
> > ioh->deleted = 0;
> > + kill(getpid(), SIGUSR2);
> > }
> > return 0;
> > }
> > diff --git a/main-loop.c b/main-loop.c
> > index eb3b6e6..f65e048 100644
> > --- a/main-loop.c
> > +++ b/main-loop.c
> > @@ -199,10 +199,27 @@ static int qemu_signal_init(void)
> > }
> > #endif
> >
> > +static void sigusr2_print(int signal)
> > +{
> > +}
> > +
> > +static void sigusr2_init(void)
> > +{
> > + struct sigaction action;
> > +
> > + memset(&action, 0, sizeof(action));
> > + sigfillset(&action.sa_mask);
> > + action.sa_handler = sigusr2_print;
> > + action.sa_flags = 0;
> > + sigaction(SIGUSR2, &action, NULL);
> > +}
> > +
> > int main_loop_init(void)
> > {
> > int ret;
> >
> > + sigusr2_init();
> > +
> > qemu_mutex_lock_iothread();
> > ret = qemu_signal_init();
> > if (ret) {
> > --
> > 1.7.10
next prev parent reply other threads:[~2012-07-01 22:30 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-01 11:06 [Qemu-devel] QEMU question: is eventfd not thread safe? Alexey Kardashevskiy
2012-07-01 12:43 ` Michael S. Tsirkin
2012-07-01 12:57 ` Alexey Kardashevskiy
2012-07-01 23:07 ` Benjamin Herrenschmidt
2012-07-02 0:06 ` Alexey Kardashevskiy
2012-07-02 0:42 ` ronnie sahlberg
2012-07-02 0:45 ` Benjamin Herrenschmidt
2012-07-02 0:44 ` Benjamin Herrenschmidt
2012-07-02 0:49 ` Benjamin Herrenschmidt
2012-07-01 22:30 ` Benjamin Herrenschmidt [this message]
2012-07-01 13:32 ` Paolo Bonzini
2012-07-01 13:40 ` Alexey Kardashevskiy
2012-07-01 14:46 ` Alexey Kardashevskiy
2012-07-01 15:03 ` Paolo Bonzini
2012-07-01 19:48 ` [Qemu-devel] [PATCH] eventfd: making it rhread safe Alexey Kardashevskiy
2012-07-09 3:10 ` Alexey Kardashevskiy
2012-07-18 8:25 ` Alexey Kardashevskiy
2012-07-18 11:47 ` Michael S. Tsirkin
2012-07-18 12:08 ` [Qemu-devel] [PATCH] eventfd: making it thread safe Alexey Kardashevskiy
2012-07-18 12:22 ` Michael S. Tsirkin
2012-07-18 12:58 ` Alexey Kardashevskiy
2012-07-18 12:52 ` Alexey Kardashevskiy
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=1341181837.2588.6.camel@pasglop \
--to=benh@kernel.crashing.org \
--cc=aik@ozlabs.ru \
--cc=alex.williamson@redhat.com \
--cc=david@gibson.dropbear.id.au \
--cc=mst@redhat.com \
--cc=qemu-devel@nongnu.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).