Commit 64e64e6c authored by David Howells's avatar David Howells
Browse files

netfs, cachefiles: Implement helpers for new write code



Implement the helpers for the new write code in cachefiles.  There's now an
optional ->prepare_write() that allows the filesystem to set the parameters
for the next write, such as maximum size and maximum segment count, and an
->issue_write() that is called to initiate an (asynchronous) write
operation.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-erofs@lists.ozlabs.org
cc: linux-fsdevel@vger.kernel.org
parent 5fb70e72
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/slab.h>
#include <linux/file.h>
#include <linux/uio.h>
#include <linux/bio.h>
#include <linux/falloc.h>
#include <linux/sched/mm.h>
#include <trace/events/fscache.h>
@@ -622,6 +623,77 @@ static int cachefiles_prepare_write(struct netfs_cache_resources *cres,
	return ret;
}

static void cachefiles_prepare_write_subreq(struct netfs_io_subrequest *subreq)
{
	struct netfs_io_request *wreq = subreq->rreq;
	struct netfs_cache_resources *cres = &wreq->cache_resources;

	_enter("W=%x[%x] %llx", wreq->debug_id, subreq->debug_index, subreq->start);

	subreq->max_len = ULONG_MAX;
	subreq->max_nr_segs = BIO_MAX_VECS;

	if (!cachefiles_cres_file(cres)) {
		if (!fscache_wait_for_operation(cres, FSCACHE_WANT_WRITE))
			return netfs_prepare_write_failed(subreq);
		if (!cachefiles_cres_file(cres))
			return netfs_prepare_write_failed(subreq);
	}
}

static void cachefiles_issue_write(struct netfs_io_subrequest *subreq)
{
	struct netfs_io_request *wreq = subreq->rreq;
	struct netfs_cache_resources *cres = &wreq->cache_resources;
	struct cachefiles_object *object = cachefiles_cres_object(cres);
	struct cachefiles_cache *cache = object->volume->cache;
	const struct cred *saved_cred;
	size_t off, pre, post, len = subreq->len;
	loff_t start = subreq->start;
	int ret;

	_enter("W=%x[%x] %llx-%llx",
	       wreq->debug_id, subreq->debug_index, start, start + len - 1);

	/* We need to start on the cache granularity boundary */
	off = start & (CACHEFILES_DIO_BLOCK_SIZE - 1);
	if (off) {
		pre = CACHEFILES_DIO_BLOCK_SIZE - off;
		if (pre >= len) {
			netfs_write_subrequest_terminated(subreq, len, false);
			return;
		}
		subreq->transferred += pre;
		start += pre;
		len -= pre;
		iov_iter_advance(&subreq->io_iter, pre);
	}

	/* We also need to end on the cache granularity boundary */
	post = len & (CACHEFILES_DIO_BLOCK_SIZE - 1);
	if (post) {
		len -= post;
		if (len == 0) {
			netfs_write_subrequest_terminated(subreq, post, false);
			return;
		}
		iov_iter_truncate(&subreq->io_iter, len);
	}

	cachefiles_begin_secure(cache, &saved_cred);
	ret = __cachefiles_prepare_write(object, cachefiles_cres_file(cres),
					 &start, &len, len, true);
	cachefiles_end_secure(cache, saved_cred);
	if (ret < 0) {
		netfs_write_subrequest_terminated(subreq, ret, false);
		return;
	}

	cachefiles_write(&subreq->rreq->cache_resources,
			 subreq->start, &subreq->io_iter,
			 netfs_write_subrequest_terminated, subreq);
}

/*
 * Clean up an operation.
 */
@@ -638,8 +710,10 @@ static const struct netfs_cache_ops cachefiles_netfs_cache_ops = {
	.end_operation		= cachefiles_end_operation,
	.read			= cachefiles_read,
	.write			= cachefiles_write,
	.issue_write		= cachefiles_issue_write,
	.prepare_read		= cachefiles_prepare_read,
	.prepare_write		= cachefiles_prepare_write,
	.prepare_write_subreq	= cachefiles_prepare_write_subreq,
	.prepare_ondemand_read	= cachefiles_prepare_ondemand_read,
	.query_occupancy	= cachefiles_query_occupancy,
};