mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
612c9384fd
commit
2b82f190c8
|
@ -388,6 +388,8 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
|
||||||
}
|
}
|
||||||
SetPagePrivate(req->wb_page);
|
SetPagePrivate(req->wb_page);
|
||||||
set_page_private(req->wb_page, (unsigned long)req);
|
set_page_private(req->wb_page, (unsigned long)req);
|
||||||
|
if (PageDirty(req->wb_page))
|
||||||
|
set_bit(PG_NEED_FLUSH, &req->wb_flags);
|
||||||
nfsi->npages++;
|
nfsi->npages++;
|
||||||
atomic_inc(&req->wb_count);
|
atomic_inc(&req->wb_count);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -407,6 +409,8 @@ static void nfs_inode_remove_request(struct nfs_page *req)
|
||||||
set_page_private(req->wb_page, 0);
|
set_page_private(req->wb_page, 0);
|
||||||
ClearPagePrivate(req->wb_page);
|
ClearPagePrivate(req->wb_page);
|
||||||
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
|
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
|
||||||
|
if (test_and_clear_bit(PG_NEED_FLUSH, &req->wb_flags))
|
||||||
|
__set_page_dirty_nobuffers(req->wb_page);
|
||||||
nfsi->npages--;
|
nfsi->npages--;
|
||||||
if (!nfsi->npages) {
|
if (!nfsi->npages) {
|
||||||
spin_unlock(&nfsi->req_lock);
|
spin_unlock(&nfsi->req_lock);
|
||||||
|
@ -1527,15 +1531,22 @@ int nfs_wb_page(struct inode *inode, struct page* page)
|
||||||
|
|
||||||
int nfs_set_page_dirty(struct page *page)
|
int nfs_set_page_dirty(struct page *page)
|
||||||
{
|
{
|
||||||
|
spinlock_t *req_lock = &NFS_I(page->mapping->host)->req_lock;
|
||||||
struct nfs_page *req;
|
struct nfs_page *req;
|
||||||
|
int ret;
|
||||||
|
|
||||||
req = nfs_page_find_request(page);
|
spin_lock(req_lock);
|
||||||
|
req = nfs_page_find_request_locked(page);
|
||||||
if (req != NULL) {
|
if (req != NULL) {
|
||||||
/* Mark any existing write requests for flushing */
|
/* Mark any existing write requests for flushing */
|
||||||
set_bit(PG_NEED_FLUSH, &req->wb_flags);
|
ret = !test_and_set_bit(PG_NEED_FLUSH, &req->wb_flags);
|
||||||
|
spin_unlock(req_lock);
|
||||||
nfs_release_request(req);
|
nfs_release_request(req);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
return __set_page_dirty_nobuffers(page);
|
ret = __set_page_dirty_nobuffers(page);
|
||||||
|
spin_unlock(req_lock);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue