xref: /linux/fs/fuse/notify.c (revision 0eaed89c18aeedf0898baf2dbf5ff027c6795152)
154243797SSamuel Moelius // SPDX-License-Identifier: GPL-2.0-only
254243797SSamuel Moelius 
354243797SSamuel Moelius #include "dev.h"
454243797SSamuel Moelius #include "fuse_i.h"
554243797SSamuel Moelius #include <linux/pagemap.h>
654243797SSamuel Moelius 
754243797SSamuel Moelius static int fuse_notify_poll(struct fuse_conn *fc, unsigned int size,
854243797SSamuel Moelius 			    struct fuse_copy_state *cs)
954243797SSamuel Moelius {
1054243797SSamuel Moelius 	struct fuse_notify_poll_wakeup_out outarg;
1154243797SSamuel Moelius 	int err;
1254243797SSamuel Moelius 
1354243797SSamuel Moelius 	if (size != sizeof(outarg))
1454243797SSamuel Moelius 		return -EINVAL;
1554243797SSamuel Moelius 
1654243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
1754243797SSamuel Moelius 	if (err)
1854243797SSamuel Moelius 		return err;
1954243797SSamuel Moelius 
2054243797SSamuel Moelius 	fuse_copy_finish(cs);
2154243797SSamuel Moelius 	return fuse_notify_poll_wakeup(fc, &outarg);
2254243797SSamuel Moelius }
2354243797SSamuel Moelius 
2454243797SSamuel Moelius static int fuse_notify_inval_inode(struct fuse_conn *fc, unsigned int size,
2554243797SSamuel Moelius 				   struct fuse_copy_state *cs)
2654243797SSamuel Moelius {
2754243797SSamuel Moelius 	struct fuse_notify_inval_inode_out outarg;
2854243797SSamuel Moelius 	int err;
2954243797SSamuel Moelius 
3054243797SSamuel Moelius 	if (size != sizeof(outarg))
3154243797SSamuel Moelius 		return -EINVAL;
3254243797SSamuel Moelius 
3354243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
3454243797SSamuel Moelius 	if (err)
3554243797SSamuel Moelius 		return err;
3654243797SSamuel Moelius 	fuse_copy_finish(cs);
3754243797SSamuel Moelius 
3854243797SSamuel Moelius 	down_read(&fc->killsb);
3954243797SSamuel Moelius 	err = fuse_reverse_inval_inode(fc, outarg.ino,
4054243797SSamuel Moelius 				       outarg.off, outarg.len);
4154243797SSamuel Moelius 	up_read(&fc->killsb);
4254243797SSamuel Moelius 	return err;
4354243797SSamuel Moelius }
4454243797SSamuel Moelius 
4554243797SSamuel Moelius static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
4654243797SSamuel Moelius 				   struct fuse_copy_state *cs)
4754243797SSamuel Moelius {
4854243797SSamuel Moelius 	struct fuse_notify_inval_entry_out outarg;
4954243797SSamuel Moelius 	int err;
5054243797SSamuel Moelius 	char *buf;
5154243797SSamuel Moelius 	struct qstr name;
5254243797SSamuel Moelius 
5354243797SSamuel Moelius 	if (size < sizeof(outarg))
5454243797SSamuel Moelius 		return -EINVAL;
5554243797SSamuel Moelius 
5654243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
5754243797SSamuel Moelius 	if (err)
5854243797SSamuel Moelius 		return err;
5954243797SSamuel Moelius 
6054243797SSamuel Moelius 	if (outarg.namelen > fc->name_max)
6154243797SSamuel Moelius 		return -ENAMETOOLONG;
6254243797SSamuel Moelius 
6354243797SSamuel Moelius 	err = -EINVAL;
6454243797SSamuel Moelius 	if (size != sizeof(outarg) + outarg.namelen + 1)
6554243797SSamuel Moelius 		return -EINVAL;
6654243797SSamuel Moelius 
6754243797SSamuel Moelius 	buf = kzalloc(outarg.namelen + 1, GFP_KERNEL);
6854243797SSamuel Moelius 	if (!buf)
6954243797SSamuel Moelius 		return -ENOMEM;
7054243797SSamuel Moelius 
7154243797SSamuel Moelius 	name.name = buf;
7254243797SSamuel Moelius 	name.len = outarg.namelen;
7354243797SSamuel Moelius 	err = fuse_copy_one(cs, buf, outarg.namelen + 1);
7454243797SSamuel Moelius 	if (err)
7554243797SSamuel Moelius 		goto err;
7654243797SSamuel Moelius 	fuse_copy_finish(cs);
7754243797SSamuel Moelius 	buf[outarg.namelen] = 0;
7854243797SSamuel Moelius 
7954243797SSamuel Moelius 	down_read(&fc->killsb);
8054243797SSamuel Moelius 	err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags);
8154243797SSamuel Moelius 	up_read(&fc->killsb);
8254243797SSamuel Moelius err:
8354243797SSamuel Moelius 	kfree(buf);
8454243797SSamuel Moelius 	return err;
8554243797SSamuel Moelius }
8654243797SSamuel Moelius 
8754243797SSamuel Moelius static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
8854243797SSamuel Moelius 			      struct fuse_copy_state *cs)
8954243797SSamuel Moelius {
9054243797SSamuel Moelius 	struct fuse_notify_delete_out outarg;
9154243797SSamuel Moelius 	int err;
9254243797SSamuel Moelius 	char *buf;
9354243797SSamuel Moelius 	struct qstr name;
9454243797SSamuel Moelius 
9554243797SSamuel Moelius 	if (size < sizeof(outarg))
9654243797SSamuel Moelius 		return -EINVAL;
9754243797SSamuel Moelius 
9854243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
9954243797SSamuel Moelius 	if (err)
10054243797SSamuel Moelius 		return err;
10154243797SSamuel Moelius 
10254243797SSamuel Moelius 	if (outarg.namelen > fc->name_max)
10354243797SSamuel Moelius 		return -ENAMETOOLONG;
10454243797SSamuel Moelius 
10554243797SSamuel Moelius 	if (size != sizeof(outarg) + outarg.namelen + 1)
10654243797SSamuel Moelius 		return -EINVAL;
10754243797SSamuel Moelius 
10854243797SSamuel Moelius 	buf = kzalloc(outarg.namelen + 1, GFP_KERNEL);
10954243797SSamuel Moelius 	if (!buf)
11054243797SSamuel Moelius 		return -ENOMEM;
11154243797SSamuel Moelius 
11254243797SSamuel Moelius 	name.name = buf;
11354243797SSamuel Moelius 	name.len = outarg.namelen;
11454243797SSamuel Moelius 	err = fuse_copy_one(cs, buf, outarg.namelen + 1);
11554243797SSamuel Moelius 	if (err)
11654243797SSamuel Moelius 		goto err;
11754243797SSamuel Moelius 	fuse_copy_finish(cs);
11854243797SSamuel Moelius 	buf[outarg.namelen] = 0;
11954243797SSamuel Moelius 
12054243797SSamuel Moelius 	down_read(&fc->killsb);
12154243797SSamuel Moelius 	err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0);
12254243797SSamuel Moelius 	up_read(&fc->killsb);
12354243797SSamuel Moelius err:
12454243797SSamuel Moelius 	kfree(buf);
12554243797SSamuel Moelius 	return err;
12654243797SSamuel Moelius }
12754243797SSamuel Moelius 
12854243797SSamuel Moelius static int fuse_notify_store(struct fuse_conn *fc, unsigned int size,
12954243797SSamuel Moelius 			     struct fuse_copy_state *cs)
13054243797SSamuel Moelius {
13154243797SSamuel Moelius 	struct fuse_notify_store_out outarg;
13254243797SSamuel Moelius 	struct inode *inode;
13354243797SSamuel Moelius 	struct address_space *mapping;
13454243797SSamuel Moelius 	u64 nodeid;
13554243797SSamuel Moelius 	int err;
13654243797SSamuel Moelius 	unsigned int num;
13754243797SSamuel Moelius 	loff_t file_size;
13854243797SSamuel Moelius 	loff_t pos;
13954243797SSamuel Moelius 	loff_t end;
14054243797SSamuel Moelius 
14154243797SSamuel Moelius 	if (size < sizeof(outarg))
14254243797SSamuel Moelius 		return -EINVAL;
14354243797SSamuel Moelius 
14454243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
14554243797SSamuel Moelius 	if (err)
14654243797SSamuel Moelius 		return err;
14754243797SSamuel Moelius 
14854243797SSamuel Moelius 	if (size - sizeof(outarg) != outarg.size)
14954243797SSamuel Moelius 		return -EINVAL;
15054243797SSamuel Moelius 
15154243797SSamuel Moelius 	if (outarg.offset >= MAX_LFS_FILESIZE)
15254243797SSamuel Moelius 		return -EINVAL;
15354243797SSamuel Moelius 
15454243797SSamuel Moelius 	nodeid = outarg.nodeid;
15554243797SSamuel Moelius 	pos = outarg.offset;
15654243797SSamuel Moelius 	num = min(outarg.size, MAX_LFS_FILESIZE - pos);
15754243797SSamuel Moelius 
15854243797SSamuel Moelius 	down_read(&fc->killsb);
15954243797SSamuel Moelius 
16054243797SSamuel Moelius 	err = -ENOENT;
16154243797SSamuel Moelius 	inode = fuse_ilookup(fc, nodeid,  NULL);
16254243797SSamuel Moelius 	if (!inode)
16354243797SSamuel Moelius 		goto out_up_killsb;
164*6edc2007SLinus Torvalds 	if (!S_ISREG(inode->i_mode)) {
165*6edc2007SLinus Torvalds 		err = -EINVAL;
166*6edc2007SLinus Torvalds 		goto out_iput;
167*6edc2007SLinus Torvalds 	}
16854243797SSamuel Moelius 
16954243797SSamuel Moelius 	mapping = inode->i_mapping;
17054243797SSamuel Moelius 	file_size = i_size_read(inode);
17154243797SSamuel Moelius 	end = pos + num;
17254243797SSamuel Moelius 	if (end > file_size) {
17354243797SSamuel Moelius 		file_size = end;
17454243797SSamuel Moelius 		fuse_write_update_attr(inode, file_size, num);
17554243797SSamuel Moelius 	}
17654243797SSamuel Moelius 
17754243797SSamuel Moelius 	while (num) {
17854243797SSamuel Moelius 		struct folio *folio;
17954243797SSamuel Moelius 		unsigned int folio_offset;
18054243797SSamuel Moelius 		unsigned int nr_bytes;
18154243797SSamuel Moelius 		pgoff_t index = pos >> PAGE_SHIFT;
18254243797SSamuel Moelius 
18354243797SSamuel Moelius 		folio = filemap_grab_folio(mapping, index);
18454243797SSamuel Moelius 		err = PTR_ERR(folio);
18554243797SSamuel Moelius 		if (IS_ERR(folio))
18654243797SSamuel Moelius 			goto out_iput;
18754243797SSamuel Moelius 
18854243797SSamuel Moelius 		folio_offset = offset_in_folio(folio, pos);
18954243797SSamuel Moelius 		nr_bytes = min(num, folio_size(folio) - folio_offset);
19054243797SSamuel Moelius 
19154243797SSamuel Moelius 		err = fuse_copy_folio(cs, &folio, folio_offset, nr_bytes, 0);
19254243797SSamuel Moelius 		if (!folio_test_uptodate(folio) && !err && folio_offset == 0 &&
19354243797SSamuel Moelius 		    (nr_bytes == folio_size(folio) || file_size == end)) {
19454243797SSamuel Moelius 			folio_zero_segment(folio, nr_bytes, folio_size(folio));
19554243797SSamuel Moelius 			folio_mark_uptodate(folio);
19654243797SSamuel Moelius 		}
19754243797SSamuel Moelius 		folio_unlock(folio);
19854243797SSamuel Moelius 		folio_put(folio);
19954243797SSamuel Moelius 
20054243797SSamuel Moelius 		if (err)
20154243797SSamuel Moelius 			goto out_iput;
20254243797SSamuel Moelius 
20354243797SSamuel Moelius 		pos += nr_bytes;
20454243797SSamuel Moelius 		num -= nr_bytes;
20554243797SSamuel Moelius 	}
20654243797SSamuel Moelius 
20754243797SSamuel Moelius 	err = 0;
20854243797SSamuel Moelius 
20954243797SSamuel Moelius out_iput:
21054243797SSamuel Moelius 	iput(inode);
21154243797SSamuel Moelius out_up_killsb:
21254243797SSamuel Moelius 	up_read(&fc->killsb);
21354243797SSamuel Moelius 	return err;
21454243797SSamuel Moelius }
21554243797SSamuel Moelius 
21654243797SSamuel Moelius struct fuse_retrieve_args {
21754243797SSamuel Moelius 	struct fuse_args_pages ap;
21854243797SSamuel Moelius 	struct fuse_notify_retrieve_in inarg;
21954243797SSamuel Moelius };
22054243797SSamuel Moelius 
22154243797SSamuel Moelius static void fuse_retrieve_end(struct fuse_args *args, int error)
22254243797SSamuel Moelius {
22354243797SSamuel Moelius 	struct fuse_retrieve_args *ra =
22454243797SSamuel Moelius 		container_of(args, typeof(*ra), ap.args);
22554243797SSamuel Moelius 
22654243797SSamuel Moelius 	release_pages(ra->ap.folios, ra->ap.num_folios);
22754243797SSamuel Moelius 	kfree(ra);
22854243797SSamuel Moelius }
22954243797SSamuel Moelius 
23054243797SSamuel Moelius static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
23154243797SSamuel Moelius 			 struct fuse_notify_retrieve_out *outarg)
23254243797SSamuel Moelius {
23354243797SSamuel Moelius 	int err;
23454243797SSamuel Moelius 	struct address_space *mapping = inode->i_mapping;
23554243797SSamuel Moelius 	loff_t file_size;
23654243797SSamuel Moelius 	unsigned int num;
23754243797SSamuel Moelius 	unsigned int offset;
23854243797SSamuel Moelius 	size_t total_len = 0;
23954243797SSamuel Moelius 	unsigned int num_pages;
24054243797SSamuel Moelius 	struct fuse_conn *fc = fm->fc;
24154243797SSamuel Moelius 	struct fuse_retrieve_args *ra;
24254243797SSamuel Moelius 	size_t args_size = sizeof(*ra);
24354243797SSamuel Moelius 	struct fuse_args_pages *ap;
24454243797SSamuel Moelius 	struct fuse_args *args;
24554243797SSamuel Moelius 	loff_t pos = outarg->offset;
24654243797SSamuel Moelius 
24754243797SSamuel Moelius 	offset = offset_in_page(pos);
24854243797SSamuel Moelius 	file_size = i_size_read(inode);
24954243797SSamuel Moelius 
25054243797SSamuel Moelius 	num = min(outarg->size, fc->max_write);
25154243797SSamuel Moelius 	if (pos > file_size)
25254243797SSamuel Moelius 		num = 0;
25354243797SSamuel Moelius 	else if (num > file_size - pos)
25454243797SSamuel Moelius 		num = file_size - pos;
25554243797SSamuel Moelius 
25654243797SSamuel Moelius 	num_pages = DIV_ROUND_UP(num + offset, PAGE_SIZE);
25754243797SSamuel Moelius 	num_pages = min(num_pages, fc->max_pages);
25854243797SSamuel Moelius 	num = min(num, num_pages << PAGE_SHIFT);
25954243797SSamuel Moelius 
26054243797SSamuel Moelius 	args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->descs[0]));
26154243797SSamuel Moelius 
26254243797SSamuel Moelius 	ra = kzalloc(args_size, GFP_KERNEL);
26354243797SSamuel Moelius 	if (!ra)
26454243797SSamuel Moelius 		return -ENOMEM;
26554243797SSamuel Moelius 
26654243797SSamuel Moelius 	ap = &ra->ap;
26754243797SSamuel Moelius 	ap->folios = (void *) (ra + 1);
26854243797SSamuel Moelius 	ap->descs = (void *) (ap->folios + num_pages);
26954243797SSamuel Moelius 
27054243797SSamuel Moelius 	args = &ap->args;
27154243797SSamuel Moelius 	args->nodeid = outarg->nodeid;
27254243797SSamuel Moelius 	args->opcode = FUSE_NOTIFY_REPLY;
27354243797SSamuel Moelius 	args->in_numargs = 3;
27454243797SSamuel Moelius 	args->in_pages = true;
27554243797SSamuel Moelius 	args->end = fuse_retrieve_end;
27654243797SSamuel Moelius 
27754243797SSamuel Moelius 	while (num && ap->num_folios < num_pages) {
27854243797SSamuel Moelius 		struct folio *folio;
27954243797SSamuel Moelius 		unsigned int folio_offset;
28054243797SSamuel Moelius 		unsigned int nr_bytes;
28154243797SSamuel Moelius 		pgoff_t index = pos >> PAGE_SHIFT;
28254243797SSamuel Moelius 
28354243797SSamuel Moelius 		folio = filemap_get_folio(mapping, index);
28454243797SSamuel Moelius 		if (IS_ERR(folio))
28554243797SSamuel Moelius 			break;
286*6edc2007SLinus Torvalds 		if (!folio_test_uptodate(folio)) {
287*6edc2007SLinus Torvalds 			folio_put(folio);
288*6edc2007SLinus Torvalds 			break;
289*6edc2007SLinus Torvalds 		}
29054243797SSamuel Moelius 
29154243797SSamuel Moelius 		folio_offset = offset_in_folio(folio, pos);
29254243797SSamuel Moelius 		nr_bytes = min(folio_size(folio) - folio_offset, num);
29354243797SSamuel Moelius 
29454243797SSamuel Moelius 		ap->folios[ap->num_folios] = folio;
29554243797SSamuel Moelius 		ap->descs[ap->num_folios].offset = folio_offset;
29654243797SSamuel Moelius 		ap->descs[ap->num_folios].length = nr_bytes;
29754243797SSamuel Moelius 		ap->num_folios++;
29854243797SSamuel Moelius 
29954243797SSamuel Moelius 		pos += nr_bytes;
30054243797SSamuel Moelius 		num -= nr_bytes;
30154243797SSamuel Moelius 		total_len += nr_bytes;
30254243797SSamuel Moelius 	}
30354243797SSamuel Moelius 	ra->inarg.offset = outarg->offset;
30454243797SSamuel Moelius 	ra->inarg.size = total_len;
30554243797SSamuel Moelius 	fuse_set_zero_arg0(args);
30654243797SSamuel Moelius 	args->in_args[1].size = sizeof(ra->inarg);
30754243797SSamuel Moelius 	args->in_args[1].value = &ra->inarg;
30854243797SSamuel Moelius 	args->in_args[2].size = total_len;
30954243797SSamuel Moelius 
31054243797SSamuel Moelius 	err = fuse_simple_notify_reply(fm, args, outarg->notify_unique);
31154243797SSamuel Moelius 	if (err)
31254243797SSamuel Moelius 		fuse_retrieve_end(args, err);
31354243797SSamuel Moelius 
31454243797SSamuel Moelius 	return err;
31554243797SSamuel Moelius }
31654243797SSamuel Moelius 
31754243797SSamuel Moelius static int fuse_notify_retrieve(struct fuse_conn *fc, unsigned int size,
31854243797SSamuel Moelius 				struct fuse_copy_state *cs)
31954243797SSamuel Moelius {
32054243797SSamuel Moelius 	struct fuse_notify_retrieve_out outarg;
32154243797SSamuel Moelius 	struct fuse_mount *fm;
32254243797SSamuel Moelius 	struct inode *inode;
32354243797SSamuel Moelius 	u64 nodeid;
32454243797SSamuel Moelius 	int err;
32554243797SSamuel Moelius 
32654243797SSamuel Moelius 	if (size != sizeof(outarg))
32754243797SSamuel Moelius 		return -EINVAL;
32854243797SSamuel Moelius 
32954243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
33054243797SSamuel Moelius 	if (err)
33154243797SSamuel Moelius 		return err;
33254243797SSamuel Moelius 
33354243797SSamuel Moelius 	fuse_copy_finish(cs);
33454243797SSamuel Moelius 
33554243797SSamuel Moelius 	if (outarg.offset >= MAX_LFS_FILESIZE)
33654243797SSamuel Moelius 		return -EINVAL;
33754243797SSamuel Moelius 
33854243797SSamuel Moelius 	down_read(&fc->killsb);
33954243797SSamuel Moelius 	err = -ENOENT;
34054243797SSamuel Moelius 	nodeid = outarg.nodeid;
34154243797SSamuel Moelius 
34254243797SSamuel Moelius 	inode = fuse_ilookup(fc, nodeid, &fm);
34354243797SSamuel Moelius 	if (inode) {
344*6edc2007SLinus Torvalds 		err = -EINVAL;
345*6edc2007SLinus Torvalds 		if (S_ISREG(inode->i_mode))
34654243797SSamuel Moelius 			err = fuse_retrieve(fm, inode, &outarg);
34754243797SSamuel Moelius 		iput(inode);
34854243797SSamuel Moelius 	}
34954243797SSamuel Moelius 	up_read(&fc->killsb);
35054243797SSamuel Moelius 
35154243797SSamuel Moelius 	return err;
35254243797SSamuel Moelius }
35354243797SSamuel Moelius 
35454243797SSamuel Moelius static int fuse_notify_resend(struct fuse_conn *fc)
35554243797SSamuel Moelius {
35654243797SSamuel Moelius 	fuse_chan_resend(fc->chan);
35754243797SSamuel Moelius 	return 0;
35854243797SSamuel Moelius }
35954243797SSamuel Moelius 
36054243797SSamuel Moelius /*
3610fa83460SJun Wu  * Increments the fuse connection epoch.  This will cause dentries and
3620fa83460SJun Wu  * readdir caches from previous epochs to be invalidated.  Additionally,
3630fa83460SJun Wu  * if inval_wq is set, a work queue is scheduled to trigger the invalidation.
36454243797SSamuel Moelius  */
36554243797SSamuel Moelius static int fuse_notify_inc_epoch(struct fuse_conn *fc)
36654243797SSamuel Moelius {
36754243797SSamuel Moelius 	atomic_inc(&fc->epoch);
36854243797SSamuel Moelius 	if (inval_wq)
36954243797SSamuel Moelius 		schedule_work(&fc->epoch_work);
37054243797SSamuel Moelius 
37154243797SSamuel Moelius 	return 0;
37254243797SSamuel Moelius }
37354243797SSamuel Moelius 
37454243797SSamuel Moelius static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size,
37554243797SSamuel Moelius 			     struct fuse_copy_state *cs)
37654243797SSamuel Moelius {
37754243797SSamuel Moelius 	struct fuse_notify_prune_out outarg;
37854243797SSamuel Moelius 	const unsigned int batch = 512;
37954243797SSamuel Moelius 	u64 *nodeids __free(kfree) = kmalloc(sizeof(u64) * batch, GFP_KERNEL);
38054243797SSamuel Moelius 	unsigned int num, i;
38154243797SSamuel Moelius 	int err;
38254243797SSamuel Moelius 
38354243797SSamuel Moelius 	if (!nodeids)
38454243797SSamuel Moelius 		return -ENOMEM;
38554243797SSamuel Moelius 
38654243797SSamuel Moelius 	if (size < sizeof(outarg))
38754243797SSamuel Moelius 		return -EINVAL;
38854243797SSamuel Moelius 
38954243797SSamuel Moelius 	err = fuse_copy_one(cs, &outarg, sizeof(outarg));
39054243797SSamuel Moelius 	if (err)
39154243797SSamuel Moelius 		return err;
39254243797SSamuel Moelius 
39354243797SSamuel Moelius 	if (size - sizeof(outarg) != array_size(outarg.count, sizeof(u64)))
39454243797SSamuel Moelius 		return -EINVAL;
39554243797SSamuel Moelius 
39654243797SSamuel Moelius 	for (; outarg.count; outarg.count -= num) {
39754243797SSamuel Moelius 		num = min(batch, outarg.count);
39854243797SSamuel Moelius 		err = fuse_copy_one(cs, nodeids, num * sizeof(u64));
39954243797SSamuel Moelius 		if (err)
40054243797SSamuel Moelius 			return err;
40154243797SSamuel Moelius 
40254243797SSamuel Moelius 		scoped_guard(rwsem_read, &fc->killsb) {
40354243797SSamuel Moelius 			for (i = 0; i < num; i++)
40454243797SSamuel Moelius 				fuse_try_prune_one_inode(fc, nodeids[i]);
40554243797SSamuel Moelius 		}
40654243797SSamuel Moelius 	}
40754243797SSamuel Moelius 	return 0;
40854243797SSamuel Moelius }
40954243797SSamuel Moelius 
41054243797SSamuel Moelius int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
41154243797SSamuel Moelius 		unsigned int size, struct fuse_copy_state *cs)
41254243797SSamuel Moelius {
41354243797SSamuel Moelius 	switch (code) {
41454243797SSamuel Moelius 	case FUSE_NOTIFY_POLL:
41554243797SSamuel Moelius 		return fuse_notify_poll(fc, size, cs);
41654243797SSamuel Moelius 
41754243797SSamuel Moelius 	case FUSE_NOTIFY_INVAL_INODE:
41854243797SSamuel Moelius 		return fuse_notify_inval_inode(fc, size, cs);
41954243797SSamuel Moelius 
42054243797SSamuel Moelius 	case FUSE_NOTIFY_INVAL_ENTRY:
42154243797SSamuel Moelius 		return fuse_notify_inval_entry(fc, size, cs);
42254243797SSamuel Moelius 
42354243797SSamuel Moelius 	case FUSE_NOTIFY_STORE:
42454243797SSamuel Moelius 		return fuse_notify_store(fc, size, cs);
42554243797SSamuel Moelius 
42654243797SSamuel Moelius 	case FUSE_NOTIFY_RETRIEVE:
42754243797SSamuel Moelius 		return fuse_notify_retrieve(fc, size, cs);
42854243797SSamuel Moelius 
42954243797SSamuel Moelius 	case FUSE_NOTIFY_DELETE:
43054243797SSamuel Moelius 		return fuse_notify_delete(fc, size, cs);
43154243797SSamuel Moelius 
43254243797SSamuel Moelius 	case FUSE_NOTIFY_RESEND:
43354243797SSamuel Moelius 		return fuse_notify_resend(fc);
43454243797SSamuel Moelius 
43554243797SSamuel Moelius 	case FUSE_NOTIFY_INC_EPOCH:
43654243797SSamuel Moelius 		return fuse_notify_inc_epoch(fc);
43754243797SSamuel Moelius 
43854243797SSamuel Moelius 	case FUSE_NOTIFY_PRUNE:
43954243797SSamuel Moelius 		return fuse_notify_prune(fc, size, cs);
44054243797SSamuel Moelius 
44154243797SSamuel Moelius 	default:
44254243797SSamuel Moelius 		return -EINVAL;
44354243797SSamuel Moelius 	}
44454243797SSamuel Moelius }
445