]> git.dujemihanovic.xyz Git - linux.git/commitdiff
NFS: Fix memory allocation in rpc_malloc()
authorTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 15 Mar 2022 02:02:22 +0000 (22:02 -0400)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Tue, 22 Mar 2022 19:52:55 +0000 (15:52 -0400)
When in a low memory situation, we do want rpciod to kick off direct
reclaim in the case where that helps, however we don't want it looping
forever in mempool_alloc().
So first try allocating from the slab using GFP_KERNEL | __GFP_NORETRY,
and then fall back to a GFP_NOWAIT allocation from the mempool.

Ditto for rpc_alloc_task()

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
include/linux/sunrpc/sched.h
net/sunrpc/sched.c

index 56710f8056d3362740fd5f9f450efe7ab89a9e93..1d7a3e51b79588d69d5a2ad3d0e9e0d7f2e66a01 100644 (file)
@@ -262,6 +262,7 @@ void                rpc_destroy_mempool(void);
 extern struct workqueue_struct *rpciod_workqueue;
 extern struct workqueue_struct *xprtiod_workqueue;
 void           rpc_prepare_task(struct rpc_task *task);
+gfp_t          rpc_task_gfp_mask(void);
 
 static inline int rpc_wait_for_completion_task(struct rpc_task *task)
 {
index 7c8f87ebdbc078d495dcc67c6c89a956170401ee..d59a033820bea90902979e681f29e72e37adc437 100644 (file)
@@ -57,6 +57,13 @@ struct workqueue_struct *rpciod_workqueue __read_mostly;
 struct workqueue_struct *xprtiod_workqueue __read_mostly;
 EXPORT_SYMBOL_GPL(xprtiod_workqueue);
 
+gfp_t rpc_task_gfp_mask(void)
+{
+       if (current->flags & PF_WQ_WORKER)
+               return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN;
+       return GFP_KERNEL;
+}
+
 unsigned long
 rpc_task_timeout(const struct rpc_task *task)
 {
@@ -1030,15 +1037,15 @@ int rpc_malloc(struct rpc_task *task)
        struct rpc_rqst *rqst = task->tk_rqstp;
        size_t size = rqst->rq_callsize + rqst->rq_rcvsize;
        struct rpc_buffer *buf;
-       gfp_t gfp = GFP_KERNEL;
-
-       if (RPC_IS_ASYNC(task))
-               gfp = GFP_NOWAIT | __GFP_NOWARN;
+       gfp_t gfp = rpc_task_gfp_mask();
 
        size += sizeof(struct rpc_buffer);
-       if (size <= RPC_BUFFER_MAXSIZE)
-               buf = mempool_alloc(rpc_buffer_mempool, gfp);
-       else
+       if (size <= RPC_BUFFER_MAXSIZE) {
+               buf = kmem_cache_alloc(rpc_buffer_slabp, gfp);
+               /* Reach for the mempool if dynamic allocation fails */
+               if (!buf && RPC_IS_ASYNC(task))
+                       buf = mempool_alloc(rpc_buffer_mempool, GFP_NOWAIT);
+       } else
                buf = kmalloc(size, gfp);
 
        if (!buf)