svn commit: r347431 - in projects/fuse2: sys/fs/fuse tests/sys/fs/fusefs

Alan Somers asomers at FreeBSD.org
Fri May 10 15:02:31 UTC 2019


Author: asomers
Date: Fri May 10 15:02:29 2019
New Revision: 347431
URL: https://svnweb.freebsd.org/changeset/base/347431

Log:
  fusefs: fix running multiple daemons concurrently
  
  When a FUSE daemon dies or closes /dev/fuse, all of that daemon's pending
  requests must be terminated.  Previously that was done in /dev/fuse's
  .d_close method.  However, d_close only gets called on the *last* close of
  the device.  That means that if multiple daemons were running concurrently,
  all but the last daemon to close would leave their I/O hanging around.  The
  problem was easily visible just by running "kyua -v parallelism=2 test" in
  fusefs's test directory.
  
  Fix this bug by terminating a daemon's pending I/O during /dev/fuse's
  cdvpriv dtor method instead.  That method runs on every close of a file.
  
  Also, fix some potential races in the tests:
  * Clear SA_RESTART when registering the daemon's signal handler so read(2)
    will return EINTR.
  * Wait for the daemon to die before unmounting the mountpoint, so we won't
    see an unwanted FUSE_DESTROY operation in the mock file system.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  projects/fuse2/sys/fs/fuse/fuse_device.c
  projects/fuse2/tests/sys/fs/fusefs/mockfs.cc

Modified: projects/fuse2/sys/fs/fuse/fuse_device.c
==============================================================================
--- projects/fuse2/sys/fs/fuse/fuse_device.c	Fri May 10 13:41:19 2019	(r347430)
+++ projects/fuse2/sys/fs/fuse/fuse_device.c	Fri May 10 15:02:29 2019	(r347431)
@@ -94,14 +94,12 @@ SDT_PROBE_DEFINE2(fusefs, , device, trace, "int", "cha
 static struct cdev *fuse_dev;
 
 static d_open_t fuse_device_open;
-static d_close_t fuse_device_close;
 static d_poll_t fuse_device_poll;
 static d_read_t fuse_device_read;
 static d_write_t fuse_device_write;
 
 static struct cdevsw fuse_device_cdevsw = {
 	.d_open = fuse_device_open,
-	.d_close = fuse_device_close,
 	.d_name = "fuse",
 	.d_poll = fuse_device_poll,
 	.d_read = fuse_device_read,
@@ -119,8 +117,31 @@ static void
 fdata_dtor(void *arg)
 {
 	struct fuse_data *fdata;
+	struct fuse_ticket *tick;
 
 	fdata = arg;
+	if (fdata == NULL)
+		return;
+
+	fdata_set_dead(fdata);
+
+	FUSE_LOCK();
+	fuse_lck_mtx_lock(fdata->aw_mtx);
+	/* wakup poll()ers */
+	selwakeuppri(&fdata->ks_rsel, PZERO + 1);
+	/* Don't let syscall handlers wait in vain */
+	while ((tick = fuse_aw_pop(fdata))) {
+		fuse_lck_mtx_lock(tick->tk_aw_mtx);
+		fticket_set_answered(tick);
+		tick->tk_aw_errno = ENOTCONN;
+		wakeup(tick);
+		fuse_lck_mtx_unlock(tick->tk_aw_mtx);
+		FUSE_ASSERT_AW_DONE(tick);
+		fuse_ticket_drop(tick);
+	}
+	fuse_lck_mtx_unlock(fdata->aw_mtx);
+	FUSE_UNLOCK();
+
 	fdata_trydestroy(fdata);
 }
 
@@ -142,41 +163,6 @@ fuse_device_open(struct cdev *dev, int oflags, int dev
 	else
 		SDT_PROBE2(fusefs, , device, trace, 1, "device open success");
 	return (error);
-}
-
-static int
-fuse_device_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
-{
-	struct fuse_data *data;
-	struct fuse_ticket *tick;
-	int error;
-
-	error = devfs_get_cdevpriv((void **)&data);
-	if (error != 0)
-		return (error);
-	if (!data)
-		panic("no fuse data upon fuse device close");
-	fdata_set_dead(data);
-
-	FUSE_LOCK();
-	fuse_lck_mtx_lock(data->aw_mtx);
-	/* wakup poll()ers */
-	selwakeuppri(&data->ks_rsel, PZERO + 1);
-	/* Don't let syscall handlers wait in vain */
-	while ((tick = fuse_aw_pop(data))) {
-		fuse_lck_mtx_lock(tick->tk_aw_mtx);
-		fticket_set_answered(tick);
-		tick->tk_aw_errno = ENOTCONN;
-		wakeup(tick);
-		fuse_lck_mtx_unlock(tick->tk_aw_mtx);
-		FUSE_ASSERT_AW_DONE(tick);
-		fuse_ticket_drop(tick);
-	}
-	fuse_lck_mtx_unlock(data->aw_mtx);
-	FUSE_UNLOCK();
-
-	SDT_PROBE2(fusefs, , device, trace, 1, "device close");
-	return (0);
 }
 
 int

Modified: projects/fuse2/tests/sys/fs/fusefs/mockfs.cc
==============================================================================
--- projects/fuse2/tests/sys/fs/fusefs/mockfs.cc	Fri May 10 13:41:19 2019	(r347430)
+++ projects/fuse2/tests/sys/fs/fusefs/mockfs.cc	Fri May 10 15:02:29 2019	(r347431)
@@ -147,7 +147,7 @@ ReturnImmediate(std::function<void(const struct mockfs
 }
 
 void sigint_handler(int __unused sig) {
-	quit = 1;
+	// Don't do anything except interrupt the daemon's read(2) call
 }
 
 void debug_fuseop(const mockfs_buf_in *in)
@@ -280,6 +280,7 @@ void debug_fuseop(const mockfs_buf_in *in)
 MockFS::MockFS(int max_readahead, bool allow_other, bool default_permissions,
 	bool push_symlinks_in, bool ro, uint32_t flags)
 {
+	struct sigaction sa;
 	struct iovec *iov = NULL;
 	int iovlen = 0;
 	char fdstr[15];
@@ -340,7 +341,12 @@ MockFS::MockFS(int max_readahead, bool allow_other, bo
 		.WillByDefault(Invoke(this, &MockFS::process_default));
 
 	init(flags);
-	signal(SIGUSR1, sigint_handler);
+	bzero(&sa, sizeof(sa));
+	sa.sa_handler = sigint_handler;
+	sa.sa_flags = 0;	/* Don't set SA_RESTART! */
+	if (0 != sigaction(SIGUSR1, &sa, NULL))
+		throw(std::system_error(errno, std::system_category(),
+			"Couldn't handle SIGUSR1"));
 	if (pthread_create(&m_daemon_id, NULL, service, (void*)this))
 		throw(std::system_error(errno, std::system_category(),
 			"Couldn't Couldn't start fuse thread"));
@@ -348,11 +354,11 @@ MockFS::MockFS(int max_readahead, bool allow_other, bo
 
 MockFS::~MockFS() {
 	kill_daemon();
-	::unmount("mountpoint", MNT_FORCE);
 	if (m_daemon_id != NULL) {
 		pthread_join(m_daemon_id, NULL);
 		m_daemon_id = NULL;
 	}
+	::unmount("mountpoint", MNT_FORCE);
 	rmdir("mountpoint");
 }
 
@@ -393,13 +399,14 @@ void MockFS::init(uint32_t flags) {
 }
 
 void MockFS::kill_daemon() {
-	if (m_daemon_id != NULL) {
+	quit = 1;
+	if (m_daemon_id != NULL)
 		pthread_kill(m_daemon_id, SIGUSR1);
-		// Closing the /dev/fuse file descriptor first allows unmount
-		// to succeed even if the daemon doesn't correctly respond to
-		// commands during the unmount sequence.
-		close(m_fuse_fd);
-	}
+	// Closing the /dev/fuse file descriptor first allows unmount to
+	// succeed even if the daemon doesn't correctly respond to commands
+	// during the unmount sequence.
+	close(m_fuse_fd);
+	m_fuse_fd = -1;
 }
 
 void MockFS::loop() {
@@ -462,6 +469,9 @@ bool MockFS::pid_ok(pid_t pid) {
 void MockFS::process_default(const mockfs_buf_in *in,
 		std::vector<mockfs_buf_out*> &out)
 {
+	if (verbosity > 1)
+		printf("%-11s REJECTED (wrong pid %d)\n",
+			opcode2opname(in->header.opcode), in->header.pid);
 	auto out0 = new mockfs_buf_out;
 	out0->header.unique = in->header.unique;
 	out0->header.error = -EOPNOTSUPP;


More information about the svn-src-projects mailing list