Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

NFS: Fix memory allocation in rpc_malloc()

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>

+15 -7
+1
include/linux/sunrpc/sched.h
··· 262 262 extern struct workqueue_struct *rpciod_workqueue; 263 263 extern struct workqueue_struct *xprtiod_workqueue; 264 264 void rpc_prepare_task(struct rpc_task *task); 265 + gfp_t rpc_task_gfp_mask(void); 265 266 266 267 static inline int rpc_wait_for_completion_task(struct rpc_task *task) 267 268 {
+14 -7
net/sunrpc/sched.c
··· 57 57 struct workqueue_struct *xprtiod_workqueue __read_mostly; 58 58 EXPORT_SYMBOL_GPL(xprtiod_workqueue); 59 59 60 + gfp_t rpc_task_gfp_mask(void) 61 + { 62 + if (current->flags & PF_WQ_WORKER) 63 + return GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN; 64 + return GFP_KERNEL; 65 + } 66 + 60 67 unsigned long 61 68 rpc_task_timeout(const struct rpc_task *task) 62 69 { ··· 1037 1030 struct rpc_rqst *rqst = task->tk_rqstp; 1038 1031 size_t size = rqst->rq_callsize + rqst->rq_rcvsize; 1039 1032 struct rpc_buffer *buf; 1040 - gfp_t gfp = GFP_KERNEL; 1041 - 1042 - if (RPC_IS_ASYNC(task)) 1043 - gfp = GFP_NOWAIT | __GFP_NOWARN; 1033 + gfp_t gfp = rpc_task_gfp_mask(); 1044 1034 1045 1035 size += sizeof(struct rpc_buffer); 1046 - if (size <= RPC_BUFFER_MAXSIZE) 1047 - buf = mempool_alloc(rpc_buffer_mempool, gfp); 1048 - else 1036 + if (size <= RPC_BUFFER_MAXSIZE) { 1037 + buf = kmem_cache_alloc(rpc_buffer_slabp, gfp); 1038 + /* Reach for the mempool if dynamic allocation fails */ 1039 + if (!buf && RPC_IS_ASYNC(task)) 1040 + buf = mempool_alloc(rpc_buffer_mempool, GFP_NOWAIT); 1041 + } else 1049 1042 buf = kmalloc(size, gfp); 1050 1043 1051 1044 if (!buf)