diff options
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r-- | fs/nfs/write.c | 92 |
1 files changed, 66 insertions, 26 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e7c8361cf201..5912274ff1a1 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -77,12 +77,14 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context*, | |||
77 | struct inode *, | 77 | struct inode *, |
78 | struct page *, | 78 | struct page *, |
79 | unsigned int, unsigned int); | 79 | unsigned int, unsigned int); |
80 | static void nfs_writeback_done_partial(struct nfs_write_data *, int); | 80 | static int nfs_writeback_done(struct rpc_task *, struct nfs_write_data *); |
81 | static void nfs_writeback_done_full(struct nfs_write_data *, int); | ||
82 | static int nfs_wait_on_write_congestion(struct address_space *, int); | 81 | static int nfs_wait_on_write_congestion(struct address_space *, int); |
83 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); | 82 | static int nfs_wait_on_requests(struct inode *, unsigned long, unsigned int); |
84 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 83 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, |
85 | unsigned int npages, int how); | 84 | unsigned int npages, int how); |
85 | static const struct rpc_call_ops nfs_write_partial_ops; | ||
86 | static const struct rpc_call_ops nfs_write_full_ops; | ||
87 | static const struct rpc_call_ops nfs_commit_ops; | ||
86 | 88 | ||
87 | static kmem_cache_t *nfs_wdata_cachep; | 89 | static kmem_cache_t *nfs_wdata_cachep; |
88 | mempool_t *nfs_wdata_mempool; | 90 | mempool_t *nfs_wdata_mempool; |
@@ -872,10 +874,12 @@ static inline int flush_task_priority(int how) | |||
872 | */ | 874 | */ |
873 | static void nfs_write_rpcsetup(struct nfs_page *req, | 875 | static void nfs_write_rpcsetup(struct nfs_page *req, |
874 | struct nfs_write_data *data, | 876 | struct nfs_write_data *data, |
877 | const struct rpc_call_ops *call_ops, | ||
875 | unsigned int count, unsigned int offset, | 878 | unsigned int count, unsigned int offset, |
876 | int how) | 879 | int how) |
877 | { | 880 | { |
878 | struct inode *inode; | 881 | struct inode *inode; |
882 | int flags; | ||
879 | 883 | ||
880 | /* Set up the RPC argument and reply structs | 884 | /* Set up the RPC argument and reply structs |
881 | * NB: take care not to mess about with data->commit et al. */ | 885 | * NB: take care not to mess about with data->commit et al. */ |
@@ -896,6 +900,9 @@ static void nfs_write_rpcsetup(struct nfs_page *req, | |||
896 | data->res.verf = &data->verf; | 900 | data->res.verf = &data->verf; |
897 | nfs_fattr_init(&data->fattr); | 901 | nfs_fattr_init(&data->fattr); |
898 | 902 | ||
903 | /* Set up the initial task struct. */ | ||
904 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
905 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, call_ops, data); | ||
899 | NFS_PROTO(inode)->write_setup(data, how); | 906 | NFS_PROTO(inode)->write_setup(data, how); |
900 | 907 | ||
901 | data->task.tk_priority = flush_task_priority(how); | 908 | data->task.tk_priority = flush_task_priority(how); |
@@ -959,14 +966,15 @@ static int nfs_flush_multi(struct list_head *head, struct inode *inode, int how) | |||
959 | list_del_init(&data->pages); | 966 | list_del_init(&data->pages); |
960 | 967 | ||
961 | data->pagevec[0] = page; | 968 | data->pagevec[0] = page; |
962 | data->complete = nfs_writeback_done_partial; | ||
963 | 969 | ||
964 | if (nbytes > wsize) { | 970 | if (nbytes > wsize) { |
965 | nfs_write_rpcsetup(req, data, wsize, offset, how); | 971 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
972 | wsize, offset, how); | ||
966 | offset += wsize; | 973 | offset += wsize; |
967 | nbytes -= wsize; | 974 | nbytes -= wsize; |
968 | } else { | 975 | } else { |
969 | nfs_write_rpcsetup(req, data, nbytes, offset, how); | 976 | nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, |
977 | nbytes, offset, how); | ||
970 | nbytes = 0; | 978 | nbytes = 0; |
971 | } | 979 | } |
972 | nfs_execute_write(data); | 980 | nfs_execute_write(data); |
@@ -1020,9 +1028,8 @@ static int nfs_flush_one(struct list_head *head, struct inode *inode, int how) | |||
1020 | } | 1028 | } |
1021 | req = nfs_list_entry(data->pages.next); | 1029 | req = nfs_list_entry(data->pages.next); |
1022 | 1030 | ||
1023 | data->complete = nfs_writeback_done_full; | ||
1024 | /* Set up the argument struct */ | 1031 | /* Set up the argument struct */ |
1025 | nfs_write_rpcsetup(req, data, count, 0, how); | 1032 | nfs_write_rpcsetup(req, data, &nfs_write_full_ops, count, 0, how); |
1026 | 1033 | ||
1027 | nfs_execute_write(data); | 1034 | nfs_execute_write(data); |
1028 | return 0; | 1035 | return 0; |
@@ -1066,8 +1073,9 @@ nfs_flush_list(struct list_head *head, int wpages, int how) | |||
1066 | /* | 1073 | /* |
1067 | * Handle a write reply that flushed part of a page. | 1074 | * Handle a write reply that flushed part of a page. |
1068 | */ | 1075 | */ |
1069 | static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | 1076 | static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) |
1070 | { | 1077 | { |
1078 | struct nfs_write_data *data = calldata; | ||
1071 | struct nfs_page *req = data->req; | 1079 | struct nfs_page *req = data->req; |
1072 | struct page *page = req->wb_page; | 1080 | struct page *page = req->wb_page; |
1073 | 1081 | ||
@@ -1077,11 +1085,14 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1077 | req->wb_bytes, | 1085 | req->wb_bytes, |
1078 | (long long)req_offset(req)); | 1086 | (long long)req_offset(req)); |
1079 | 1087 | ||
1080 | if (status < 0) { | 1088 | if (nfs_writeback_done(task, data) != 0) |
1089 | return; | ||
1090 | |||
1091 | if (task->tk_status < 0) { | ||
1081 | ClearPageUptodate(page); | 1092 | ClearPageUptodate(page); |
1082 | SetPageError(page); | 1093 | SetPageError(page); |
1083 | req->wb_context->error = status; | 1094 | req->wb_context->error = task->tk_status; |
1084 | dprintk(", error = %d\n", status); | 1095 | dprintk(", error = %d\n", task->tk_status); |
1085 | } else { | 1096 | } else { |
1086 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1097 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
1087 | if (data->verf.committed < NFS_FILE_SYNC) { | 1098 | if (data->verf.committed < NFS_FILE_SYNC) { |
@@ -1102,6 +1113,11 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1102 | nfs_writepage_release(req); | 1113 | nfs_writepage_release(req); |
1103 | } | 1114 | } |
1104 | 1115 | ||
1116 | static const struct rpc_call_ops nfs_write_partial_ops = { | ||
1117 | .rpc_call_done = nfs_writeback_done_partial, | ||
1118 | .rpc_release = nfs_writedata_release, | ||
1119 | }; | ||
1120 | |||
1105 | /* | 1121 | /* |
1106 | * Handle a write reply that flushes a whole page. | 1122 | * Handle a write reply that flushes a whole page. |
1107 | * | 1123 | * |
@@ -1109,11 +1125,15 @@ static void nfs_writeback_done_partial(struct nfs_write_data *data, int status) | |||
1109 | * writebacks since the page->count is kept > 1 for as long | 1125 | * writebacks since the page->count is kept > 1 for as long |
1110 | * as the page has a write request pending. | 1126 | * as the page has a write request pending. |
1111 | */ | 1127 | */ |
1112 | static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | 1128 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) |
1113 | { | 1129 | { |
1130 | struct nfs_write_data *data = calldata; | ||
1114 | struct nfs_page *req; | 1131 | struct nfs_page *req; |
1115 | struct page *page; | 1132 | struct page *page; |
1116 | 1133 | ||
1134 | if (nfs_writeback_done(task, data) != 0) | ||
1135 | return; | ||
1136 | |||
1117 | /* Update attributes as result of writeback. */ | 1137 | /* Update attributes as result of writeback. */ |
1118 | while (!list_empty(&data->pages)) { | 1138 | while (!list_empty(&data->pages)) { |
1119 | req = nfs_list_entry(data->pages.next); | 1139 | req = nfs_list_entry(data->pages.next); |
@@ -1126,13 +1146,13 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1126 | req->wb_bytes, | 1146 | req->wb_bytes, |
1127 | (long long)req_offset(req)); | 1147 | (long long)req_offset(req)); |
1128 | 1148 | ||
1129 | if (status < 0) { | 1149 | if (task->tk_status < 0) { |
1130 | ClearPageUptodate(page); | 1150 | ClearPageUptodate(page); |
1131 | SetPageError(page); | 1151 | SetPageError(page); |
1132 | req->wb_context->error = status; | 1152 | req->wb_context->error = task->tk_status; |
1133 | end_page_writeback(page); | 1153 | end_page_writeback(page); |
1134 | nfs_inode_remove_request(req); | 1154 | nfs_inode_remove_request(req); |
1135 | dprintk(", error = %d\n", status); | 1155 | dprintk(", error = %d\n", task->tk_status); |
1136 | goto next; | 1156 | goto next; |
1137 | } | 1157 | } |
1138 | end_page_writeback(page); | 1158 | end_page_writeback(page); |
@@ -1154,18 +1174,28 @@ static void nfs_writeback_done_full(struct nfs_write_data *data, int status) | |||
1154 | } | 1174 | } |
1155 | } | 1175 | } |
1156 | 1176 | ||
1177 | static const struct rpc_call_ops nfs_write_full_ops = { | ||
1178 | .rpc_call_done = nfs_writeback_done_full, | ||
1179 | .rpc_release = nfs_writedata_release, | ||
1180 | }; | ||
1181 | |||
1182 | |||
1157 | /* | 1183 | /* |
1158 | * This function is called when the WRITE call is complete. | 1184 | * This function is called when the WRITE call is complete. |
1159 | */ | 1185 | */ |
1160 | void nfs_writeback_done(struct rpc_task *task, void *calldata) | 1186 | static int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data) |
1161 | { | 1187 | { |
1162 | struct nfs_write_data *data = calldata; | ||
1163 | struct nfs_writeargs *argp = &data->args; | 1188 | struct nfs_writeargs *argp = &data->args; |
1164 | struct nfs_writeres *resp = &data->res; | 1189 | struct nfs_writeres *resp = &data->res; |
1190 | int status; | ||
1165 | 1191 | ||
1166 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", | 1192 | dprintk("NFS: %4d nfs_writeback_done (status %d)\n", |
1167 | task->tk_pid, task->tk_status); | 1193 | task->tk_pid, task->tk_status); |
1168 | 1194 | ||
1195 | /* Call the NFS version-specific code */ | ||
1196 | status = NFS_PROTO(data->inode)->write_done(task, data); | ||
1197 | if (status != 0) | ||
1198 | return status; | ||
1169 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); | 1199 | nfs_add_stats(data->inode, NFSIOS_SERVERWRITTENBYTES, resp->count); |
1170 | 1200 | ||
1171 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1201 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
@@ -1210,7 +1240,7 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1210 | argp->stable = NFS_FILE_SYNC; | 1240 | argp->stable = NFS_FILE_SYNC; |
1211 | } | 1241 | } |
1212 | rpc_restart_call(task); | 1242 | rpc_restart_call(task); |
1213 | return; | 1243 | return -EAGAIN; |
1214 | } | 1244 | } |
1215 | if (time_before(complain, jiffies)) { | 1245 | if (time_before(complain, jiffies)) { |
1216 | printk(KERN_WARNING | 1246 | printk(KERN_WARNING |
@@ -1221,11 +1251,7 @@ void nfs_writeback_done(struct rpc_task *task, void *calldata) | |||
1221 | /* Can't do anything about it except throw an error. */ | 1251 | /* Can't do anything about it except throw an error. */ |
1222 | task->tk_status = -EIO; | 1252 | task->tk_status = -EIO; |
1223 | } | 1253 | } |
1224 | 1254 | return 0; | |
1225 | /* | ||
1226 | * Process the nfs_page list | ||
1227 | */ | ||
1228 | data->complete(data, task->tk_status); | ||
1229 | } | 1255 | } |
1230 | 1256 | ||
1231 | 1257 | ||
@@ -1239,10 +1265,12 @@ void nfs_commit_release(void *wdata) | |||
1239 | * Set up the argument/result storage required for the RPC call. | 1265 | * Set up the argument/result storage required for the RPC call. |
1240 | */ | 1266 | */ |
1241 | static void nfs_commit_rpcsetup(struct list_head *head, | 1267 | static void nfs_commit_rpcsetup(struct list_head *head, |
1242 | struct nfs_write_data *data, int how) | 1268 | struct nfs_write_data *data, |
1269 | int how) | ||
1243 | { | 1270 | { |
1244 | struct nfs_page *first; | 1271 | struct nfs_page *first; |
1245 | struct inode *inode; | 1272 | struct inode *inode; |
1273 | int flags; | ||
1246 | 1274 | ||
1247 | /* Set up the RPC argument and reply structs | 1275 | /* Set up the RPC argument and reply structs |
1248 | * NB: take care not to mess about with data->commit et al. */ | 1276 | * NB: take care not to mess about with data->commit et al. */ |
@@ -1262,7 +1290,10 @@ static void nfs_commit_rpcsetup(struct list_head *head, | |||
1262 | data->res.fattr = &data->fattr; | 1290 | data->res.fattr = &data->fattr; |
1263 | data->res.verf = &data->verf; | 1291 | data->res.verf = &data->verf; |
1264 | nfs_fattr_init(&data->fattr); | 1292 | nfs_fattr_init(&data->fattr); |
1265 | 1293 | ||
1294 | /* Set up the initial task struct. */ | ||
1295 | flags = (how & FLUSH_SYNC) ? 0 : RPC_TASK_ASYNC; | ||
1296 | rpc_init_task(&data->task, NFS_CLIENT(inode), flags, &nfs_commit_ops, data); | ||
1266 | NFS_PROTO(inode)->commit_setup(data, how); | 1297 | NFS_PROTO(inode)->commit_setup(data, how); |
1267 | 1298 | ||
1268 | data->task.tk_priority = flush_task_priority(how); | 1299 | data->task.tk_priority = flush_task_priority(how); |
@@ -1303,7 +1334,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how) | |||
1303 | /* | 1334 | /* |
1304 | * COMMIT call returned | 1335 | * COMMIT call returned |
1305 | */ | 1336 | */ |
1306 | void nfs_commit_done(struct rpc_task *task, void *calldata) | 1337 | static void nfs_commit_done(struct rpc_task *task, void *calldata) |
1307 | { | 1338 | { |
1308 | struct nfs_write_data *data = calldata; | 1339 | struct nfs_write_data *data = calldata; |
1309 | struct nfs_page *req; | 1340 | struct nfs_page *req; |
@@ -1312,6 +1343,10 @@ void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1312 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", | 1343 | dprintk("NFS: %4d nfs_commit_done (status %d)\n", |
1313 | task->tk_pid, task->tk_status); | 1344 | task->tk_pid, task->tk_status); |
1314 | 1345 | ||
1346 | /* Call the NFS version-specific code */ | ||
1347 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | ||
1348 | return; | ||
1349 | |||
1315 | while (!list_empty(&data->pages)) { | 1350 | while (!list_empty(&data->pages)) { |
1316 | req = nfs_list_entry(data->pages.next); | 1351 | req = nfs_list_entry(data->pages.next); |
1317 | nfs_list_remove_request(req); | 1352 | nfs_list_remove_request(req); |
@@ -1345,6 +1380,11 @@ void nfs_commit_done(struct rpc_task *task, void *calldata) | |||
1345 | } | 1380 | } |
1346 | sub_page_state(nr_unstable,res); | 1381 | sub_page_state(nr_unstable,res); |
1347 | } | 1382 | } |
1383 | |||
1384 | static const struct rpc_call_ops nfs_commit_ops = { | ||
1385 | .rpc_call_done = nfs_commit_done, | ||
1386 | .rpc_release = nfs_commit_release, | ||
1387 | }; | ||
1348 | #endif | 1388 | #endif |
1349 | 1389 | ||
1350 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, | 1390 | static int nfs_flush_inode(struct inode *inode, unsigned long idx_start, |