Commit 22cc2ba5 authored by Chuck Lever's avatar Chuck Lever
Browse files

SUNRPC: Handle NULL entries in svc_rqst_release_pages



svc_rqst_release_pages() releases response pages between rq_respages
and rq_next_page. It currently passes the entire range to
release_pages(), which does not expect NULL entries.

A subsequent patch preserves the rq_next_page pointer in
svc_rdma_save_io_pages() so that it accurately records how many
response pages were consumed. After that change, the range

  [rq_respages, rq_next_page)

can contain NULL entries where pages have already been transferred
to a send context.

Iterate through the range entry by entry, skipping NULLs, to handle
this case correctly.

Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent ee66b9e3
Loading
Loading
Loading
Loading
+14 −8
Original line number Diff line number Diff line
@@ -990,19 +990,25 @@ EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
 * svc_rqst_release_pages - Release Reply buffer pages
 * @rqstp: RPC transaction context
 *
 * Release response pages that might still be in flight after
 * svc_send, and any spliced filesystem-owned pages.
 * Release response pages in the range [rq_respages, rq_next_page).
 * NULL entries in this range are skipped, allowing transports to
 * transfer pages to a send context before this function runs.
 */
void svc_rqst_release_pages(struct svc_rqst *rqstp)
{
	int i, count = rqstp->rq_next_page - rqstp->rq_respages;
	struct page **pp;

	if (count) {
		release_pages(rqstp->rq_respages, count);
		for (i = 0; i < count; i++)
			rqstp->rq_respages[i] = NULL;
	for (pp = rqstp->rq_respages; pp < rqstp->rq_next_page; pp++) {
		if (*pp) {
			if (!folio_batch_add(&rqstp->rq_fbatch,
					     page_folio(*pp)))
				__folio_batch_release(&rqstp->rq_fbatch);
			*pp = NULL;
		}
	}
	if (rqstp->rq_fbatch.nr)
		__folio_batch_release(&rqstp->rq_fbatch);
}

/**
 * svc_exit_thread - finalise the termination of a sunrpc server thread