diff options
-rw-r--r-- | fs/nfs/direct.c | 50 | ||||
-rw-r--r-- | fs/nfs/write.c | 67 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 4 |
3 files changed, 73 insertions, 48 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 9d9085b93a32..abf8e0286e35 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -508,27 +508,34 @@ static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq) | |||
508 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) | 508 | static void nfs_direct_commit_result(struct rpc_task *task, void *calldata) |
509 | { | 509 | { |
510 | struct nfs_write_data *data = calldata; | 510 | struct nfs_write_data *data = calldata; |
511 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
512 | 511 | ||
513 | /* Call the NFS version-specific code */ | 512 | /* Call the NFS version-specific code */ |
514 | if (NFS_PROTO(data->inode)->commit_done(task, data) != 0) | 513 | NFS_PROTO(data->inode)->commit_done(task, data); |
515 | return; | 514 | } |
516 | if (unlikely(task->tk_status < 0)) { | 515 | |
516 | static void nfs_direct_commit_release(void *calldata) | ||
517 | { | ||
518 | struct nfs_write_data *data = calldata; | ||
519 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
520 | int status = data->task.tk_status; | ||
521 | |||
522 | if (status < 0) { | ||
517 | dprintk("NFS: %5u commit failed with error %d.\n", | 523 | dprintk("NFS: %5u commit failed with error %d.\n", |
518 | task->tk_pid, task->tk_status); | 524 | data->task.tk_pid, status); |
519 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 525 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
520 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { | 526 | } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { |
521 | dprintk("NFS: %5u commit verify failed\n", task->tk_pid); | 527 | dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); |
522 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 528 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
523 | } | 529 | } |
524 | 530 | ||
525 | dprintk("NFS: %5u commit returned %d\n", task->tk_pid, task->tk_status); | 531 | dprintk("NFS: %5u commit returned %d\n", data->task.tk_pid, status); |
526 | nfs_direct_write_complete(dreq, data->inode); | 532 | nfs_direct_write_complete(dreq, data->inode); |
533 | nfs_commitdata_release(calldata); | ||
527 | } | 534 | } |
528 | 535 | ||
529 | static const struct rpc_call_ops nfs_commit_direct_ops = { | 536 | static const struct rpc_call_ops nfs_commit_direct_ops = { |
530 | .rpc_call_done = nfs_direct_commit_result, | 537 | .rpc_call_done = nfs_direct_commit_result, |
531 | .rpc_release = nfs_commit_release, | 538 | .rpc_release = nfs_direct_commit_release, |
532 | }; | 539 | }; |
533 | 540 | ||
534 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) | 541 | static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq) |
@@ -596,7 +603,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
596 | 603 | ||
597 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) | 604 | static void nfs_alloc_commit_data(struct nfs_direct_req *dreq) |
598 | { | 605 | { |
599 | dreq->commit_data = nfs_commit_alloc(); | 606 | dreq->commit_data = nfs_commitdata_alloc(); |
600 | if (dreq->commit_data != NULL) | 607 | if (dreq->commit_data != NULL) |
601 | dreq->commit_data->req = (struct nfs_page *) dreq; | 608 | dreq->commit_data->req = (struct nfs_page *) dreq; |
602 | } | 609 | } |
@@ -617,11 +624,20 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
617 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | 624 | static void nfs_direct_write_result(struct rpc_task *task, void *calldata) |
618 | { | 625 | { |
619 | struct nfs_write_data *data = calldata; | 626 | struct nfs_write_data *data = calldata; |
620 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
621 | int status = task->tk_status; | ||
622 | 627 | ||
623 | if (nfs_writeback_done(task, data) != 0) | 628 | if (nfs_writeback_done(task, data) != 0) |
624 | return; | 629 | return; |
630 | } | ||
631 | |||
632 | /* | ||
633 | * NB: Return the value of the first error return code. Subsequent | ||
634 | * errors after the first one are ignored. | ||
635 | */ | ||
636 | static void nfs_direct_write_release(void *calldata) | ||
637 | { | ||
638 | struct nfs_write_data *data = calldata; | ||
639 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
640 | int status = data->task.tk_status; | ||
625 | 641 | ||
626 | spin_lock(&dreq->lock); | 642 | spin_lock(&dreq->lock); |
627 | 643 | ||
@@ -643,23 +659,13 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata) | |||
643 | break; | 659 | break; |
644 | case NFS_ODIRECT_DO_COMMIT: | 660 | case NFS_ODIRECT_DO_COMMIT: |
645 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { | 661 | if (memcmp(&dreq->verf, &data->verf, sizeof(dreq->verf))) { |
646 | dprintk("NFS: %5u write verify failed\n", task->tk_pid); | 662 | dprintk("NFS: %5u write verify failed\n", data->task.tk_pid); |
647 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | 663 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; |
648 | } | 664 | } |
649 | } | 665 | } |
650 | } | 666 | } |
651 | out_unlock: | 667 | out_unlock: |
652 | spin_unlock(&dreq->lock); | 668 | spin_unlock(&dreq->lock); |
653 | } | ||
654 | |||
655 | /* | ||
656 | * NB: Return the value of the first error return code. Subsequent | ||
657 | * errors after the first one are ignored. | ||
658 | */ | ||
659 | static void nfs_direct_write_release(void *calldata) | ||
660 | { | ||
661 | struct nfs_write_data *data = calldata; | ||
662 | struct nfs_direct_req *dreq = (struct nfs_direct_req *) data->req; | ||
663 | 669 | ||
664 | if (put_dreq(dreq)) | 670 | if (put_dreq(dreq)) |
665 | nfs_direct_write_complete(dreq, data->inode); | 671 | nfs_direct_write_complete(dreq, data->inode); |
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; | |||
48 | static mempool_t *nfs_wdata_mempool; | 48 | static mempool_t *nfs_wdata_mempool; |
49 | static mempool_t *nfs_commit_mempool; | 49 | static mempool_t *nfs_commit_mempool; |
50 | 50 | ||
51 | struct nfs_write_data *nfs_commit_alloc(void) | 51 | struct 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) { | 986 | static 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) | |||
1012 | out: | 1018 | out: |
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 | ||
1017 | static const struct rpc_call_ops nfs_write_partial_ops = { | 1024 | static 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 = { | |||
1029 | static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | 1036 | static 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 | |||
1043 | static 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 | ||
1075 | static const struct rpc_call_ops nfs_write_full_ops = { | 1087 | static 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) |
1163 | void nfs_commit_release(void *data) | 1175 | void 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) | |||
1261 | static void nfs_commit_done(struct rpc_task *task, void *calldata) | 1273 | static 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 | |||
1285 | static 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 | ||
1312 | static const struct rpc_call_ops nfs_commit_ops = { | 1331 | static const struct rpc_call_ops nfs_commit_ops = { |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index f4a0e4c218df..7f0602c87712 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -466,9 +466,9 @@ extern int nfs_wb_page(struct inode *inode, struct page* page); | |||
466 | extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); | 466 | extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); |
467 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 467 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) |
468 | extern int nfs_commit_inode(struct inode *, int); | 468 | extern int nfs_commit_inode(struct inode *, int); |
469 | extern struct nfs_write_data *nfs_commit_alloc(void); | 469 | extern struct nfs_write_data *nfs_commitdata_alloc(void); |
470 | extern void nfs_commit_free(struct nfs_write_data *wdata); | 470 | extern void nfs_commit_free(struct nfs_write_data *wdata); |
471 | extern void nfs_commit_release(void *wdata); | 471 | extern void nfs_commitdata_release(void *wdata); |
472 | #else | 472 | #else |
473 | static inline int | 473 | static inline int |
474 | nfs_commit_inode(struct inode *inode, int how) | 474 | nfs_commit_inode(struct inode *inode, int how) |