Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 18 Jul 2019 15:30:01 +0000 (UTC)
From:      Alan Somers <asomers@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r350113 - projects/fuse2/sys/fs/fuse
Message-ID:  <201907181530.x6IFU10M006793@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: asomers
Date: Thu Jul 18 15:30:00 2019
New Revision: 350113
URL: https://svnweb.freebsd.org/changeset/base/350113

Log:
  fusefs: fix another semi-infinite loop bug regarding signal handling
  
  fticket_wait_answer would spin if it received an unhandled signal whose
  default disposition is to terminate.  The reason is because msleep(9) would
  return EINTR even for a masked signal.  One reason is when the thread is
  stopped, which happens for example during sigexit().  Fix this bug by
  returning immediately if fticket_wait_answer ever gets interrupted a second
  time, for any reason.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/fuse2/sys/fs/fuse/fuse_ipc.c

Modified: projects/fuse2/sys/fs/fuse/fuse_ipc.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_ipc.c	Thu Jul 18 13:58:04 2019	(r350112)
+++ projects/fuse2/sys/fs/fuse/fuse_ipc.c	Thu Jul 18 15:30:00 2019	(r350113)
@@ -439,11 +439,12 @@ fticket_wait_answer(struct fuse_ticket *ftick)
 	sigset_t blockedset, oldset;
 	int err = 0, stops_deferred;
 	struct fuse_data *data;
+	bool interrupted = false;
 
 	if (fsess_isimpl(ftick->tk_data->mp, FUSE_INTERRUPT)) {
 		SIGEMPTYSET(blockedset);
 	} else {
-		/* May as well block all signals */
+		/* Block all signals except (implicitly) SIGKILL */
 		SIGFILLSET(blockedset);
 	}
 	stops_deferred = sigdeferstop(SIGDEFERSTOP_SILENT);
@@ -489,7 +490,6 @@ retry:
 		 * or EAGAIN to the interrupt.
 		 */
 		sigset_t tmpset;
-		int sig;
 
 		SDT_PROBE2(fusefs, , ipc, trace, 4,
 			"fticket_wait_answer: interrupt");
@@ -498,22 +498,28 @@ retry:
 
 		PROC_LOCK(td->td_proc);
 		mtx_lock(&td->td_proc->p_sigacts->ps_mtx);
-		sig = cursig(td);
 		tmpset = td->td_proc->p_siglist;
 		SIGSETOR(tmpset, td->td_siglist);
 		mtx_unlock(&td->td_proc->p_sigacts->ps_mtx);
 		PROC_UNLOCK(td->td_proc);
 
 		fuse_lck_mtx_lock(ftick->tk_aw_mtx);
-		if (!SIGISMEMBER(tmpset, SIGKILL)) { 
+		if (!interrupted && !SIGISMEMBER(tmpset, SIGKILL)) { 
 			/* 
-			 * Block the just-delivered signal while we wait for an
-			 * interrupt response
+			 * Block all signals while we wait for an interrupt
+			 * response.  The protocol doesn't discriminate between
+			 * different signals.
 			 */
-			SIGADDSET(blockedset, sig);
+			SIGFILLSET(blockedset);
+			interrupted = true;
 			goto retry;
 		} else {
-			/* Return immediately for fatal signals */
+			/*
+			 * Return immediately for fatal signals, or if this is
+			 * the second interruption.  We should only be
+			 * interrupted twice if the thread is stopped, for
+			 * example during sigexit.
+			 */
 		}
 	} else if (err) {
 		SDT_PROBE2(fusefs, , ipc, trace, 6,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201907181530.x6IFU10M006793>