From 7b096a997fad199eddccfb6784e4b85184d9af17 Mon Sep 17 00:00:00 2001 From: Alan Somers Date: Tue, 15 Jun 2021 17:17:28 -0600 Subject: fusefs: support EVFILT_WRITE on /dev/fuse /dev/fuse is always ready for writing, so it's kind of dumb to poll it. But some applications do it anyway. Better to return ready than EINVAL. Reviewed by: emaste, pfg Differential Revision: https://reviews.freebsd.org/D30784 (cherry picked from commit 7b8622fa220b9c08041102f638f848c48e022644) Simplify fuse_device_filt_write It always returns 1, so why bother having a variable. Pull Request: https://github.com/freebsd/freebsd-src/pull/478 (cherry picked from commit 9b876fbd504e5c718d8d0275b32d806ab14558c8) --- sys/fs/fuse/fuse_device.c | 20 +++++++++++++++++++- tests/sys/fs/fusefs/mockfs.cc | 20 +++++++++++++++++--- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/sys/fs/fuse/fuse_device.c b/sys/fs/fuse/fuse_device.c index cab5925c91de..f8807d6d1c26 100644 --- a/sys/fs/fuse/fuse_device.c +++ b/sys/fs/fuse/fuse_device.c @@ -119,6 +119,7 @@ static struct cdevsw fuse_device_cdevsw = { }; static int fuse_device_filt_read(struct knote *kn, long hint); +static int fuse_device_filt_write(struct knote *kn, long hint); static void fuse_device_filt_detach(struct knote *kn); struct filterops fuse_device_rfiltops = { @@ -127,6 +128,11 @@ struct filterops fuse_device_rfiltops = { .f_event = fuse_device_filt_read, }; +struct filterops fuse_device_wfiltops = { + .f_isfd = 1, + .f_event = fuse_device_filt_write, +}; + /**************************** * * >>> Fuse device op defs @@ -180,12 +186,14 @@ fuse_device_filter(struct cdev *dev, struct knote *kn) error = devfs_get_cdevpriv((void **)&data); - /* EVFILT_WRITE is not supported; the device is always ready to write */ if (error == 0 && kn->kn_filter == EVFILT_READ) { kn->kn_fop = &fuse_device_rfiltops; kn->kn_hook = data; knlist_add(&data->ks_rsel.si_note, kn, 0); error = 0; + } else if (error == 0 && kn->kn_filter == EVFILT_WRITE) { + kn->kn_fop = &fuse_device_wfiltops; + error = 0; } else if (error == 0) { error = EINVAL; kn->kn_data = error; @@ -231,6 +239,16 @@ fuse_device_filt_read(struct knote *kn, long hint) return (ready); } +static int +fuse_device_filt_write(struct knote *kn, long hint) +{ + + kn->kn_data = 0; + + /* The device is always ready to write, so we return 1*/ + return (1); +} + /* * Resources are set up on a per-open basis */ diff --git a/tests/sys/fs/fusefs/mockfs.cc b/tests/sys/fs/fusefs/mockfs.cc index 7e4991fb7bb9..7003472ca52b 100644 --- a/tests/sys/fs/fusefs/mockfs.cc +++ b/tests/sys/fs/fusefs/mockfs.cc @@ -867,8 +867,8 @@ void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) { timeout_ts.tv_sec = 0; timeout_ts.tv_nsec = timeout_ms * 1'000'000; while (nready == 0) { - EV_SET(&changes[0], m_fuse_fd, EVFILT_READ, EV_ADD, 0, - 0, 0); + EV_SET(&changes[0], m_fuse_fd, EVFILT_READ, + EV_ADD | EV_ONESHOT, 0, 0, 0); nready = kevent(m_kq, &changes[0], 1, &events[0], 1, &timeout_ts); if (m_quit) @@ -930,12 +930,26 @@ void MockFS::read_request(mockfs_buf_in &in, ssize_t &res) { void MockFS::write_response(const mockfs_buf_out &out) { fd_set writefds; pollfd fds[1]; + struct kevent changes[1]; + struct kevent events[1]; int nready, nfds; ssize_t r; switch (m_pm) { case BLOCKING: - case KQ: /* EVFILT_WRITE is not supported */ + break; + case KQ: + EV_SET(&changes[0], m_fuse_fd, EVFILT_WRITE, + EV_ADD | EV_ONESHOT, 0, 0, 0); + nready = kevent(m_kq, &changes[0], 1, &events[0], 1, + NULL); + ASSERT_LE(0, nready) << strerror(errno); + ASSERT_EQ(events[0].ident, (uintptr_t)m_fuse_fd); + if (events[0].flags & EV_ERROR) + FAIL() << strerror(events[0].data); + else if (events[0].flags & EV_EOF) + FAIL() << strerror(events[0].fflags); + m_nready = events[0].data; break; case POLL: fds[0].fd = m_fuse_fd; -- cgit v1.2.3