aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/write.c117
-rw-r--r--include/linux/nfs_page.h30
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
464static inline
465int nfs_write_need_commit(struct nfs_write_data *data)
466{
467 return data->verf.committed != NFS_FILE_SYNC;
468}
469
470static inline
471int 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
484static inline void
485nfs_mark_request_commit(struct nfs_page *req)
486{
487}
488
489static inline
490int nfs_write_need_commit(struct nfs_write_data *data)
491{
492 return 0;
493}
494
495static inline
496int 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
747static void nfs_writepage_release(struct nfs_page *req) 784static 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
763out:
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
1055out:
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); 1108remove_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
55extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx, 53extern 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
124static inline int
125nfs_defer_commit(struct nfs_page *req)
126{
127 return !test_and_set_bit(PG_NEED_COMMIT, &req->wb_flags);
128}
129
130static inline void
131nfs_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
138static inline int
139nfs_defer_reschedule(struct nfs_page *req)
140{
141 return !test_and_set_bit(PG_NEED_RESCHED, &req->wb_flags);
142}
143
144static inline void
145nfs_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
152static inline struct nfs_page * 122static inline struct nfs_page *
153nfs_list_entry(struct list_head *head) 123nfs_list_entry(struct list_head *head)
154{ 124{