mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] fuse: fix the bug of missing EPOLLET event wakeup
@ 2025-12-25 11:03 Zhang Tianci
  2026-01-07  3:11 ` Zhang Tianci
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Zhang Tianci @ 2025-12-25 11:03 UTC (permalink / raw)
  To: miklos
  Cc: linux-fsdevel, linux-kernel, Zhang Tianci, Geng Xueyu, Wang Jian,
	Xie Yongji

Users using Go have reported an issue to us:
When performing read/write operations with goroutines,
since fuse's file->f_ops->poll is not empty,
read/write operations are conducted via epoll.
Additionally, goroutines use the EPOLLET wake-up mode.

Currently, the implementation of fuse_file_poll has
the following problem:
After receiving EAGAIN during read/write operations,
the goroutine calls epoll_wait again, but then results in
permanent blocking. This is because a wake-up event
is required in EPOLLET mode.

The modification idea of this patch is based on the
implementation of epoll_wait:
After epoll_wait calls ->poll() for EPOLLET events,
it does not reinsert them into the ready list.
In this case, ep_poll_callback() needs to be used to
reinsert them into the ready list, so that the behavior
of EPOLLET is consistent with that of non-EPOLLET.

Reported-by: Geng Xueyu <gengxueyu.520@bytedance.com>
Reported-by: Wang Jian <wangjian.pg@bytedance.com>
Suggested-by: Xie Yongji <xieyongji@bytedance.com>
Signed-off-by: Zhang Tianci <zhangtianci.1997@bytedance.com>
---

Here is the reproducer for the bug:

1. Change libfuse/example/passthrough.c's xmp_read() to
   always return -EAGAIN and mount it on /mnt_fuse. 
2. Then create test file:
   dd if=/dev/zero of=/mnt_fuse/test_poll bs=1M count=10
3. compile and run the following test case.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/epoll.h>

#define MAX_EVENTS 10
#define BUF_SIZE 4096

int main() {
    int epfd, nfds, fd;
    struct epoll_event ev, events[MAX_EVENTS];
    char buffer[BUF_SIZE];

    fd = open("/mnt_fuse/test_poll", O_RDWR|O_NONBLOCK|O_CREAT, 0644);
    if (fd == -1) {
	perror("open");
	return -1;
    }

    epfd = epoll_create1(0);
    if (epfd == -1) {
        perror("epoll_create1");
	return -1;
    }

    ev.data.fd = fd;
    ev.events = EPOLLIN | EPOLLET;

    if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) == -1) {
        perror("epoll_ctl: fd");
	return -1;
    }

    printf("Epoll is monitoring fd=%d.\n", fd);

    while (1) {
        nfds = epoll_wait(epfd, events, MAX_EVENTS, -1);
        if (nfds == -1) {
            if (errno == EINTR) {
		continue;
	    }
            perror("epoll_wait");
	    return -1;
        }

        for (int i = 0; i < nfds; ++i) {
            int current_fd = events[i].data.fd;

            if (current_fd == fd) {
                printf("[Notification] Data arrived on fd\n", fd);

                while (1) {
                    ssize_t count = read(current_fd, buffer, BUF_SIZE);

                    if (count == -1) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                            printf("[Info] Buffer is empty, waiting for next event...\n");
                            break;
                        } else {
                            perror("read");
                            close(current_fd);
			    return -1;
                        }
                    } else if (count == 0) {
                        printf("[Info] EOF detected. Closing.\n");
                        close(current_fd);
                        return 0;
                    }
                    printf(">>> Read %zd bytes\n", count);
                }
            }
        }
    }

    close(epfd);
    return 0;
}

 fs/fuse/file.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 01bc894e9c2ba..025eea58232c2 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2735,10 +2735,11 @@ __poll_t fuse_file_poll(struct file *file, poll_table *wait)
 	FUSE_ARGS(args);
 	int err;
 
+	poll_wait(file, &ff->poll_wait, wait);
+
 	if (fm->fc->no_poll)
-		return DEFAULT_POLLMASK;
+		goto no_poll;
 
-	poll_wait(file, &ff->poll_wait, wait);
 	inarg.events = mangle_poll(poll_requested_events(wait));
 
 	/*
@@ -2764,9 +2765,13 @@ __poll_t fuse_file_poll(struct file *file, poll_table *wait)
 		return demangle_poll(outarg.revents);
 	if (err == -ENOSYS) {
 		fm->fc->no_poll = 1;
-		return DEFAULT_POLLMASK;
+		goto no_poll;
 	}
 	return EPOLLERR;
+
+no_poll:
+	wake_up_interruptible_sync(&ff->poll_wait);
+	return DEFAULT_POLLMASK;
 }
 EXPORT_SYMBOL_GPL(fuse_file_poll);
 
-- 
2.39.5


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fuse: fix the bug of missing EPOLLET event wakeup
  2025-12-25 11:03 [PATCH] fuse: fix the bug of missing EPOLLET event wakeup Zhang Tianci
@ 2026-01-07  3:11 ` Zhang Tianci
  2026-01-27  6:41   ` Zhang Tianci
  2026-01-27 10:37 ` Miklos Szeredi
  2026-01-27 16:23 ` Markus Elfring
  2 siblings, 1 reply; 5+ messages in thread
From: Zhang Tianci @ 2026-01-07  3:11 UTC (permalink / raw)
  To: miklos; +Cc: linux-fsdevel, linux-kernel, Geng Xueyu, Wang Jian, Xie Yongji

gently ping...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fuse: fix the bug of missing EPOLLET event wakeup
  2026-01-07  3:11 ` Zhang Tianci
@ 2026-01-27  6:41   ` Zhang Tianci
  0 siblings, 0 replies; 5+ messages in thread
From: Zhang Tianci @ 2026-01-27  6:41 UTC (permalink / raw)
  To: miklos; +Cc: linux-fsdevel, linux-kernel, Geng Xueyu, Wang Jian, Xie Yongji

gently ping...

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fuse: fix the bug of missing EPOLLET event wakeup
  2025-12-25 11:03 [PATCH] fuse: fix the bug of missing EPOLLET event wakeup Zhang Tianci
  2026-01-07  3:11 ` Zhang Tianci
@ 2026-01-27 10:37 ` Miklos Szeredi
  2026-01-27 16:23 ` Markus Elfring
  2 siblings, 0 replies; 5+ messages in thread
From: Miklos Szeredi @ 2026-01-27 10:37 UTC (permalink / raw)
  To: Zhang Tianci
  Cc: linux-fsdevel, linux-kernel, Geng Xueyu, Wang Jian, Xie Yongji

On Thu, 25 Dec 2025 at 12:03, Zhang Tianci
<zhangtianci.1997@bytedance.com> wrote:
>
> Users using Go have reported an issue to us:
> When performing read/write operations with goroutines,
> since fuse's file->f_ops->poll is not empty,

Another one of those historical mistakes...

> read/write operations are conducted via epoll.
> Additionally, goroutines use the EPOLLET wake-up mode.
>
> Currently, the implementation of fuse_file_poll has
> the following problem:
> After receiving EAGAIN during read/write operations,

Why is read/write returning EAGAIN?

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] fuse: fix the bug of missing EPOLLET event wakeup
  2025-12-25 11:03 [PATCH] fuse: fix the bug of missing EPOLLET event wakeup Zhang Tianci
  2026-01-07  3:11 ` Zhang Tianci
  2026-01-27 10:37 ` Miklos Szeredi
@ 2026-01-27 16:23 ` Markus Elfring
  2 siblings, 0 replies; 5+ messages in thread
From: Markus Elfring @ 2026-01-27 16:23 UTC (permalink / raw)
  To: Zhang Tianci, linux-fsdevel
  Cc: LKML, Geng Xueyu, Miklos Szeredi, Wang Jian, Xie Yongji

…
> After receiving EAGAIN during read/write operations,
> the goroutine calls epoll_wait again, but then results in
> permanent blocking. This is because a wake-up event
> is required in EPOLLET mode.
…

You may occasionally put more than 57 characters into text lines
of such a change description.
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/process/submitting-patches.rst?h=v6.19-rc7#n659

Regards,
Markus

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-01-27 16:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-25 11:03 [PATCH] fuse: fix the bug of missing EPOLLET event wakeup Zhang Tianci
2026-01-07  3:11 ` Zhang Tianci
2026-01-27  6:41   ` Zhang Tianci
2026-01-27 10:37 ` Miklos Szeredi
2026-01-27 16:23 ` Markus Elfring

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®