diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-27 16:23:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-27 16:23:02 -0400 |
commit | 28890d3598c352ae065b560e0fded3e79c800ba1 (patch) | |
tree | 93267c5b29b9e81185e66a6c2e70e67dc626b63f /fs/nfs/write.c | |
parent | 91d41fdf31f74e6e2e5f3cb018eca4200e36e202 (diff) | |
parent | ed1e6211a0a134ff23592c6f057af982ad5dab52 (diff) |
Merge branch 'nfs-for-3.1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
* 'nfs-for-3.1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (44 commits)
NFSv4: Don't use the delegation->inode in nfs_mark_return_delegation()
nfs: don't use d_move in nfs_async_rename_done
RDMA: Increasing RPCRDMA_MAX_DATA_SEGS
SUNRPC: Replace xprt->resend and xprt->sending with a priority queue
SUNRPC: Allow caller of rpc_sleep_on() to select priority levels
SUNRPC: Support dynamic slot allocation for TCP connections
SUNRPC: Clean up the slot table allocation
SUNRPC: Initalise the struct xprt upon allocation
SUNRPC: Ensure that we grab the XPRT_LOCK before calling xprt_alloc_slot
pnfs: simplify pnfs files module autoloading
nfs: document nfsv4 sillyrename issues
NFS: Convert nfs4_set_ds_client to EXPORT_SYMBOL_GPL
SUNRPC: Convert the backchannel exports to EXPORT_SYMBOL_GPL
SUNRPC: sunrpc should not explicitly depend on NFS config options
NFS: Clean up - simplify the switch to read/write-through-MDS
NFS: Move the pnfs write code into pnfs.c
NFS: Move the pnfs read code into pnfs.c
NFS: Allow the nfs_pageio_descriptor to signal that a re-coalesce is needed
NFS: Use the nfs_pageio_descriptor->pg_bsize in the read/write request
NFS: Cache rpc_ops in struct nfs_pageio_descriptor
...
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 156 |
1 files changed, 92 insertions, 64 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 00e37501fa3b..b39b37f80913 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -97,7 +97,7 @@ void nfs_writedata_free(struct nfs_write_data *p) | |||
97 | mempool_free(p, nfs_wdata_mempool); | 97 | mempool_free(p, nfs_wdata_mempool); |
98 | } | 98 | } |
99 | 99 | ||
100 | static void nfs_writedata_release(struct nfs_write_data *wdata) | 100 | void nfs_writedata_release(struct nfs_write_data *wdata) |
101 | { | 101 | { |
102 | put_lseg(wdata->lseg); | 102 | put_lseg(wdata->lseg); |
103 | put_nfs_open_context(wdata->args.context); | 103 | put_nfs_open_context(wdata->args.context); |
@@ -845,11 +845,9 @@ EXPORT_SYMBOL_GPL(nfs_initiate_write); | |||
845 | /* | 845 | /* |
846 | * Set up the argument/result storage required for the RPC call. | 846 | * Set up the argument/result storage required for the RPC call. |
847 | */ | 847 | */ |
848 | static int nfs_write_rpcsetup(struct nfs_page *req, | 848 | static void nfs_write_rpcsetup(struct nfs_page *req, |
849 | struct nfs_write_data *data, | 849 | struct nfs_write_data *data, |
850 | const struct rpc_call_ops *call_ops, | ||
851 | unsigned int count, unsigned int offset, | 850 | unsigned int count, unsigned int offset, |
852 | struct pnfs_layout_segment *lseg, | ||
853 | int how) | 851 | int how) |
854 | { | 852 | { |
855 | struct inode *inode = req->wb_context->dentry->d_inode; | 853 | struct inode *inode = req->wb_context->dentry->d_inode; |
@@ -860,7 +858,6 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
860 | data->req = req; | 858 | data->req = req; |
861 | data->inode = inode = req->wb_context->dentry->d_inode; | 859 | data->inode = inode = req->wb_context->dentry->d_inode; |
862 | data->cred = req->wb_context->cred; | 860 | data->cred = req->wb_context->cred; |
863 | data->lseg = get_lseg(lseg); | ||
864 | 861 | ||
865 | data->args.fh = NFS_FH(inode); | 862 | data->args.fh = NFS_FH(inode); |
866 | data->args.offset = req_offset(req) + offset; | 863 | data->args.offset = req_offset(req) + offset; |
@@ -872,24 +869,51 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
872 | data->args.context = get_nfs_open_context(req->wb_context); | 869 | data->args.context = get_nfs_open_context(req->wb_context); |
873 | data->args.lock_context = req->wb_lock_context; | 870 | data->args.lock_context = req->wb_lock_context; |
874 | data->args.stable = NFS_UNSTABLE; | 871 | data->args.stable = NFS_UNSTABLE; |
875 | if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { | 872 | switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { |
876 | data->args.stable = NFS_DATA_SYNC; | 873 | case 0: |
877 | if (!nfs_need_commit(NFS_I(inode))) | 874 | break; |
878 | data->args.stable = NFS_FILE_SYNC; | 875 | case FLUSH_COND_STABLE: |
876 | if (nfs_need_commit(NFS_I(inode))) | ||
877 | break; | ||
878 | default: | ||
879 | data->args.stable = NFS_FILE_SYNC; | ||
879 | } | 880 | } |
880 | 881 | ||
881 | data->res.fattr = &data->fattr; | 882 | data->res.fattr = &data->fattr; |
882 | data->res.count = count; | 883 | data->res.count = count; |
883 | data->res.verf = &data->verf; | 884 | data->res.verf = &data->verf; |
884 | nfs_fattr_init(&data->fattr); | 885 | nfs_fattr_init(&data->fattr); |
886 | } | ||
885 | 887 | ||
886 | if (data->lseg && | 888 | static int nfs_do_write(struct nfs_write_data *data, |
887 | (pnfs_try_to_write_data(data, call_ops, how) == PNFS_ATTEMPTED)) | 889 | const struct rpc_call_ops *call_ops, |
888 | return 0; | 890 | int how) |
891 | { | ||
892 | struct inode *inode = data->args.context->dentry->d_inode; | ||
889 | 893 | ||
890 | return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how); | 894 | return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how); |
891 | } | 895 | } |
892 | 896 | ||
897 | static int nfs_do_multiple_writes(struct list_head *head, | ||
898 | const struct rpc_call_ops *call_ops, | ||
899 | int how) | ||
900 | { | ||
901 | struct nfs_write_data *data; | ||
902 | int ret = 0; | ||
903 | |||
904 | while (!list_empty(head)) { | ||
905 | int ret2; | ||
906 | |||
907 | data = list_entry(head->next, struct nfs_write_data, list); | ||
908 | list_del_init(&data->list); | ||
909 | |||
910 | ret2 = nfs_do_write(data, call_ops, how); | ||
911 | if (ret == 0) | ||
912 | ret = ret2; | ||
913 | } | ||
914 | return ret; | ||
915 | } | ||
916 | |||
893 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 917 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
894 | * call this on each, which will prepare them to be retried on next | 918 | * call this on each, which will prepare them to be retried on next |
895 | * writeback using standard nfs. | 919 | * writeback using standard nfs. |
@@ -907,17 +931,15 @@ static void nfs_redirty_request(struct nfs_page *req) | |||
907 | * Generate multiple small requests to write out a single | 931 | * Generate multiple small requests to write out a single |
908 | * contiguous dirty area on one page. | 932 | * contiguous dirty area on one page. |
909 | */ | 933 | */ |
910 | static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | 934 | static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head *res) |
911 | { | 935 | { |
912 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); | 936 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); |
913 | struct page *page = req->wb_page; | 937 | struct page *page = req->wb_page; |
914 | struct nfs_write_data *data; | 938 | struct nfs_write_data *data; |
915 | size_t wsize = NFS_SERVER(desc->pg_inode)->wsize, nbytes; | 939 | size_t wsize = desc->pg_bsize, nbytes; |
916 | unsigned int offset; | 940 | unsigned int offset; |
917 | int requests = 0; | 941 | int requests = 0; |
918 | int ret = 0; | 942 | int ret = 0; |
919 | struct pnfs_layout_segment *lseg; | ||
920 | LIST_HEAD(list); | ||
921 | 943 | ||
922 | nfs_list_remove_request(req); | 944 | nfs_list_remove_request(req); |
923 | 945 | ||
@@ -927,6 +949,7 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
927 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 949 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
928 | 950 | ||
929 | 951 | ||
952 | offset = 0; | ||
930 | nbytes = desc->pg_count; | 953 | nbytes = desc->pg_count; |
931 | do { | 954 | do { |
932 | size_t len = min(nbytes, wsize); | 955 | size_t len = min(nbytes, wsize); |
@@ -934,45 +957,21 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) | |||
934 | data = nfs_writedata_alloc(1); | 957 | data = nfs_writedata_alloc(1); |
935 | if (!data) | 958 | if (!data) |
936 | goto out_bad; | 959 | goto out_bad; |
937 | list_add(&data->pages, &list); | 960 | data->pagevec[0] = page; |
961 | nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags); | ||
962 | list_add(&data->list, res); | ||
938 | requests++; | 963 | requests++; |
939 | nbytes -= len; | 964 | nbytes -= len; |
965 | offset += len; | ||
940 | } while (nbytes != 0); | 966 | } while (nbytes != 0); |
941 | atomic_set(&req->wb_complete, requests); | 967 | atomic_set(&req->wb_complete, requests); |
942 | 968 | desc->pg_rpc_callops = &nfs_write_partial_ops; | |
943 | BUG_ON(desc->pg_lseg); | ||
944 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, | ||
945 | req_offset(req), desc->pg_count, | ||
946 | IOMODE_RW, GFP_NOFS); | ||
947 | ClearPageError(page); | ||
948 | offset = 0; | ||
949 | nbytes = desc->pg_count; | ||
950 | do { | ||
951 | int ret2; | ||
952 | |||
953 | data = list_entry(list.next, struct nfs_write_data, pages); | ||
954 | list_del_init(&data->pages); | ||
955 | |||
956 | data->pagevec[0] = page; | ||
957 | |||
958 | if (nbytes < wsize) | ||
959 | wsize = nbytes; | ||
960 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | ||
961 | wsize, offset, lseg, desc->pg_ioflags); | ||
962 | if (ret == 0) | ||
963 | ret = ret2; | ||
964 | offset += wsize; | ||
965 | nbytes -= wsize; | ||
966 | } while (nbytes != 0); | ||
967 | |||
968 | put_lseg(lseg); | ||
969 | desc->pg_lseg = NULL; | ||
970 | return ret; | 969 | return ret; |
971 | 970 | ||
972 | out_bad: | 971 | out_bad: |
973 | while (!list_empty(&list)) { | 972 | while (!list_empty(res)) { |
974 | data = list_entry(list.next, struct nfs_write_data, pages); | 973 | data = list_entry(res->next, struct nfs_write_data, list); |
975 | list_del(&data->pages); | 974 | list_del(&data->list); |
976 | nfs_writedata_free(data); | 975 | nfs_writedata_free(data); |
977 | } | 976 | } |
978 | nfs_redirty_request(req); | 977 | nfs_redirty_request(req); |
@@ -987,14 +986,13 @@ out_bad: | |||
987 | * This is the case if nfs_updatepage detects a conflicting request | 986 | * This is the case if nfs_updatepage detects a conflicting request |
988 | * that has been written but not committed. | 987 | * that has been written but not committed. |
989 | */ | 988 | */ |
990 | static int nfs_flush_one(struct nfs_pageio_descriptor *desc) | 989 | static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *res) |
991 | { | 990 | { |
992 | struct nfs_page *req; | 991 | struct nfs_page *req; |
993 | struct page **pages; | 992 | struct page **pages; |
994 | struct nfs_write_data *data; | 993 | struct nfs_write_data *data; |
995 | struct list_head *head = &desc->pg_list; | 994 | struct list_head *head = &desc->pg_list; |
996 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | 995 | int ret = 0; |
997 | int ret; | ||
998 | 996 | ||
999 | data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, | 997 | data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, |
1000 | desc->pg_count)); | 998 | desc->pg_count)); |
@@ -1016,32 +1014,62 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc) | |||
1016 | *pages++ = req->wb_page; | 1014 | *pages++ = req->wb_page; |
1017 | } | 1015 | } |
1018 | req = nfs_list_entry(data->pages.next); | 1016 | req = nfs_list_entry(data->pages.next); |
1019 | if ((!lseg) && list_is_singular(&data->pages)) | ||
1020 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, | ||
1021 | req_offset(req), desc->pg_count, | ||
1022 | IOMODE_RW, GFP_NOFS); | ||
1023 | 1017 | ||
1024 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && | 1018 | if ((desc->pg_ioflags & FLUSH_COND_STABLE) && |
1025 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) | 1019 | (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) |
1026 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 1020 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
1027 | 1021 | ||
1028 | /* Set up the argument struct */ | 1022 | /* Set up the argument struct */ |
1029 | ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); | 1023 | nfs_write_rpcsetup(req, data, desc->pg_count, 0, desc->pg_ioflags); |
1024 | list_add(&data->list, res); | ||
1025 | desc->pg_rpc_callops = &nfs_write_full_ops; | ||
1030 | out: | 1026 | out: |
1031 | put_lseg(lseg); /* Cleans any gotten in ->pg_test */ | ||
1032 | desc->pg_lseg = NULL; | ||
1033 | return ret; | 1027 | return ret; |
1034 | } | 1028 | } |
1035 | 1029 | ||
1036 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 1030 | int nfs_generic_flush(struct nfs_pageio_descriptor *desc, struct list_head *head) |
1031 | { | ||
1032 | if (desc->pg_bsize < PAGE_CACHE_SIZE) | ||
1033 | return nfs_flush_multi(desc, head); | ||
1034 | return nfs_flush_one(desc, head); | ||
1035 | } | ||
1036 | |||
1037 | static int nfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) | ||
1038 | { | ||
1039 | LIST_HEAD(head); | ||
1040 | int ret; | ||
1041 | |||
1042 | ret = nfs_generic_flush(desc, &head); | ||
1043 | if (ret == 0) | ||
1044 | ret = nfs_do_multiple_writes(&head, desc->pg_rpc_callops, | ||
1045 | desc->pg_ioflags); | ||
1046 | return ret; | ||
1047 | } | ||
1048 | |||
1049 | static const struct nfs_pageio_ops nfs_pageio_write_ops = { | ||
1050 | .pg_test = nfs_generic_pg_test, | ||
1051 | .pg_doio = nfs_generic_pg_writepages, | ||
1052 | }; | ||
1053 | |||
1054 | static void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, | ||
1037 | struct inode *inode, int ioflags) | 1055 | struct inode *inode, int ioflags) |
1038 | { | 1056 | { |
1039 | size_t wsize = NFS_SERVER(inode)->wsize; | 1057 | nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops, |
1058 | NFS_SERVER(inode)->wsize, ioflags); | ||
1059 | } | ||
1060 | |||
1061 | void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio) | ||
1062 | { | ||
1063 | pgio->pg_ops = &nfs_pageio_write_ops; | ||
1064 | pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize; | ||
1065 | } | ||
1066 | EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds); | ||
1040 | 1067 | ||
1041 | if (wsize < PAGE_CACHE_SIZE) | 1068 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
1042 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); | 1069 | struct inode *inode, int ioflags) |
1043 | else | 1070 | { |
1044 | nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags); | 1071 | if (!pnfs_pageio_init_write(pgio, inode, ioflags)) |
1072 | nfs_pageio_init_write_mds(pgio, inode, ioflags); | ||
1045 | } | 1073 | } |
1046 | 1074 | ||
1047 | /* | 1075 | /* |