diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-08-01 11:53:49 -0400 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2017-08-15 11:54:47 -0400 |
commit | e824f99adaaf1ed0e03eac8574599af6d992163d (patch) | |
tree | c5d2716566d21f023bd278dae6a92a06cbe72816 | |
parent | b30d2f04c35d539bf8003b3e014c389abefc249b (diff) |
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: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r-- | fs/nfs/direct.c | 4 | ||||
-rw-r--r-- | fs/nfs/inode.c | 1 | ||||
-rw-r--r-- | fs/nfs/pnfs_nfs.c | 15 | ||||
-rw-r--r-- | fs/nfs/write.c | 24 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 1 |
5 files changed, 23 insertions, 22 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 6fb9fad2d1e6..d2972d537469 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -616,13 +616,13 @@ nfs_direct_write_scan_commit_list(struct inode *inode, | |||
616 | struct list_head *list, | 616 | struct list_head *list, |
617 | struct nfs_commit_info *cinfo) | 617 | struct nfs_commit_info *cinfo) |
618 | { | 618 | { |
619 | spin_lock(&cinfo->inode->i_lock); | 619 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
620 | #ifdef CONFIG_NFS_V4_1 | 620 | #ifdef CONFIG_NFS_V4_1 |
621 | if (cinfo->ds != NULL && cinfo->ds->nwritten != 0) | 621 | if (cinfo->ds != NULL && cinfo->ds->nwritten != 0) |
622 | NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo); | 622 | NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo); |
623 | #endif | 623 | #endif |
624 | nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0); | 624 | nfs_scan_commit_list(&cinfo->mds->list, list, cinfo, 0); |
625 | spin_unlock(&cinfo->inode->i_lock); | 625 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
626 | } | 626 | } |
627 | 627 | ||
628 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | 628 | static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 109279d6d91b..34d9ebbc0dfd 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -2016,6 +2016,7 @@ static void init_once(void *foo) | |||
2016 | nfsi->commit_info.ncommit = 0; | 2016 | nfsi->commit_info.ncommit = 0; |
2017 | atomic_set(&nfsi->commit_info.rpcs_out, 0); | 2017 | atomic_set(&nfsi->commit_info.rpcs_out, 0); |
2018 | init_rwsem(&nfsi->rmdir_sem); | 2018 | init_rwsem(&nfsi->rmdir_sem); |
2019 | mutex_init(&nfsi->commit_mutex); | ||
2019 | nfs4_init_once(nfsi); | 2020 | nfs4_init_once(nfsi); |
2020 | } | 2021 | } |
2021 | 2022 | ||
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c index 25f28fa64c57..2cdee8ce2094 100644 --- a/fs/nfs/pnfs_nfs.c +++ b/fs/nfs/pnfs_nfs.c | |||
@@ -98,14 +98,13 @@ pnfs_generic_transfer_commit_list(struct list_head *src, struct list_head *dst, | |||
98 | if (!nfs_lock_request(req)) | 98 | if (!nfs_lock_request(req)) |
99 | continue; | 99 | continue; |
100 | kref_get(&req->wb_kref); | 100 | kref_get(&req->wb_kref); |
101 | if (cond_resched_lock(&cinfo->inode->i_lock)) | ||
102 | list_safe_reset_next(req, tmp, wb_list); | ||
103 | nfs_request_remove_commit_list(req, cinfo); | 101 | nfs_request_remove_commit_list(req, cinfo); |
104 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); | 102 | clear_bit(PG_COMMIT_TO_DS, &req->wb_flags); |
105 | nfs_list_add_request(req, dst); | 103 | nfs_list_add_request(req, dst); |
106 | ret++; | 104 | ret++; |
107 | if ((ret == max) && !cinfo->dreq) | 105 | if ((ret == max) && !cinfo->dreq) |
108 | break; | 106 | break; |
107 | cond_resched(); | ||
109 | } | 108 | } |
110 | return ret; | 109 | return ret; |
111 | } | 110 | } |
@@ -119,7 +118,7 @@ pnfs_generic_scan_ds_commit_list(struct pnfs_commit_bucket *bucket, | |||
119 | struct list_head *dst = &bucket->committing; | 118 | struct list_head *dst = &bucket->committing; |
120 | int ret; | 119 | int ret; |
121 | 120 | ||
122 | lockdep_assert_held(&cinfo->inode->i_lock); | 121 | lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex); |
123 | ret = pnfs_generic_transfer_commit_list(src, dst, cinfo, max); | 122 | ret = pnfs_generic_transfer_commit_list(src, dst, cinfo, max); |
124 | if (ret) { | 123 | if (ret) { |
125 | cinfo->ds->nwritten -= ret; | 124 | cinfo->ds->nwritten -= ret; |
@@ -142,7 +141,7 @@ int pnfs_generic_scan_commit_lists(struct nfs_commit_info *cinfo, | |||
142 | { | 141 | { |
143 | int i, rv = 0, cnt; | 142 | int i, rv = 0, cnt; |
144 | 143 | ||
145 | lockdep_assert_held(&cinfo->inode->i_lock); | 144 | lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex); |
146 | for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) { | 145 | for (i = 0; i < cinfo->ds->nbuckets && max != 0; i++) { |
147 | cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i], | 146 | cnt = pnfs_generic_scan_ds_commit_list(&cinfo->ds->buckets[i], |
148 | cinfo, max); | 147 | cinfo, max); |
@@ -162,7 +161,7 @@ void pnfs_generic_recover_commit_reqs(struct list_head *dst, | |||
162 | int nwritten; | 161 | int nwritten; |
163 | int i; | 162 | int i; |
164 | 163 | ||
165 | lockdep_assert_held(&cinfo->inode->i_lock); | 164 | lockdep_assert_held(&NFS_I(cinfo->inode)->commit_mutex); |
166 | restart: | 165 | restart: |
167 | for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { | 166 | for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { |
168 | nwritten = pnfs_generic_transfer_commit_list(&b->written, | 167 | nwritten = pnfs_generic_transfer_commit_list(&b->written, |
@@ -953,12 +952,12 @@ pnfs_layout_mark_request_commit(struct nfs_page *req, | |||
953 | struct list_head *list; | 952 | struct list_head *list; |
954 | struct pnfs_commit_bucket *buckets; | 953 | struct pnfs_commit_bucket *buckets; |
955 | 954 | ||
956 | spin_lock(&cinfo->inode->i_lock); | 955 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
957 | buckets = cinfo->ds->buckets; | 956 | buckets = cinfo->ds->buckets; |
958 | list = &buckets[ds_commit_idx].written; | 957 | list = &buckets[ds_commit_idx].written; |
959 | if (list_empty(list)) { | 958 | if (list_empty(list)) { |
960 | if (!pnfs_is_valid_lseg(lseg)) { | 959 | if (!pnfs_is_valid_lseg(lseg)) { |
961 | spin_unlock(&cinfo->inode->i_lock); | 960 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
962 | cinfo->completion_ops->resched_write(cinfo, req); | 961 | cinfo->completion_ops->resched_write(cinfo, req); |
963 | return; | 962 | return; |
964 | } | 963 | } |
@@ -975,7 +974,7 @@ pnfs_layout_mark_request_commit(struct nfs_page *req, | |||
975 | cinfo->ds->nwritten++; | 974 | cinfo->ds->nwritten++; |
976 | 975 | ||
977 | nfs_request_add_commit_list_locked(req, list, cinfo); | 976 | nfs_request_add_commit_list_locked(req, list, cinfo); |
978 | spin_unlock(&cinfo->inode->i_lock); | 977 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
979 | nfs_mark_page_unstable(req->wb_page, cinfo); | 978 | nfs_mark_page_unstable(req->wb_page, cinfo); |
980 | } | 979 | } |
981 | EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit); | 980 | EXPORT_SYMBOL_GPL(pnfs_layout_mark_request_commit); |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 8d8fa6d4cfcc..5ab5ca24b48a 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -195,7 +195,7 @@ nfs_page_find_swap_request(struct page *page) | |||
195 | struct nfs_page *req = NULL; | 195 | struct nfs_page *req = NULL; |
196 | if (!PageSwapCache(page)) | 196 | if (!PageSwapCache(page)) |
197 | return NULL; | 197 | return NULL; |
198 | spin_lock(&inode->i_lock); | 198 | mutex_lock(&nfsi->commit_mutex); |
199 | if (PageSwapCache(page)) { | 199 | if (PageSwapCache(page)) { |
200 | req = nfs_page_search_commits_for_head_request_locked(nfsi, | 200 | req = nfs_page_search_commits_for_head_request_locked(nfsi, |
201 | page); | 201 | page); |
@@ -204,7 +204,7 @@ nfs_page_find_swap_request(struct page *page) | |||
204 | kref_get(&req->wb_kref); | 204 | kref_get(&req->wb_kref); |
205 | } | 205 | } |
206 | } | 206 | } |
207 | spin_unlock(&inode->i_lock); | 207 | mutex_unlock(&nfsi->commit_mutex); |
208 | return req; | 208 | return req; |
209 | } | 209 | } |
210 | 210 | ||
@@ -856,7 +856,8 @@ nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi, | |||
856 | * number of outstanding requests requiring a commit as well as | 856 | * number of outstanding requests requiring a commit as well as |
857 | * the MM page stats. | 857 | * the MM page stats. |
858 | * | 858 | * |
859 | * The caller must hold cinfo->inode->i_lock, and the nfs_page lock. | 859 | * The caller must hold NFS_I(cinfo->inode)->commit_mutex, and the |
860 | * nfs_page lock. | ||
860 | */ | 861 | */ |
861 | void | 862 | void |
862 | nfs_request_add_commit_list_locked(struct nfs_page *req, struct list_head *dst, | 863 | 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 | void | 885 | void |
885 | nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo) | 886 | nfs_request_add_commit_list(struct nfs_page *req, struct nfs_commit_info *cinfo) |
886 | { | 887 | { |
887 | spin_lock(&cinfo->inode->i_lock); | 888 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
888 | nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo); | 889 | nfs_request_add_commit_list_locked(req, &cinfo->mds->list, cinfo); |
889 | spin_unlock(&cinfo->inode->i_lock); | 890 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
890 | if (req->wb_page) | 891 | if (req->wb_page) |
891 | nfs_mark_page_unstable(req->wb_page, cinfo); | 892 | nfs_mark_page_unstable(req->wb_page, cinfo); |
892 | } | 893 | } |
@@ -964,11 +965,11 @@ nfs_clear_request_commit(struct nfs_page *req) | |||
964 | struct nfs_commit_info cinfo; | 965 | struct nfs_commit_info cinfo; |
965 | 966 | ||
966 | nfs_init_cinfo_from_inode(&cinfo, inode); | 967 | nfs_init_cinfo_from_inode(&cinfo, inode); |
967 | spin_lock(&inode->i_lock); | 968 | mutex_lock(&NFS_I(inode)->commit_mutex); |
968 | if (!pnfs_clear_request_commit(req, &cinfo)) { | 969 | if (!pnfs_clear_request_commit(req, &cinfo)) { |
969 | nfs_request_remove_commit_list(req, &cinfo); | 970 | nfs_request_remove_commit_list(req, &cinfo); |
970 | } | 971 | } |
971 | spin_unlock(&inode->i_lock); | 972 | mutex_unlock(&NFS_I(inode)->commit_mutex); |
972 | nfs_clear_page_commit(req->wb_page); | 973 | nfs_clear_page_commit(req->wb_page); |
973 | } | 974 | } |
974 | } | 975 | } |
@@ -1027,7 +1028,7 @@ nfs_reqs_to_commit(struct nfs_commit_info *cinfo) | |||
1027 | return cinfo->mds->ncommit; | 1028 | return cinfo->mds->ncommit; |
1028 | } | 1029 | } |
1029 | 1030 | ||
1030 | /* cinfo->inode->i_lock held by caller */ | 1031 | /* NFS_I(cinfo->inode)->commit_mutex held by caller */ |
1031 | int | 1032 | int |
1032 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, | 1033 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, |
1033 | struct nfs_commit_info *cinfo, int max) | 1034 | struct nfs_commit_info *cinfo, int max) |
@@ -1039,13 +1040,12 @@ nfs_scan_commit_list(struct list_head *src, struct list_head *dst, | |||
1039 | if (!nfs_lock_request(req)) | 1040 | if (!nfs_lock_request(req)) |
1040 | continue; | 1041 | continue; |
1041 | kref_get(&req->wb_kref); | 1042 | kref_get(&req->wb_kref); |
1042 | if (cond_resched_lock(&cinfo->inode->i_lock)) | ||
1043 | list_safe_reset_next(req, tmp, wb_list); | ||
1044 | nfs_request_remove_commit_list(req, cinfo); | 1043 | nfs_request_remove_commit_list(req, cinfo); |
1045 | nfs_list_add_request(req, dst); | 1044 | nfs_list_add_request(req, dst); |
1046 | ret++; | 1045 | ret++; |
1047 | if ((ret == max) && !cinfo->dreq) | 1046 | if ((ret == max) && !cinfo->dreq) |
1048 | break; | 1047 | break; |
1048 | cond_resched(); | ||
1049 | } | 1049 | } |
1050 | return ret; | 1050 | return ret; |
1051 | } | 1051 | } |
@@ -1065,7 +1065,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, | |||
1065 | { | 1065 | { |
1066 | int ret = 0; | 1066 | int ret = 0; |
1067 | 1067 | ||
1068 | spin_lock(&cinfo->inode->i_lock); | 1068 | mutex_lock(&NFS_I(cinfo->inode)->commit_mutex); |
1069 | if (cinfo->mds->ncommit > 0) { | 1069 | if (cinfo->mds->ncommit > 0) { |
1070 | const int max = INT_MAX; | 1070 | const int max = INT_MAX; |
1071 | 1071 | ||
@@ -1073,7 +1073,7 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst, | |||
1073 | cinfo, max); | 1073 | cinfo, max); |
1074 | ret += pnfs_scan_commit_lists(inode, cinfo, max - ret); | 1074 | ret += pnfs_scan_commit_lists(inode, cinfo, max - ret); |
1075 | } | 1075 | } |
1076 | spin_unlock(&cinfo->inode->i_lock); | 1076 | mutex_unlock(&NFS_I(cinfo->inode)->commit_mutex); |
1077 | return ret; | 1077 | return ret; |
1078 | } | 1078 | } |
1079 | 1079 | ||
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 5cc91d6381a3..121a702888b4 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -163,6 +163,7 @@ struct nfs_inode { | |||
163 | /* Readers: in-flight sillydelete RPC calls */ | 163 | /* Readers: in-flight sillydelete RPC calls */ |
164 | /* Writers: rmdir */ | 164 | /* Writers: rmdir */ |
165 | struct rw_semaphore rmdir_sem; | 165 | struct rw_semaphore rmdir_sem; |
166 | struct mutex commit_mutex; | ||
166 | 167 | ||
167 | #if IS_ENABLED(CONFIG_NFS_V4) | 168 | #if IS_ENABLED(CONFIG_NFS_V4) |
168 | struct nfs4_cached_acl *nfs4_acl; | 169 | struct nfs4_cached_acl *nfs4_acl; |