NFSv4: Convert nfs_lock_and_join_requests() to use nfs_page_find_head_request()
authorTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 1 Aug 2017 16:06:30 +0000 (12:06 -0400)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 15 Aug 2017 15:54:47 +0000 (11:54 -0400)
Hide the locking from nfs_lock_and_join_requests() so that we can
separate out the requirements for swapcache pages.

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

index 759e37d26acf94f9afaf2474b164baed850292d0..a06167e20b720f6dfb5aa14e5c40ba7aed4ef642 100644 (file)
@@ -154,6 +154,14 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
        set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
 }
 
+static struct nfs_page *
+nfs_page_private_request(struct page *page)
+{
+       if (!PagePrivate(page))
+               return NULL;
+       return (struct nfs_page *)page_private(page);
+}
+
 /*
  * nfs_page_find_head_request_locked - find head request associated with @page
  *
@@ -164,11 +172,10 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
 static struct nfs_page *
 nfs_page_find_head_request_locked(struct nfs_inode *nfsi, struct page *page)
 {
-       struct nfs_page *req = NULL;
+       struct nfs_page *req;
 
-       if (PagePrivate(page))
-               req = (struct nfs_page *)page_private(page);
-       else if (unlikely(PageSwapCache(page)))
+       req = nfs_page_private_request(page);
+       if (!req && unlikely(PageSwapCache(page)))
                req = nfs_page_search_commits_for_head_request_locked(nfsi,
                        page);
 
@@ -448,31 +455,29 @@ nfs_lock_and_join_requests(struct page *page)
        int ret;
 
 try_again:
-       if (!(PagePrivate(page) || PageSwapCache(page)))
-               return NULL;
-       spin_lock(&inode->i_lock);
        /*
         * A reference is taken only on the head request which acts as a
         * reference to the whole page group - the group will not be destroyed
         * until the head reference is released.
         */
-       head = nfs_page_find_head_request_locked(NFS_I(inode), page);
-
-       if (!head) {
-               spin_unlock(&inode->i_lock);
+       head = nfs_page_find_head_request(page);
+       if (!head)
                return NULL;
-       }
 
        /* lock the page head first in order to avoid an ABBA inefficiency */
        if (!nfs_lock_request(head)) {
-               spin_unlock(&inode->i_lock);
                ret = nfs_wait_on_request(head);
                nfs_release_request(head);
                if (ret < 0)
                        return ERR_PTR(ret);
                goto try_again;
        }
-       spin_unlock(&inode->i_lock);
+
+       /* Ensure that nobody removed the request before we locked it */
+       if (head != nfs_page_private_request(page) && !PageSwapCache(page)) {
+               nfs_unlock_and_release_request(head);
+               goto try_again;
+       }
 
        ret = nfs_page_group_lock(head);
        if (ret < 0) {
@@ -559,7 +564,7 @@ try_again:
                return NULL;
        }
 
-       /* still holds ref on head from nfs_page_find_head_request_locked
+       /* still holds ref on head from nfs_page_find_head_request
         * and still has lock on head from lock loop */
        return head;
 }