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