projects/linux·blob master · refs

446 lines · 9.6 KiB

1// SPDX-License-Identifier: GPL-2.0-only
2
3#include "dev.h"
4#include "fuse_i.h"
5
6#include <linux/iomap.h>
7#include <linux/pagemap.h>
8
9static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size,
10 struct fuse_copy_state *cs)
11{
12 struct fuse_notify_poll_wakeup_out outarg;
13 int err;
14
15 if (size != sizeof(outarg))
16 return -EINVAL;
17
18 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
19 if (err)
20 return err;
21
22 fuse_copy_finish(cs);
23 return fuse_notify_poll_wakeup(fc, &outarg);
24}
25
26static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size,
27 struct fuse_copy_state *cs)
28{
29 struct fuse_notify_inval_inode_out outarg;
30 int err;
31
32 if (size != sizeof(outarg))
33 return -EINVAL;
34
35 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
36 if (err)
37 return err;
38 fuse_copy_finish(cs);
39
40 down_read(&fc->killsb);
41 err = fuse_reverse_inval_inode(fc, outarg.ino,
42 outarg.off, outarg.len);
43 up_read(&fc->killsb);
44 return err;
45}
46
47static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
48 struct fuse_copy_state *cs)
49{
50 struct fuse_notify_inval_entry_out outarg;
51 int err;
52 char *buf;
53 struct qstr name;
54
55 if (size < sizeof(outarg))
56 return -EINVAL;
57
58 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
59 if (err)
60 return err;
61
62 if (outarg.namelen > fc->name_max)
63 return -ENAMETOOLONG;
64
65 err = -EINVAL;
66 if (size != sizeof(outarg) + outarg.namelen + 1)
67 return -EINVAL;
68
69 buf = kzalloc(outarg.namelen + 1, GFP_KERNEL);
70 if (!buf)
71 return -ENOMEM;
72
73 name.name = buf;
74 name.len = outarg.namelen;
75 err = fuse_copy_one(cs, buf, outarg.namelen + 1);
76 if (err)
77 goto err;
78 fuse_copy_finish(cs);
79 buf[outarg.namelen] = 0;
80
81 down_read(&fc->killsb);
82 err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags);
83 up_read(&fc->killsb);
84err:
85 kfree(buf);
86 return err;
87}
88
89static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
90 struct fuse_copy_state *cs)
91{
92 struct fuse_notify_delete_out outarg;
93 int err;
94 char *buf;
95 struct qstr name;
96
97 if (size < sizeof(outarg))
98 return -EINVAL;
99
100 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
101 if (err)
102 return err;
103
104 if (outarg.namelen > fc->name_max)
105 return -ENAMETOOLONG;
106
107 if (size != sizeof(outarg) + outarg.namelen + 1)
108 return -EINVAL;
109
110 buf = kzalloc(outarg.namelen + 1, GFP_KERNEL);
111 if (!buf)
112 return -ENOMEM;
113
114 name.name = buf;
115 name.len = outarg.namelen;
116 err = fuse_copy_one(cs, buf, outarg.namelen + 1);
117 if (err)
118 goto err;
119 fuse_copy_finish(cs);
120 buf[outarg.namelen] = 0;
121
122 down_read(&fc->killsb);
123 err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0);
124 up_read(&fc->killsb);
125err:
126 kfree(buf);
127 return err;
128}
129
130static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
131 struct fuse_copy_state *cs)
132{
133 struct fuse_notify_store_out outarg;
134 struct inode *inode;
135 struct address_space *mapping;
136 u64 nodeid;
137 int err;
138 unsigned int num;
139 loff_t file_size;
140 loff_t pos;
141 loff_t end;
142
143 if (size < sizeof(outarg))
144 return -EINVAL;
145
146 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
147 if (err)
148 return err;
149
150 if (size - sizeof(outarg) != outarg.size)
151 return -EINVAL;
152
153 if (outarg.offset >= MAX_LFS_FILESIZE)
154 return -EINVAL;
155
156 nodeid = outarg.nodeid;
157 pos = outarg.offset;
158 num = min(outarg.size, MAX_LFS_FILESIZE - pos);
159
160 down_read(&fc->killsb);
161
162 err = -ENOENT;
163 inode = fuse_ilookup(fc, nodeid, NULL);
164 if (!inode)
165 goto out_up_killsb;
166 if (!S_ISREG(inode->i_mode)) {
167 err = -EINVAL;
168 goto out_iput;
169 }
170
171 mapping = inode->i_mapping;
172 file_size = i_size_read(inode);
173 end = pos + num;
174 if (end > file_size) {
175 file_size = end;
176 fuse_write_update_attr(inode, file_size, num);
177 }
178
179 while (num) {
180 struct folio *folio;
181 unsigned int folio_offset;
182 unsigned int nr_bytes;
183 pgoff_t index = pos >> PAGE_SHIFT;
184
185 folio = filemap_grab_folio(mapping, index);
186 err = PTR_ERR(folio);
187 if (IS_ERR(folio))
188 goto out_iput;
189
190 folio_offset = offset_in_folio(folio, pos);
191 nr_bytes = min(num, folio_size(folio) - folio_offset);
192
193 err = fuse_copy_folio(cs, &folio, folio_offset, nr_bytes, 0);
194 if (!folio_test_uptodate(folio) && !err && folio_offset == 0 &&
195 (nr_bytes == folio_size(folio) || file_size == end)) {
196 folio_zero_segment(folio, nr_bytes, folio_size(folio));
197 iomap_folio_mark_uptodate(folio);
198 }
199 folio_unlock(folio);
200 folio_put(folio);
201
202 if (err)
203 goto out_iput;
204
205 pos += nr_bytes;
206 num -= nr_bytes;
207 }
208
209 err = 0;
210
211out_iput:
212 iput(inode);
213out_up_killsb:
214 up_read(&fc->killsb);
215 return err;
216}
217
218struct fuse_retrieve_args {
219 struct fuse_args_pages ap;
220 struct fuse_notify_retrieve_in inarg;
221};
222
223static void fuse_retrieve_end(struct fuse_args *args, int error)
224{
225 struct fuse_retrieve_args *ra =
226 container_of(args, typeof(*ra), ap.args);
227
228 release_pages(ra->ap.folios, ra->ap.num_folios);
229 kfree(ra);
230}
231
232static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
233 struct fuse_notify_retrieve_out *outarg)
234{
235 int err;
236 struct address_space *mapping = inode->i_mapping;
237 loff_t file_size;
238 unsigned int num;
239 unsigned int offset;
240 size_t total_len = 0;
241 unsigned int num_pages;
242 struct fuse_conn *fc = fm->fc;
243 struct fuse_retrieve_args *ra;
244 size_t args_size = sizeof(*ra);
245 struct fuse_args_pages *ap;
246 struct fuse_args *args;
247 loff_t pos = outarg->offset;
248
249 offset = offset_in_page(pos);
250 file_size = i_size_read(inode);
251
252 num = min(outarg->size, fc->max_write);
253 if (pos > file_size)
254 num = 0;
255 else if (num > file_size - pos)
256 num = file_size - pos;
257
258 num_pages = DIV_ROUND_UP(num + offset, PAGE_SIZE);
259 num_pages = min(num_pages, fc->max_pages);
260 num = min(num, num_pages << PAGE_SHIFT);
261
262 args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->descs[0]));
263
264 ra = kzalloc(args_size, GFP_KERNEL);
265 if (!ra)
266 return -ENOMEM;
267
268 ap = &ra->ap;
269 ap->folios = (void *) (ra + 1);
270 ap->descs = (void *) (ap->folios + num_pages);
271
272 args = &ap->args;
273 args->nodeid = outarg->nodeid;
274 args->opcode = FUSE_NOTIFY_REPLY;
275 args->in_numargs = 3;
276 args->in_pages = true;
277 args->end = fuse_retrieve_end;
278
279 while (num && ap->num_folios < num_pages) {
280 struct folio *folio;
281 unsigned int folio_offset;
282 unsigned int nr_bytes;
283 pgoff_t index = pos >> PAGE_SHIFT;
284
285 folio = filemap_get_folio(mapping, index);
286 if (IS_ERR(folio))
287 break;
288 if (!folio_test_uptodate(folio)) {
289 folio_put(folio);
290 break;
291 }
292
293 folio_offset = offset_in_folio(folio, pos);
294 nr_bytes = min(folio_size(folio) - folio_offset, num);
295
296 ap->folios[ap->num_folios] = folio;
297 ap->descs[ap->num_folios].offset = folio_offset;
298 ap->descs[ap->num_folios].length = nr_bytes;
299 ap->num_folios++;
300
301 pos += nr_bytes;
302 num -= nr_bytes;
303 total_len += nr_bytes;
304 }
305 ra->inarg.offset = outarg->offset;
306 ra->inarg.size = total_len;
307 fuse_set_zero_arg0(args);
308 args->in_args[1].size = sizeof(ra->inarg);
309 args->in_args[1].value = &ra->inarg;
310 args->in_args[2].size = total_len;
311
312 err = fuse_simple_notify_reply(fm, args, outarg->notify_unique);
313 if (err)
314 fuse_retrieve_end(args, err);
315
316 return err;
317}
318
319static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
320 struct fuse_copy_state *cs)
321{
322 struct fuse_notify_retrieve_out outarg;
323 struct fuse_mount *fm;
324 struct inode *inode;
325 u64 nodeid;
326 int err;
327
328 if (size != sizeof(outarg))
329 return -EINVAL;
330
331 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
332 if (err)
333 return err;
334
335 fuse_copy_finish(cs);
336
337 if (outarg.offset >= MAX_LFS_FILESIZE)
338 return -EINVAL;
339
340 down_read(&fc->killsb);
341 err = -ENOENT;
342 nodeid = outarg.nodeid;
343
344 inode = fuse_ilookup(fc, nodeid, &fm);
345 if (inode) {
346 err = -EINVAL;
347 if (S_ISREG(inode->i_mode))
348 err = fuse_retrieve(fm, inode, &outarg);
349 iput(inode);
350 }
351 up_read(&fc->killsb);
352
353 return err;
354}
355
356static int fuse_notify_resend(struct fuse_conn *fc)
357{
358 fuse_chan_resend(fc->chan);
359 return 0;
360}
361
362/*
363 * Increments the fuse connection epoch. This will cause dentries and
364 * readdir caches from previous epochs to be invalidated. Additionally,
365 * if inval_wq is set, a work queue is scheduled to trigger the invalidation.
366 */
367static int fuse_notify_inc_epoch(struct fuse_conn *fc)
368{
369 atomic_inc(&fc->epoch);
370 if (inval_wq)
371 schedule_work(&fc->epoch_work);
372
373 return 0;
374}
375
376static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size,
377 struct fuse_copy_state *cs)
378{
379 struct fuse_notify_prune_out outarg;
380 const unsigned int batch = 512;
381 u64 *nodeids __free(kfree) = kmalloc(sizeof(u64) * batch, GFP_KERNEL);
382 unsigned int num, i;
383 int err;
384
385 if (!nodeids)
386 return -ENOMEM;
387
388 if (size < sizeof(outarg))
389 return -EINVAL;
390
391 err = fuse_copy_one(cs, &outarg, sizeof(outarg));
392 if (err)
393 return err;
394
395 if (size - sizeof(outarg) != array_size(outarg.count, sizeof(u64)))
396 return -EINVAL;
397
398 for (; outarg.count; outarg.count -= num) {
399 num = min(batch, outarg.count);
400 err = fuse_copy_one(cs, nodeids, num * sizeof(u64));
401 if (err)
402 return err;
403
404 scoped_guard(rwsem_read, &fc->killsb) {
405 for (i = 0; i < num; i++)
406 fuse_try_prune_one_inode(fc, nodeids[i]);
407 }
408 }
409 return 0;
410}
411
412int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
413 unsigned int size, struct fuse_copy_state *cs)
414{
415 switch (code) {
416 case FUSE_NOTIFY_POLL:
417 return fuse_notify_poll(fc, size, cs);
418
419 case FUSE_NOTIFY_INVAL_INODE:
420 return fuse_notify_inval_inode(fc, size, cs);
421
422 case FUSE_NOTIFY_INVAL_ENTRY:
423 return fuse_notify_inval_entry(fc, size, cs);
424
425 case FUSE_NOTIFY_STORE:
426 return fuse_notify_store(fc, size, cs);
427
428 case FUSE_NOTIFY_RETRIEVE:
429 return fuse_notify_retrieve(fc, size, cs);
430
431 case FUSE_NOTIFY_DELETE:
432 return fuse_notify_delete(fc, size, cs);
433
434 case FUSE_NOTIFY_RESEND:
435 return fuse_notify_resend(fc);
436
437 case FUSE_NOTIFY_INC_EPOCH:
438 return fuse_notify_inc_epoch(fc);
439
440 case FUSE_NOTIFY_PRUNE:
441 return fuse_notify_prune(fc, size, cs);
442
443 default:
444 return -EINVAL;
445 }
446}