Re: another nfs puzzle

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2005-12-06 at 14:04 -0800, Kenny Simpson wrote:
> Hi again,
>   I am seeing some odd behavior with O_DIRECT.  If a file opened with O_DIRECT has a page mmap'd,
> and the file is extended via pwrite, then the mmap'd region seems to get lost - i.e. it neither
> takes up system memory, nor does it get written out.
> 

Does the attached patch fix it?

Cheers,
  Trond

NFS: Fix another O_DIRECT race

 Ensure we call unmap_mapping_range() and sync dirty pages to disk before
 doing an NFS direct write.

 Signed-off-by: Trond Myklebust <[email protected]>
---

 fs/nfs/direct.c |   43 ++++++++++++++++++++++++-------------------
 1 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index a2d2814..ce83000 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -111,6 +111,21 @@ nfs_get_user_pages(int rw, unsigned long
 	return result;
 }
 
+static int nfs_sync_mapping(struct address_space *mapping, loff_t offset, size_t len)
+{
+	int ret;
+	if (mapping->nrpages)
+		return 0;
+
+	unmap_mapping_range(mapping, offset, len, 0);
+	ret = filemap_fdatawrite(mapping);
+	if (ret == 0)
+		ret = filemap_fdatawait(mapping);
+	if (ret == 0)
+		ret = nfs_wb_all(mapping->host);
+	return ret;
+}
+
 /**
  * nfs_free_user_pages - tear down page struct array
  * @pages: array of page struct pointers underlying target buffer
@@ -676,15 +691,9 @@ nfs_file_direct_read(struct kiocb *iocb,
 	if (!count)
 		goto out;
 
-	if (mapping->nrpages) {
-		retval = filemap_fdatawrite(mapping);
-		if (retval == 0)
-			retval = nfs_wb_all(inode);
-		if (retval == 0)
-			retval = filemap_fdatawait(mapping);
-		if (retval)
-			goto out;
-	}
+	retval = nfs_sync_mapping(mapping, pos, count);
+	if (retval)
+		goto out;
 
 	retval = nfs_direct_read(inode, ctx, &iov, pos, 1);
 	if (retval > 0)
@@ -762,19 +771,15 @@ nfs_file_direct_write(struct kiocb *iocb
 	if (!count)
 		goto out;
 
-	if (mapping->nrpages) {
-		retval = filemap_fdatawrite(mapping);
-		if (retval == 0)
-			retval = nfs_wb_all(inode);
-		if (retval == 0)
-			retval = filemap_fdatawait(mapping);
-		if (retval)
-			goto out;
-	}
+	retval = nfs_sync_mapping(mapping, pos, count);
+	if (retval)
+		goto out;
 
 	retval = nfs_direct_write(inode, ctx, &iov, pos, 1);
 	if (mapping->nrpages)
-		invalidate_inode_pages2(mapping);
+		invalidate_inode_pages2_range(mapping,
+				pos >> PAGE_CACHE_SHIFT,
+				(pos + count - 1) >> PAGE_CACHE_SHIFT);
 	if (retval > 0)
 		*ppos = pos + retval;
 

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux