mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 09:04:39 +02:00
SUNRPC: Track consumed rq_pages entries
The rq_pages array holds pages allocated for incoming RPC requests. Two transport receive paths NULL entries in rq_pages to prevent svc_rqst_release_pages() from freeing pages that the transport has taken ownership of: - svc_tcp_save_pages() moves partial request data pages to svsk->sk_pages during multi-fragment TCP reassembly. - svc_rdma_clear_rqst_pages() moves request data pages to head->rc_pages because they are targets of active RDMA Read WRs. A new rq_pages_nfree field in struct svc_rqst records how many entries were NULLed. svc_alloc_arg() uses it to refill only those entries rather than scanning the full rq_pages array. In steady state, the transport NULLs a handful of entries per RPC, so the allocator visits only those entries instead of the full ~259 slots (for 1MB messages). Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
26c8e6eb75
commit
7ed7504287
|
|
@ -143,6 +143,15 @@ extern u32 svc_max_payload(const struct svc_rqst *rqstp);
|
|||
* server thread needs to allocate more to replace those used in
|
||||
* sending.
|
||||
*
|
||||
* rq_pages request page contract:
|
||||
*
|
||||
* Transport receive paths that move request data pages out of
|
||||
* rq_pages -- TCP multi-fragment reassembly (svc_tcp_save_pages)
|
||||
* and RDMA Read I/O (svc_rdma_clear_rqst_pages) -- NULL those
|
||||
* entries to prevent svc_rqst_release_pages() from freeing pages
|
||||
* still in transport use, and set rq_pages_nfree to the count.
|
||||
* svc_alloc_arg() refills only that many rq_pages entries.
|
||||
*
|
||||
* xdr_buf holds responses; the structure fits NFS read responses
|
||||
* (header, data pages, optional tail) and enables sharing of
|
||||
* client-side routines.
|
||||
|
|
@ -204,6 +213,7 @@ struct svc_rqst {
|
|||
struct folio *rq_scratch_folio;
|
||||
struct xdr_buf rq_res;
|
||||
unsigned long rq_maxpages; /* entries per page array */
|
||||
unsigned long rq_pages_nfree; /* rq_pages entries NULLed by transport */
|
||||
struct page * *rq_pages; /* Call buffer pages */
|
||||
struct page * *rq_respages; /* Reply buffer pages */
|
||||
struct page * *rq_next_page; /* next reply page to use */
|
||||
|
|
|
|||
|
|
@ -655,6 +655,7 @@ svc_init_buffer(struct svc_rqst *rqstp, const struct svc_serv *serv, int node)
|
|||
return false;
|
||||
}
|
||||
|
||||
rqstp->rq_pages_nfree = rqstp->rq_maxpages;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -675,12 +675,17 @@ static bool svc_fill_pages(struct svc_rqst *rqstp, struct page **pages,
|
|||
static bool svc_alloc_arg(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct xdr_buf *arg = &rqstp->rq_arg;
|
||||
unsigned long pages;
|
||||
unsigned long pages, nfree;
|
||||
|
||||
pages = rqstp->rq_maxpages;
|
||||
|
||||
if (!svc_fill_pages(rqstp, rqstp->rq_pages, pages))
|
||||
return false;
|
||||
nfree = rqstp->rq_pages_nfree;
|
||||
if (nfree) {
|
||||
if (!svc_fill_pages(rqstp, rqstp->rq_pages, nfree))
|
||||
return false;
|
||||
rqstp->rq_pages_nfree = 0;
|
||||
}
|
||||
|
||||
if (!svc_fill_pages(rqstp, rqstp->rq_respages, pages))
|
||||
return false;
|
||||
rqstp->rq_next_page = rqstp->rq_respages;
|
||||
|
|
|
|||
|
|
@ -1009,6 +1009,7 @@ static void svc_tcp_save_pages(struct svc_sock *svsk, struct svc_rqst *rqstp)
|
|||
svsk->sk_pages[i] = rqstp->rq_pages[i];
|
||||
rqstp->rq_pages[i] = NULL;
|
||||
}
|
||||
rqstp->rq_pages_nfree = npages;
|
||||
}
|
||||
|
||||
static void svc_tcp_clear_pages(struct svc_sock *svsk)
|
||||
|
|
|
|||
|
|
@ -1107,6 +1107,7 @@ static void svc_rdma_clear_rqst_pages(struct svc_rqst *rqstp,
|
|||
head->rc_pages[i] = rqstp->rq_pages[i];
|
||||
rqstp->rq_pages[i] = NULL;
|
||||
}
|
||||
rqstp->rq_pages_nfree = head->rc_page_count;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user