Commit ed603bcf authored by Chuck Lever's avatar Chuck Lever
Browse files

sunrpc: Replace the rq_pages array with dynamically-allocated memory



As a step towards making NFSD's maximum rsize and wsize variable at
run-time, replace the fixed-size rq_vec[] array in struct svc_rqst
with a chunk of dynamically-allocated memory.

On a system with 8-byte pointers and 4KB pages, pahole reports that
the rq_pages[] array is 2080 bytes. This patch replaces that with
a single 8-byte pointer field.

Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Reviewed-by: default avatarNeilBrown <neil@brown.name>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 1a587912
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -205,7 +205,8 @@ struct svc_rqst {
	struct xdr_stream	rq_res_stream;
	struct page		*rq_scratch_page;
	struct xdr_buf		rq_res;
	struct page		*rq_pages[RPCSVC_MAXPAGES + 1];
	unsigned long		rq_maxpages;	/* num of entries in rq_pages */
	struct page *		*rq_pages;
	struct page *		*rq_respages;	/* points into rq_pages */
	struct page *		*rq_next_page; /* next reply page to use */
	struct page *		*rq_page_end;  /* one past the last page */
+17 −14
Original line number Diff line number Diff line
@@ -636,20 +636,22 @@ svc_destroy(struct svc_serv **servp)
EXPORT_SYMBOL_GPL(svc_destroy);

static bool
svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
svc_init_buffer(struct svc_rqst *rqstp, const struct svc_serv *serv, int node)
{
	unsigned long pages, ret;
	unsigned long ret;

	pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
				       * We assume one is at most one page
				       */
	WARN_ON_ONCE(pages > RPCSVC_MAXPAGES);
	if (pages > RPCSVC_MAXPAGES)
		pages = RPCSVC_MAXPAGES;
	rqstp->rq_maxpages = svc_serv_maxpages(serv);

	/* rq_pages' last entry is NULL for historical reasons. */
	rqstp->rq_pages = kcalloc_node(rqstp->rq_maxpages + 1,
				       sizeof(struct page *),
				       GFP_KERNEL, node);
	if (!rqstp->rq_pages)
		return false;

	ret = alloc_pages_bulk_node(GFP_KERNEL, node, pages,
	ret = alloc_pages_bulk_node(GFP_KERNEL, node, rqstp->rq_maxpages,
				    rqstp->rq_pages);
	return ret == pages;
	return ret == rqstp->rq_maxpages;
}

/*
@@ -658,11 +660,12 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size, int node)
static void
svc_release_buffer(struct svc_rqst *rqstp)
{
	unsigned int i;
	unsigned long i;

	for (i = 0; i < ARRAY_SIZE(rqstp->rq_pages); i++)
	for (i = 0; i < rqstp->rq_maxpages; i++)
		if (rqstp->rq_pages[i])
			put_page(rqstp->rq_pages[i]);
	kfree(rqstp->rq_pages);
}

static void
@@ -704,7 +707,7 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node)
	if (!rqstp->rq_resp)
		goto out_enomem;

	if (!svc_init_buffer(rqstp, serv->sv_max_mesg, node))
	if (!svc_init_buffer(rqstp, serv, node))
		goto out_enomem;

	rqstp->rq_err = -EAGAIN; /* No error yet */
@@ -896,7 +899,7 @@ EXPORT_SYMBOL_GPL(svc_set_num_threads);
bool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
{
	struct page **begin = rqstp->rq_pages;
	struct page **end = &rqstp->rq_pages[RPCSVC_MAXPAGES];
	struct page **end = &rqstp->rq_pages[rqstp->rq_maxpages];

	if (unlikely(rqstp->rq_next_page < begin || rqstp->rq_next_page > end)) {
		trace_svc_replace_page_err(rqstp);
+1 −9
Original line number Diff line number Diff line
@@ -652,18 +652,10 @@ static void svc_check_conn_limits(struct svc_serv *serv)

static bool svc_alloc_arg(struct svc_rqst *rqstp)
{
	struct svc_serv *serv = rqstp->rq_server;
	struct xdr_buf *arg = &rqstp->rq_arg;
	unsigned long pages, filled, ret;

	pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;
	if (pages > RPCSVC_MAXPAGES) {
		pr_warn_once("svc: warning: pages=%lu > RPCSVC_MAXPAGES=%lu\n",
			     pages, RPCSVC_MAXPAGES);
		/* use as many pages as possible */
		pages = RPCSVC_MAXPAGES;
	}

	pages = rqstp->rq_maxpages;
	for (filled = 0; filled < pages; filled = ret) {
		ret = alloc_pages_bulk(GFP_KERNEL, pages, rqstp->rq_pages);
		if (ret > filled)
+1 −1
Original line number Diff line number Diff line
@@ -765,7 +765,7 @@ static int svc_rdma_build_read_segment(struct svc_rqst *rqstp,
		}
		len -= seg_len;

		if (len && ((head->rc_curpage + 1) > ARRAY_SIZE(rqstp->rq_pages)))
		if (len && ((head->rc_curpage + 1) > rqstp->rq_maxpages))
			goto out_overrun;
	}