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/nfs/nfs4filelayout.c | |
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/nfs/nfs4filelayout.c')
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 82 |
1 files changed, 62 insertions, 20 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 379a085f8f2..c24e077c282 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, |