diff options
| -rw-r--r-- | fs/nfs/write.c | 117 | ||||
| -rw-r--r-- | include/linux/nfs_page.h | 30 |
2 files changed, 71 insertions, 76 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index ad2e91b4904f..3ed4feb8c856 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -460,6 +460,43 @@ nfs_mark_request_commit(struct nfs_page *req) | |||
| 460 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | 460 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); |
| 461 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | 461 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); |
| 462 | } | 462 | } |
| 463 | |||
| 464 | static inline | ||
| 465 | int nfs_write_need_commit(struct nfs_write_data *data) | ||
| 466 | { | ||
| 467 | return data->verf.committed != NFS_FILE_SYNC; | ||
| 468 | } | ||
| 469 | |||
| 470 | static inline | ||
| 471 | int nfs_reschedule_unstable_write(struct nfs_page *req) | ||
| 472 | { | ||
| 473 | if (test_and_clear_bit(PG_NEED_COMMIT, &req->wb_flags)) { | ||
| 474 | nfs_mark_request_commit(req); | ||
| 475 | return 1; | ||
| 476 | } | ||
| 477 | if (test_and_clear_bit(PG_NEED_RESCHED, &req->wb_flags)) { | ||
| 478 | nfs_redirty_request(req); | ||
| 479 | return 1; | ||
| 480 | } | ||
| 481 | return 0; | ||
| 482 | } | ||
| 483 | #else | ||
| 484 | static inline void | ||
| 485 | nfs_mark_request_commit(struct nfs_page *req) | ||
| 486 | { | ||
| 487 | } | ||
| 488 | |||
| 489 | static inline | ||
| 490 | int nfs_write_need_commit(struct nfs_write_data *data) | ||
| 491 | { | ||
| 492 | return 0; | ||
| 493 | } | ||
| 494 | |||
| 495 | static inline | ||
| 496 | int nfs_reschedule_unstable_write(struct nfs_page *req) | ||
| 497 | { | ||
| 498 | return 0; | ||
| 499 | } | ||
| 463 | #endif | 500 | #endif |
| 464 | 501 | ||
| 465 | /* | 502 | /* |
| @@ -746,26 +783,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
| 746 | 783 | ||
| 747 | static void nfs_writepage_release(struct nfs_page *req) | 784 | static void nfs_writepage_release(struct nfs_page *req) |
| 748 | { | 785 | { |
| 749 | nfs_end_page_writeback(req->wb_page); | ||
| 750 | 786 | ||
| 751 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 787 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { |
| 752 | if (!PageError(req->wb_page)) { | 788 | nfs_end_page_writeback(req->wb_page); |
| 753 | if (NFS_NEED_RESCHED(req)) { | 789 | nfs_inode_remove_request(req); |
| 754 | nfs_redirty_request(req); | 790 | } else |
| 755 | goto out; | 791 | nfs_end_page_writeback(req->wb_page); |
| 756 | } else if (NFS_NEED_COMMIT(req)) { | ||
| 757 | nfs_mark_request_commit(req); | ||
| 758 | goto out; | ||
| 759 | } | ||
| 760 | } | ||
| 761 | nfs_inode_remove_request(req); | ||
| 762 | |||
| 763 | out: | ||
| 764 | nfs_clear_commit(req); | ||
| 765 | nfs_clear_reschedule(req); | ||
| 766 | #else | ||
| 767 | nfs_inode_remove_request(req); | ||
| 768 | #endif | ||
| 769 | nfs_clear_page_writeback(req); | 792 | nfs_clear_page_writeback(req); |
| 770 | } | 793 | } |
| 771 | 794 | ||
| @@ -1008,22 +1031,28 @@ static void nfs_writeback_done_partial(struct rpc_task *task, void *calldata) | |||
| 1008 | nfs_set_pageerror(page); | 1031 | nfs_set_pageerror(page); |
| 1009 | req->wb_context->error = task->tk_status; | 1032 | req->wb_context->error = task->tk_status; |
| 1010 | dprintk(", error = %d\n", task->tk_status); | 1033 | dprintk(", error = %d\n", task->tk_status); |
| 1011 | } else { | 1034 | goto out; |
| 1012 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | ||
| 1013 | if (data->verf.committed < NFS_FILE_SYNC) { | ||
| 1014 | if (!NFS_NEED_COMMIT(req)) { | ||
| 1015 | nfs_defer_commit(req); | ||
| 1016 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | ||
| 1017 | dprintk(" defer commit\n"); | ||
| 1018 | } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) { | ||
| 1019 | nfs_defer_reschedule(req); | ||
| 1020 | dprintk(" server reboot detected\n"); | ||
| 1021 | } | ||
| 1022 | } else | ||
| 1023 | #endif | ||
| 1024 | dprintk(" OK\n"); | ||
| 1025 | } | 1035 | } |
| 1026 | 1036 | ||
| 1037 | if (nfs_write_need_commit(data)) { | ||
| 1038 | spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; | ||
| 1039 | |||
| 1040 | spin_lock(req_lock); | ||
| 1041 | if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) { | ||
| 1042 | /* Do nothing we need to resend the writes */ | ||
| 1043 | } else if (!test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags)) { | ||
| 1044 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | ||
| 1045 | dprintk(" defer commit\n"); | ||
| 1046 | } else if (memcmp(&req->wb_verf, &data->verf, sizeof(req->wb_verf))) { | ||
| 1047 | set_bit(PG_NEED_RESCHED, &req->wb_flags); | ||
| 1048 | clear_bit(PG_NEED_COMMIT, &req->wb_flags); | ||
| 1049 | dprintk(" server reboot detected\n"); | ||
| 1050 | } | ||
| 1051 | spin_unlock(req_lock); | ||
| 1052 | } else | ||
| 1053 | dprintk(" OK\n"); | ||
| 1054 | |||
| 1055 | out: | ||
| 1027 | if (atomic_dec_and_test(&req->wb_complete)) | 1056 | if (atomic_dec_and_test(&req->wb_complete)) |
| 1028 | nfs_writepage_release(req); | 1057 | nfs_writepage_release(req); |
| 1029 | } | 1058 | } |
| @@ -1064,25 +1093,21 @@ static void nfs_writeback_done_full(struct rpc_task *task, void *calldata) | |||
| 1064 | if (task->tk_status < 0) { | 1093 | if (task->tk_status < 0) { |
| 1065 | nfs_set_pageerror(page); | 1094 | nfs_set_pageerror(page); |
| 1066 | req->wb_context->error = task->tk_status; | 1095 | req->wb_context->error = task->tk_status; |
| 1067 | nfs_end_page_writeback(page); | ||
| 1068 | nfs_inode_remove_request(req); | ||
| 1069 | dprintk(", error = %d\n", task->tk_status); | 1096 | dprintk(", error = %d\n", task->tk_status); |
| 1070 | goto next; | 1097 | goto remove_request; |
| 1071 | } | 1098 | } |
| 1072 | nfs_end_page_writeback(page); | ||
| 1073 | 1099 | ||
| 1074 | #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4) | 1100 | if (nfs_write_need_commit(data)) { |
| 1075 | if (data->args.stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) { | 1101 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
| 1076 | nfs_inode_remove_request(req); | 1102 | nfs_mark_request_commit(req); |
| 1077 | dprintk(" OK\n"); | 1103 | nfs_end_page_writeback(page); |
| 1104 | dprintk(" marked for commit\n"); | ||
| 1078 | goto next; | 1105 | goto next; |
| 1079 | } | 1106 | } |
| 1080 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1107 | dprintk(" OK\n"); |
| 1081 | nfs_mark_request_commit(req); | 1108 | remove_request: |
| 1082 | dprintk(" marked for commit\n"); | 1109 | nfs_end_page_writeback(page); |
| 1083 | #else | ||
| 1084 | nfs_inode_remove_request(req); | 1110 | nfs_inode_remove_request(req); |
| 1085 | #endif | ||
| 1086 | next: | 1111 | next: |
| 1087 | nfs_clear_page_writeback(req); | 1112 | nfs_clear_page_writeback(req); |
| 1088 | } | 1113 | } |
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index d111be639140..16b0266b14fd 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -49,8 +49,6 @@ struct nfs_page { | |||
| 49 | }; | 49 | }; |
| 50 | 50 | ||
| 51 | #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) | 51 | #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) |
| 52 | #define NFS_NEED_COMMIT(req) (test_bit(PG_NEED_COMMIT,&(req)->wb_flags)) | ||
| 53 | #define NFS_NEED_RESCHED(req) (test_bit(PG_NEED_RESCHED,&(req)->wb_flags)) | ||
| 54 | 52 | ||
| 55 | extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx, | 53 | extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx, |
| 56 | struct inode *inode, | 54 | struct inode *inode, |
| @@ -121,34 +119,6 @@ nfs_list_remove_request(struct nfs_page *req) | |||
| 121 | req->wb_list_head = NULL; | 119 | req->wb_list_head = NULL; |
| 122 | } | 120 | } |
| 123 | 121 | ||
| 124 | static inline int | ||
| 125 | nfs_defer_commit(struct nfs_page *req) | ||
| 126 | { | ||
| 127 | return !test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags); | ||
| 128 | } | ||
| 129 | |||
| 130 | static inline void | ||
| 131 | nfs_clear_commit(struct nfs_page *req) | ||
| 132 | { | ||
| 133 | smp_mb__before_clear_bit(); | ||
| 134 | clear_bit(PG_NEED_COMMIT, &req->wb_flags); | ||
| 135 | smp_mb__after_clear_bit(); | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline int | ||
| 139 | nfs_defer_reschedule(struct nfs_page *req) | ||
| 140 | { | ||
| 141 | return !test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags); | ||
| 142 | } | ||
| 143 | |||
| 144 | static inline void | ||
| 145 | nfs_clear_reschedule(struct nfs_page *req) | ||
| 146 | { | ||
| 147 | smp_mb__before_clear_bit(); | ||
| 148 | clear_bit(PG_NEED_RESCHED, &req->wb_flags); | ||
| 149 | smp_mb__after_clear_bit(); | ||
| 150 | } | ||
| 151 | |||
| 152 | static inline struct nfs_page * | 122 | static inline struct nfs_page * |
| 153 | nfs_list_entry(struct list_head *head) | 123 | nfs_list_entry(struct list_head *head) |
| 154 | { | 124 | { |
