netfs: Extend the netfs_io_*request structs to handle writes
authorDavid Howells <dhowells@redhat.com>
Wed, 9 Feb 2022 19:52:13 +0000 (19:52 +0000)
committerDavid Howells <dhowells@redhat.com>
Thu, 28 Dec 2023 09:45:19 +0000 (09:45 +0000)
Modify the netfs_io_request struct to act as a point around which writes
can be coordinated.  It represents and pins a range of pages that need
writing and a list of regions of dirty data in that range of pages.

If RMW is required, the original data can be downloaded into the bounce
buffer, decrypted if necessary, the modifications made, then the modified
data can be reencrypted/recompressed and sent back to the server.

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/netfs/internal.h
fs/netfs/main.c
fs/netfs/objects.c
fs/netfs/stats.c
include/linux/netfs.h
include/trace/events/netfs.h

index b908c7e0a90134e9e1ba4c9429da8056d3826c81..2bf2e82b2ad79f830ef4c87b3985209705b9d925 100644 (file)
@@ -110,6 +110,12 @@ extern atomic_t netfs_n_rh_write_begin;
 extern atomic_t netfs_n_rh_write_done;
 extern atomic_t netfs_n_rh_write_failed;
 extern atomic_t netfs_n_rh_write_zskip;
+extern atomic_t netfs_n_wh_upload;
+extern atomic_t netfs_n_wh_upload_done;
+extern atomic_t netfs_n_wh_upload_failed;
+extern atomic_t netfs_n_wh_write;
+extern atomic_t netfs_n_wh_write_done;
+extern atomic_t netfs_n_wh_write_failed;
 
 int netfs_stats_show(struct seq_file *m, void *v);
 
index 97ce1436615b725eb12747db03b643975830e077..ab6cac11067625287d1e47afa5d69ce7e07db052 100644 (file)
@@ -25,10 +25,11 @@ MODULE_PARM_DESC(netfs_debug, "Netfs support debugging mask");
 LIST_HEAD(netfs_io_requests);
 DEFINE_SPINLOCK(netfs_proc_lock);
 
-static const char *netfs_origins[] = {
+static const char *netfs_origins[nr__netfs_io_origin] = {
        [NETFS_READAHEAD]       = "RA",
        [NETFS_READPAGE]        = "RP",
        [NETFS_READ_FOR_WRITE]  = "RW",
+       [NETFS_WRITEBACK]       = "WB",
 };
 
 /*
index 4df5e5eeada6848cd5669825d3c53ac476569835..65a17dd4ab492c9ed07dabeac0e2ff7b68b52e14 100644 (file)
@@ -20,6 +20,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
        struct inode *inode = file ? file_inode(file) : mapping->host;
        struct netfs_inode *ctx = netfs_inode(inode);
        struct netfs_io_request *rreq;
+       bool cached = netfs_is_cache_enabled(ctx);
        int ret;
 
        rreq = kzalloc(ctx->ops->io_request_size ?: sizeof(struct netfs_io_request),
@@ -37,7 +38,10 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
        rreq->debug_id  = atomic_inc_return(&debug_ids);
        INIT_LIST_HEAD(&rreq->subrequests);
        refcount_set(&rreq->ref, 1);
+
        __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
+       if (cached)
+               __set_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags);
        if (rreq->netfs_ops->init_request) {
                ret = rreq->netfs_ops->init_request(rreq, file);
                if (ret < 0) {
@@ -46,6 +50,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
                }
        }
 
+       trace_netfs_rreq_ref(rreq->debug_id, 1, netfs_rreq_trace_new);
        netfs_proc_add_rreq(rreq);
        netfs_stat(&netfs_n_rh_rreq);
        return rreq;
@@ -129,6 +134,7 @@ struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq
                         sizeof(struct netfs_io_subrequest),
                         GFP_KERNEL);
        if (subreq) {
+               INIT_WORK(&subreq->work, NULL);
                INIT_LIST_HEAD(&subreq->rreq_link);
                refcount_set(&subreq->ref, 2);
                subreq->rreq = rreq;
index 6025dc485f7ea60e0eb08109999d6823f9692f13..c1f85cd595a47f0ddc21fb5cf083faad3957b6cd 100644 (file)
@@ -27,6 +27,12 @@ atomic_t netfs_n_rh_write_begin;
 atomic_t netfs_n_rh_write_done;
 atomic_t netfs_n_rh_write_failed;
 atomic_t netfs_n_rh_write_zskip;
+atomic_t netfs_n_wh_upload;
+atomic_t netfs_n_wh_upload_done;
+atomic_t netfs_n_wh_upload_failed;
+atomic_t netfs_n_wh_write;
+atomic_t netfs_n_wh_write_done;
+atomic_t netfs_n_wh_write_failed;
 
 int netfs_stats_show(struct seq_file *m, void *v)
 {
@@ -50,10 +56,14 @@ int netfs_stats_show(struct seq_file *m, void *v)
                   atomic_read(&netfs_n_rh_read),
                   atomic_read(&netfs_n_rh_read_done),
                   atomic_read(&netfs_n_rh_read_failed));
+       seq_printf(m, "Netfs  : UL=%u us=%u uf=%u\n",
+                  atomic_read(&netfs_n_wh_upload),
+                  atomic_read(&netfs_n_wh_upload_done),
+                  atomic_read(&netfs_n_wh_upload_failed));
        seq_printf(m, "Netfs  : WR=%u ws=%u wf=%u\n",
-                  atomic_read(&netfs_n_rh_write),
-                  atomic_read(&netfs_n_rh_write_done),
-                  atomic_read(&netfs_n_rh_write_failed));
+                  atomic_read(&netfs_n_wh_write),
+                  atomic_read(&netfs_n_wh_write_done),
+                  atomic_read(&netfs_n_wh_write_failed));
        return fscache_stats_show(m);
 }
 EXPORT_SYMBOL(netfs_stats_show);
index 44cd13ad695af85b8b16554df3c12864657ca446..f302123a3e3840ce21e982633c6f3eb2b1b06411 100644 (file)
@@ -118,6 +118,9 @@ enum netfs_io_source {
        NETFS_DOWNLOAD_FROM_SERVER,
        NETFS_READ_FROM_CACHE,
        NETFS_INVALID_READ,
+       NETFS_UPLOAD_TO_SERVER,
+       NETFS_WRITE_TO_CACHE,
+       NETFS_INVALID_WRITE,
 } __mode(byte);
 
 typedef void (*netfs_io_terminated_t)(void *priv, ssize_t transferred_or_error,
@@ -149,9 +152,14 @@ struct netfs_cache_resources {
 };
 
 /*
- * Descriptor for a single component subrequest.
+ * Descriptor for a single component subrequest.  Each operation represents an
+ * individual read/write from/to a server, a cache, a journal, etc..
+ *
+ * The buffer iterator is persistent for the life of the subrequest struct and
+ * the pages it points to can be relied on to exist for the duration.
  */
 struct netfs_io_subrequest {
+       struct work_struct      work;
        struct netfs_io_request *rreq;          /* Supervising I/O request */
        struct list_head        rreq_link;      /* Link in rreq->subrequests */
        struct iov_iter         io_iter;        /* Iterator for this subrequest */
@@ -176,6 +184,8 @@ enum netfs_io_origin {
        NETFS_READAHEAD,                /* This read was triggered by readahead */
        NETFS_READPAGE,                 /* This read is a synchronous read */
        NETFS_READ_FOR_WRITE,           /* This read is to prepare a write */
+       NETFS_WRITEBACK,                /* This write was triggered by writepages */
+       nr__netfs_io_origin
 } __mode(byte);
 
 /*
@@ -198,6 +208,7 @@ struct netfs_io_request {
        struct bio_vec          *direct_bv;     /* DIO buffer list (when handling iovec-iter) */
        unsigned int            direct_bv_count; /* Number of elements in direct_bv[] */
        unsigned int            debug_id;
+       unsigned int            subreq_counter; /* Next subreq->debug_index */
        atomic_t                nr_outstanding; /* Number of 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 */
@@ -216,6 +227,8 @@ struct netfs_io_request {
 #define NETFS_RREQ_DONT_UNLOCK_FOLIOS  3       /* Don't unlock the folios on completion */
 #define NETFS_RREQ_FAILED              4       /* The request failed */
 #define NETFS_RREQ_IN_PROGRESS         5       /* Unlocked when the request completes */
+#define NETFS_RREQ_WRITE_TO_CACHE      7       /* Need to write to the cache */
+#define NETFS_RREQ_UPLOAD_TO_SERVER    8       /* Need to write to the server */
        const struct netfs_request_ops *netfs_ops;
 };
 
index fce6d0bc78e5e628f21509e107cd6b141ccf2545..4ea4e34d279f2b0e944563d24eef9992eb18430b 100644 (file)
@@ -24,7 +24,8 @@
 #define netfs_rreq_origins                                     \
        EM(NETFS_READAHEAD,                     "RA")           \
        EM(NETFS_READPAGE,                      "RP")           \
-       E_(NETFS_READ_FOR_WRITE,                "RW")
+       EM(NETFS_READ_FOR_WRITE,                "RW")           \
+       E_(NETFS_WRITEBACK,                     "WB")
 
 #define netfs_rreq_traces                                      \
        EM(netfs_rreq_trace_assess,             "ASSESS ")      \
        EM(NETFS_FILL_WITH_ZEROES,              "ZERO")         \
        EM(NETFS_DOWNLOAD_FROM_SERVER,          "DOWN")         \
        EM(NETFS_READ_FROM_CACHE,               "READ")         \
-       E_(NETFS_INVALID_READ,                  "INVL")         \
+       EM(NETFS_INVALID_READ,                  "INVL")         \
+       EM(NETFS_UPLOAD_TO_SERVER,              "UPLD")         \
+       EM(NETFS_WRITE_TO_CACHE,                "WRIT")         \
+       E_(NETFS_INVALID_WRITE,                 "INVL")
 
 #define netfs_sreq_traces                                      \
        EM(netfs_sreq_trace_download_instead,   "RDOWN")        \