netfs, cachefiles: Pass upper bound length to allow expansion
authorDavid Howells <dhowells@redhat.com>
Wed, 22 Nov 2023 17:18:17 +0000 (17:18 +0000)
committerDavid Howells <dhowells@redhat.com>
Thu, 28 Dec 2023 09:45:25 +0000 (09:45 +0000)
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

fs/cachefiles/internal.h
fs/cachefiles/io.c
fs/cachefiles/ondemand.c
fs/netfs/fscache_io.c
fs/netfs/io.c
fs/netfs/objects.c
fs/netfs/output.c
fs/smb/client/fscache.c
include/linux/netfs.h

index 2ad58c465208480e42106393ae01fd2f317389ee..1af48d576a34d6e1e1f9f9919ecea746d7ae4ac8 100644 (file)
@@ -233,7 +233,7 @@ extern bool cachefiles_begin_operation(struct netfs_cache_resources *cres,
                                       enum fscache_want_state want_state);
 extern int __cachefiles_prepare_write(struct cachefiles_object *object,
                                      struct file *file,
-                                     loff_t *_start, size_t *_len,
+                                     loff_t *_start, size_t *_len, size_t upper_len,
                                      bool no_space_allocated_yet);
 extern int __cachefiles_write(struct cachefiles_object *object,
                              struct file *file,
index 009d23cd435b544d2b7176c86a0f42eb4d2e2a4a..bffffedce4a93936aab4298815510f5cb3c79d11 100644 (file)
@@ -518,7 +518,7 @@ cachefiles_prepare_ondemand_read(struct netfs_cache_resources *cres,
  */
 int __cachefiles_prepare_write(struct cachefiles_object *object,
                               struct file *file,
-                              loff_t *_start, size_t *_len,
+                              loff_t *_start, size_t *_len, size_t upper_len,
                               bool no_space_allocated_yet)
 {
        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);
        *_start = start - down;
        *_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
         * 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,
-                                   loff_t *_start, size_t *_len, loff_t i_size,
-                                   bool no_space_allocated_yet)
+                                   loff_t *_start, size_t *_len, size_t upper_len,
+                                   loff_t i_size, bool no_space_allocated_yet)
 {
        struct cachefiles_object *object = cachefiles_cres_object(cres);
        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);
        ret = __cachefiles_prepare_write(object, cachefiles_cres_file(cres),
-                                        _start, _len,
+                                        _start, _len, upper_len,
                                         no_space_allocated_yet);
        cachefiles_end_secure(cache, saved_cred);
        return ret;
index 0254ed39f68ceb75dcb2ec840af88b136ac21fe3..9301d1eb05045343127323559e711d3405a6fded 100644 (file)
@@ -52,7 +52,7 @@ static ssize_t cachefiles_ondemand_fd_write_iter(struct kiocb *kiocb,
                return -ENOBUFS;
 
        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);
        if (ret < 0)
                return ret;
index 79171a68793046a97c10fe4a86df1af6ffcb50fc..ad572f7ee897b9d26d2439a6a1178332d2a2e547 100644 (file)
@@ -237,7 +237,7 @@ void __fscache_write_to_cache(struct fscache_cookie *cookie,
                                    fscache_access_io_write) < 0)
                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)
                goto abandon_end;
 
index 01c7ff27228e43a5f333f48f3ed80977173686f0..14c18be5aca009c32d8c6ab537d8f994f05be434 100644 (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,
-                                              rreq->i_size, true);
+                                              subreq->len, rreq->i_size, true);
                if (ret < 0) {
                        trace_netfs_failure(rreq, subreq, ret, netfs_fail_prepare_write);
                        trace_netfs_sreq(subreq, netfs_sreq_trace_write_skip);
index 93f1d74311993805f9e33ac1f30c09e03b3c64a2..b4e3bd836e5dffc6a4c04f473f5a29f12275b91e 100644 (file)
@@ -33,6 +33,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
 
        rreq->start     = start;
        rreq->len       = len;
+       rreq->upper_len = len;
        rreq->origin    = origin;
        rreq->netfs_ops = ctx->ops;
        rreq->mapping   = mapping;
index 560cbcea0c0aef95c69861848097c3c5e5827e6f..cc9065733b42380fb377af8ca8b2f9ecee6150d0 100644 (file)
@@ -280,7 +280,7 @@ EXPORT_SYMBOL(netfs_queue_write_request);
  */
 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_inode *ctx = netfs_inode(wreq->inode);
        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");
-       subreq = netfs_create_write_request(wreq, NETFS_WRITE_TO_CACHE, start, len,
-                                           netfs_write_to_cache_op_worker);
-       if (!subreq)
+       ret = fscache_begin_write_operation(cres, cookie);
+       if (ret < 0)
                return;
 
-       cres = &wreq->cache_resources;
-       ret = fscache_begin_read_operation(cres, cookie);
-       if (ret < 0) {
-               netfs_write_subrequest_terminated(subreq, ret, false);
+       ret = cres->ops->prepare_write(cres, &start, &len, wreq->upper_len,
+                                      i_size_read(wreq->inode), true);
+       if (ret < 0)
                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);
+       subreq = netfs_create_write_request(wreq, NETFS_WRITE_TO_CACHE, start, len,
+                                           netfs_write_to_cache_op_worker);
+       if (!subreq)
                return;
-       }
 
-       netfs_queue_write_request(subreq);
+       netfs_write_to_cache_op(subreq);
 }
 
 /*
index e5cad149f5a2d7d3f12d53ef61f78332a828c367..c4a3cb736881ae73fe2e002fcb2f5cadbe6cd731 100644 (file)
@@ -180,7 +180,7 @@ static int fscache_fallback_write_pages(struct inode *inode, loff_t start, size_
        if (ret < 0)
                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);
        if (ret == 0)
                ret = fscache_write(&cres, start, &iter, NULL, NULL);
index 19a41c437af3f80d063803888436fbbd86afb621..2856389f4694c0f406c167b94312f13643a07d74 100644 (file)
@@ -261,6 +261,7 @@ struct netfs_io_request {
        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                  len;            /* Length of the request */
+       size_t                  upper_len;      /* Length can be extended to here */
        size_t                  transferred;    /* Amount to be indicated as transferred */
        short                   error;          /* 0 or error that occurred */
        enum netfs_io_origin    origin;         /* Origin of the request */
@@ -357,8 +358,8 @@ struct netfs_cache_ops {
         * actually do.
         */
        int (*prepare_write)(struct netfs_cache_resources *cres,
-                            loff_t *_start, size_t *_len, loff_t i_size,
-                            bool no_space_allocated_yet);
+                            loff_t *_start, size_t *_len, size_t upper_len,
+                            loff_t i_size, bool no_space_allocated_yet);
 
        /* Prepare an on-demand read operation, shortening it to a cached/uncached
         * boundary as appropriate.