From mboxrd@z Thu Jan 1 00:00:00 1970 From: Anders Kaseorg Subject: [PATCH v2] fifo: Do not restart open() if it already found a partner Date: Sun, 15 Jul 2012 17:14:25 -0400 (EDT) Message-ID: References: <1340712298-4583-1-git-send-email-andersk@mit.edu> <20120626202009.GA382@burratino> Mime-Version: 1.0 Content-Type: TEXT/PLAIN; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Return-path: Received: from DMZ-MAILSEC-SCANNER-4.MIT.EDU ([18.9.25.15]:54489 "EHLO dmz-mailsec-scanner-4.mit.edu" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750865Ab2GOVO3 convert rfc822-to-8bit (ORCPT ); Sun, 15 Jul 2012 17:14:29 -0400 In-Reply-To: Sender: dash-owner@vger.kernel.org List-Id: dash@vger.kernel.org To: Linus Torvalds Cc: Jonathan Nieder , Alexander Viro , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, dash@vger.kernel.org If a parent and child process open the two ends of a fifo, and the child immediately exits, the parent may receive a SIGCHLD before its open() returns. In that case, we need to make sure that open() will return successfully after the SIGCHLD handler returns, instead of throwing EINTR or being restarted. Otherwise, the restarted open() would incorrectly wait for a second partner on the other end. The following test demonstrates the EINTR that was wrongly thrown from the parent=E2=80=99s open(). Change .sa_flags =3D 0 to .sa_flags =3D S= A_RESTART to see a deadlock instead, in which the restarted open() waits for a second reader that will never come. (On my systems, this happens pretty reliably within about 5 to 500 iterations. Others report that it manages to loop ~forever sometimes; YMMV.) #include #include #include #include #include #include #include #include #define CHECK(x) do if ((x) =3D=3D -1) {perror(#x); abort();} while(0= ) void handler(int signum) {} int main() { struct sigaction act =3D {.sa_handler =3D handler, .sa_flags =3D = 0}; CHECK(sigaction(SIGCHLD, &act, NULL)); CHECK(mknod("fifo", S_IFIFO | S_IRWXU, 0)); for (;;) { int fd; pid_t pid; putc('.', stderr); CHECK(pid =3D fork()); if (pid =3D=3D 0) { CHECK(fd =3D open("fifo", O_RDONLY)); _exit(0); } CHECK(fd =3D open("fifo", O_WRONLY)); CHECK(close(fd)); CHECK(waitpid(pid, NULL, 0)); } } This is what I suspect was causing the Git test suite to fail in t9010-svn-fe.sh: http://bugs.debian.org/678852 Signed-off-by: Anders Kaseorg Reviewed-by: Jonathan Nieder --- (Re-sending v2 to Linus with no changes.) fs/fifo.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/fifo.c b/fs/fifo.c index b1a524d..cf6f434 100644 --- a/fs/fifo.c +++ b/fs/fifo.c @@ -14,7 +14,7 @@ #include #include =20 -static void wait_for_partner(struct inode* inode, unsigned int *cnt) +static int wait_for_partner(struct inode* inode, unsigned int *cnt) { int cur =3D *cnt;=09 =20 @@ -23,6 +23,7 @@ static void wait_for_partner(struct inode* inode, uns= igned int *cnt) if (signal_pending(current)) break; } + return cur =3D=3D *cnt ? -ERESTARTSYS : 0; } =20 static void wake_up_partner(struct inode* inode) @@ -67,8 +68,7 @@ static int fifo_open(struct inode *inode, struct file= *filp) * seen a writer */ filp->f_version =3D pipe->w_counter; } else { - wait_for_partner(inode, &pipe->w_counter); - if(signal_pending(current)) + if (wait_for_partner(inode, &pipe->w_counter)) goto err_rd; } } @@ -90,8 +90,7 @@ static int fifo_open(struct inode *inode, struct file= *filp) wake_up_partner(inode); =20 if (!pipe->readers) { - wait_for_partner(inode, &pipe->r_counter); - if (signal_pending(current)) + if (wait_for_partner(inode, &pipe->r_counter)) goto err_wr; } break; --=20 1.7.11.1