NFS: Don't check request offset and size without holding a lock
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 17 Jul 2017 15:11:49 +0000 (11:11 -0400)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 15 Aug 2017 15:54:46 +0000 (11:54 -0400)
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>
fs/nfs/write.c

index c940e615f5dc74fa60cde6486b4177d6658fa97f..84b6818e5278522f2643ce2aee4a18ccb6900a5f 100644 (file)
@@ -523,6 +523,17 @@ try_again:
        total_bytes = head->wb_bytes;
        for (subreq = head->wb_this_page; subreq != head;
                        subreq = subreq->wb_this_page) {
+               if (!nfs_lock_request(subreq)) {
+                       /* releases page group bit lock and
+                        * inode spin lock and all references */
+                       ret = nfs_unroll_locks_and_wait(inode, head,
+                               subreq);
+
+                       if (ret == 0)
+                               goto try_again;
+
+                       return ERR_PTR(ret);
+               }
                /*
                 * Subrequests are always contiguous, non overlapping
                 * and in order - but may be repeated (mirrored writes).
@@ -533,21 +544,10 @@ try_again:
                } 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);
                }
-
-               if (!nfs_lock_request(subreq)) {
-                       /* releases page group bit lock and
-                        * inode spin lock and all references */
-                       ret = nfs_unroll_locks_and_wait(inode, head,
-                               subreq);
-
-                       if (ret == 0)
-                               goto try_again;
-
-                       return ERR_PTR(ret);
-               }
        }
 
        /* Now that all requests are locked, make sure they aren't on any list.