diff options
Diffstat (limited to 'fs/cachefiles/io.c')
| -rw-r--r-- | fs/cachefiles/io.c | 76 | 
1 files changed, 75 insertions, 1 deletions
diff --git a/fs/cachefiles/io.c b/fs/cachefiles/io.c index 1d685357e67f..e667dbcd20e8 100644 --- a/fs/cachefiles/io.c +++ b/fs/cachefiles/io.c @@ -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> @@ -493,7 +494,7 @@ out_no_object:   * boundary as appropriate.   */  static enum netfs_io_source cachefiles_prepare_read(struct netfs_io_subrequest *subreq, -						    loff_t i_size) +						    unsigned long long i_size)  {  	return cachefiles_do_prepare_read(&subreq->rreq->cache_resources,  					  subreq->start, &subreq->len, i_size, @@ -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,  };  |