Commit e824f99a authored by Trond Myklebust's avatar Trond Myklebust

NFSv4: Use a mutex to protect the per-inode commit lists

The commit lists can get very large, so using the inode->i_lock can
end up affecting general metadata performance.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@primarydata.com>
parent b30d2f04
...@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode, ...@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode,
struct list_head *list, struct list_head *list,
struct nfs_commit_info *cinfo) struct nfs_commit_info *cinfo)
{ {
spin_lock(&cinfo->inode->i_lock); mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
#ifdef CONFIG_NFS_V4_1 #ifdef CONFIG_NFS_V4_1
if (cinfo->ds != NULL && cinfo->ds->nwritten != 0) if (cinfo->ds != NULL && cinfo->ds->nwritten != 0)
NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo); NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo);
#endif #endif
nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0); 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) static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
......
...@@ -2016,6 +2016,7 @@ static void init_once(void *foo) ...@@ -2016,6 +2016,7 @@ static void init_once(void *foo)
nfsi->commit_info.ncommit = 0; nfsi->commit_info.ncommit = 0;
atomic_set(&nfsi->commit_info.rpcs_out, 0); atomic_set(&nfsi->commit_info.rpcs_out, 0);
init_rwsem(&nfsi->rmdir_sem); init_rwsem(&nfsi->rmdir_sem);
mutex_init(&nfsi->commit_mutex);
nfs4_init_once(nfsi); nfs4_init_once(nfsi);
} }
......
...@@ -98,14 +98,13 @@ pnfs_generic_transfer_commit_list(struct list_head *src, struct list_head *dst, ...@@ -98,14 +98,13 @@ pnfs_generic_transfer_commit_list(struct list_head *src, struct list_head *dst,
if (!nfs_lock_request(req)) if (!nfs_lock_request(req))
continue; continue;
kref_get(&req->wb_kref); 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_request_remove_commit_list(req, cinfo);
clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
nfs_list_add_request(req, dst); nfs_list_add_request(req, dst);
ret++; ret++;
if ((ret == max) && !cinfo->dreq) if ((ret == max) && !cinfo->dreq)
break; break;
cond_resched();
} }
return ret; return ret;
} }
...@@ -119,7 +118,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket, ...@@ -119,7 +118,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket,
struct list_head *dst = &bucket->committing; struct list_head *dst = &bucket->committing;
int ret; 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); ret = pnfs_generic_transfer_commit_list(src, dst, cinfo, max);
if (ret) { if (ret) {
cinfo->ds->nwritten -= ret; cinfo->ds->nwritten -= ret;
...@@ -142,7 +141,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, ...@@ -142,7 +141,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo,
{ {
int i, rv = 0, cnt; 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++) { for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) {
cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i], cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i],
cinfo, max); cinfo, max);
...@@ -162,7 +161,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst, ...@@ -162,7 +161,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst,
int nwritten; int nwritten;
int i; int i;
lockdep_assert_held(&cinfo->inode->i_lock); lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex);
restart: restart:
for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
nwritten = pnfs_generic_transfer_commit_list(&b->written, nwritten = pnfs_generic_transfer_commit_list(&b->written,
...@@ -953,12 +952,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req, ...@@ -953,12 +952,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
struct list_head *list; struct list_head *list;
struct pnfs_commit_bucket *buckets; struct pnfs_commit_bucket *buckets;
spin_lock(&cinfo->inode->i_lock); mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
buckets = cinfo->ds->buckets; buckets = cinfo->ds->buckets;
list = &buckets[ds_commit_idx].written; list = &buckets[ds_commit_idx].written;
if (list_empty(list)) { if (list_empty(list)) {
if (!pnfs_is_valid_lseg(lseg)) { 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); cinfo->completion_ops->resched_write(cinfo, req);
return; return;
} }
...@@ -975,7 +974,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req, ...@@ -975,7 +974,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req,
cinfo->ds->nwritten++; cinfo->ds->nwritten++;
nfs_request_add_commit_list_locked(req, list, cinfo); 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); nfs_mark_page_unstable(req->wb_page, cinfo);
} }
EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit); EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit);
......
...@@ -195,7 +195,7 @@ nfs_page_find_swap_request(struct page *page) ...@@ -195,7 +195,7 @@ nfs_page_find_swap_request(struct page *page)
struct nfs_page *req = NULL; struct nfs_page *req = NULL;
if (!PageSwapCache(page)) if (!PageSwapCache(page))
return NULL; return NULL;
spin_lock(&inode->i_lock); mutex_lock(&nfsi->commit_mutex);
if (PageSwapCache(page)) { if (PageSwapCache(page)) {
req = nfs_page_search_commits_for_head_request_locked(nfsi, req = nfs_page_search_commits_for_head_request_locked(nfsi,
page); page);
...@@ -204,7 +204,7 @@ nfs_page_find_swap_request(struct page *page) ...@@ -204,7 +204,7 @@ nfs_page_find_swap_request(struct page *page)
kref_get(&req->wb_kref); kref_get(&req->wb_kref);
} }
} }
spin_unlock(&inode->i_lock); mutex_unlock(&nfsi->commit_mutex);
return req; return req;
} }
...@@ -856,7 +856,8 @@ nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi, ...@@ -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 * number of outstanding requests requiring a commit as well as
* the MM page stats. * 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 void
nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst, 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); ...@@ -884,9 +885,9 @@ EXPORT_SYMBOL_GPL(nfs_request_add_commit_list_locked);
void void
nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo) 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); 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) if (req->wb_page)
nfs_mark_page_unstable(req->wb_page, cinfo); nfs_mark_page_unstable(req->wb_page, cinfo);
} }
...@@ -964,11 +965,11 @@ nfs_clear_request_commit(struct nfs_page *req) ...@@ -964,11 +965,11 @@ nfs_clear_request_commit(struct nfs_page *req)
struct nfs_commit_info cinfo; struct nfs_commit_info cinfo;
nfs_init_cinfo_from_inode(&cinfo, inode); 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)) { if (!pnfs_clear_request_commit(req, &cinfo)) {
nfs_request_remove_commit_list(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); nfs_clear_page_commit(req->wb_page);
} }
} }
...@@ -1027,7 +1028,7 @@ nfs_reqs_to_commit(struct nfs_commit_info *cinfo) ...@@ -1027,7 +1028,7 @@ nfs_reqs_to_commit(struct nfs_commit_info *cinfo)
return cinfo->mds->ncommit; return cinfo->mds->ncommit;
} }
/* cinfo->inode->i_lock held by caller */ /* NFS_I(cinfo->inode)->commit_mutex held by caller */
int int
nfs_scan_commit_list(struct list_head *src, struct list_head *dst, nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
struct nfs_commit_info *cinfo, int max) struct nfs_commit_info *cinfo, int max)
...@@ -1039,13 +1040,12 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst, ...@@ -1039,13 +1040,12 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
if (!nfs_lock_request(req)) if (!nfs_lock_request(req))
continue; continue;
kref_get(&req->wb_kref); 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_request_remove_commit_list(req, cinfo);
nfs_list_add_request(req, dst); nfs_list_add_request(req, dst);
ret++; ret++;
if ((ret == max) && !cinfo->dreq) if ((ret == max) && !cinfo->dreq)
break; break;
cond_resched();
} }
return ret; return ret;
} }
...@@ -1065,7 +1065,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, ...@@ -1065,7 +1065,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst,
{ {
int ret = 0; int ret = 0;
spin_lock(&cinfo->inode->i_lock); mutex_lock(&NFS_I(cinfo->inode)->commit_mutex);
if (cinfo->mds->ncommit > 0) { if (cinfo->mds->ncommit > 0) {
const int max = INT_MAX; const int max = INT_MAX;
...@@ -1073,7 +1073,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, ...@@ -1073,7 +1073,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst,
cinfo, max); cinfo, max);
ret += pnfs_scan_commit_lists(inode, cinfo, max - ret); 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; return ret;
} }
......
...@@ -163,6 +163,7 @@ struct nfs_inode { ...@@ -163,6 +163,7 @@ struct nfs_inode {
/* Readers: in-flight sillydelete RPC calls */ /* Readers: in-flight sillydelete RPC calls */
/* Writers: rmdir */ /* Writers: rmdir */
struct rw_semaphore rmdir_sem; struct rw_semaphore rmdir_sem;
struct mutex commit_mutex;
#if IS_ENABLED(CONFIG_NFS_V4) #if IS_ENABLED(CONFIG_NFS_V4)
struct nfs4_cached_acl *nfs4_acl; struct nfs4_cached_acl *nfs4_acl;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment