diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 155 |
1 files changed, 97 insertions, 58 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index c8278f4046c..47a3ad63e0d 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "iostat.h" | 28 | #include "iostat.h" |
29 | #include "nfs4_fs.h" | 29 | #include "nfs4_fs.h" |
30 | #include "fscache.h" | 30 | #include "fscache.h" |
31 | #include "pnfs.h" | ||
31 | 32 | ||
32 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE | 33 | #define NFSDBG_FACILITY NFSDBG_PAGECACHE |
33 | 34 | ||
@@ -96,6 +97,7 @@ void nfs_writedata_free(struct nfs_write_data *p) | |||
96 | 97 | ||
97 | static void nfs_writedata_release(struct nfs_write_data *wdata) | 98 | static void nfs_writedata_release(struct nfs_write_data *wdata) |
98 | { | 99 | { |
100 | put_lseg(wdata->lseg); | ||
99 | put_nfs_open_context(wdata->args.context); | 101 | put_nfs_open_context(wdata->args.context); |
100 | nfs_writedata_free(wdata); | 102 | nfs_writedata_free(wdata); |
101 | } | 103 | } |
@@ -781,25 +783,21 @@ static int flush_task_priority(int how) | |||
781 | return RPC_PRIORITY_NORMAL; | 783 | return RPC_PRIORITY_NORMAL; |
782 | } | 784 | } |
783 | 785 | ||
784 | /* | 786 | int nfs_initiate_write(struct nfs_write_data *data, |
785 | * Set up the argument/result storage required for the RPC call. | 787 | struct rpc_clnt *clnt, |
786 | */ | 788 | const struct rpc_call_ops *call_ops, |
787 | static int nfs_write_rpcsetup(struct nfs_page *req, | 789 | int how) |
788 | struct nfs_write_data *data, | ||
789 | const struct rpc_call_ops *call_ops, | ||
790 | unsigned int count, unsigned int offset, | ||
791 | int how) | ||
792 | { | 790 | { |
793 | struct inode *inode = req->wb_context->path.dentry->d_inode; | 791 | struct inode *inode = data->inode; |
794 | int priority = flush_task_priority(how); | 792 | int priority = flush_task_priority(how); |
795 | struct rpc_task *task; | 793 | struct rpc_task *task; |
796 | struct rpc_message msg = { | 794 | struct rpc_message msg = { |
797 | .rpc_argp = &data->args, | 795 | .rpc_argp = &data->args, |
798 | .rpc_resp = &data->res, | 796 | .rpc_resp = &data->res, |
799 | .rpc_cred = req->wb_context->cred, | 797 | .rpc_cred = data->cred, |
800 | }; | 798 | }; |
801 | struct rpc_task_setup task_setup_data = { | 799 | struct rpc_task_setup task_setup_data = { |
802 | .rpc_client = NFS_CLIENT(inode), | 800 | .rpc_client = clnt, |
803 | .task = &data->task, | 801 | .task = &data->task, |
804 | .rpc_message = &msg, | 802 | .rpc_message = &msg, |
805 | .callback_ops = call_ops, | 803 | .callback_ops = call_ops, |
@@ -810,12 +808,52 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
810 | }; | 808 | }; |
811 | int ret = 0; | 809 | int ret = 0; |
812 | 810 | ||
811 | /* Set up the initial task struct. */ | ||
812 | NFS_PROTO(inode)->write_setup(data, &msg); | ||
813 | |||
814 | dprintk("NFS: %5u initiated write call " | ||
815 | "(req %s/%lld, %u bytes @ offset %llu)\n", | ||
816 | data->task.tk_pid, | ||
817 | inode->i_sb->s_id, | ||
818 | (long long)NFS_FILEID(inode), | ||
819 | data->args.count, | ||
820 | (unsigned long long)data->args.offset); | ||
821 | |||
822 | task = rpc_run_task(&task_setup_data); | ||
823 | if (IS_ERR(task)) { | ||
824 | ret = PTR_ERR(task); | ||
825 | goto out; | ||
826 | } | ||
827 | if (how & FLUSH_SYNC) { | ||
828 | ret = rpc_wait_for_completion_task(task); | ||
829 | if (ret == 0) | ||
830 | ret = task->tk_status; | ||
831 | } | ||
832 | rpc_put_task(task); | ||
833 | out: | ||
834 | return ret; | ||
835 | } | ||
836 | EXPORT_SYMBOL_GPL(nfs_initiate_write); | ||
837 | |||
838 | /* | ||
839 | * Set up the argument/result storage required for the RPC call. | ||
840 | */ | ||
841 | static int nfs_write_rpcsetup(struct nfs_page *req, | ||
842 | struct nfs_write_data *data, | ||
843 | const struct rpc_call_ops *call_ops, | ||
844 | unsigned int count, unsigned int offset, | ||
845 | struct pnfs_layout_segment *lseg, | ||
846 | int how) | ||
847 | { | ||
848 | struct inode *inode = req->wb_context->path.dentry->d_inode; | ||
849 | |||
813 | /* Set up the RPC argument and reply structs | 850 | /* Set up the RPC argument and reply structs |
814 | * NB: take care not to mess about with data->commit et al. */ | 851 | * NB: take care not to mess about with data->commit et al. */ |
815 | 852 | ||
816 | data->req = req; | 853 | data->req = req; |
817 | data->inode = inode = req->wb_context->path.dentry->d_inode; | 854 | data->inode = inode = req->wb_context->path.dentry->d_inode; |
818 | data->cred = msg.rpc_cred; | 855 | data->cred = req->wb_context->cred; |
856 | data->lseg = get_lseg(lseg); | ||
819 | 857 | ||
820 | data->args.fh = NFS_FH(inode); | 858 | data->args.fh = NFS_FH(inode); |
821 | data->args.offset = req_offset(req) + offset; | 859 | data->args.offset = req_offset(req) + offset; |
@@ -836,30 +874,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
836 | data->res.verf = &data->verf; | 874 | data->res.verf = &data->verf; |
837 | nfs_fattr_init(&data->fattr); | 875 | nfs_fattr_init(&data->fattr); |
838 | 876 | ||
839 | /* Set up the initial task struct. */ | 877 | if (data->lseg && |
840 | NFS_PROTO(inode)->write_setup(data, &msg); | 878 | (pnfs_try_to_write_data(data, call_ops, how) == PNFS_ATTEMPTED)) |
841 | 879 | return 0; | |
842 | dprintk("NFS: %5u initiated write call " | ||
843 | "(req %s/%lld, %u bytes @ offset %llu)\n", | ||
844 | data->task.tk_pid, | ||
845 | inode->i_sb->s_id, | ||
846 | (long long)NFS_FILEID(inode), | ||
847 | count, | ||
848 | (unsigned long long)data->args.offset); | ||
849 | 880 | ||
850 | task = rpc_run_task(&task_setup_data); | 881 | return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how); |
851 | if (IS_ERR(task)) { | ||
852 | ret = PTR_ERR(task); | ||
853 | goto out; | ||
854 | } | ||
855 | if (how & FLUSH_SYNC) { | ||
856 | ret = rpc_wait_for_completion_task(task); | ||
857 | if (ret == 0) | ||
858 | ret = task->tk_status; | ||
859 | } | ||
860 | rpc_put_task(task); | ||
861 | out: | ||
862 | return ret; | ||
863 | } | 882 | } |
864 | 883 | ||
865 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 884 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
@@ -879,20 +898,21 @@ static void nfs_redirty_request(struct nfs_page *req) | |||
879 | * Generate multiple small requests to write out a single | 898 | * Generate multiple small requests to write out a single |
880 | * contiguous dirty area on one page. | 899 | * contiguous dirty area on one page. |
881 | */ | 900 | */ |
882 | static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) | 901 | static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) |
883 | { | 902 | { |
884 | struct nfs_page *req = nfs_list_entry(head->next); | 903 | struct nfs_page *req = nfs_list_entry(desc->pg_list.next); |
885 | struct page *page = req->wb_page; | 904 | struct page *page = req->wb_page; |
886 | struct nfs_write_data *data; | 905 | struct nfs_write_data *data; |
887 | size_t wsize = NFS_SERVER(inode)->wsize, nbytes; | 906 | size_t wsize = NFS_SERVER(desc->pg_inode)->wsize, nbytes; |
888 | unsigned int offset; | 907 | unsigned int offset; |
889 | int requests = 0; | 908 | int requests = 0; |
890 | int ret = 0; | 909 | int ret = 0; |
910 | struct pnfs_layout_segment *lseg; | ||
891 | LIST_HEAD(list); | 911 | LIST_HEAD(list); |
892 | 912 | ||
893 | nfs_list_remove_request(req); | 913 | nfs_list_remove_request(req); |
894 | 914 | ||
895 | nbytes = count; | 915 | nbytes = desc->pg_count; |
896 | do { | 916 | do { |
897 | size_t len = min(nbytes, wsize); | 917 | size_t len = min(nbytes, wsize); |
898 | 918 | ||
@@ -905,9 +925,11 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
905 | } while (nbytes != 0); | 925 | } while (nbytes != 0); |
906 | atomic_set(&req->wb_complete, requests); | 926 | atomic_set(&req->wb_complete, requests); |
907 | 927 | ||
928 | BUG_ON(desc->pg_lseg); | ||
929 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); | ||
908 | ClearPageError(page); | 930 | ClearPageError(page); |
909 | offset = 0; | 931 | offset = 0; |
910 | nbytes = count; | 932 | nbytes = desc->pg_count; |
911 | do { | 933 | do { |
912 | int ret2; | 934 | int ret2; |
913 | 935 | ||
@@ -919,13 +941,15 @@ static int nfs_flush_multi(struct inode *inode, struct list_head *head, unsigned | |||
919 | if (nbytes < wsize) | 941 | if (nbytes < wsize) |
920 | wsize = nbytes; | 942 | wsize = nbytes; |
921 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, | 943 | ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
922 | wsize, offset, how); | 944 | wsize, offset, lseg, desc->pg_ioflags); |
923 | if (ret == 0) | 945 | if (ret == 0) |
924 | ret = ret2; | 946 | ret = ret2; |
925 | offset += wsize; | 947 | offset += wsize; |
926 | nbytes -= wsize; | 948 | nbytes -= wsize; |
927 | } while (nbytes != 0); | 949 | } while (nbytes != 0); |
928 | 950 | ||
951 | put_lseg(lseg); | ||
952 | desc->pg_lseg = NULL; | ||
929 | return ret; | 953 | return ret; |
930 | 954 | ||
931 | out_bad: | 955 | out_bad: |
@@ -946,16 +970,26 @@ out_bad: | |||
946 | * This is the case if nfs_updatepage detects a conflicting request | 970 | * This is the case if nfs_updatepage detects a conflicting request |
947 | * that has been written but not committed. | 971 | * that has been written but not committed. |
948 | */ | 972 | */ |
949 | static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned int npages, size_t count, int how) | 973 | static int nfs_flush_one(struct nfs_pageio_descriptor *desc) |
950 | { | 974 | { |
951 | struct nfs_page *req; | 975 | struct nfs_page *req; |
952 | struct page **pages; | 976 | struct page **pages; |
953 | struct nfs_write_data *data; | 977 | struct nfs_write_data *data; |
978 | struct list_head *head = &desc->pg_list; | ||
979 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | ||
980 | int ret; | ||
954 | 981 | ||
955 | data = nfs_writedata_alloc(npages); | 982 | data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, |
956 | if (!data) | 983 | desc->pg_count)); |
957 | goto out_bad; | 984 | if (!data) { |
958 | 985 | while (!list_empty(head)) { | |
986 | req = nfs_list_entry(head->next); | ||
987 | nfs_list_remove_request(req); | ||
988 | nfs_redirty_request(req); | ||
989 | } | ||
990 | ret = -ENOMEM; | ||
991 | goto out; | ||
992 | } | ||
959 | pages = data->pagevec; | 993 | pages = data->pagevec; |
960 | while (!list_empty(head)) { | 994 | while (!list_empty(head)) { |
961 | req = nfs_list_entry(head->next); | 995 | req = nfs_list_entry(head->next); |
@@ -965,16 +999,15 @@ static int nfs_flush_one(struct inode *inode, struct list_head *head, unsigned i | |||
965 | *pages++ = req->wb_page; | 999 | *pages++ = req->wb_page; |
966 | } | 1000 | } |
967 | req = nfs_list_entry(data->pages.next); | 1001 | req = nfs_list_entry(data->pages.next); |
1002 | if ((!lseg) && list_is_singular(&data->pages)) | ||
1003 | lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, IOMODE_RW); | ||
968 | 1004 | ||
969 | /* Set up the argument struct */ | 1005 | /* Set up the argument struct */ |
970 | return nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); | 1006 | ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); |
971 | out_bad: | 1007 | out: |
972 | while (!list_empty(head)) { | 1008 | put_lseg(lseg); /* Cleans any gotten in ->pg_test */ |
973 | req = nfs_list_entry(head->next); | 1009 | desc->pg_lseg = NULL; |
974 | nfs_list_remove_request(req); | 1010 | return ret; |
975 | nfs_redirty_request(req); | ||
976 | } | ||
977 | return -ENOMEM; | ||
978 | } | 1011 | } |
979 | 1012 | ||
980 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 1013 | static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
@@ -982,6 +1015,8 @@ static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | |||
982 | { | 1015 | { |
983 | size_t wsize = NFS_SERVER(inode)->wsize; | 1016 | size_t wsize = NFS_SERVER(inode)->wsize; |
984 | 1017 | ||
1018 | pnfs_pageio_init_write(pgio, inode); | ||
1019 | |||
985 | if (wsize < PAGE_CACHE_SIZE) | 1020 | if (wsize < PAGE_CACHE_SIZE) |
986 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); | 1021 | nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); |
987 | else | 1022 | else |
@@ -1132,7 +1167,7 @@ static const struct rpc_call_ops nfs_write_full_ops = { | |||
1132 | /* | 1167 | /* |
1133 | * This function is called when the WRITE call is complete. | 1168 | * This function is called when the WRITE call is complete. |
1134 | */ | 1169 | */ |
1135 | int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | 1170 | void nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) |
1136 | { | 1171 | { |
1137 | struct nfs_writeargs *argp = &data->args; | 1172 | struct nfs_writeargs *argp = &data->args; |
1138 | struct nfs_writeres *resp = &data->res; | 1173 | struct nfs_writeres *resp = &data->res; |
@@ -1151,7 +1186,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1151 | */ | 1186 | */ |
1152 | status = NFS_PROTO(data->inode)->write_done(task, data); | 1187 | status = NFS_PROTO(data->inode)->write_done(task, data); |
1153 | if (status != 0) | 1188 | if (status != 0) |
1154 | return status; | 1189 | return; |
1155 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); | 1190 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); |
1156 | 1191 | ||
1157 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1192 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -1166,6 +1201,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1166 | */ | 1201 | */ |
1167 | static unsigned long complain; | 1202 | static unsigned long complain; |
1168 | 1203 | ||
1204 | /* Note this will print the MDS for a DS write */ | ||
1169 | if (time_before(complain, jiffies)) { | 1205 | if (time_before(complain, jiffies)) { |
1170 | dprintk("NFS: faulty NFS server %s:" | 1206 | dprintk("NFS: faulty NFS server %s:" |
1171 | " (committed = %d) != (stable = %d)\n", | 1207 | " (committed = %d) != (stable = %d)\n", |
@@ -1186,6 +1222,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1186 | /* Was this an NFSv2 write or an NFSv3 stable write? */ | 1222 | /* Was this an NFSv2 write or an NFSv3 stable write? */ |
1187 | if (resp->verf->committed != NFS_UNSTABLE) { | 1223 | if (resp->verf->committed != NFS_UNSTABLE) { |
1188 | /* Resend from where the server left off */ | 1224 | /* Resend from where the server left off */ |
1225 | data->mds_offset += resp->count; | ||
1189 | argp->offset += resp->count; | 1226 | argp->offset += resp->count; |
1190 | argp->pgbase += resp->count; | 1227 | argp->pgbase += resp->count; |
1191 | argp->count -= resp->count; | 1228 | argp->count -= resp->count; |
@@ -1196,7 +1233,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1196 | argp->stable = NFS_FILE_SYNC; | 1233 | argp->stable = NFS_FILE_SYNC; |
1197 | } | 1234 | } |
1198 | nfs_restart_rpc(task, server->nfs_client); | 1235 | nfs_restart_rpc(task, server->nfs_client); |
1199 | return -EAGAIN; | 1236 | return; |
1200 | } | 1237 | } |
1201 | if (time_before(complain, jiffies)) { | 1238 | if (time_before(complain, jiffies)) { |
1202 | printk(KERN_WARNING | 1239 | printk(KERN_WARNING |
@@ -1207,7 +1244,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) | |||
1207 | /* Can't do anything about it except throw an error. */ | 1244 | /* Can't do anything about it except throw an error. */ |
1208 | task->tk_status = -EIO; | 1245 | task->tk_status = -EIO; |
1209 | } | 1246 | } |
1210 | return 0; | 1247 | return; |
1211 | } | 1248 | } |
1212 | 1249 | ||
1213 | 1250 | ||
@@ -1292,6 +1329,8 @@ static int nfs_commit_rpcsetup(struct list_head *head, | |||
1292 | task = rpc_run_task(&task_setup_data); | 1329 | task = rpc_run_task(&task_setup_data); |
1293 | if (IS_ERR(task)) | 1330 | if (IS_ERR(task)) |
1294 | return PTR_ERR(task); | 1331 | return PTR_ERR(task); |
1332 | if (how & FLUSH_SYNC) | ||
1333 | rpc_wait_for_completion_task(task); | ||
1295 | rpc_put_task(task); | 1334 | rpc_put_task(task); |
1296 | return 0; | 1335 | return 0; |
1297 | } | 1336 | } |