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>

authored by Trond Myklebust and committed by Linus Torvalds 2b82f190 612c9384

+14 -3
+14 -3
fs/nfs/write.c
··· 388 } 389 SetPagePrivate(req->wb_page); 390 set_page_private(req->wb_page, (unsigned long)req); 391 nfsi->npages++; 392 atomic_inc(&req->wb_count); 393 return 0; ··· 409 set_page_private(req->wb_page, 0); 410 ClearPagePrivate(req->wb_page); 411 radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); 412 nfsi->npages--; 413 if (!nfsi->npages) { 414 spin_unlock(&nfsi->req_lock); ··· 1531 1532 int nfs_set_page_dirty(struct page *page) 1533 { 1534 struct nfs_page *req; 1535 1536 - req = nfs_page_find_request(page); 1537 if (req != NULL) { 1538 /* Mark any existing write requests for flushing */ 1539 - set_bit(PG_NEED_FLUSH, &req->wb_flags); 1540 nfs_release_request(req); 1541 } 1542 - return __set_page_dirty_nobuffers(page); 1543 } 1544 1545
··· 388 } 389 SetPagePrivate(req->wb_page); 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); 393 nfsi->npages++; 394 atomic_inc(&req->wb_count); 395 return 0; ··· 407 set_page_private(req->wb_page, 0); 408 ClearPagePrivate(req->wb_page); 409 radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index); 410 + if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags)) 411 + __set_page_dirty_nobuffers(req->wb_page); 412 nfsi->npages--; 413 if (!nfsi->npages) { 414 spin_unlock(&nfsi->req_lock); ··· 1527 1528 int nfs_set_page_dirty(struct page *page) 1529 { 1530 + spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock; 1531 struct nfs_page *req; 1532 + int ret; 1533 1534 + spin_lock(req_lock); 1535 + req = nfs_page_find_request_locked(page); 1536 if (req != NULL) { 1537 /* Mark any existing write requests for flushing */ 1538 + ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags); 1539 + spin_unlock(req_lock); 1540 nfs_release_request(req); 1541 + return ret; 1542 } 1543 + ret = __set_page_dirty_nobuffers(page); 1544 + spin_unlock(req_lock); 1545 + return ret; 1546 } 1547 1548