Skip to content

Commit

Permalink
NFS: Fix memory allocation in rpc_malloc()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Trond Myklebust committed Mar 22, 2022
1 parent d0afde5 commit 33e5c76
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 7 deletions.
1 change: 1 addition & 0 deletions include/linux/sunrpc/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
21 changes: 14 additions & 7 deletions net/sunrpc/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 33e5c76

Please sign in to comment.