Skip to content

Commit

Permalink
NFS: Fix a writeback race...
Browse files Browse the repository at this point in the history
This patch fixes a regression that was introduced by commit
44dd151

We cannot zero the user page in nfs_mark_uptodate() any more, since

  a) We'd be modifying the page without holding the page lock
  b) We can race with other updates of the page, most notably
     because of the call to nfs_wb_page() in nfs_writepage_setup().

Instead, we do the zeroing in nfs_update_request() if we see that we're
creating a request that might potentially be marked as up to date.

Thanks to Olivier Paquet for reporting the bug and providing a test-case.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Trond Myklebust authored and Trond Myklebust committed Oct 19, 2007
1 parent 4fa4d23 commit 61e930a
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions fs/nfs/write.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int
return;
if (count != nfs_page_length(page))
return;
if (count != PAGE_CACHE_SIZE)
zero_user_page(page, count, PAGE_CACHE_SIZE - count, KM_USER0);
SetPageUptodate(page);
}

Expand Down Expand Up @@ -627,7 +625,8 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
return ERR_PTR(error);
}
spin_unlock(&inode->i_lock);
return new;
req = new;
goto zero_page;
}
spin_unlock(&inode->i_lock);

Expand Down Expand Up @@ -655,13 +654,23 @@ static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
if (offset < req->wb_offset) {
req->wb_offset = offset;
req->wb_pgbase = offset;
req->wb_bytes = rqend - req->wb_offset;
req->wb_bytes = max(end, rqend) - req->wb_offset;
goto zero_page;
}

if (end > rqend)
req->wb_bytes = end - req->wb_offset;

return req;
zero_page:
/* If this page might potentially be marked as up to date,
* then we need to zero any uninitalised data. */
if (req->wb_pgbase == 0 && req->wb_bytes != PAGE_CACHE_SIZE
&& !PageUptodate(req->wb_page))
zero_user_page(req->wb_page, req->wb_bytes,
PAGE_CACHE_SIZE - req->wb_bytes,
KM_USER0);
return req;
}

int nfs_flush_incompatible(struct file *file, struct page *page)
Expand Down

0 comments on commit 61e930a

Please sign in to comment.