diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-04-09 19:07:08 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-04-09 19:08:17 -0400 |
commit | a6305ddb080fb483ca41ca56cacb6f96089f0c8e (patch) | |
tree | 82c41752da42726ad1d7ed27203acbf06892dbaa /fs | |
parent | b80c3cb628f0ebc241b02e38dd028969fb8026a2 (diff) |
NFS: Fix a race with the new commit code
This patch fixes a race which occurs due to the fact that we release the
PG_writeback flag while still holding the nfs_page locked.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/write.c | 17 |
1 files changed, 10 insertions, 7 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 7f40ea305543..40297c4f1ee0 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -201,6 +201,7 @@ static int nfs_set_page_writeback(struct page *page) | |||
201 | struct inode *inode = page->mapping->host; | 201 | struct inode *inode = page->mapping->host; |
202 | struct nfs_server *nfss = NFS_SERVER(inode); | 202 | struct nfs_server *nfss = NFS_SERVER(inode); |
203 | 203 | ||
204 | page_cache_get(page); | ||
204 | if (atomic_long_inc_return(&nfss->writeback) > | 205 | if (atomic_long_inc_return(&nfss->writeback) > |
205 | NFS_CONGESTION_ON_THRESH) { | 206 | NFS_CONGESTION_ON_THRESH) { |
206 | set_bdi_congested(&nfss->backing_dev_info, | 207 | set_bdi_congested(&nfss->backing_dev_info, |
@@ -216,6 +217,7 @@ static void nfs_end_page_writeback(struct page *page) | |||
216 | struct nfs_server *nfss = NFS_SERVER(inode); | 217 | struct nfs_server *nfss = NFS_SERVER(inode); |
217 | 218 | ||
218 | end_page_writeback(page); | 219 | end_page_writeback(page); |
220 | page_cache_release(page); | ||
219 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) | 221 | if (atomic_long_dec_return(&nfss->writeback) < NFS_CONGESTION_OFF_THRESH) |
220 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); | 222 | clear_bdi_congested(&nfss->backing_dev_info, BLK_RW_ASYNC); |
221 | } | 223 | } |
@@ -665,6 +667,7 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page, | |||
665 | /* Update file length */ | 667 | /* Update file length */ |
666 | nfs_grow_file(page, offset, count); | 668 | nfs_grow_file(page, offset, count); |
667 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); | 669 | nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes); |
670 | nfs_mark_request_dirty(req); | ||
668 | nfs_clear_page_tag_locked(req); | 671 | nfs_clear_page_tag_locked(req); |
669 | return 0; | 672 | return 0; |
670 | } | 673 | } |
@@ -749,13 +752,12 @@ int nfs_updatepage(struct file *file, struct page *page, | |||
749 | 752 | ||
750 | static void nfs_writepage_release(struct nfs_page *req) | 753 | static void nfs_writepage_release(struct nfs_page *req) |
751 | { | 754 | { |
755 | struct page *page = req->wb_page; | ||
752 | 756 | ||
753 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) { | 757 | if (PageError(req->wb_page) || !nfs_reschedule_unstable_write(req)) |
754 | nfs_end_page_writeback(req->wb_page); | ||
755 | nfs_inode_remove_request(req); | 758 | nfs_inode_remove_request(req); |
756 | } else | ||
757 | nfs_end_page_writeback(req->wb_page); | ||
758 | nfs_clear_page_tag_locked(req); | 759 | nfs_clear_page_tag_locked(req); |
760 | nfs_end_page_writeback(page); | ||
759 | } | 761 | } |
760 | 762 | ||
761 | static int flush_task_priority(int how) | 763 | static int flush_task_priority(int how) |
@@ -847,9 +849,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req, | |||
847 | */ | 849 | */ |
848 | static void nfs_redirty_request(struct nfs_page *req) | 850 | static void nfs_redirty_request(struct nfs_page *req) |
849 | { | 851 | { |
852 | struct page *page = req->wb_page; | ||
853 | |||
850 | nfs_mark_request_dirty(req); | 854 | nfs_mark_request_dirty(req); |
851 | nfs_end_page_writeback(req->wb_page); | ||
852 | nfs_clear_page_tag_locked(req); | 855 | nfs_clear_page_tag_locked(req); |
856 | nfs_end_page_writeback(page); | ||
853 | } | 857 | } |
854 | 858 | ||
855 | /* | 859 | /* |
@@ -1084,16 +1088,15 @@ static void nfs_writeback_release_full(void *calldata) | |||
1084 | if (nfs_write_need_commit(data)) { | 1088 | if (nfs_write_need_commit(data)) { |
1085 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); | 1089 | memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf)); |
1086 | nfs_mark_request_commit(req); | 1090 | nfs_mark_request_commit(req); |
1087 | nfs_end_page_writeback(page); | ||
1088 | dprintk(" marked for commit\n"); | 1091 | dprintk(" marked for commit\n"); |
1089 | goto next; | 1092 | goto next; |
1090 | } | 1093 | } |
1091 | dprintk(" OK\n"); | 1094 | dprintk(" OK\n"); |
1092 | remove_request: | 1095 | remove_request: |
1093 | nfs_end_page_writeback(page); | ||
1094 | nfs_inode_remove_request(req); | 1096 | nfs_inode_remove_request(req); |
1095 | next: | 1097 | next: |
1096 | nfs_clear_page_tag_locked(req); | 1098 | nfs_clear_page_tag_locked(req); |
1099 | nfs_end_page_writeback(page); | ||
1097 | } | 1100 | } |
1098 | nfs_writedata_release(calldata); | 1101 | nfs_writedata_release(calldata); |
1099 | } | 1102 | } |