Skip to content

Commit

Permalink
NFS: Avoid races between writebacks and truncation
Browse files Browse the repository at this point in the history
Currently, there is no serialisation between NFS asynchronous writebacks
and truncation at the page level due to the fact that nfs_sync_inode()
cannot lock the pages that it is about to write out.

This means that it is possible to be flushing out data (and calling something
like set_page_writeback()) while the page cache is busy evicting the page.
Oops...

Use the hooks provided in try_to_release_page() to ensure that dirty pages
are always written back to storage before we evict them.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Mar 20, 2006
1 parent b92dccf commit cd52ed3
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 2 deletions.
13 changes: 13 additions & 0 deletions fs/nfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,17 @@ static int nfs_commit_write(struct file *file, struct page *page, unsigned offse
return status;
}

static int nfs_invalidate_page(struct page *page, unsigned long offset)
{
/* FIXME: we really should cancel any unstarted writes on this page */
return 1;
}

static int nfs_release_page(struct page *page, gfp_t gfp)
{
return !nfs_wb_page(page->mapping->host, page);
}

struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage,
.readpages = nfs_readpages,
Expand All @@ -324,6 +335,8 @@ struct address_space_operations nfs_file_aops = {
.writepages = nfs_writepages,
.prepare_write = nfs_prepare_write,
.commit_write = nfs_commit_write,
.invalidatepage = nfs_invalidate_page,
.releasepage = nfs_release_page,
#ifdef CONFIG_NFS_DIRECTIO
.direct_IO = nfs_direct_IO,
#endif
Expand Down
10 changes: 8 additions & 2 deletions fs/nfs/pagelist.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
atomic_set(&req->wb_complete, 0);
req->wb_index = page->index;
page_cache_get(page);
BUG_ON(PagePrivate(page));
BUG_ON(!PageLocked(page));
BUG_ON(page->mapping->host != inode);
SetPagePrivate(page);
req->wb_offset = offset;
req->wb_pgbase = offset;
req->wb_bytes = count;
Expand Down Expand Up @@ -147,8 +151,10 @@ void nfs_clear_page_writeback(struct nfs_page *req)
*/
void nfs_clear_request(struct nfs_page *req)
{
if (req->wb_page) {
page_cache_release(req->wb_page);
struct page *page = req->wb_page;
if (page != NULL) {
ClearPagePrivate(page);
page_cache_release(page);
req->wb_page = NULL;
}
}
Expand Down

0 comments on commit cd52ed3

Please sign in to comment.