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 | { |