NFS: Teach nfs_try_to_update_request() to deal with request page_groups
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 17 Jul 2017 23:50:23 +0000 (19:50 -0400)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 15 Aug 2017 15:54:47 +0000 (11:54 -0400)
Simplify the code, and avoid some flushes to disk.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/write.c

index ee981353d4aa110b001a7619f8a324452a001535..0b4d1ef168e019626e5ea0dcd6d6c6ec6da96887 100644 (file)
@@ -1107,39 +1107,19 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
 
        end = offset + bytes;
 
-       for (;;) {
-               if (!(PagePrivate(page) || PageSwapCache(page)))
-                       return NULL;
-               spin_lock(&inode->i_lock);
-               req = nfs_page_find_head_request_locked(NFS_I(inode), page);
-               if (req == NULL)
-                       goto out_unlock;
-
-               /* should be handled by nfs_flush_incompatible */
-               WARN_ON_ONCE(req->wb_head != req);
-               WARN_ON_ONCE(req->wb_this_page != req);
-
-               rqend = req->wb_offset + req->wb_bytes;
-               /*
-                * Tell the caller to flush out the request if
-                * the offsets are non-contiguous.
-                * Note: nfs_flush_incompatible() will already
-                * have flushed out requests having wrong owners.
-                */
-               if (offset > rqend
-                   || end < req->wb_offset)
-                       goto out_flushme;
-
-               if (nfs_lock_request(req))
-                       break;
+       req = nfs_lock_and_join_requests(page);
+       if (IS_ERR_OR_NULL(req))
+               return req;
 
-               /* The request is locked, so wait and then retry */
-               spin_unlock(&inode->i_lock);
-               error = nfs_wait_on_request(req);
-               nfs_release_request(req);
-               if (error != 0)
-                       goto out_err;
-       }
+       rqend = req->wb_offset + req->wb_bytes;
+       /*
+        * Tell the caller to flush out the request if
+        * the offsets are non-contiguous.
+        * Note: nfs_flush_incompatible() will already
+        * have flushed out requests having wrong owners.
+        */
+       if (offset > rqend || end < req->wb_offset)
+               goto out_flushme;
 
        /* Okay, the request matches. Update the region */
        if (offset < req->wb_offset) {
@@ -1150,17 +1130,17 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
                req->wb_bytes = end - req->wb_offset;
        else
                req->wb_bytes = rqend - req->wb_offset;
-out_unlock:
-       if (req)
-               nfs_clear_request_commit(req);
-       spin_unlock(&inode->i_lock);
        return req;
 out_flushme:
-       spin_unlock(&inode->i_lock);
-       nfs_release_request(req);
+       /*
+        * Note: we mark the request dirty here because
+        * nfs_lock_and_join_requests() cannot preserve
+        * commit flags, so we have to replay the write.
+        */
+       nfs_mark_request_dirty(req);
+       nfs_unlock_and_release_request(req);
        error = nfs_wb_page(inode, page);
-out_err:
-       return ERR_PTR(error);
+       return (error < 0) ? ERR_PTR(error) : NULL;
 }
 
 /*