netfs, cachefiles: Pass upper bound length to allow expansion

Make netfslib pass the maximum length to the ->prepare_write() op to tell
the cache how much it can expand the length of a write to.  This allows a
write to the server at the end of a file to be limited to a few bytes
whilst writing an entire block to the cache (something required by direct
I/O).

Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: linux-cachefs@redhat.com
cc: linux-fsdevel@vger.kernel.org
cc: linux-mm@kvack.org
This commit is contained in:
David Howells 2023-11-22 17:18:17 +00:00
parent 80645bd4aa
commit e0ace6ca98
9 changed files with 26 additions and 27 deletions

View File

@ -233,7 +233,7 @@ extern bool cachefiles_begin_operation(struct netfs_cache_resources *cres,
enum fscache_want_state want_state); enum fscache_want_state want_state);
extern int __cachefiles_prepare_write(struct cachefiles_object *object, extern int __cachefiles_prepare_write(struct cachefiles_object *object,
struct file *file, struct file *file,
loff_t *_start, size_t *_len, loff_t *_start, size_t *_len, size_t upper_len,
bool no_space_allocated_yet); bool no_space_allocated_yet);
extern int __cachefiles_write(struct cachefiles_object *object, extern int __cachefiles_write(struct cachefiles_object *object,
struct file *file, struct file *file,

View File

@ -518,7 +518,7 @@ cachefiles_prepare_ondemand_read(struct netfs_cache_resources *cres,
*/ */
int __cachefiles_prepare_write(struct cachefiles_object *object, int __cachefiles_prepare_write(struct cachefiles_object *object,
struct file *file, struct file *file,
loff_t *_start, size_t *_len, loff_t *_start, size_t *_len, size_t upper_len,
bool no_space_allocated_yet) bool no_space_allocated_yet)
{ {
struct cachefiles_cache *cache = object->volume->cache; struct cachefiles_cache *cache = object->volume->cache;
@ -530,6 +530,8 @@ int __cachefiles_prepare_write(struct cachefiles_object *object,
down = start - round_down(start, PAGE_SIZE); down = start - round_down(start, PAGE_SIZE);
*_start = start - down; *_start = start - down;
*_len = round_up(down + len, PAGE_SIZE); *_len = round_up(down + len, PAGE_SIZE);
if (down < start || *_len > upper_len)
return -ENOBUFS;
/* We need to work out whether there's sufficient disk space to perform /* We need to work out whether there's sufficient disk space to perform
* the write - but we can skip that check if we have space already * the write - but we can skip that check if we have space already
@ -592,8 +594,8 @@ check_space:
} }
static int cachefiles_prepare_write(struct netfs_cache_resources *cres, static int cachefiles_prepare_write(struct netfs_cache_resources *cres,
loff_t *_start, size_t *_len, loff_t i_size, loff_t *_start, size_t *_len, size_t upper_len,
bool no_space_allocated_yet) loff_t i_size, bool no_space_allocated_yet)
{ {
struct cachefiles_object *object = cachefiles_cres_object(cres); struct cachefiles_object *object = cachefiles_cres_object(cres);
struct cachefiles_cache *cache = object->volume->cache; struct cachefiles_cache *cache = object->volume->cache;
@ -609,7 +611,7 @@ static int cachefiles_prepare_write(struct netfs_cache_resources *cres,
cachefiles_begin_secure(cache, &saved_cred); cachefiles_begin_secure(cache, &saved_cred);
ret = __cachefiles_prepare_write(object, cachefiles_cres_file(cres), ret = __cachefiles_prepare_write(object, cachefiles_cres_file(cres),
_start, _len, _start, _len, upper_len,
no_space_allocated_yet); no_space_allocated_yet);
cachefiles_end_secure(cache, saved_cred); cachefiles_end_secure(cache, saved_cred);
return ret; return ret;

View File

@ -52,7 +52,7 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
return -ENOBUFS; return -ENOBUFS;
cachefiles_begin_secure(cache, &saved_cred); cachefiles_begin_secure(cache, &saved_cred);
ret = __cachefiles_prepare_write(object, file, &pos, &len, true); ret = __cachefiles_prepare_write(object, file, &pos, &len, len, true);
cachefiles_end_secure(cache, saved_cred); cachefiles_end_secure(cache, saved_cred);
if (ret < 0) if (ret < 0)
return ret; return ret;

View File

@ -237,7 +237,7 @@ void __fscache_write_to_cache(struct fscache_cookie *cookie,
fscache_access_io_write) < 0) fscache_access_io_write) < 0)
goto abandon_free; goto abandon_free;
ret = cres->ops->prepare_write(cres, &start, &len, i_size, false); ret = cres->ops->prepare_write(cres, &start, &len, len, i_size, false);
if (ret < 0) if (ret < 0)
goto abandon_end; goto abandon_end;

View File

@ -199,7 +199,7 @@ static void netfs_rreq_do_write_to_cache(struct netfs_io_request *rreq)
} }
ret = cres->ops->prepare_write(cres, &subreq->start, &subreq->len, ret = cres->ops->prepare_write(cres, &subreq->start, &subreq->len,
rreq->i_size, true); subreq->len, rreq->i_size, true);
if (ret < 0) { if (ret < 0) {
trace_netfs_failure(rreq, subreq, ret, netfs_fail_prepare_write); trace_netfs_failure(rreq, subreq, ret, netfs_fail_prepare_write);
trace_netfs_sreq(subreq, netfs_sreq_trace_write_skip); trace_netfs_sreq(subreq, netfs_sreq_trace_write_skip);

View File

@ -33,6 +33,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
rreq->start = start; rreq->start = start;
rreq->len = len; rreq->len = len;
rreq->upper_len = len;
rreq->origin = origin; rreq->origin = origin;
rreq->netfs_ops = ctx->ops; rreq->netfs_ops = ctx->ops;
rreq->mapping = mapping; rreq->mapping = mapping;

View File

@ -280,7 +280,7 @@ EXPORT_SYMBOL(netfs_queue_write_request);
*/ */
static void netfs_set_up_write_to_cache(struct netfs_io_request *wreq) static void netfs_set_up_write_to_cache(struct netfs_io_request *wreq)
{ {
struct netfs_cache_resources *cres; struct netfs_cache_resources *cres = &wreq->cache_resources;
struct netfs_io_subrequest *subreq; struct netfs_io_subrequest *subreq;
struct netfs_inode *ctx = netfs_inode(wreq->inode); struct netfs_inode *ctx = netfs_inode(wreq->inode);
struct fscache_cookie *cookie = netfs_i_cookie(ctx); struct fscache_cookie *cookie = netfs_i_cookie(ctx);
@ -294,26 +294,21 @@ static void netfs_set_up_write_to_cache(struct netfs_io_request *wreq)
} }
_debug("write to cache"); _debug("write to cache");
ret = fscache_begin_write_operation(cres, cookie);
if (ret < 0)
return;
ret = cres->ops->prepare_write(cres, &start, &len, wreq->upper_len,
i_size_read(wreq->inode), true);
if (ret < 0)
return;
subreq = netfs_create_write_request(wreq, NETFS_WRITE_TO_CACHE, start, len, subreq = netfs_create_write_request(wreq, NETFS_WRITE_TO_CACHE, start, len,
netfs_write_to_cache_op_worker); netfs_write_to_cache_op_worker);
if (!subreq) if (!subreq)
return; return;
cres = &wreq->cache_resources; netfs_write_to_cache_op(subreq);
ret = fscache_begin_read_operation(cres, cookie);
if (ret < 0) {
netfs_write_subrequest_terminated(subreq, ret, false);
return;
}
ret = cres->ops->prepare_write(cres, &start, &len, i_size_read(wreq->inode),
true);
if (ret < 0) {
netfs_write_subrequest_terminated(subreq, ret, false);
return;
}
netfs_queue_write_request(subreq);
} }
/* /*

View File

@ -180,7 +180,7 @@ static int fscache_fallback_write_pages(struct inode *inode, loff_t start, size_
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = cres.ops->prepare_write(&cres, &start, &len, i_size_read(inode), ret = cres.ops->prepare_write(&cres, &start, &len, len, i_size_read(inode),
no_space_allocated_yet); no_space_allocated_yet);
if (ret == 0) if (ret == 0)
ret = fscache_write(&cres, start, &iter, NULL, NULL); ret = fscache_write(&cres, start, &iter, NULL, NULL);

View File

@ -261,6 +261,7 @@ struct netfs_io_request {
atomic_t nr_copy_ops; /* Number of copy-to-cache ops in progress */ atomic_t nr_copy_ops; /* Number of copy-to-cache ops in progress */
size_t submitted; /* Amount submitted for I/O so far */ size_t submitted; /* Amount submitted for I/O so far */
size_t len; /* Length of the request */ size_t len; /* Length of the request */
size_t upper_len; /* Length can be extended to here */
size_t transferred; /* Amount to be indicated as transferred */ size_t transferred; /* Amount to be indicated as transferred */
short error; /* 0 or error that occurred */ short error; /* 0 or error that occurred */
enum netfs_io_origin origin; /* Origin of the request */ enum netfs_io_origin origin; /* Origin of the request */
@ -357,8 +358,8 @@ struct netfs_cache_ops {
* actually do. * actually do.
*/ */
int (*prepare_write)(struct netfs_cache_resources *cres, int (*prepare_write)(struct netfs_cache_resources *cres,
loff_t *_start, size_t *_len, loff_t i_size, loff_t *_start, size_t *_len, size_t upper_len,
bool no_space_allocated_yet); loff_t i_size, bool no_space_allocated_yet);
/* Prepare an on-demand read operation, shortening it to a cached/uncached /* Prepare an on-demand read operation, shortening it to a cached/uncached
* boundary as appropriate. * boundary as appropriate.