Skip to content

Commit d099aac

Browse files
committed
nfs: fold nfs_page_group_lock_subrequests into nfs_lock_and_join_requests
jira VULN-136536 cve-pre CVE-2025-39697 commit-author Christoph Hellwig <hch@lst.de> commit 25edbca upstream-diff Used linux-6.6.y backport 9a1963404cc2eef69d2f8a42861bdf63d087dd5d for the clean cherry pick Fold nfs_page_group_lock_subrequests into nfs_lock_and_join_requests to prepare for future changes to this code, and move the helpers to write.c as well. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com> (cherry picked from commit 9a1963404cc2eef69d2f8a42861bdf63d087dd5d) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent a5cda26 commit d099aac

3 files changed

Lines changed: 69 additions & 84 deletions

File tree

fs/nfs/pagelist.c

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -205,83 +205,6 @@ nfs_page_group_lock_head(struct nfs_page *req)
205205
return head;
206206
}
207207

208-
/*
209-
* nfs_unroll_locks - unlock all newly locked reqs and wait on @req
210-
* @head: head request of page group, must be holding head lock
211-
* @req: request that couldn't lock and needs to wait on the req bit lock
212-
*
213-
* This is a helper function for nfs_lock_and_join_requests
214-
* returns 0 on success, < 0 on error.
215-
*/
216-
static void
217-
nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
218-
{
219-
struct nfs_page *tmp;
220-
221-
/* relinquish all the locks successfully grabbed this run */
222-
for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
223-
if (!kref_read(&tmp->wb_kref))
224-
continue;
225-
nfs_unlock_and_release_request(tmp);
226-
}
227-
}
228-
229-
/*
230-
* nfs_page_group_lock_subreq - try to lock a subrequest
231-
* @head: head request of page group
232-
* @subreq: request to lock
233-
*
234-
* This is a helper function for nfs_lock_and_join_requests which
235-
* must be called with the head request and page group both locked.
236-
* On error, it returns with the page group unlocked.
237-
*/
238-
static int
239-
nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
240-
{
241-
int ret;
242-
243-
if (!kref_get_unless_zero(&subreq->wb_kref))
244-
return 0;
245-
while (!nfs_lock_request(subreq)) {
246-
nfs_page_group_unlock(head);
247-
ret = nfs_wait_on_request(subreq);
248-
if (!ret)
249-
ret = nfs_page_group_lock(head);
250-
if (ret < 0) {
251-
nfs_unroll_locks(head, subreq);
252-
nfs_release_request(subreq);
253-
return ret;
254-
}
255-
}
256-
return 0;
257-
}
258-
259-
/*
260-
* nfs_page_group_lock_subrequests - try to lock the subrequests
261-
* @head: head request of page group
262-
*
263-
* This is a helper function for nfs_lock_and_join_requests which
264-
* must be called with the head request locked.
265-
*/
266-
int nfs_page_group_lock_subrequests(struct nfs_page *head)
267-
{
268-
struct nfs_page *subreq;
269-
int ret;
270-
271-
ret = nfs_page_group_lock(head);
272-
if (ret < 0)
273-
return ret;
274-
/* lock each request in the page group */
275-
for (subreq = head->wb_this_page; subreq != head;
276-
subreq = subreq->wb_this_page) {
277-
ret = nfs_page_group_lock_subreq(head, subreq);
278-
if (ret < 0)
279-
return ret;
280-
}
281-
nfs_page_group_unlock(head);
282-
return 0;
283-
}
284-
285208
/*
286209
* nfs_page_set_headlock - set the request PG_HEADLOCK
287210
* @req: request that is to be locked

fs/nfs/write.c

Lines changed: 69 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,57 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
547547
nfs_destroy_unlinked_subrequests(destroy_list, head, inode);
548548
}
549549

550+
/*
551+
* nfs_unroll_locks - unlock all newly locked reqs and wait on @req
552+
* @head: head request of page group, must be holding head lock
553+
* @req: request that couldn't lock and needs to wait on the req bit lock
554+
*
555+
* This is a helper function for nfs_lock_and_join_requests
556+
* returns 0 on success, < 0 on error.
557+
*/
558+
static void
559+
nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
560+
{
561+
struct nfs_page *tmp;
562+
563+
/* relinquish all the locks successfully grabbed this run */
564+
for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
565+
if (!kref_read(&tmp->wb_kref))
566+
continue;
567+
nfs_unlock_and_release_request(tmp);
568+
}
569+
}
570+
571+
/*
572+
* nfs_page_group_lock_subreq - try to lock a subrequest
573+
* @head: head request of page group
574+
* @subreq: request to lock
575+
*
576+
* This is a helper function for nfs_lock_and_join_requests which
577+
* must be called with the head request and page group both locked.
578+
* On error, it returns with the page group unlocked.
579+
*/
580+
static int
581+
nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
582+
{
583+
int ret;
584+
585+
if (!kref_get_unless_zero(&subreq->wb_kref))
586+
return 0;
587+
while (!nfs_lock_request(subreq)) {
588+
nfs_page_group_unlock(head);
589+
ret = nfs_wait_on_request(subreq);
590+
if (!ret)
591+
ret = nfs_page_group_lock(head);
592+
if (ret < 0) {
593+
nfs_unroll_locks(head, subreq);
594+
nfs_release_request(subreq);
595+
return ret;
596+
}
597+
}
598+
return 0;
599+
}
600+
550601
/*
551602
* nfs_lock_and_join_requests - join all subreqs to the head req
552603
* @folio: the folio used to lookup the "page group" of nfs_page structures
@@ -565,7 +616,7 @@ void nfs_join_page_group(struct nfs_page *head, struct nfs_commit_info *cinfo,
565616
static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
566617
{
567618
struct inode *inode = folio_file_mapping(folio)->host;
568-
struct nfs_page *head;
619+
struct nfs_page *head, *subreq;
569620
struct nfs_commit_info cinfo;
570621
int ret;
571622

@@ -579,16 +630,28 @@ static struct nfs_page *nfs_lock_and_join_requests(struct folio *folio)
579630
if (IS_ERR_OR_NULL(head))
580631
return head;
581632

633+
ret = nfs_page_group_lock(head);
634+
if (ret < 0)
635+
goto out_unlock;
636+
582637
/* lock each request in the page group */
583-
ret = nfs_page_group_lock_subrequests(head);
584-
if (ret < 0) {
585-
nfs_unlock_and_release_request(head);
586-
return ERR_PTR(ret);
638+
for (subreq = head->wb_this_page;
639+
subreq != head;
640+
subreq = subreq->wb_this_page) {
641+
ret = nfs_page_group_lock_subreq(head, subreq);
642+
if (ret < 0)
643+
goto out_unlock;
587644
}
588645

589-
nfs_join_page_group(head, &cinfo, inode);
646+
nfs_page_group_unlock(head);
590647

648+
nfs_init_cinfo_from_inode(&cinfo, inode);
649+
nfs_join_page_group(head, &cinfo, inode);
591650
return head;
651+
652+
out_unlock:
653+
nfs_unlock_and_release_request(head);
654+
return ERR_PTR(ret);
592655
}
593656

594657
static void nfs_write_error(struct nfs_page *req, int error)

include/linux/nfs_page.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,6 @@ extern int nfs_wait_on_request(struct nfs_page *);
156156
extern void nfs_unlock_request(struct nfs_page *req);
157157
extern void nfs_unlock_and_release_request(struct nfs_page *);
158158
extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req);
159-
extern int nfs_page_group_lock_subrequests(struct nfs_page *head);
160159
extern void nfs_join_page_group(struct nfs_page *head,
161160
struct nfs_commit_info *cinfo,
162161
struct inode *inode);

0 commit comments

Comments
 (0)