Merge tag 'vfs-6.10.netfs' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[sfrench/cifs-2.6.git] / fs / netfs / objects.c
index 610ceb5bd86c08ba7c61905d07d19092940f44ae..c90d482b16505d319dede502bcf23c7bed38e254 100644 (file)
@@ -6,6 +6,8 @@
  */
 
 #include <linux/slab.h>
+#include <linux/mempool.h>
+#include <linux/delay.h>
 #include "internal.h"
 
 /*
@@ -20,17 +22,22 @@ 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;
+       mempool_t *mempool = ctx->ops->request_pool ?: &netfs_request_pool;
+       struct kmem_cache *cache = mempool->pool_data;
        bool is_unbuffered = (origin == NETFS_UNBUFFERED_WRITE ||
                              origin == NETFS_DIO_READ ||
                              origin == NETFS_DIO_WRITE);
        bool cached = !is_unbuffered && netfs_is_cache_enabled(ctx);
        int ret;
 
-       rreq = kzalloc(ctx->ops->io_request_size ?: sizeof(struct netfs_io_request),
-                      GFP_KERNEL);
-       if (!rreq)
-               return ERR_PTR(-ENOMEM);
+       for (;;) {
+               rreq = mempool_alloc(mempool, GFP_KERNEL);
+               if (rreq)
+                       break;
+               msleep(10);
+       }
 
+       memset(rreq, 0, kmem_cache_size(cache));
        rreq->start     = start;
        rreq->len       = len;
        rreq->upper_len = len;
@@ -40,19 +47,27 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping,
        rreq->inode     = inode;
        rreq->i_size    = i_size_read(inode);
        rreq->debug_id  = atomic_inc_return(&debug_ids);
+       rreq->wsize     = INT_MAX;
+       spin_lock_init(&rreq->lock);
+       INIT_LIST_HEAD(&rreq->io_streams[0].subrequests);
+       INIT_LIST_HEAD(&rreq->io_streams[1].subrequests);
        INIT_LIST_HEAD(&rreq->subrequests);
        INIT_WORK(&rreq->work, NULL);
        refcount_set(&rreq->ref, 1);
 
        __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags);
-       if (cached)
+       if (cached) {
                __set_bit(NETFS_RREQ_WRITE_TO_CACHE, &rreq->flags);
+               if (test_bit(NETFS_ICTX_USE_PGPRIV2, &ctx->flags))
+                       /* Filesystem uses deprecated PG_private_2 marking. */
+                       __set_bit(NETFS_RREQ_USE_PGPRIV2, &rreq->flags);
+       }
        if (file && file->f_flags & O_NONBLOCK)
                __set_bit(NETFS_RREQ_NONBLOCK, &rreq->flags);
        if (rreq->netfs_ops->init_request) {
                ret = rreq->netfs_ops->init_request(rreq, file);
                if (ret < 0) {
-                       kfree(rreq);
+                       mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);
                        return ERR_PTR(ret);
                }
        }
@@ -74,6 +89,8 @@ void netfs_get_request(struct netfs_io_request *rreq, enum netfs_rreq_ref_trace
 void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async)
 {
        struct netfs_io_subrequest *subreq;
+       struct netfs_io_stream *stream;
+       int s;
 
        while (!list_empty(&rreq->subrequests)) {
                subreq = list_first_entry(&rreq->subrequests,
@@ -82,6 +99,25 @@ void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async)
                netfs_put_subrequest(subreq, was_async,
                                     netfs_sreq_trace_put_clear);
        }
+
+       for (s = 0; s < ARRAY_SIZE(rreq->io_streams); s++) {
+               stream = &rreq->io_streams[s];
+               while (!list_empty(&stream->subrequests)) {
+                       subreq = list_first_entry(&stream->subrequests,
+                                                 struct netfs_io_subrequest, rreq_link);
+                       list_del(&subreq->rreq_link);
+                       netfs_put_subrequest(subreq, was_async,
+                                            netfs_sreq_trace_put_clear);
+               }
+       }
+}
+
+static void netfs_free_request_rcu(struct rcu_head *rcu)
+{
+       struct netfs_io_request *rreq = container_of(rcu, struct netfs_io_request, rcu);
+
+       mempool_free(rreq, rreq->netfs_ops->request_pool ?: &netfs_request_pool);
+       netfs_stat_d(&netfs_n_rh_rreq);
 }
 
 static void netfs_free_request(struct work_struct *work)
@@ -106,8 +142,7 @@ static void netfs_free_request(struct work_struct *work)
                }
                kvfree(rreq->direct_bv);
        }
-       kfree_rcu(rreq, rcu);
-       netfs_stat_d(&netfs_n_rh_rreq);
+       call_rcu(&rreq->rcu, netfs_free_request_rcu);
 }
 
 void netfs_put_request(struct netfs_io_request *rreq, bool was_async,
@@ -139,19 +174,25 @@ void netfs_put_request(struct netfs_io_request *rreq, bool was_async,
 struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq)
 {
        struct netfs_io_subrequest *subreq;
-
-       subreq = kzalloc(rreq->netfs_ops->io_subrequest_size ?:
-                        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;
-               netfs_get_request(rreq, netfs_rreq_trace_get_subreq);
-               netfs_stat(&netfs_n_rh_sreq);
+       mempool_t *mempool = rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool;
+       struct kmem_cache *cache = mempool->pool_data;
+
+       for (;;) {
+               subreq = mempool_alloc(rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool,
+                                      GFP_KERNEL);
+               if (subreq)
+                       break;
+               msleep(10);
        }
 
+       memset(subreq, 0, kmem_cache_size(cache));
+       INIT_WORK(&subreq->work, NULL);
+       INIT_LIST_HEAD(&subreq->rreq_link);
+       refcount_set(&subreq->ref, 2);
+       subreq->rreq = rreq;
+       subreq->debug_index = atomic_inc_return(&rreq->subreq_counter);
+       netfs_get_request(rreq, netfs_rreq_trace_get_subreq);
+       netfs_stat(&netfs_n_rh_sreq);
        return subreq;
 }
 
@@ -173,7 +214,7 @@ static void netfs_free_subrequest(struct netfs_io_subrequest *subreq,
        trace_netfs_sreq(subreq, netfs_sreq_trace_free);
        if (rreq->netfs_ops->free_subrequest)
                rreq->netfs_ops->free_subrequest(subreq);
-       kfree(subreq);
+       mempool_free(subreq, rreq->netfs_ops->subrequest_pool ?: &netfs_subrequest_pool);
        netfs_stat_d(&netfs_n_rh_sreq);
        netfs_put_request(rreq, was_async, netfs_rreq_trace_put_subreq);
 }