aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-15 17:16:40 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-03-17 11:09:33 -0400
commit8dd3775889345850ecddd689b5c200cdd91bd8c9 (patch)
treeea697cfcac3f3a927e90d0048e9ed76b5a3ea8e5 /fs
parent95a13f7b33be87d85d8e6652126a3f4d64d164db (diff)
NFSv4.1: Clean ups and bugfixes for the pNFS read/writeback/commit code
Move more pnfs-isms out of the generic commit code. Bugfixes: - filelayout_scan_commit_lists doesn't need to get/put the lseg. In fact since it is run under the inode->i_lock, the lseg_put() can deadlock. - Ensure that we distinguish between what needs to be done for commit-to-data server and what needs to be done for commit-to-MDS using the new flag PG_COMMIT_TO_DS. Otherwise we may end up calling put_lseg() on a bucket for a struct nfs_page that got written through the MDS. - Fix a case where we were using list_del() on an nfs_page->wb_list instead of list_del_init(). - filelayout_initiate_commit needs to call filelayout_commit_release on error instead of the mds_ops->rpc_release(). Otherwise it won't clear the commit lock. Cleanups: - Let the files layout manage the commit lists for the pNFS case. Don't expose stuff like pnfs_choose_commit_list, and the fact that the commit buckets hold references to the layout segment in common code. - Cast out the put_lseg() calls for the struct nfs_read/write_data->lseg into the pNFS layer from whence they came. - Let the pNFS layer manage the NFS_INO_PNFS_COMMIT bit. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Fred Isaman <iisaman@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/internal.h4
-rw-r--r--fs/nfs/nfs4filelayout.c82
-rw-r--r--fs/nfs/pnfs.c3
-rw-r--r--fs/nfs/pnfs.h55
-rw-r--r--fs/nfs/read.c1
-rw-r--r--fs/nfs/write.c124
6 files changed, 172 insertions, 97 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 04a914704e7b..2476dc69365f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -308,8 +308,6 @@ extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio);
308extern void nfs_readdata_release(struct nfs_read_data *rdata); 308extern void nfs_readdata_release(struct nfs_read_data *rdata);
309 309
310/* write.c */ 310/* write.c */
311extern int nfs_scan_commit_list(struct list_head *src, struct list_head *dst,
312 int max);
313extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, 311extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc,
314 struct list_head *head); 312 struct list_head *head);
315extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, 313extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio,
@@ -334,6 +332,8 @@ void nfs_retry_commit(struct list_head *page_list,
334void nfs_commit_clear_lock(struct nfs_inode *nfsi); 332void nfs_commit_clear_lock(struct nfs_inode *nfsi);
335void nfs_commitdata_release(void *data); 333void nfs_commitdata_release(void *data);
336void nfs_commit_release_pages(struct nfs_write_data *data); 334void nfs_commit_release_pages(struct nfs_write_data *data);
335void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head);
336void nfs_request_remove_commit_list(struct nfs_page *req);
337 337
338#ifdef CONFIG_MIGRATION 338#ifdef CONFIG_MIGRATION
339extern int nfs_migrate_page(struct address_space *, 339extern int nfs_migrate_page(struct address_space *,
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c
index 379a085f8f25..c24e077c2820 100644
--- a/fs/nfs/nfs4filelayout.c
+++ b/fs/nfs/nfs4filelayout.c
@@ -224,6 +224,7 @@ static void filelayout_read_release(void *data)
224{ 224{
225 struct nfs_read_data *rdata = (struct nfs_read_data *)data; 225 struct nfs_read_data *rdata = (struct nfs_read_data *)data;
226 226
227 put_lseg(rdata->lseg);
227 rdata->mds_ops->rpc_release(data); 228 rdata->mds_ops->rpc_release(data);
228} 229}
229 230
@@ -310,6 +311,7 @@ static void filelayout_write_release(void *data)
310{ 311{
311 struct nfs_write_data *wdata = (struct nfs_write_data *)data; 312 struct nfs_write_data *wdata = (struct nfs_write_data *)data;
312 313
314 put_lseg(wdata->lseg);
313 wdata->mds_ops->rpc_release(data); 315 wdata->mds_ops->rpc_release(data);
314} 316}
315 317
@@ -320,6 +322,7 @@ static void filelayout_commit_release(void *data)
320 nfs_commit_release_pages(wdata); 322 nfs_commit_release_pages(wdata);
321 if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding)) 323 if (atomic_dec_and_test(&NFS_I(wdata->inode)->commits_outstanding))
322 nfs_commit_clear_lock(NFS_I(wdata->inode)); 324 nfs_commit_clear_lock(NFS_I(wdata->inode));
325 put_lseg(wdata->lseg);
323 nfs_commitdata_release(wdata); 326 nfs_commitdata_release(wdata);
324} 327}
325 328
@@ -779,11 +782,16 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j)
779 782
780/* The generic layer is about to remove the req from the commit list. 783/* The generic layer is about to remove the req from the commit list.
781 * If this will make the bucket empty, it will need to put the lseg reference. 784 * If this will make the bucket empty, it will need to put the lseg reference.
782 * Note inode lock is held, so we can't do the put here.
783 */ 785 */
784static struct pnfs_layout_segment * 786static void
785filelayout_remove_commit_req(struct nfs_page *req) 787filelayout_clear_request_commit(struct nfs_page *req)
786{ 788{
789 struct pnfs_layout_segment *freeme = NULL;
790 struct inode *inode = req->wb_context->dentry->d_inode;
791
792 spin_lock(&inode->i_lock);
793 if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags))
794 goto out;
787 if (list_is_singular(&req->wb_list)) { 795 if (list_is_singular(&req->wb_list)) {
788 struct inode *inode = req->wb_context->dentry->d_inode; 796 struct inode *inode = req->wb_context->dentry->d_inode;
789 struct pnfs_layout_segment *lseg; 797 struct pnfs_layout_segment *lseg;
@@ -792,11 +800,16 @@ filelayout_remove_commit_req(struct nfs_page *req)
792 * since there is only one relevant lseg... 800 * since there is only one relevant lseg...
793 */ 801 */
794 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) { 802 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) {
795 if (lseg->pls_range.iomode == IOMODE_RW) 803 if (lseg->pls_range.iomode == IOMODE_RW) {
796 return lseg; 804 freeme = lseg;
805 break;
806 }
797 } 807 }
798 } 808 }
799 return NULL; 809out:
810 nfs_request_remove_commit_list(req);
811 spin_unlock(&inode->i_lock);
812 put_lseg(freeme);
800} 813}
801 814
802static struct list_head * 815static struct list_head *
@@ -829,9 +842,20 @@ filelayout_choose_commit_list(struct nfs_page *req,
829 */ 842 */
830 get_lseg(lseg); 843 get_lseg(lseg);
831 } 844 }
845 set_bit(PG_COMMIT_TO_DS, &req->wb_flags);
832 return list; 846 return list;
833} 847}
834 848
849static void
850filelayout_mark_request_commit(struct nfs_page *req,
851 struct pnfs_layout_segment *lseg)
852{
853 struct list_head *list;
854
855 list = filelayout_choose_commit_list(req, lseg);
856 nfs_request_add_commit_list(req, list);
857}
858
835static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) 859static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i)
836{ 860{
837 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 861 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
@@ -872,7 +896,7 @@ static int filelayout_initiate_commit(struct nfs_write_data *data, int how)
872 set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags); 896 set_bit(lo_fail_bit(IOMODE_RW), &lseg->pls_layout->plh_flags);
873 set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); 897 set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags);
874 prepare_to_resend_writes(data); 898 prepare_to_resend_writes(data);
875 data->mds_ops->rpc_release(data); 899 filelayout_commit_release(data);
876 return -EAGAIN; 900 return -EAGAIN;
877 } 901 }
878 dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how); 902 dprintk("%s ino %lu, how %d\n", __func__, data->inode->i_ino, how);
@@ -895,7 +919,7 @@ find_only_write_lseg_locked(struct inode *inode)
895 919
896 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) 920 list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list)
897 if (lseg->pls_range.iomode == IOMODE_RW) 921 if (lseg->pls_range.iomode == IOMODE_RW)
898 return get_lseg(lseg); 922 return lseg;
899 return NULL; 923 return NULL;
900} 924}
901 925
@@ -905,10 +929,33 @@ static struct pnfs_layout_segment *find_only_write_lseg(struct inode *inode)
905 929
906 spin_lock(&inode->i_lock); 930 spin_lock(&inode->i_lock);
907 rv = find_only_write_lseg_locked(inode); 931 rv = find_only_write_lseg_locked(inode);
932 if (rv)
933 get_lseg(rv);
908 spin_unlock(&inode->i_lock); 934 spin_unlock(&inode->i_lock);
909 return rv; 935 return rv;
910} 936}
911 937
938static int
939filelayout_scan_ds_commit_list(struct nfs4_fl_commit_bucket *bucket, int max)
940{
941 struct list_head *src = &bucket->written;
942 struct list_head *dst = &bucket->committing;
943 struct nfs_page *req, *tmp;
944 int ret = 0;
945
946 list_for_each_entry_safe(req, tmp, src, wb_list) {
947 if (!nfs_lock_request(req))
948 continue;
949 nfs_request_remove_commit_list(req);
950 clear_bit(PG_COMMIT_TO_DS, &req->wb_flags);
951 nfs_list_add_request(req, dst);
952 ret++;
953 if (ret == max)
954 break;
955 }
956 return ret;
957}
958
912/* Move reqs from written to committing lists, returning count of number moved. 959/* Move reqs from written to committing lists, returning count of number moved.
913 * Note called with i_lock held. 960 * Note called with i_lock held.
914 */ 961 */
@@ -920,21 +967,16 @@ static int filelayout_scan_commit_lists(struct inode *inode, int max)
920 967
921 lseg = find_only_write_lseg_locked(inode); 968 lseg = find_only_write_lseg_locked(inode);
922 if (!lseg) 969 if (!lseg)
923 return 0; 970 goto out_done;
924 fl = FILELAYOUT_LSEG(lseg); 971 fl = FILELAYOUT_LSEG(lseg);
925 if (fl->commit_through_mds) 972 if (fl->commit_through_mds)
926 goto out_put; 973 goto out_done;
927 for (i = 0; i < fl->number_of_buckets; i++) { 974 for (i = 0; i < fl->number_of_buckets && max != 0; i++) {
928 if (list_empty(&fl->commit_buckets[i].written)) 975 cnt = filelayout_scan_ds_commit_list(&fl->commit_buckets[i], max);
929 continue;
930 cnt = nfs_scan_commit_list(&fl->commit_buckets[i].written,
931 &fl->commit_buckets[i].committing,
932 max);
933 max -= cnt; 976 max -= cnt;
934 rv += cnt; 977 rv += cnt;
935 } 978 }
936out_put: 979out_done:
937 put_lseg(lseg);
938 return rv; 980 return rv;
939} 981}
940 982
@@ -1033,8 +1075,8 @@ static struct pnfs_layoutdriver_type filelayout_type = {
1033 .free_lseg = filelayout_free_lseg, 1075 .free_lseg = filelayout_free_lseg,
1034 .pg_read_ops = &filelayout_pg_read_ops, 1076 .pg_read_ops = &filelayout_pg_read_ops,
1035 .pg_write_ops = &filelayout_pg_write_ops, 1077 .pg_write_ops = &filelayout_pg_write_ops,
1036 .choose_commit_list = filelayout_choose_commit_list, 1078 .mark_request_commit = filelayout_mark_request_commit,
1037 .remove_commit_req = filelayout_remove_commit_req, 1079 .clear_request_commit = filelayout_clear_request_commit,
1038 .scan_commit_lists = filelayout_scan_commit_lists, 1080 .scan_commit_lists = filelayout_scan_commit_lists,
1039 .commit_pagelist = filelayout_commit_pagelist, 1081 .commit_pagelist = filelayout_commit_pagelist,
1040 .read_pagelist = filelayout_read_pagelist, 1082 .read_pagelist = filelayout_read_pagelist,
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 6f1c1e3d12bc..b5d451586943 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1210,6 +1210,7 @@ void pnfs_ld_write_done(struct nfs_write_data *data)
1210 } 1210 }
1211 data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages); 1211 data->task.tk_status = pnfs_write_done_resend_to_mds(data->inode, &data->pages);
1212 } 1212 }
1213 put_lseg(data->lseg);
1213 data->mds_ops->rpc_release(data); 1214 data->mds_ops->rpc_release(data);
1214} 1215}
1215EXPORT_SYMBOL_GPL(pnfs_ld_write_done); 1216EXPORT_SYMBOL_GPL(pnfs_ld_write_done);
@@ -1223,6 +1224,7 @@ pnfs_write_through_mds(struct nfs_pageio_descriptor *desc,
1223 nfs_list_add_request(data->req, &desc->pg_list); 1224 nfs_list_add_request(data->req, &desc->pg_list);
1224 nfs_pageio_reset_write_mds(desc); 1225 nfs_pageio_reset_write_mds(desc);
1225 desc->pg_recoalesce = 1; 1226 desc->pg_recoalesce = 1;
1227 put_lseg(data->lseg);
1226 nfs_writedata_release(data); 1228 nfs_writedata_release(data);
1227} 1229}
1228 1230
@@ -1323,6 +1325,7 @@ void pnfs_ld_read_done(struct nfs_read_data *data)
1323 data->mds_ops->rpc_call_done(&data->task, data); 1325 data->mds_ops->rpc_call_done(&data->task, data);
1324 } else 1326 } else
1325 pnfs_ld_handle_read_error(data); 1327 pnfs_ld_handle_read_error(data);
1328 put_lseg(data->lseg);
1326 data->mds_ops->rpc_release(data); 1329 data->mds_ops->rpc_release(data);
1327} 1330}
1328EXPORT_SYMBOL_GPL(pnfs_ld_read_done); 1331EXPORT_SYMBOL_GPL(pnfs_ld_read_done);
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index ef92f676cf1e..e98ff3027d3a 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -94,9 +94,9 @@ struct pnfs_layoutdriver_type {
94 const struct nfs_pageio_ops *pg_read_ops; 94 const struct nfs_pageio_ops *pg_read_ops;
95 const struct nfs_pageio_ops *pg_write_ops; 95 const struct nfs_pageio_ops *pg_write_ops;
96 96
97 struct list_head * (*choose_commit_list) (struct nfs_page *req, 97 void (*mark_request_commit) (struct nfs_page *req,
98 struct pnfs_layout_segment *lseg); 98 struct pnfs_layout_segment *lseg);
99 struct pnfs_layout_segment *(*remove_commit_req) (struct nfs_page *req); 99 void (*clear_request_commit) (struct nfs_page *req);
100 int (*scan_commit_lists) (struct inode *inode, int max); 100 int (*scan_commit_lists) (struct inode *inode, int max);
101 int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how); 101 int (*commit_pagelist)(struct inode *inode, struct list_head *mds_pages, int how);
102 102
@@ -269,39 +269,42 @@ pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
269 return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how); 269 return NFS_SERVER(inode)->pnfs_curr_ld->commit_pagelist(inode, mds_pages, how);
270} 270}
271 271
272static inline struct list_head * 272static inline bool
273pnfs_choose_commit_list(struct nfs_page *req, struct pnfs_layout_segment *lseg) 273pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
274{ 274{
275 struct inode *inode = req->wb_context->dentry->d_inode; 275 struct inode *inode = req->wb_context->dentry->d_inode;
276 struct list_head *rv; 276 struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
277 277
278 if (lseg && NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list) 278 if (lseg == NULL || ld->mark_request_commit == NULL)
279 rv = NFS_SERVER(inode)->pnfs_curr_ld->choose_commit_list(req, lseg); 279 return false;
280 else 280 ld->mark_request_commit(req, lseg);
281 rv = &NFS_I(inode)->commit_list; 281 return true;
282 return rv;
283} 282}
284 283
285static inline struct pnfs_layout_segment * 284static inline bool
286pnfs_clear_request_commit(struct nfs_page *req) 285pnfs_clear_request_commit(struct nfs_page *req)
287{ 286{
288 struct inode *inode = req->wb_context->dentry->d_inode; 287 struct inode *inode = req->wb_context->dentry->d_inode;
288 struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
289 289
290 if (NFS_SERVER(inode)->pnfs_curr_ld && 290 if (ld == NULL || ld->clear_request_commit == NULL)
291 NFS_SERVER(inode)->pnfs_curr_ld->remove_commit_req) 291 return false;
292 return NFS_SERVER(inode)->pnfs_curr_ld->remove_commit_req(req); 292 ld->clear_request_commit(req);
293 else 293 return true;
294 return NULL;
295} 294}
296 295
297static inline int 296static inline int
298pnfs_scan_commit_lists(struct inode *inode, int max) 297pnfs_scan_commit_lists(struct inode *inode, int max)
299{ 298{
300 if (NFS_SERVER(inode)->pnfs_curr_ld && 299 struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld;
301 NFS_SERVER(inode)->pnfs_curr_ld->scan_commit_lists) 300 int ret;
302 return NFS_SERVER(inode)->pnfs_curr_ld->scan_commit_lists(inode, max); 301
303 else 302 if (ld == NULL || ld->scan_commit_lists == NULL)
304 return 0; 303 return 0;
304 ret = ld->scan_commit_lists(inode, max);
305 if (ret != 0)
306 set_bit(NFS_INO_PNFS_COMMIT, &NFS_I(inode)->flags);
307 return ret;
305} 308}
306 309
307/* Should the pNFS client commit and return the layout upon a setattr */ 310/* Should the pNFS client commit and return the layout upon a setattr */
@@ -403,18 +406,16 @@ pnfs_commit_list(struct inode *inode, struct list_head *mds_pages, int how)
403 return PNFS_NOT_ATTEMPTED; 406 return PNFS_NOT_ATTEMPTED;
404} 407}
405 408
406static inline struct list_head * 409static inline bool
407pnfs_choose_commit_list(struct nfs_page *req, struct pnfs_layout_segment *lseg) 410pnfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
408{ 411{
409 struct inode *inode = req->wb_context->dentry->d_inode; 412 return false;
410
411 return &NFS_I(inode)->commit_list;
412} 413}
413 414
414static inline struct pnfs_layout_segment * 415static inline bool
415pnfs_clear_request_commit(struct nfs_page *req) 416pnfs_clear_request_commit(struct nfs_page *req)
416{ 417{
417 return NULL; 418 return false;
418} 419}
419 420
420static inline int 421static inline int
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 3c2540d532c7..2662c0298dd0 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -66,7 +66,6 @@ void nfs_readdata_free(struct nfs_read_data *p)
66 66
67void nfs_readdata_release(struct nfs_read_data *rdata) 67void nfs_readdata_release(struct nfs_read_data *rdata)
68{ 68{
69 put_lseg(rdata->lseg);
70 put_nfs_open_context(rdata->args.context); 69 put_nfs_open_context(rdata->args.context);
71 nfs_readdata_free(rdata); 70 nfs_readdata_free(rdata);
72} 71}
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index a630ad65d64c..0de19f413f92 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -100,7 +100,6 @@ void nfs_writedata_free(struct nfs_write_data *p)
100 100
101void nfs_writedata_release(struct nfs_write_data *wdata) 101void nfs_writedata_release(struct nfs_write_data *wdata)
102{ 102{
103 put_lseg(wdata->lseg);
104 put_nfs_open_context(wdata->args.context); 103 put_nfs_open_context(wdata->args.context);
105 nfs_writedata_free(wdata); 104 nfs_writedata_free(wdata);
106} 105}
@@ -393,8 +392,6 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
393 spin_unlock(&inode->i_lock); 392 spin_unlock(&inode->i_lock);
394} 393}
395 394
396static struct pnfs_layout_segment *nfs_clear_request_commit(struct nfs_page *req);
397
398/* 395/*
399 * Remove a write request from an inode 396 * Remove a write request from an inode
400 */ 397 */
@@ -402,18 +399,15 @@ static void nfs_inode_remove_request(struct nfs_page *req)
402{ 399{
403 struct inode *inode = req->wb_context->dentry->d_inode; 400 struct inode *inode = req->wb_context->dentry->d_inode;
404 struct nfs_inode *nfsi = NFS_I(inode); 401 struct nfs_inode *nfsi = NFS_I(inode);
405 struct pnfs_layout_segment *lseg;
406 402
407 BUG_ON (!NFS_WBACK_BUSY(req)); 403 BUG_ON (!NFS_WBACK_BUSY(req));
408 404
409 spin_lock(&inode->i_lock); 405 spin_lock(&inode->i_lock);
410 lseg = nfs_clear_request_commit(req);
411 set_page_private(req->wb_page, 0); 406 set_page_private(req->wb_page, 0);
412 ClearPagePrivate(req->wb_page); 407 ClearPagePrivate(req->wb_page);
413 clear_bit(PG_MAPPED, &req->wb_flags); 408 clear_bit(PG_MAPPED, &req->wb_flags);
414 nfsi->npages--; 409 nfsi->npages--;
415 spin_unlock(&inode->i_lock); 410 spin_unlock(&inode->i_lock);
416 put_lseg(lseg);
417 nfs_release_request(req); 411 nfs_release_request(req);
418} 412}
419 413
@@ -424,26 +418,69 @@ nfs_mark_request_dirty(struct nfs_page *req)
424} 418}
425 419
426#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 420#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
427/* 421/**
428 * Add a request to the inode's commit list. 422 * nfs_request_add_commit_list - add request to a commit list
423 * @req: pointer to a struct nfs_page
424 * @head: commit list head
425 *
426 * This sets the PG_CLEAN bit, updates the inode global count of
427 * number of outstanding requests requiring a commit as well as
428 * the MM page stats.
429 *
430 * The caller must _not_ hold the inode->i_lock, but must be
431 * holding the nfs_page lock.
429 */ 432 */
430static void 433void
431nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) 434nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head)
432{ 435{
433 struct inode *inode = req->wb_context->dentry->d_inode; 436 struct inode *inode = req->wb_context->dentry->d_inode;
434 struct nfs_inode *nfsi = NFS_I(inode);
435 struct list_head *clist;
436 437
437 clist = pnfs_choose_commit_list(req, lseg);
438 spin_lock(&inode->i_lock);
439 set_bit(PG_CLEAN, &(req)->wb_flags); 438 set_bit(PG_CLEAN, &(req)->wb_flags);
440 nfs_list_add_request(req, clist); 439 spin_lock(&inode->i_lock);
441 nfsi->ncommit++; 440 nfs_list_add_request(req, head);
441 NFS_I(inode)->ncommit++;
442 spin_unlock(&inode->i_lock); 442 spin_unlock(&inode->i_lock);
443 inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); 443 inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
444 inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE); 444 inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
445 __mark_inode_dirty(inode, I_DIRTY_DATASYNC); 445 __mark_inode_dirty(inode, I_DIRTY_DATASYNC);
446} 446}
447EXPORT_SYMBOL_GPL(nfs_request_add_commit_list);
448
449/**
450 * nfs_request_remove_commit_list - Remove request from a commit list
451 * @req: pointer to a nfs_page
452 *
453 * This clears the PG_CLEAN bit, and updates the inode global count of
454 * number of outstanding requests requiring a commit
455 * It does not update the MM page stats.
456 *
457 * The caller _must_ hold the inode->i_lock and the nfs_page lock.
458 */
459void
460nfs_request_remove_commit_list(struct nfs_page *req)
461{
462 struct inode *inode = req->wb_context->dentry->d_inode;
463
464 if (!test_and_clear_bit(PG_CLEAN, &(req)->wb_flags))
465 return;
466 nfs_list_remove_request(req);
467 NFS_I(inode)->ncommit--;
468}
469EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list);
470
471
472/*
473 * Add a request to the inode's commit list.
474 */
475static void
476nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
477{
478 struct inode *inode = req->wb_context->dentry->d_inode;
479
480 if (pnfs_mark_request_commit(req, lseg))
481 return;
482 nfs_request_add_commit_list(req, &NFS_I(inode)->commit_list);
483}
447 484
448static void 485static void
449nfs_clear_page_commit(struct page *page) 486nfs_clear_page_commit(struct page *page)
@@ -452,18 +489,19 @@ nfs_clear_page_commit(struct page *page)
452 dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE); 489 dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
453} 490}
454 491
455static struct pnfs_layout_segment * 492static void
456nfs_clear_request_commit(struct nfs_page *req) 493nfs_clear_request_commit(struct nfs_page *req)
457{ 494{
458 struct pnfs_layout_segment *lseg = NULL; 495 if (test_bit(PG_CLEAN, &req->wb_flags)) {
496 struct inode *inode = req->wb_context->dentry->d_inode;
459 497
460 if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) { 498 if (!pnfs_clear_request_commit(req)) {
499 spin_lock(&inode->i_lock);
500 nfs_request_remove_commit_list(req);
501 spin_unlock(&inode->i_lock);
502 }
461 nfs_clear_page_commit(req->wb_page); 503 nfs_clear_page_commit(req->wb_page);
462 lseg = pnfs_clear_request_commit(req);
463 NFS_I(req->wb_context->dentry->d_inode)->ncommit--;
464 list_del(&req->wb_list);
465 } 504 }
466 return lseg;
467} 505}
468 506
469static inline 507static inline
@@ -490,15 +528,14 @@ int nfs_reschedule_unstable_write(struct nfs_page *req,
490 return 0; 528 return 0;
491} 529}
492#else 530#else
493static inline void 531static void
494nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) 532nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
495{ 533{
496} 534}
497 535
498static inline struct pnfs_layout_segment * 536static void
499nfs_clear_request_commit(struct nfs_page *req) 537nfs_clear_request_commit(struct nfs_page *req)
500{ 538{
501 return NULL;
502} 539}
503 540
504static inline 541static inline
@@ -523,25 +560,23 @@ nfs_need_commit(struct nfs_inode *nfsi)
523} 560}
524 561
525/* i_lock held by caller */ 562/* i_lock held by caller */
526int 563static int
527nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max) 564nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max)
528{ 565{
529 struct nfs_page *req, *tmp; 566 struct nfs_page *req, *tmp;
530 int ret = 0; 567 int ret = 0;
531 568
532 list_for_each_entry_safe(req, tmp, src, wb_list) { 569 list_for_each_entry_safe(req, tmp, src, wb_list) {
533 if (nfs_lock_request_dontget(req)) { 570 if (!nfs_lock_request(req))
534 kref_get(&req->wb_kref); 571 continue;
535 list_move_tail(&req->wb_list, dst); 572 nfs_request_remove_commit_list(req);
536 clear_bit(PG_CLEAN, &(req)->wb_flags); 573 nfs_list_add_request(req, dst);
537 ret++; 574 ret++;
538 if (ret == max) 575 if (ret == max)
539 break; 576 break;
540 }
541 } 577 }
542 return ret; 578 return ret;
543} 579}
544EXPORT_SYMBOL_GPL(nfs_scan_commit_list);
545 580
546/* 581/*
547 * nfs_scan_commit - Scan an inode for commit requests 582 * nfs_scan_commit - Scan an inode for commit requests
@@ -559,14 +594,12 @@ nfs_scan_commit(struct inode *inode, struct list_head *dst)
559 594
560 spin_lock(&inode->i_lock); 595 spin_lock(&inode->i_lock);
561 if (nfsi->ncommit > 0) { 596 if (nfsi->ncommit > 0) {
597 const int max = INT_MAX;
562 int pnfs_ret; 598 int pnfs_ret;
563 599
564 ret = nfs_scan_commit_list(&nfsi->commit_list, dst, INT_MAX); 600 ret = nfs_scan_commit_list(&nfsi->commit_list, dst, max);
565 pnfs_ret = pnfs_scan_commit_lists(inode, INT_MAX - ret); 601 pnfs_ret = pnfs_scan_commit_lists(inode, max - ret);
566 if (pnfs_ret) { 602 ret += pnfs_ret;
567 ret += pnfs_ret;
568 set_bit(NFS_INO_PNFS_COMMIT, &nfsi->flags);
569 }
570 nfsi->ncommit -= ret; 603 nfsi->ncommit -= ret;
571 } 604 }
572 spin_unlock(&inode->i_lock); 605 spin_unlock(&inode->i_lock);
@@ -601,7 +634,6 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
601 unsigned int rqend; 634 unsigned int rqend;
602 unsigned int end; 635 unsigned int end;
603 int error; 636 int error;
604 struct pnfs_layout_segment *lseg = NULL;
605 637
606 if (!PagePrivate(page)) 638 if (!PagePrivate(page))
607 return NULL; 639 return NULL;
@@ -637,8 +669,6 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
637 spin_lock(&inode->i_lock); 669 spin_lock(&inode->i_lock);
638 } 670 }
639 671
640 lseg = nfs_clear_request_commit(req);
641
642 /* Okay, the request matches. Update the region */ 672 /* Okay, the request matches. Update the region */
643 if (offset < req->wb_offset) { 673 if (offset < req->wb_offset) {
644 req->wb_offset = offset; 674 req->wb_offset = offset;
@@ -650,7 +680,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
650 req->wb_bytes = rqend - req->wb_offset; 680 req->wb_bytes = rqend - req->wb_offset;
651out_unlock: 681out_unlock:
652 spin_unlock(&inode->i_lock); 682 spin_unlock(&inode->i_lock);
653 put_lseg(lseg); 683 nfs_clear_request_commit(req);
654 return req; 684 return req;
655out_flushme: 685out_flushme:
656 spin_unlock(&inode->i_lock); 686 spin_unlock(&inode->i_lock);
@@ -1337,7 +1367,6 @@ void nfs_commitdata_release(void *data)
1337{ 1367{
1338 struct nfs_write_data *wdata = data; 1368 struct nfs_write_data *wdata = data;
1339 1369
1340 put_lseg(wdata->lseg);
1341 put_nfs_open_context(wdata->args.context); 1370 put_nfs_open_context(wdata->args.context);
1342 nfs_commit_free(wdata); 1371 nfs_commit_free(wdata);
1343} 1372}
@@ -1647,6 +1676,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
1647 if (req == NULL) 1676 if (req == NULL)
1648 break; 1677 break;
1649 if (nfs_lock_request_dontget(req)) { 1678 if (nfs_lock_request_dontget(req)) {
1679 nfs_clear_request_commit(req);
1650 nfs_inode_remove_request(req); 1680 nfs_inode_remove_request(req);
1651 /* 1681 /*
1652 * In case nfs_inode_remove_request has marked the 1682 * In case nfs_inode_remove_request has marked the