projects/linux·blob master · refs

141 lines · 3.3 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2
3#include "dev.h"
4#include "fuse_i.h"
5
6void 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 */
28static 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 */
59static 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}
116EXPORT_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 */
122int 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