diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-15 17:16:40 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-17 11:09:33 -0400 |
commit | 8dd3775889345850ecddd689b5c200cdd91bd8c9 (patch) | |
tree | ea697cfcac3f3a927e90d0048e9ed76b5a3ea8e5 /fs | |
parent | 95a13f7b33be87d85d8e6652126a3f4d64d164db (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.h | 4 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 82 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 3 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 55 | ||||
-rw-r--r-- | fs/nfs/read.c | 1 | ||||
-rw-r--r-- | fs/nfs/write.c | 124 |
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); | |||
308 | extern void nfs_readdata_release(struct nfs_read_data *rdata); | 308 | extern void nfs_readdata_release(struct nfs_read_data *rdata); |
309 | 309 | ||
310 | /* write.c */ | 310 | /* write.c */ |
311 | extern int nfs_scan_commit_list(struct list_head *src, struct list_head *dst, | ||
312 | int max); | ||
313 | extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, | 311 | extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, |
314 | struct list_head *head); | 312 | struct list_head *head); |
315 | extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, | 313 | extern void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, |
@@ -334,6 +332,8 @@ void nfs_retry_commit(struct list_head *page_list, | |||
334 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); | 332 | void nfs_commit_clear_lock(struct nfs_inode *nfsi); |
335 | void nfs_commitdata_release(void *data); | 333 | void nfs_commitdata_release(void *data); |
336 | void nfs_commit_release_pages(struct nfs_write_data *data); | 334 | void nfs_commit_release_pages(struct nfs_write_data *data); |
335 | void nfs_request_add_commit_list(struct nfs_page *req, struct list_head *head); | ||
336 | void nfs_request_remove_commit_list(struct nfs_page *req); | ||
337 | 337 | ||
338 | #ifdef CONFIG_MIGRATION | 338 | #ifdef CONFIG_MIGRATION |
339 | extern int nfs_migrate_page(struct address_space *, | 339 | extern 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 | */ |
784 | static struct pnfs_layout_segment * | 786 | static void |
785 | filelayout_remove_commit_req(struct nfs_page *req) | 787 | filelayout_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; | 809 | out: |
810 | nfs_request_remove_commit_list(req); | ||
811 | spin_unlock(&inode->i_lock); | ||
812 | put_lseg(freeme); | ||
800 | } | 813 | } |
801 | 814 | ||
802 | static struct list_head * | 815 | static 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 | ||
849 | static void | ||
850 | filelayout_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 | |||
835 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | 859 | static 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 | ||
938 | static int | ||
939 | filelayout_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 | } |
936 | out_put: | 979 | out_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 | } |
1215 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); | 1216 | EXPORT_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 | } |
1328 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); | 1331 | EXPORT_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 | ||
272 | static inline struct list_head * | 272 | static inline bool |
273 | pnfs_choose_commit_list(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 273 | pnfs_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 | ||
285 | static inline struct pnfs_layout_segment * | 284 | static inline bool |
286 | pnfs_clear_request_commit(struct nfs_page *req) | 285 | pnfs_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 | ||
297 | static inline int | 296 | static inline int |
298 | pnfs_scan_commit_lists(struct inode *inode, int max) | 297 | pnfs_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 | ||
406 | static inline struct list_head * | 409 | static inline bool |
407 | pnfs_choose_commit_list(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 410 | pnfs_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 | ||
414 | static inline struct pnfs_layout_segment * | 415 | static inline bool |
415 | pnfs_clear_request_commit(struct nfs_page *req) | 416 | pnfs_clear_request_commit(struct nfs_page *req) |
416 | { | 417 | { |
417 | return NULL; | 418 | return false; |
418 | } | 419 | } |
419 | 420 | ||
420 | static inline int | 421 | static 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 | ||
67 | void nfs_readdata_release(struct nfs_read_data *rdata) | 67 | void 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 | ||
101 | void nfs_writedata_release(struct nfs_write_data *wdata) | 101 | void 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 | ||
396 | static 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 | */ |
430 | static void | 433 | void |
431 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 434 | nfs_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 | } |
447 | EXPORT_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 | */ | ||
459 | void | ||
460 | nfs_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 | } | ||
469 | EXPORT_SYMBOL_GPL(nfs_request_remove_commit_list); | ||
470 | |||
471 | |||
472 | /* | ||
473 | * Add a request to the inode's commit list. | ||
474 | */ | ||
475 | static void | ||
476 | nfs_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 | ||
448 | static void | 485 | static void |
449 | nfs_clear_page_commit(struct page *page) | 486 | nfs_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 | ||
455 | static struct pnfs_layout_segment * | 492 | static void |
456 | nfs_clear_request_commit(struct nfs_page *req) | 493 | nfs_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 | ||
469 | static inline | 507 | static 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 |
493 | static inline void | 531 | static void |
494 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) | 532 | nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg) |
495 | { | 533 | { |
496 | } | 534 | } |
497 | 535 | ||
498 | static inline struct pnfs_layout_segment * | 536 | static void |
499 | nfs_clear_request_commit(struct nfs_page *req) | 537 | nfs_clear_request_commit(struct nfs_page *req) |
500 | { | 538 | { |
501 | return NULL; | ||
502 | } | 539 | } |
503 | 540 | ||
504 | static inline | 541 | static 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 */ |
526 | int | 563 | static int |
527 | nfs_scan_commit_list(struct list_head *src, struct list_head *dst, int max) | 564 | nfs_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 | } |
544 | EXPORT_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; |
651 | out_unlock: | 681 | out_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; |
655 | out_flushme: | 685 | out_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 |