fs/fuse/notify.c

Source file repositories/reference/linux-study-clean/fs/fuse/notify.c

File Facts

System
Linux kernel
Corpus path
fs/fuse/notify.c
Extension
.c
Size
9761 bytes
Lines
445
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct fuse_retrieve_args {
	struct fuse_args_pages ap;
	struct fuse_notify_retrieve_in inarg;
};

static void fuse_retrieve_end(struct fuse_args *args, int error)
{
	struct fuse_retrieve_args *ra =
		container_of(args, typeof(*ra), ap.args);

	release_pages(ra->ap.folios, ra->ap.num_folios);
	kfree(ra);
}

static int fuse_retrieve(struct fuse_mount *fm, struct inode *inode,
			 struct fuse_notify_retrieve_out *outarg)
{
	int err;
	struct address_space *mapping = inode->i_mapping;
	loff_t file_size;
	unsigned int num;
	unsigned int offset;
	size_t total_len = 0;
	unsigned int num_pages;
	struct fuse_conn *fc = fm->fc;
	struct fuse_retrieve_args *ra;
	size_t args_size = sizeof(*ra);
	struct fuse_args_pages *ap;
	struct fuse_args *args;
	loff_t pos = outarg->offset;

	offset = offset_in_page(pos);
	file_size = i_size_read(inode);

	num = min(outarg->size, fc->max_write);
	if (pos > file_size)
		num = 0;
	else if (num > file_size - pos)
		num = file_size - pos;

	num_pages = DIV_ROUND_UP(num + offset, PAGE_SIZE);
	num_pages = min(num_pages, fc->max_pages);
	num = min(num, num_pages << PAGE_SHIFT);

	args_size += num_pages * (sizeof(ap->folios[0]) + sizeof(ap->descs[0]));

	ra = kzalloc(args_size, GFP_KERNEL);
	if (!ra)
		return -ENOMEM;

	ap = &ra->ap;
	ap->folios = (void *) (ra + 1);
	ap->descs = (void *) (ap->folios + num_pages);

	args = &ap->args;
	args->nodeid = outarg->nodeid;
	args->opcode = FUSE_NOTIFY_REPLY;
	args->in_numargs = 3;
	args->in_pages = true;
	args->end = fuse_retrieve_end;

	while (num && ap->num_folios < num_pages) {
		struct folio *folio;
		unsigned int folio_offset;
		unsigned int nr_bytes;
		pgoff_t index = pos >> PAGE_SHIFT;

		folio = filemap_get_folio(mapping, index);
		if (IS_ERR(folio))
			break;
		if (!folio_test_uptodate(folio)) {
			folio_put(folio);
			break;
		}

		folio_offset = offset_in_folio(folio, pos);
		nr_bytes = min(folio_size(folio) - folio_offset, num);

		ap->folios[ap->num_folios] = folio;
		ap->descs[ap->num_folios].offset = folio_offset;
		ap->descs[ap->num_folios].length = nr_bytes;
		ap->num_folios++;

		pos += nr_bytes;
		num -= nr_bytes;
		total_len += nr_bytes;
	}
	ra->inarg.offset = outarg->offset;
	ra->inarg.size = total_len;
	fuse_set_zero_arg0(args);

Annotation

Implementation Notes