[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] libxenstore: Use poll() with a non-blocking read()
> On Aug 16, 2015, at 1:59 AM, Ian Campbell <ian.campbell@xxxxxxxxxx> wrote: > > On Thu, 2015-08-13 at 16:44 -0500, Jonathan Creekmore wrote: >> With the addition of FMODE_ATOMIC_POS in the Linux 3.14 kernel, >> concurrent blocking file accesses to a single open file descriptor can >> cause a deadlock trying to grab the file position lock. If a watch has >> been set up, causing a read_thread to blocking read on the file >> descriptor, then future writes that would cause the background read to >> complete will block waiting on the file position lock before they can >> execute. > > This sounds like you are describing a kernel bug. Shouldn't this be > fixed in the kernel? > > In fact it even sounds a bit familiar, I wonder if it is fixed in some > version of Linux >> 3.14? (CCing a few relevant maintainers) > So, the latest I saw on the LKML, the problem still existed as of 3.17 and, looking forward through 4.2, the problem still exists there as well. I saw a few posts back in March 2015 talking about the deadlock, but it appeared to have gotten no traction. It isnât a deadlock in the kernel, but rather a deadlock between the two blocking reads or a blocking read or write. The slight rewrite I applied in my patch effectively works around the problem and prevents the library from flip-flopping the nonblocking flag on the file descriptor between two threads. >> This race condition only occurs when libxenstore is accessing >> the xenstore daemon through the /proc/xen/xenbus file and not through >> the unix domain socket, which is the case when the xenstore daemon is >> running as a stub domain or when oxenstored is passed --disable-socket. >> >> Arguably, since the /proc/xen/xenbus file is declared nonseekable, then >> the file position lock need not be grabbed, since the file cannot be >> seeked. However, that is not how the kernel API works. On the other >> hand, using the poll() API to implement the blocking for the read_all() >> function prevents the file descriptor from being switched back and forth >> between blocking and non-blocking modes between two threads. >> >> Signed-off-by: Jonathan Creekmore <jonathan.creekmore@xxxxxxxxx> >> --- >> tools/xenstore/xs.c | 52 ++++++++++++++++--------------------------- >> --------- >> 1 file changed, 16 insertions(+), 36 deletions(-) >> >> diff --git a/tools/xenstore/xs.c b/tools/xenstore/xs.c >> index d1e01ba..9b75493 100644 >> --- a/tools/xenstore/xs.c >> +++ b/tools/xenstore/xs.c >> @@ -31,6 +31,7 @@ >> #include <signal.h> >> #include <stdint.h> >> #include <errno.h> >> +#include <poll.h> >> #include "xenstore.h" >> #include "list.h" >> #include "utils.h" >> @@ -145,22 +146,6 @@ struct xs_handle { >> >> static int read_message(struct xs_handle *h, int nonblocking); >> >> -static bool setnonblock(int fd, int nonblock) { >> - int flags = fcntl(fd, F_GETFL); >> - if (flags == -1) >> - return false; >> - >> - if (nonblock) >> - flags |= O_NONBLOCK; >> - else >> - flags &= ~O_NONBLOCK; >> - >> - if (fcntl(fd, F_SETFL, flags) == -1) >> - return false; >> - >> - return true; >> -} >> - >> int xs_fileno(struct xs_handle *h) >> { >> char c = 0; >> @@ -216,7 +201,7 @@ error: >> static int get_dev(const char *connect_to) >> { >> /* We cannot open read-only because requests are writes */ >> - return open(connect_to, O_RDWR); >> + return open(connect_to, O_RDWR | O_NONBLOCK); >> } >> >> static struct xs_handle *get_handle(const char *connect_to) >> @@ -365,42 +350,37 @@ static bool read_all(int fd, void *data, >> unsigned int len, int nonblocking) >> /* With nonblocking, either reads either everything >> requested, >> * or nothing. */ >> { >> - if (!len) >> - return true; >> - >> - if (nonblocking && !setnonblock(fd, 1)) >> - return false; >> + int done; >> + struct pollfd fds[] = { >> + { >> + .fd = fd, >> + .events = POLLIN >> + } >> + }; >> >> while (len) { >> - int done; >> + if (!nonblocking) { >> + if (poll(fds, 1, -1) < 1) { >> + return false; >> + } >> + } >> >> done = read(fd, data, len); >> if (done < 0) { >> if (errno == EINTR) >> continue; >> - goto out_false; >> + return false; >> } >> if (done == 0) { >> /* It closed fd on us? EBADF is >> appropriate. */ >> errno = EBADF; >> - goto out_false; >> + return false; >> } >> data += done; >> len -= done; >> - >> - if (nonblocking) { >> - nonblocking = 0; >> - if (!setnonblock(fd, 0)) >> - goto out_false; >> - } >> } >> >> return true; >> - >> -out_false: >> - if (nonblocking) >> - setnonblock(fd, 0); >> - return false; >> } >> >> #ifdef XSTEST _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |