aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-07-27 16:23:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-07-27 16:23:02 -0400
commit28890d3598c352ae065b560e0fded3e79c800ba1 (patch)
tree93267c5b29b9e81185e66a6c2e70e67dc626b63f /fs/nfs/write.c
parent91d41fdf31f74e6e2e5f3cb018eca4200e36e202 (diff)
parented1e6211a0a134ff23592c6f057af982ad5dab52 (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.c156
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
100static void nfs_writedata_release(struct nfs_write_data *wdata) 100void 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 */
848static int nfs_write_rpcsetup(struct nfs_page *req, 848static 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 && 888static 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
897static 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 */
910static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) 934static 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
972out_bad: 971out_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 */
990static int nfs_flush_one(struct nfs_pageio_descriptor *desc) 989static 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;
1030out: 1026out:
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
1036static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, 1030int 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
1037static 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
1049static 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
1054static 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
1061void 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}
1066EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
1040 1067
1041 if (wsize < PAGE_CACHE_SIZE) 1068static 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/*