Skip to content

Commit a62f8e3

Browse files
author
Trond Myklebust
committed
NFS: Clean up nfs_lock_and_join_requests()
Clean up nfs_lock_and_join_requests() to simplify the calculation of the range covered by the page group, taking into account the presence of mirrors. Signed-off-by: Trond Myklebust <[email protected]>
1 parent 377840e commit a62f8e3

File tree

3 files changed

+95
-71
lines changed

3 files changed

+95
-71
lines changed

fs/nfs/pagelist.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,80 @@ nfs_async_iocounter_wait(struct rpc_task *task, struct nfs_lock_context *l_ctx)
130130
}
131131
EXPORT_SYMBOL_GPL(nfs_async_iocounter_wait);
132132

133+
/*
134+
* nfs_unroll_locks - unlock all newly locked reqs and wait on @req
135+
* @head: head request of page group, must be holding head lock
136+
* @req: request that couldn't lock and needs to wait on the req bit lock
137+
*
138+
* This is a helper function for nfs_lock_and_join_requests
139+
* returns 0 on success, < 0 on error.
140+
*/
141+
static void
142+
nfs_unroll_locks(struct nfs_page *head, struct nfs_page *req)
143+
{
144+
struct nfs_page *tmp;
145+
146+
/* relinquish all the locks successfully grabbed this run */
147+
for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
148+
if (!kref_read(&tmp->wb_kref))
149+
continue;
150+
nfs_unlock_and_release_request(tmp);
151+
}
152+
}
153+
154+
/*
155+
* nfs_page_group_lock_subreq - try to lock a subrequest
156+
* @head: head request of page group
157+
* @subreq: request to lock
158+
*
159+
* This is a helper function for nfs_lock_and_join_requests which
160+
* must be called with the head request and page group both locked.
161+
* On error, it returns with the page group unlocked.
162+
*/
163+
static int
164+
nfs_page_group_lock_subreq(struct nfs_page *head, struct nfs_page *subreq)
165+
{
166+
int ret;
167+
168+
if (!kref_get_unless_zero(&subreq->wb_kref))
169+
return 0;
170+
while (!nfs_lock_request(subreq)) {
171+
nfs_page_group_unlock(head);
172+
ret = nfs_wait_on_request(subreq);
173+
if (!ret)
174+
ret = nfs_page_group_lock(head);
175+
if (ret < 0) {
176+
nfs_unroll_locks(head, subreq);
177+
nfs_release_request(subreq);
178+
return ret;
179+
}
180+
}
181+
return 0;
182+
}
183+
184+
/*
185+
* nfs_page_group_lock_subrequests - try to lock the subrequests
186+
* @head: head request of page group
187+
*
188+
* This is a helper function for nfs_lock_and_join_requests which
189+
* must be called with the head request and page group both locked.
190+
* On error, it returns with the page group unlocked.
191+
*/
192+
int nfs_page_group_lock_subrequests(struct nfs_page *head)
193+
{
194+
struct nfs_page *subreq;
195+
int ret;
196+
197+
/* lock each request in the page group */
198+
for (subreq = head->wb_this_page; subreq != head;
199+
subreq = subreq->wb_this_page) {
200+
ret = nfs_page_group_lock_subreq(head, subreq);
201+
if (ret < 0)
202+
return ret;
203+
}
204+
return 0;
205+
}
206+
133207
/*
134208
* nfs_page_set_headlock - set the request PG_HEADLOCK
135209
* @req: request that is to be locked

fs/nfs/write.c

Lines changed: 20 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -379,34 +379,6 @@ static void nfs_end_page_writeback(struct nfs_page *req)
379379
clear_bdi_congested(inode_to_bdi(inode), BLK_RW_ASYNC);
380380
}
381381

382-
/*
383-
* nfs_unroll_locks_and_wait - unlock all newly locked reqs and wait on @req
384-
*
385-
* this is a helper function for nfs_lock_and_join_requests
386-
*
387-
* @inode - inode associated with request page group, must be holding inode lock
388-
* @head - head request of page group, must be holding head lock
389-
* @req - request that couldn't lock and needs to wait on the req bit lock
390-
*
391-
* NOTE: this must be called holding page_group bit lock
392-
* which will be released before returning.
393-
*
394-
* returns 0 on success, < 0 on error.
395-
*/
396-
static void
397-
nfs_unroll_locks(struct inode *inode, struct nfs_page *head,
398-
struct nfs_page *req)
399-
{
400-
struct nfs_page *tmp;
401-
402-
/* relinquish all the locks successfully grabbed this run */
403-
for (tmp = head->wb_this_page ; tmp != req; tmp = tmp->wb_this_page) {
404-
if (!kref_read(&tmp->wb_kref))
405-
continue;
406-
nfs_unlock_and_release_request(tmp);
407-
}
408-
}
409-
410382
/*
411383
* nfs_destroy_unlinked_subrequests - destroy recently unlinked subrequests
412384
*
@@ -487,7 +459,7 @@ nfs_lock_and_join_requests(struct page *page)
487459
struct inode *inode = page_file_mapping(page)->host;
488460
struct nfs_page *head, *subreq;
489461
struct nfs_page *destroy_list = NULL;
490-
unsigned int total_bytes;
462+
unsigned int pgbase, off, bytes;
491463
int ret;
492464

493465
try_again:
@@ -520,49 +492,30 @@ nfs_lock_and_join_requests(struct page *page)
520492
goto release_request;
521493

522494
/* lock each request in the page group */
523-
total_bytes = head->wb_bytes;
495+
ret = nfs_page_group_lock_subrequests(head);
496+
if (ret < 0)
497+
goto release_request;
498+
499+
pgbase = head->wb_pgbase;
500+
bytes = head->wb_bytes;
501+
off = head->wb_offset;
524502
for (subreq = head->wb_this_page; subreq != head;
525503
subreq = subreq->wb_this_page) {
526-
527-
if (!kref_get_unless_zero(&subreq->wb_kref)) {
528-
if (subreq->wb_offset == head->wb_offset + total_bytes)
529-
total_bytes += subreq->wb_bytes;
530-
continue;
531-
}
532-
533-
while (!nfs_lock_request(subreq)) {
534-
/*
535-
* Unlock page to allow nfs_page_group_sync_on_bit()
536-
* to succeed
537-
*/
538-
nfs_page_group_unlock(head);
539-
ret = nfs_wait_on_request(subreq);
540-
if (!ret)
541-
ret = nfs_page_group_lock(head);
542-
if (ret < 0) {
543-
nfs_unroll_locks(inode, head, subreq);
544-
nfs_release_request(subreq);
545-
goto release_request;
546-
}
547-
}
548-
/*
549-
* Subrequests are always contiguous, non overlapping
550-
* and in order - but may be repeated (mirrored writes).
551-
*/
552-
if (subreq->wb_offset == (head->wb_offset + total_bytes)) {
553-
/* keep track of how many bytes this group covers */
554-
total_bytes += subreq->wb_bytes;
555-
} else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset ||
556-
((subreq->wb_offset + subreq->wb_bytes) >
557-
(head->wb_offset + total_bytes)))) {
558-
nfs_page_group_unlock(head);
559-
nfs_unroll_locks(inode, head, subreq);
560-
nfs_unlock_and_release_request(subreq);
561-
ret = -EIO;
562-
goto release_request;
504+
/* Subrequests should always form a contiguous range */
505+
if (pgbase > subreq->wb_pgbase) {
506+
off -= pgbase - subreq->wb_pgbase;
507+
bytes += pgbase - subreq->wb_pgbase;
508+
pgbase = subreq->wb_pgbase;
563509
}
510+
bytes = max(subreq->wb_pgbase + subreq->wb_bytes
511+
- pgbase, bytes);
564512
}
565513

514+
/* Set the head request's range to cover the former page group */
515+
head->wb_pgbase = pgbase;
516+
head->wb_bytes = bytes;
517+
head->wb_offset = off;
518+
566519
/* Now that all requests are locked, make sure they aren't on any list.
567520
* Commit list removal accounting is done after locks are dropped */
568521
subreq = head;
@@ -576,10 +529,6 @@ nfs_lock_and_join_requests(struct page *page)
576529
/* destroy list will be terminated by head */
577530
destroy_list = head->wb_this_page;
578531
head->wb_this_page = head;
579-
580-
/* change head request to cover whole range that
581-
* the former page group covered */
582-
head->wb_bytes = total_bytes;
583532
}
584533

585534
/* Postpone destruction of this request */

include/linux/nfs_page.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
139139
extern int nfs_wait_on_request(struct nfs_page *);
140140
extern void nfs_unlock_request(struct nfs_page *req);
141141
extern void nfs_unlock_and_release_request(struct nfs_page *);
142+
extern int nfs_page_group_lock_subrequests(struct nfs_page *head);
142143
extern int nfs_page_group_lock(struct nfs_page *);
143144
extern void nfs_page_group_unlock(struct nfs_page *);
144145
extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int);

0 commit comments

Comments
 (0)