netfs, cachefiles: Implement helpers for new write code
authorDavid Howells <dhowells@redhat.com>
Mon, 18 Mar 2024 20:31:13 +0000 (20:31 +0000)
committerDavid Howells <dhowells@redhat.com>
Wed, 1 May 2024 17:07:37 +0000 (18:07 +0100)
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: David Howells <dhowells@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
cc: netfs@lists.linux.dev
cc: linux-erofs@lists.ozlabs.org
cc: linux-fsdevel@vger.kernel.org

fs/cachefiles/io.c

index 5ba5c7814fe41386f6120fefeb12e50ed488af9f..e667dbcd20e8ca7339c7dde53270fe00f62a7ee2 100644 (file)
@@ -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,
 };