Commit 33e5c765 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

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: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent d0afde5f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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)
{
+14 −7
Original line number Diff line number Diff line
@@ -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)