From: Miklos Szeredi Date: Tue, 31 Mar 2026 11:49:22 +0000 (+0200) Subject: fuse: create poll.c X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b8b072cbafb817d5cb95da50a6295a4169af1aa2;p=thirdparty%2Fkernel%2Fstable.git fuse: create poll.c Move f_op->poll related functions to the new source file. Signed-off-by: Miklos Szeredi --- diff --git a/fs/fuse/Makefile b/fs/fuse/Makefile index 08be6817a1cc..26086bf5b494 100644 --- a/fs/fuse/Makefile +++ b/fs/fuse/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_VIRTIO_FS) += virtiofs.o fuse-y := trace.o # put trace.o first so we see ftrace errors sooner fuse-y += dev.o dir.o file.o inode.o control.o xattr.o acl.o readdir.o ioctl.o req_timeout.o req.o +fuse-y += poll.o fuse-y += iomode.o fuse-$(CONFIG_FUSE_DAX) += dax.o fuse-$(CONFIG_FUSE_PASSTHROUGH) += passthrough.o backing.o diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index dbbd20265dfc..18a9c4f3d63c 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -80,10 +80,10 @@ void fuse_chan_set_initialized(struct fuse_chan *fch) wake_up_all(&fch->blocked_waitq); } -static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background) +static bool fuse_block_alloc(struct fuse_chan *fch, bool for_background) { - return !fc->chan->initialized || (for_background && fc->chan->blocked) || - (fc->chan->io_uring && fc->chan->connected && !fuse_uring_ready(fc->chan)); + return !fch->initialized || (for_background && fch->blocked) || + (fch->io_uring && fch->connected && !fuse_uring_ready(fch)); } static void fuse_drop_waiting(struct fuse_chan *fch) @@ -109,10 +109,10 @@ static struct fuse_req *fuse_get_req(struct fuse_chan *fch, bool for_background) atomic_inc(&fch->num_waiting); - if (fuse_block_alloc(fch->conn, for_background)) { + if (fuse_block_alloc(fch, for_background)) { err = -EINTR; if (wait_event_state_exclusive(fch->blocked_waitq, - !fuse_block_alloc(fch->conn, for_background), + !fuse_block_alloc(fch, for_background), (TASK_KILLABLE | TASK_FREEZABLE))) goto out; } @@ -2070,21 +2070,21 @@ static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size, * if the FUSE daemon takes careful measures to avoid processing duplicated * non-idempotent requests. */ -static void fuse_resend(struct fuse_conn *fc) +static void fuse_resend(struct fuse_chan *fch) { struct fuse_dev *fud; struct fuse_req *req, *next; - struct fuse_iqueue *fiq = &fc->chan->iq; + struct fuse_iqueue *fiq = &fch->iq; LIST_HEAD(to_queue); unsigned int i; - spin_lock(&fc->chan->lock); - if (!fc->chan->connected) { - spin_unlock(&fc->chan->lock); + spin_lock(&fch->lock); + if (!fch->connected) { + spin_unlock(&fch->lock); return; } - list_for_each_entry(fud, &fc->chan->devices, entry) { + list_for_each_entry(fud, &fch->devices, entry) { struct fuse_pqueue *fpq = &fud->pq; spin_lock(&fpq->lock); @@ -2092,7 +2092,7 @@ static void fuse_resend(struct fuse_conn *fc) list_splice_tail_init(&fpq->processing[i], &to_queue); spin_unlock(&fpq->lock); } - spin_unlock(&fc->chan->lock); + spin_unlock(&fch->lock); list_for_each_entry_safe(req, next, &to_queue, list) { set_bit(FR_PENDING, &req->flags); @@ -2124,7 +2124,7 @@ static void fuse_resend(struct fuse_conn *fc) static int fuse_notify_resend(struct fuse_conn *fc) { - fuse_resend(fc); + fuse_resend(fc->chan); return 0; } @@ -2512,23 +2512,6 @@ void fuse_dev_end_requests(struct list_head *head) } } -static void end_polls(struct fuse_conn *fc) -{ - struct rb_node *p; - - spin_lock(&fc->lock); - p = rb_first(&fc->polled_files); - - while (p) { - struct fuse_file *ff; - ff = rb_entry(p, struct fuse_file, polled_node); - wake_up_interruptible_all(&ff->poll_wait); - - p = rb_next(p); - } - spin_unlock(&fc->lock); -} - /* * Abort all requests. * @@ -2606,7 +2589,7 @@ void fuse_chan_abort(struct fuse_chan *fch, bool abort_with_err) wake_up_all(&fiq->waitq); spin_unlock(&fiq->lock); kill_fasync(&fiq->fasync, SIGIO, POLL_IN); - end_polls(fch->conn); + fuse_end_polls(fch->conn); wake_up_all(&fch->blocked_waitq); spin_unlock(&fch->lock); diff --git a/fs/fuse/dev.h b/fs/fuse/dev.h index 9a1f79b130bd..2c4d0c53ffbb 100644 --- a/fs/fuse/dev.h +++ b/fs/fuse/dev.h @@ -49,6 +49,8 @@ void fuse_init_server_timeout(struct fuse_chan *fch, unsigned int timeout); void fuse_chan_abort(struct fuse_chan *fch, bool abort_with_err); void fuse_chan_wait_aborted(struct fuse_chan *fch); +void fuse_end_polls(struct fuse_conn *fc); + #ifdef CONFIG_FUSE_IO_URING bool fuse_uring_enabled(void); void fuse_uring_destruct(struct fuse_chan *fch); diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 057ff884500d..e8833e2a6610 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -2683,125 +2683,6 @@ static loff_t fuse_file_llseek(struct file *file, loff_t offset, int whence) return retval; } -/* - * All files which have been polled are linked to RB tree - * fuse_conn->polled_files which is indexed by kh. Walk the tree and - * find the matching one. - */ -static struct rb_node **fuse_find_polled_node(struct fuse_conn *fc, u64 kh, - struct rb_node **parent_out) -{ - struct rb_node **link = &fc->polled_files.rb_node; - struct rb_node *last = NULL; - - while (*link) { - struct fuse_file *ff; - - last = *link; - ff = rb_entry(last, struct fuse_file, polled_node); - - if (kh < ff->kh) - link = &last->rb_left; - else if (kh > ff->kh) - link = &last->rb_right; - else - return link; - } - - if (parent_out) - *parent_out = last; - return link; -} - -/* - * The file is about to be polled. Make sure it's on the polled_files - * RB tree. Note that files once added to the polled_files tree are - * not removed before the file is released. This is because a file - * polled once is likely to be polled again. - */ -static void fuse_register_polled_file(struct fuse_conn *fc, - struct fuse_file *ff) -{ - spin_lock(&fc->lock); - if (RB_EMPTY_NODE(&ff->polled_node)) { - struct rb_node **link, *parent; - - link = fuse_find_polled_node(fc, ff->kh, &parent); - BUG_ON(*link); - rb_link_node(&ff->polled_node, parent, link); - rb_insert_color(&ff->polled_node, &fc->polled_files); - } - spin_unlock(&fc->lock); -} - -__poll_t fuse_file_poll(struct file *file, poll_table *wait) -{ - struct fuse_file *ff = file->private_data; - struct fuse_mount *fm = ff->fm; - struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh }; - struct fuse_poll_out outarg; - FUSE_ARGS(args); - int err; - - if (fm->fc->no_poll) - return DEFAULT_POLLMASK; - - poll_wait(file, &ff->poll_wait, wait); - inarg.events = mangle_poll(poll_requested_events(wait)); - - /* - * Ask for notification iff there's someone waiting for it. - * The client may ignore the flag and always notify. - */ - if (waitqueue_active(&ff->poll_wait)) { - inarg.flags |= FUSE_POLL_SCHEDULE_NOTIFY; - fuse_register_polled_file(fm->fc, ff); - } - - args.opcode = FUSE_POLL; - args.nodeid = ff->nodeid; - args.in_numargs = 1; - args.in_args[0].size = sizeof(inarg); - args.in_args[0].value = &inarg; - args.out_numargs = 1; - args.out_args[0].size = sizeof(outarg); - args.out_args[0].value = &outarg; - err = fuse_simple_request(fm, &args); - - if (!err) - return demangle_poll(outarg.revents); - if (err == -ENOSYS) { - fm->fc->no_poll = 1; - return DEFAULT_POLLMASK; - } - return EPOLLERR; -} -EXPORT_SYMBOL_GPL(fuse_file_poll); - -/* - * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and - * wakes up the poll waiters. - */ -int fuse_notify_poll_wakeup(struct fuse_conn *fc, - struct fuse_notify_poll_wakeup_out *outarg) -{ - u64 kh = outarg->kh; - struct rb_node **link; - - spin_lock(&fc->lock); - - link = fuse_find_polled_node(fc, kh, NULL); - if (*link) { - struct fuse_file *ff; - - ff = rb_entry(*link, struct fuse_file, polled_node); - wake_up_interruptible_sync(&ff->poll_wait); - } - - spin_unlock(&fc->lock); - return 0; -} - static void fuse_do_truncate(struct file *file) { struct inode *inode = file->f_mapping->host; diff --git a/fs/fuse/poll.c b/fs/fuse/poll.c new file mode 100644 index 000000000000..bce3ee2e861e --- /dev/null +++ b/fs/fuse/poll.c @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include "dev.h" +#include "fuse_i.h" + +void fuse_end_polls(struct fuse_conn *fc) +{ + struct rb_node *p; + + spin_lock(&fc->lock); + p = rb_first(&fc->polled_files); + + while (p) { + struct fuse_file *ff; + ff = rb_entry(p, struct fuse_file, polled_node); + wake_up_interruptible_all(&ff->poll_wait); + + p = rb_next(p); + } + spin_unlock(&fc->lock); +} + +/* + * All files which have been polled are linked to RB tree + * fuse_conn->polled_files which is indexed by kh. Walk the tree and + * find the matching one. + */ +static struct rb_node **fuse_find_polled_node(struct fuse_conn *fc, u64 kh, + struct rb_node **parent_out) +{ + struct rb_node **link = &fc->polled_files.rb_node; + struct rb_node *last = NULL; + + while (*link) { + struct fuse_file *ff; + + last = *link; + ff = rb_entry(last, struct fuse_file, polled_node); + + if (kh < ff->kh) + link = &last->rb_left; + else if (kh > ff->kh) + link = &last->rb_right; + else + return link; + } + + if (parent_out) + *parent_out = last; + return link; +} + +/* + * The file is about to be polled. Make sure it's on the polled_files + * RB tree. Note that files once added to the polled_files tree are + * not removed before the file is released. This is because a file + * polled once is likely to be polled again. + */ +static void fuse_register_polled_file(struct fuse_conn *fc, + struct fuse_file *ff) +{ + spin_lock(&fc->lock); + if (RB_EMPTY_NODE(&ff->polled_node)) { + struct rb_node **link, *parent; + + link = fuse_find_polled_node(fc, ff->kh, &parent); + BUG_ON(*link); + rb_link_node(&ff->polled_node, parent, link); + rb_insert_color(&ff->polled_node, &fc->polled_files); + } + spin_unlock(&fc->lock); +} + +__poll_t fuse_file_poll(struct file *file, poll_table *wait) +{ + struct fuse_file *ff = file->private_data; + struct fuse_mount *fm = ff->fm; + struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh }; + struct fuse_poll_out outarg; + FUSE_ARGS(args); + int err; + + if (fm->fc->no_poll) + return DEFAULT_POLLMASK; + + poll_wait(file, &ff->poll_wait, wait); + inarg.events = mangle_poll(poll_requested_events(wait)); + + /* + * Ask for notification iff there's someone waiting for it. + * The client may ignore the flag and always notify. + */ + if (waitqueue_active(&ff->poll_wait)) { + inarg.flags |= FUSE_POLL_SCHEDULE_NOTIFY; + fuse_register_polled_file(fm->fc, ff); + } + + args.opcode = FUSE_POLL; + args.nodeid = ff->nodeid; + args.in_numargs = 1; + args.in_args[0].size = sizeof(inarg); + args.in_args[0].value = &inarg; + args.out_numargs = 1; + args.out_args[0].size = sizeof(outarg); + args.out_args[0].value = &outarg; + err = fuse_simple_request(fm, &args); + + if (!err) + return demangle_poll(outarg.revents); + if (err == -ENOSYS) { + fm->fc->no_poll = 1; + return DEFAULT_POLLMASK; + } + return EPOLLERR; +} +EXPORT_SYMBOL_GPL(fuse_file_poll); + +/* + * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and + * wakes up the poll waiters. + */ +int fuse_notify_poll_wakeup(struct fuse_conn *fc, + struct fuse_notify_poll_wakeup_out *outarg) +{ + u64 kh = outarg->kh; + struct rb_node **link; + + spin_lock(&fc->lock); + + link = fuse_find_polled_node(fc, kh, NULL); + if (*link) { + struct fuse_file *ff; + + ff = rb_entry(*link, struct fuse_file, polled_node); + wake_up_interruptible_sync(&ff->poll_wait); + } + + spin_unlock(&fc->lock); + return 0; +} +