fs/netfs/buffered_write.c

Source file repositories/reference/linux-study-clean/fs/netfs/buffered_write.c

File Facts

System
Linux kernel
Corpus path
fs/netfs/buffered_write.c
Extension
.c
Size
17758 bytes
Lines
617
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: exported/initcall integration point
Status
integration 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

if (copied > gap) {
			add = DIV_ROUND_UP(copied - gap, SECTOR_SIZE);

			inode->i_blocks = min_t(blkcnt_t,
						DIV_ROUND_UP(end, SECTOR_SIZE),
						inode->i_blocks + add);
		}
	}
	spin_unlock(&inode->i_lock);
}

/**
 * netfs_perform_write - Copy data into the pagecache.
 * @iocb: The operation parameters
 * @iter: The source buffer
 * @netfs_group: Grouping for dirty folios (eg. ceph snaps).
 *
 * Copy data into pagecache folios attached to the inode specified by @iocb.
 * The caller must hold appropriate inode locks.
 *
 * Dirty folios are tagged with a netfs_folio struct if they're not up to date
 * to indicate the range modified.  Dirty folios may also be tagged with a
 * netfs-specific grouping such that data from an old group gets flushed before
 * a new one is started.
 */
ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter,
			    struct netfs_group *netfs_group)
{
	struct file *file = iocb->ki_filp;
	struct inode *inode = file_inode(file);
	struct address_space *mapping = inode->i_mapping;
	struct netfs_inode *ctx = netfs_inode(inode);
	struct writeback_control wbc = {
		.sync_mode	= WB_SYNC_NONE,
		.for_sync	= true,
		.nr_to_write	= LONG_MAX,
		.range_start	= iocb->ki_pos,
		.range_end	= iocb->ki_pos + iter->count,
	};
	struct netfs_io_request *wreq = NULL;
	struct folio *folio = NULL, *writethrough = NULL;
	unsigned int bdp_flags = (iocb->ki_flags & IOCB_NOWAIT) ? BDP_ASYNC : 0;
	ssize_t written = 0, ret, ret2;
	loff_t pos = iocb->ki_pos;
	size_t max_chunk = mapping_max_folio_size(mapping);
	bool maybe_trouble = false;

	if (unlikely(iocb->ki_flags & (IOCB_DSYNC | IOCB_SYNC))
	    ) {
		wbc_attach_fdatawrite_inode(&wbc, mapping->host);

		ret = filemap_write_and_wait_range(mapping, pos, pos + iter->count);
		if (ret < 0) {
			wbc_detach_inode(&wbc);
			goto out;
		}

		wreq = netfs_begin_writethrough(iocb, iter->count);
		if (IS_ERR(wreq)) {
			wbc_detach_inode(&wbc);
			ret = PTR_ERR(wreq);
			wreq = NULL;
			goto out;
		}
		if (!is_sync_kiocb(iocb))
			wreq->iocb = iocb;
		netfs_stat(&netfs_n_wh_writethrough);
	} else {
		netfs_stat(&netfs_n_wh_buffered_write);
	}

	do {
		enum netfs_folio_trace trace;
		struct netfs_folio *finfo;
		struct netfs_group *group;
		unsigned long long fpos;
		size_t flen;
		size_t offset;	/* Offset into pagecache folio */
		size_t part;	/* Bytes to write to folio */
		size_t copied;	/* Bytes copied from user */
		void *priv;

		offset = pos & (max_chunk - 1);
		part = min(max_chunk - offset, iov_iter_count(iter));

		/* Bring in the user pages that we will copy from _first_ lest
		 * we hit a nasty deadlock on copying from the same page as
		 * we're writing to, without it being marked uptodate.
		 *
		 * Not only is this an optimisation, but it is also required to

Annotation

Implementation Notes