NFS: Don't check request offset and size without holding a lock

Request offsets and sizes are not guaranteed to be stable unless you
are holding the request locked.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
This commit is contained in:
Trond Myklebust 2017-07-17 11:11:49 -04:00
parent a0e265bc78
commit e14bebf6de
1 changed files with 14 additions and 14 deletions

View File

@ -523,20 +523,6 @@ nfs_lock_and_join_requests(struct page *page)
total_bytes = head->wb_bytes;
for (subreq = head->wb_this_page; subreq != head;
subreq = subreq->wb_this_page) {
/*
* Subrequests are always contiguous, non overlapping
* and in order - but may be repeated (mirrored writes).
*/
if (subreq->wb_offset == (head->wb_offset + total_bytes)) {
/* keep track of how many bytes this group covers */
total_bytes += subreq->wb_bytes;
} else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset ||
((subreq->wb_offset + subreq->wb_bytes) >
(head->wb_offset + total_bytes)))) {
nfs_unroll_locks_and_wait(inode, head, subreq);
return ERR_PTR(-EIO);
}
if (!nfs_lock_request(subreq)) {
/* releases page group bit lock and
* inode spin lock and all references */
@ -548,6 +534,20 @@ nfs_lock_and_join_requests(struct page *page)
return ERR_PTR(ret);
}
/*
* Subrequests are always contiguous, non overlapping
* and in order - but may be repeated (mirrored writes).
*/
if (subreq->wb_offset == (head->wb_offset + total_bytes)) {
/* keep track of how many bytes this group covers */
total_bytes += subreq->wb_bytes;
} else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset ||
((subreq->wb_offset + subreq->wb_bytes) >
(head->wb_offset + total_bytes)))) {
nfs_unlock_request(subreq);
nfs_unroll_locks_and_wait(inode, head, subreq);
return ERR_PTR(-EIO);
}
}
/* Now that all requests are locked, make sure they aren't on any list.