aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/write.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-15 16:56:39 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2008-04-19 16:53:05 -0400
commitc9d8f89d9816c1d16ada492aa547a4d692508c0d (patch)
treed85339019cff084c11d4fceaf194fc5e34588d61 /fs/nfs/write.c
parentfdd1e74c89fe39259a29c494209abad63ff76f82 (diff)
NFS: Ensure that the write code cleans up properly when rpc_run_task() fails
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/write.c')
-rw-r--r--fs/nfs/write.c67
1 files changed, 43 insertions, 24 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 997b42aa3702..31681bb5e4c1 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -48,7 +48,7 @@ static struct kmem_cache *nfs_wdata_cachep;
48static mempool_t *nfs_wdata_mempool; 48static mempool_t *nfs_wdata_mempool;
49static mempool_t *nfs_commit_mempool; 49static mempool_t *nfs_commit_mempool;
50 50
51struct nfs_write_data *nfs_commit_alloc(void) 51struct nfs_write_data *nfs_commitdata_alloc(void)
52{ 52{
53 struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS); 53 struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS);
54 54
@@ -973,7 +973,6 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
973{ 973{
974 struct nfs_write_data *data = calldata; 974 struct nfs_write_data *data = calldata;
975 struct nfs_page *req = data->req; 975 struct nfs_page *req = data->req;
976 struct page *page = req->wb_page;
977 976
978 dprintk("NFS: write (%s/%Ld %d@%Ld)", 977 dprintk("NFS: write (%s/%Ld %d@%Ld)",
979 req->wb_context->path.dentry->d_inode->i_sb->s_id, 978 req->wb_context->path.dentry->d_inode->i_sb->s_id,
@@ -981,13 +980,20 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
981 req->wb_bytes, 980 req->wb_bytes,
982 (long long)req_offset(req)); 981 (long long)req_offset(req));
983 982
984 if (nfs_writeback_done(task, data) != 0) 983 nfs_writeback_done(task, data);
985 return; 984}
986 985
987 if (task->tk_status < 0) { 986static void nfs_writeback_release_partial(void *calldata)
987{
988 struct nfs_write_data *data = calldata;
989 struct nfs_page *req = data->req;
990 struct page *page = req->wb_page;
991 int status = data->task.tk_status;
992
993 if (status < 0) {
988 nfs_set_pageerror(page); 994 nfs_set_pageerror(page);
989 nfs_context_set_write_error(req->wb_context, task->tk_status); 995 nfs_context_set_write_error(req->wb_context, status);
990 dprintk(", error = %d\n", task->tk_status); 996 dprintk(", error = %d\n", status);
991 goto out; 997 goto out;
992 } 998 }
993 999
@@ -1012,11 +1018,12 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata)
1012out: 1018out:
1013 if (atomic_dec_and_test(&req->wb_complete)) 1019 if (atomic_dec_and_test(&req->wb_complete))
1014 nfs_writepage_release(req); 1020 nfs_writepage_release(req);
1021 nfs_writedata_release(calldata);
1015} 1022}
1016 1023
1017static const struct rpc_call_ops nfs_write_partial_ops = { 1024static const struct rpc_call_ops nfs_write_partial_ops = {
1018 .rpc_call_done = nfs_writeback_done_partial, 1025 .rpc_call_done = nfs_writeback_done_partial,
1019 .rpc_release = nfs_writedata_release, 1026 .rpc_release = nfs_writeback_release_partial,
1020}; 1027};
1021 1028
1022/* 1029/*
@@ -1029,17 +1036,21 @@ static const struct rpc_call_ops nfs_write_partial_ops = {
1029static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) 1036static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
1030{ 1037{
1031 struct nfs_write_data *data = calldata; 1038 struct nfs_write_data *data = calldata;
1032 struct nfs_page *req;
1033 struct page *page;
1034 1039
1035 if (nfs_writeback_done(task, data) != 0) 1040 nfs_writeback_done(task, data);
1036 return; 1041}
1042
1043static void nfs_writeback_release_full(void *calldata)
1044{
1045 struct nfs_write_data *data = calldata;
1046 int status = data->task.tk_status;
1037 1047
1038 /* Update attributes as result of writeback. */ 1048 /* Update attributes as result of writeback. */
1039 while (!list_empty(&data->pages)) { 1049 while (!list_empty(&data->pages)) {
1040 req = nfs_list_entry(data->pages.next); 1050 struct nfs_page *req = nfs_list_entry(data->pages.next);
1051 struct page *page = req->wb_page;
1052
1041 nfs_list_remove_request(req); 1053 nfs_list_remove_request(req);
1042 page = req->wb_page;
1043 1054
1044 dprintk("NFS: write (%s/%Ld %d@%Ld)", 1055 dprintk("NFS: write (%s/%Ld %d@%Ld)",
1045 req->wb_context->path.dentry->d_inode->i_sb->s_id, 1056 req->wb_context->path.dentry->d_inode->i_sb->s_id,
@@ -1047,10 +1058,10 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata)
1047 req->wb_bytes, 1058 req->wb_bytes,
1048 (long long)req_offset(req)); 1059 (long long)req_offset(req));
1049 1060
1050 if (task->tk_status < 0) { 1061 if (status < 0) {
1051 nfs_set_pageerror(page); 1062 nfs_set_pageerror(page);
1052 nfs_context_set_write_error(req->wb_context, task->tk_status); 1063 nfs_context_set_write_error(req->wb_context, status);
1053 dprintk(", error = %d\n", task->tk_status); 1064 dprintk(", error = %d\n", status);
1054 goto remove_request; 1065 goto remove_request;
1055 } 1066 }
1056 1067
@@ -1070,11 +1081,12 @@ remove_request:
1070 next: 1081 next:
1071 nfs_clear_page_tag_locked(req); 1082 nfs_clear_page_tag_locked(req);
1072 } 1083 }
1084 nfs_writedata_release(calldata);
1073} 1085}
1074 1086
1075static const struct rpc_call_ops nfs_write_full_ops = { 1087static const struct rpc_call_ops nfs_write_full_ops = {
1076 .rpc_call_done = nfs_writeback_done_full, 1088 .rpc_call_done = nfs_writeback_done_full,
1077 .rpc_release = nfs_writedata_release, 1089 .rpc_release = nfs_writeback_release_full,
1078}; 1090};
1079 1091
1080 1092
@@ -1160,7 +1172,7 @@ int nfs_writeback_done(struct rpc_task *task, struct nfs_write_data *data)
1160 1172
1161 1173
1162#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) 1174#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
1163void nfs_commit_release(void *data) 1175void nfs_commitdata_release(void *data)
1164{ 1176{
1165 struct nfs_write_data *wdata = data; 1177 struct nfs_write_data *wdata = data;
1166 1178
@@ -1233,7 +1245,7 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
1233 struct nfs_write_data *data; 1245 struct nfs_write_data *data;
1234 struct nfs_page *req; 1246 struct nfs_page *req;
1235 1247
1236 data = nfs_commit_alloc(); 1248 data = nfs_commitdata_alloc();
1237 1249
1238 if (!data) 1250 if (!data)
1239 goto out_bad; 1251 goto out_bad;
@@ -1261,7 +1273,6 @@ nfs_commit_list(struct inode *inode, struct list_head *head, int how)
1261static void nfs_commit_done(struct rpc_task *task, void *calldata) 1273static void nfs_commit_done(struct rpc_task *task, void *calldata)
1262{ 1274{
1263 struct nfs_write_data *data = calldata; 1275 struct nfs_write_data *data = calldata;
1264 struct nfs_page *req;
1265 1276
1266 dprintk("NFS: %5u nfs_commit_done (status %d)\n", 1277 dprintk("NFS: %5u nfs_commit_done (status %d)\n",
1267 task->tk_pid, task->tk_status); 1278 task->tk_pid, task->tk_status);
@@ -1269,6 +1280,13 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
1269 /* Call the NFS version-specific code */ 1280 /* Call the NFS version-specific code */
1270 if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) 1281 if (NFS_PROTO(data->inode)->commit_done(task, data) != 0)
1271 return; 1282 return;
1283}
1284
1285static void nfs_commit_release(void *calldata)
1286{
1287 struct nfs_write_data *data = calldata;
1288 struct nfs_page *req;
1289 int status = data->task.tk_status;
1272 1290
1273 while (!list_empty(&data->pages)) { 1291 while (!list_empty(&data->pages)) {
1274 req = nfs_list_entry(data->pages.next); 1292 req = nfs_list_entry(data->pages.next);
@@ -1283,10 +1301,10 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
1283 (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode), 1301 (long long)NFS_FILEID(req->wb_context->path.dentry->d_inode),
1284 req->wb_bytes, 1302 req->wb_bytes,
1285 (long long)req_offset(req)); 1303 (long long)req_offset(req));
1286 if (task->tk_status < 0) { 1304 if (status < 0) {
1287 nfs_context_set_write_error(req->wb_context, task->tk_status); 1305 nfs_context_set_write_error(req->wb_context, status);
1288 nfs_inode_remove_request(req); 1306 nfs_inode_remove_request(req);
1289 dprintk(", error = %d\n", task->tk_status); 1307 dprintk(", error = %d\n", status);
1290 goto next; 1308 goto next;
1291 } 1309 }
1292 1310
@@ -1307,6 +1325,7 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata)
1307 next: 1325 next:
1308 nfs_clear_page_tag_locked(req); 1326 nfs_clear_page_tag_locked(req);
1309 } 1327 }
1328 nfs_commitdata_release(calldata);
1310} 1329}
1311 1330
1312static const struct rpc_call_ops nfs_commit_ops = { 1331static const struct rpc_call_ops nfs_commit_ops = {