NFSv4: Use a mutex to protect the per-inode commit lists
authorTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 1 Aug 2017 15:53:49 +0000 (11:53 -0400)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Tue, 15 Aug 2017 15:54:47 +0000 (11:54 -0400)
The commit lists can get very large, so using the inode->i_lock can
end up affecting general metadata performance.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/direct.c
fs/nfs/inode.c
fs/nfs/pnfs_nfs.c
fs/nfs/write.c
include/linux/nfs_fs.h

index 6fb9fad2d1e6cf6909cfe6dfb2e482bff969e7df..d2972d5374695050cdc3598f6488510af87b3379 100644 (file)
@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
                                  struct list_head *list,
                                  struct nfs_commit_info *cinfo)
 {
-       spin_lock(&cinfo->inode->i_lock);
+       mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
 #ifdef CONFIG_NFS_V4_1
        if (cinfo->ds != NULL && cinfo->ds->nwritten != 0)
                NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo);
 #endif
        nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0);
-       spin_unlock(&cinfo->inode->i_lock);
+       mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
 }
 
 static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
index 109279d6d91bd61421ef572bbcaa1dfe9fa0e9c8..34d9ebbc0dfdf3eb588c6a680477624062081394 100644 (file)
@@ -2016,6 +2016,7 @@ static void init_once(void *foo)
        nfsi->commit_info.ncommit = 0;
        atomic_set(&nfsi->commit_info.rpcs_out, 0);
        init_rwsem(&nfsi->rmdir_sem);
+       mutex_init(&nfsi->commit_mutex);
        nfs4_init_once(nfsi);
 }
 
index 25f28fa64c575129130d916d566674da792376ae..2cdee8ce209492903115df0e513a01665e6bb6b9 100644 (file)
@@ -98,14 +98,13 @@ pnfs_generic_transfer_commit_list(struct list_head *src, struct list_head *dst,
                if (!nfs_lock_request(req))
                        continue;
                kref_get(&req->wb_kref);
-               if (cond_resched_lock(&cinfo->inode->i_lock))
-                       list_safe_reset_next(req, tmp, wb_list);
                nfs_request_remove_commit_list(req, cinfo);
                clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
                nfs_list_add_request(req, dst);
                ret++;
                if ((ret == max) && !cinfo->dreq)
                        break;
+               cond_resched();
        }
        return ret;
 }
@@ -119,7 +118,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
        struct list_head *dst = &bucket->committing;
        int ret;
 
-       lockdep_assert_held(&cinfo->inode->i_lock);
+       lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
        ret = pnfs_generic_transfer_commit_list(src, dst, cinfo, max);
        if (ret) {
                cinfo->ds->nwritten -= ret;
@@ -142,7 +141,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo,
 {
        int i, rv = 0, cnt;
 
-       lockdep_assert_held(&cinfo->inode->i_lock);
+       lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
        for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) {
                cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i],
                                                       cinfo, max);
@@ -162,7 +161,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
        int nwritten;
        int i;
 
-       lockdep_assert_held(&cinfo->inode->i_lock);
+       lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
 restart:
        for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
                nwritten = pnfs_generic_transfer_commit_list(&b->written,
@@ -953,12 +952,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
        struct list_head *list;
        struct pnfs_commit_bucket *buckets;
 
-       spin_lock(&cinfo->inode->i_lock);
+       mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
        buckets = cinfo->ds->buckets;
        list = &buckets[ds_commit_idx].written;
        if (list_empty(list)) {
                if (!pnfs_is_valid_lseg(lseg)) {
-                       spin_unlock(&cinfo->inode->i_lock);
+                       mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
                        cinfo->completion_ops->resched_write(cinfo, req);
                        return;
                }
@@ -975,7 +974,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
        cinfo->ds->nwritten++;
 
        nfs_request_add_commit_list_locked(req, list, cinfo);
-       spin_unlock(&cinfo->inode->i_lock);
+       mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
        nfs_mark_page_unstable(req->wb_page, cinfo);
 }
 EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
index 8d8fa6d4cfcc32d12c88844566fd27be1b1f2b0a..5ab5ca24b48a469340c0d965d7817a23e8912410 100644 (file)
@@ -195,7 +195,7 @@ nfs_page_find_swap_request(struct page *page)
        struct nfs_page *req = NULL;
        if (!PageSwapCache(page))
                return NULL;
-       spin_lock(&inode->i_lock);
+       mutex_lock(&nfsi->commit_mutex);
        if (PageSwapCache(page)) {
                req = nfs_page_search_commits_for_head_request_locked(nfsi,
                        page);
@@ -204,7 +204,7 @@ nfs_page_find_swap_request(struct page *page)
                        kref_get(&req->wb_kref);
                }
        }
-       spin_unlock(&inode->i_lock);
+       mutex_unlock(&nfsi->commit_mutex);
        return req;
 }
 
@@ -856,7 +856,8 @@ nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi,
  * number of outstanding requests requiring a commit as well as
  * the MM page stats.
  *
- * The caller must hold cinfo->inode->i_lock, and the nfs_page lock.
+ * The caller must hold NFS_I(cinfo->inode)->commit_mutex, and the
+ * nfs_page lock.
  */
 void
 nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst,
@@ -884,9 +885,9 @@ EXPORT_SYMBOL_GPL(nfs_request_add_commit_list_locked);
 void
 nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo)
 {
-       spin_lock(&cinfo->inode->i_lock);
+       mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
        nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo);
-       spin_unlock(&cinfo->inode->i_lock);
+       mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
        if (req->wb_page)
                nfs_mark_page_unstable(req->wb_page, cinfo);
 }
@@ -964,11 +965,11 @@ nfs_clear_request_commit(struct nfs_page *req)
                struct nfs_commit_info cinfo;
 
                nfs_init_cinfo_from_inode(&cinfo, inode);
-               spin_lock(&inode->i_lock);
+               mutex_lock(&NFS_I(inode)->commit_mutex);
                if (!pnfs_clear_request_commit(req, &cinfo)) {
                        nfs_request_remove_commit_list(req, &cinfo);
                }
-               spin_unlock(&inode->i_lock);
+               mutex_unlock(&NFS_I(inode)->commit_mutex);
                nfs_clear_page_commit(req->wb_page);
        }
 }
@@ -1027,7 +1028,7 @@ nfs_reqs_to_commit(struct nfs_commit_info *cinfo)
        return cinfo->mds->ncommit;
 }
 
-/* cinfo->inode->i_lock held by caller */
+/* NFS_I(cinfo->inode)->commit_mutex held by caller */
 int
 nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
                     struct nfs_commit_info *cinfo, int max)
@@ -1039,13 +1040,12 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
                if (!nfs_lock_request(req))
                        continue;
                kref_get(&req->wb_kref);
-               if (cond_resched_lock(&cinfo->inode->i_lock))
-                       list_safe_reset_next(req, tmp, wb_list);
                nfs_request_remove_commit_list(req, cinfo);
                nfs_list_add_request(req, dst);
                ret++;
                if ((ret == max) && !cinfo->dreq)
                        break;
+               cond_resched();
        }
        return ret;
 }
@@ -1065,7 +1065,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst,
 {
        int ret = 0;
 
-       spin_lock(&cinfo->inode->i_lock);
+       mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
        if (cinfo->mds->ncommit > 0) {
                const int max = INT_MAX;
 
@@ -1073,7 +1073,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst,
                                           cinfo, max);
                ret += pnfs_scan_commit_lists(inode, cinfo, max - ret);
        }
-       spin_unlock(&cinfo->inode->i_lock);
+       mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex);
        return ret;
 }
 
index 5cc91d6381a35ce73d64fbf40743a21ef2876d68..121a702888b49ccaec99838987dfcdd68b81cadb 100644 (file)
@@ -163,6 +163,7 @@ struct nfs_inode {
        /* Readers: in-flight sillydelete RPC calls */
        /* Writers: rmdir */
        struct rw_semaphore     rmdir_sem;
+       struct mutex            commit_mutex;
 
 #if IS_ENABLED(CONFIG_NFS_V4)
        struct nfs4_cached_acl  *nfs4_acl;