aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2010-04-09 19:07:08 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-04-09 19:08:17 -0400
commita6305ddb080fb483ca41ca56cacb6f96089f0c8e (patch)
tree82c41752da42726ad1d7ed27203acbf06892dbaa /fs
parentb80c3cb628f0ebc241b02e38dd028969fb8026a2 (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.c17
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
750static void nfs_writepage_release(struct nfs_page *req) 753static 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
761static int flush_task_priority(int how) 763static int flush_task_priority(int how)
@@ -847,9 +849,11 @@ static int nfs_write_rpcsetup(struct nfs_page *req,
847 */ 849 */
848static void nfs_redirty_request(struct nfs_page *req) 850static 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");
1092remove_request: 1095remove_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}