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. MFC after: 2 weeks Reviewed by: emaste, pfg Differential Revision: https://reviews.freebsd.org/D30784
This commit is contained in:
@@ -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,18 @@ fuse_device_filt_read(struct knote *kn, long hint)
|
||||
return (ready);
|
||||
}
|
||||
|
||||
static int
|
||||
fuse_device_filt_write(struct knote *kn, long hint)
|
||||
{
|
||||
int ready;
|
||||
|
||||
/* The device is always ready to write */
|
||||
kn->kn_data = 0;
|
||||
ready = 1;
|
||||
|
||||
return (ready);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resources are set up on a per-open basis
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user