xref: /linux/fs/fuse/poll.c (revision 3dc7c001169d112b3e514cacff6c93091c57af9a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 
3 #include "dev.h"
4 #include "fuse_i.h"
5 
6 void fuse_end_polls(struct fuse_conn *fc)
7 {
8 	struct rb_node *p;
9 
10 	spin_lock(&fc->lock);
11 	p = rb_first(&fc->polled_files);
12 
13 	while (p) {
14 		struct fuse_file *ff;
15 		ff = rb_entry(p, struct fuse_file, polled_node);
16 		wake_up_interruptible_all(&ff->poll_wait);
17 
18 		p = rb_next(p);
19 	}
20 	spin_unlock(&fc->lock);
21 }
22 
23 /*
24  * All files which have been polled are linked to RB tree
25  * fuse_conn->polled_files which is indexed by kh.  Walk the tree and
26  * find the matching one.
27  */
28 static struct rb_node **fuse_find_polled_node(struct fuse_conn *fc, u64 kh,
29 					      struct rb_node **parent_out)
30 {
31 	struct rb_node **link = &fc->polled_files.rb_node;
32 	struct rb_node *last = NULL;
33 
34 	while (*link) {
35 		struct fuse_file *ff;
36 
37 		last = *link;
38 		ff = rb_entry(last, struct fuse_file, polled_node);
39 
40 		if (kh < ff->kh)
41 			link = &last->rb_left;
42 		else if (kh > ff->kh)
43 			link = &last->rb_right;
44 		else
45 			return link;
46 	}
47 
48 	if (parent_out)
49 		*parent_out = last;
50 	return link;
51 }
52 
53 /*
54  * The file is about to be polled.  Make sure it's on the polled_files
55  * RB tree.  Note that files once added to the polled_files tree are
56  * not removed before the file is released.  This is because a file
57  * polled once is likely to be polled again.
58  */
59 static void fuse_register_polled_file(struct fuse_conn *fc,
60 				      struct fuse_file *ff)
61 {
62 	spin_lock(&fc->lock);
63 	if (RB_EMPTY_NODE(&ff->polled_node)) {
64 		struct rb_node **link, *parent;
65 
66 		link = fuse_find_polled_node(fc, ff->kh, &parent);
67 		BUG_ON(*link);
68 		rb_link_node(&ff->polled_node, parent, link);
69 		rb_insert_color(&ff->polled_node, &fc->polled_files);
70 	}
71 	spin_unlock(&fc->lock);
72 }
73 
74 __poll_t fuse_file_poll(struct file *file, poll_table *wait)
75 {
76 	struct fuse_file *ff = file->private_data;
77 	struct fuse_mount *fm = ff->fm;
78 	struct fuse_poll_in inarg = { .fh = ff->fh, .kh = ff->kh };
79 	struct fuse_poll_out outarg;
80 	FUSE_ARGS(args);
81 	int err;
82 
83 	if (fm->fc->no_poll)
84 		return DEFAULT_POLLMASK;
85 
86 	poll_wait(file, &ff->poll_wait, wait);
87 	inarg.events = mangle_poll(poll_requested_events(wait));
88 
89 	/*
90 	 * Ask for notification iff there's someone waiting for it.
91 	 * The client may ignore the flag and always notify.
92 	 */
93 	if (waitqueue_active(&ff->poll_wait)) {
94 		inarg.flags |= FUSE_POLL_SCHEDULE_NOTIFY;
95 		fuse_register_polled_file(fm->fc, ff);
96 	}
97 
98 	args.opcode = FUSE_POLL;
99 	args.nodeid = ff->nodeid;
100 	args.in_numargs = 1;
101 	args.in_args[0].size = sizeof(inarg);
102 	args.in_args[0].value = &inarg;
103 	args.out_numargs = 1;
104 	args.out_args[0].size = sizeof(outarg);
105 	args.out_args[0].value = &outarg;
106 	err = fuse_simple_request(fm, &args);
107 
108 	if (!err)
109 		return demangle_poll(outarg.revents);
110 	if (err == -ENOSYS) {
111 		fm->fc->no_poll = 1;
112 		return DEFAULT_POLLMASK;
113 	}
114 	return EPOLLERR;
115 }
116 EXPORT_SYMBOL_GPL(fuse_file_poll);
117 
118 /*
119  * This is called from fuse_handle_notify() on FUSE_NOTIFY_POLL and
120  * wakes up the poll waiters.
121  */
122 int fuse_notify_poll_wakeup(struct fuse_conn *fc,
123 			    struct fuse_notify_poll_wakeup_out *outarg)
124 {
125 	u64 kh = outarg->kh;
126 	struct rb_node **link;
127 
128 	spin_lock(&fc->lock);
129 
130 	link = fuse_find_polled_node(fc, kh, NULL);
131 	if (*link) {
132 		struct fuse_file *ff;
133 
134 		ff = rb_entry(*link, struct fuse_file, polled_node);
135 		wake_up_interruptible_sync(&ff->poll_wait);
136 	}
137 
138 	spin_unlock(&fc->lock);
139 	return 0;
140 }
141 
142