aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-04-20 16:12:50 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-04-21 01:56:30 -0400
commit2b82f190c81bf1524447c021df4e9ce8ef379bd5 (patch)
tree3f4ebb8c0379715fe38897474856bdbab5750250 /fs/nfs
parent612c9384fd0486686699f7d49b774f0c7a79c511 (diff)
NFS: Fix race in nfs_set_page_dirty
Protect nfs_set_page_dirty() against races with nfs_inode_add_request. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/write.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index ce5b4a9f2d8b..797558941745 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -388,6 +388,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
388 } 388 }
389 SetPagePrivate(req->wb_page); 389 SetPagePrivate(req->wb_page);
390 set_page_private(req->wb_page, (unsigned long)req); 390 set_page_private(req->wb_page, (unsigned long)req);
391 if (PageDirty(req->wb_page))
392 set_bit(PG_NEED_FLUSH, &req->wb_flags);
391 nfsi->npages++; 393 nfsi->npages++;
392 atomic_inc(&req->wb_count); 394 atomic_inc(&req->wb_count);
393 return 0; 395 return 0;
@@ -407,6 +409,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
407 set_page_private(req->wb_page, 0); 409 set_page_private(req->wb_page, 0);
408 ClearPagePrivate(req->wb_page); 410 ClearPagePrivate(req->wb_page);
409 radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); 411 radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
412 if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags))
413 __set_page_dirty_nobuffers(req->wb_page);
410 nfsi->npages--; 414 nfsi->npages--;
411 if (!nfsi->npages) { 415 if (!nfsi->npages) {
412 spin_unlock(&nfsi->req_lock); 416 spin_unlock(&nfsi->req_lock);
@@ -1527,15 +1531,22 @@ int nfs_wb_page(struct inode *inode, struct page* page)
1527 1531
1528int nfs_set_page_dirty(struct page *page) 1532int nfs_set_page_dirty(struct page *page)
1529{ 1533{
1534 spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
1530 struct nfs_page *req; 1535 struct nfs_page *req;
1536 int ret;
1531 1537
1532 req = nfs_page_find_request(page); 1538 spin_lock(req_lock);
1539 req = nfs_page_find_request_locked(page);
1533 if (req != NULL) { 1540 if (req != NULL) {
1534 /* Mark any existing write requests for flushing */ 1541 /* Mark any existing write requests for flushing */
1535 set_bit(PG_NEED_FLUSH, &req->wb_flags); 1542 ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags);
1543 spin_unlock(req_lock);
1536 nfs_release_request(req); 1544 nfs_release_request(req);
1545 return ret;
1537 } 1546 }
1538 return __set_page_dirty_nobuffers(page); 1547 ret = __set_page_dirty_nobuffers(page);
1548 spin_unlock(req_lock);
1549 return ret;
1539} 1550}
1540 1551
1541 1552