Bug 167688 - [fusefs] Incorrect signal handling with direct_io
Summary: [fusefs] Incorrect signal handling with direct_io
Status: Closed Overcome By Events
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: Unspecified
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-05-07 16:50 UTC by Artem Zaytsev
Modified: 2019-04-03 15:43 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Artem Zaytsev 2012-05-07 16:50:12 UTC
If while reading a file from fusefs signal is received, then read(2) will return 0 and errno 0 (just like EOF) instead of EINTR.

How-To-Repeat: /* --------------------------- fuse.c ------------------------ */
#include <fuse.h>
#include <string.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>

int fs_getattr(const char *name, struct stat *st) {
	st->st_mode = S_IFREG;
	st->st_size = 1;
	
	return 0;
}

int fs_read(const char *name, char *buf, size_t bufSize, off_t off, struct fuse_file_info *fi) {
	sleep(10);
	return 1;
}

int main(int argc, char **argv) {
	struct fuse_operations operations;

	memset(&operations, 0, sizeof(operations));
	operations.read = fs_read;
	operations.getattr = fs_getattr;

	return fuse_main(argc, argv, &operations, NULL);
}
/* ----------------------------------------------------------- */


/* ------------------------- reader.c ------------------------ */
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>

void on_alarm(int s) {
	fprintf(stderr, "alarm\n");
}

int main(int argc, char **argv) {
	int fd, readed;
	char buf[16];
	
	if(argc < 2)
		exit(255);

	fd = open(argv[1], O_RDONLY);
	if(fd < 0) {
		perror("open");
		exit(errno);
	}

	/* handler required, SIG_IGN will mask the error */
	signal(SIGALRM, on_alarm);
	alarm(1);

	readed = read(fd, buf, sizeof(buf));
	fprintf(stderr, "Readed: %d, errno=%d\n", (int)readed, (int)errno);

	return 0;
}
/* ---------------------------------------------------------- */

# cc -o fs -Wall -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=26 -I/usr/local/include -L/usr/local/lib -pthread -lfuse fuse.c
# cc -o reader -Wall reader.c

# mkdir mnt

# ./fs -o allow_other -o direct_io mnt
# ./reader mnt
<<< sleep for 1 second >>>
alarm
Readed: 0, errno=0
Comment 1 Mark Linimon freebsd_committer freebsd_triage 2012-05-07 19:49:28 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-fs

Over to maintainer(s).
Comment 2 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 08:00:37 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped
Comment 3 Conrad Meyer freebsd_committer freebsd_triage 2018-08-10 09:00:48 UTC
Is this still present?  I had a quick look around but don't see any recent changes that I would expect to fix this.
Comment 4 Alan Somers freebsd_committer freebsd_triage 2018-12-28 00:57:39 UTC
I cannot reproduce this on 12.0.  The signal does not interrupt the read(2).
Comment 5 Conrad Meyer freebsd_committer freebsd_triage 2018-12-28 01:05:20 UTC
(In reply to Alan Somers from comment #4)
> The signal does not interrupt the read(2).

Hm, isn't that part of the bug?  Signals are supposed to interrupt blocked I/O; not interrupting explains the symptoms from the description mostly (sleep, then signal handler, then read returns zero).
Comment 6 Conrad Meyer freebsd_committer freebsd_triage 2018-12-28 01:07:25 UTC
That said, it seems like all sleeps in the read path in sys/fs/fuse use PCATCH.  There is a PCATCH-less tsleep associated with flush, but I don't know why that would be invoked for a read.
Comment 7 Conrad Meyer freebsd_committer freebsd_triage 2018-12-28 01:12:33 UTC
(In reply to Conrad Meyer from comment #6)
Sigh.  Yes, we PCATCH, *but*:

314 static int
315 fticket_wait_answer(struct fuse_ticket *ftick)
316 {
...
334         fuse_block_sigs(&tset);
335         err = msleep(ftick, &ftick->tk_aw_mtx, PCATCH, "fu_ans",
336             data->daemon_timeout * hz);
337         fuse_restore_sigs(&tset);

We block all signals but SIGKILL.
Comment 8 Alan Somers freebsd_committer freebsd_triage 2019-04-03 15:43:00 UTC
Firstly, let me thank you for such a good reproduction case.  This is certainly the best reproduction case I've ever seen for a user-reported fuse bug, and it ranks highly for the best reproduction cases I've ever seen for a user-reported bug on any project.

That said, I'm going to close the issue because I can't reproduce it.  Judging by the date of your post, you were probably using the sysutils/fusefs-kmod port, which has been replaced by the in-tree fusefs(5) driver.  There have been many improvements.

I plan to tackle interruptibility in bug 236530.