Skip to content

Commit 381e0b9

Browse files
committed
nfs: fold nfs_page_group_lock_subrequests into nfs_lock_and_join_requests
jira VULN-136535 cve-pre CVE-2025-39697 commit-author Christoph Hellwig <[email protected]> commit 25edbca upstream-diff Used linux-5.15.y backport fd947b71cc1b86c4731f8d470f5ab5df94e838d8 as baseline, then accounted in 'nfs_lock_and_join_requests()' for the missing b193a78 backport. 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 <[email protected]> Reviewed-by: Sagi Grimberg <[email protected]> Signed-off-by: Anna Schumaker <[email protected]> Signed-off-by: Trond Myklebust <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit fd947b71cc1b86c4731f8d470f5ab5df94e838d8) Signed-off-by: Marcin Wcisło <[email protected]>
1 parent ce23ac8 commit 381e0b9

File tree

3 files changed

+68
-84
lines changed

3 files changed

+68
-84
lines changed

fs/nfs/pagelist.c

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -167,83 +167,6 @@ nfs_page_group_lock_head(struct nfs_page *req)
167167
return head;
168168
}
169169

170-
/*
171-
* nfs_unroll_locks - unlock all newly locked reqs and wait on @req
172-
* @head: head request of page group, must be holding head lock
173-
* @req: request that couldn't lock and needs to wait on the req bit lock
174-
*
175-
* This is a helper function for nfs_lock_and_join_requests
176-
* returns 0 on success, < 0 on error.
177-
*/
178-
static void
179-
nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
180-
{
181-
struct nfs_page *tmp;
182-
183-
/* relinquish all the locks successfully grabbed this run */
184-
for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
185-
if (!kref_read(&tmp->wb_kref))
186-
continue;
187-
nfs_unlock_and_release_request(tmp);
188-
}
189-
}
190-
191-
/*
192-
* nfs_page_group_lock_subreq - try to lock a subrequest
193-
* @head: head request of page group
194-
* @subreq: request to lock
195-
*
196-
* This is a helper function for nfs_lock_and_join_requests which
197-
* must be called with the head request and page group both locked.
198-
* On error, it returns with the page group unlocked.
199-
*/
200-
static int
201-
nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
202-
{
203-
int ret;
204-
205-
if (!kref_get_unless_zero(&subreq->wb_kref))
206-
return 0;
207-
while (!nfs_lock_request(subreq)) {
208-
nfs_page_group_unlock(head);
209-
ret = nfs_wait_on_request(subreq);
210-
if (!ret)
211-
ret = nfs_page_group_lock(head);
212-
if (ret < 0) {
213-
nfs_unroll_locks(head, subreq);
214-
nfs_release_request(subreq);
215-
return ret;
216-
}
217-
}
218-
return 0;
219-
}
220-
221-
/*
222-
* nfs_page_group_lock_subrequests - try to lock the subrequests
223-
* @head: head request of page group
224-
*
225-
* This is a helper function for nfs_lock_and_join_requests which
226-
* must be called with the head request locked.
227-
*/
228-
int nfs_page_group_lock_subrequests(struct nfs_page *head)
229-
{
230-
struct nfs_page *subreq;
231-
int ret;
232-
233-
ret = nfs_page_group_lock(head);
234-
if (ret < 0)
235-
return ret;
236-
/* lock each request in the page group */
237-
for (subreq = head->wb_this_page; subreq != head;
238-
subreq = subreq->wb_this_page) {
239-
ret = nfs_page_group_lock_subreq(head, subreq);
240-
if (ret < 0)
241-
return ret;
242-
}
243-
nfs_page_group_unlock(head);
244-
return 0;
245-
}
246-
247170
/*
248171
* nfs_page_set_headlock - set the request PG_HEADLOCK
249172
* @req: request that is to be locked

fs/nfs/write.c

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,57 @@ nfs_join_page_group(struct nfs_page *head, struct inode *inode)
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
* @page: the page used to lookup the "page group" of nfs_page structures
@@ -566,7 +617,7 @@ static struct nfs_page *
566617
nfs_lock_and_join_requests(struct page *page)
567618
{
568619
struct inode *inode = page_file_mapping(page)->host;
569-
struct nfs_page *head;
620+
struct nfs_page *head, *subreq;
570621
int ret;
571622

572623
/*
@@ -578,16 +629,27 @@ nfs_lock_and_join_requests(struct page *page)
578629
if (IS_ERR_OR_NULL(head))
579630
return head;
580631

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

588-
nfs_join_page_group(head, inode);
645+
nfs_page_group_unlock(head);
589646

647+
nfs_join_page_group(head, inode);
590648
return head;
649+
650+
out_unlock:
651+
nfs_unlock_and_release_request(head);
652+
return ERR_PTR(ret);
591653
}
592654

593655
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
@@ -144,7 +144,6 @@ extern int nfs_wait_on_request(struct nfs_page *);
144144
extern void nfs_unlock_request(struct nfs_page *req);
145145
extern void nfs_unlock_and_release_request(struct nfs_page *);
146146
extern struct nfs_page *nfs_page_group_lock_head(struct nfs_page *req);
147-
extern int nfs_page_group_lock_subrequests(struct nfs_page *head);
148147
extern void nfs_join_page_group(struct nfs_page *head, struct inode *inode);
149148
extern int nfs_page_group_lock(struct nfs_page *);
150149
extern void nfs_page_group_unlock(struct nfs_page *);

0 commit comments

Comments
 (0)