commit a1a0d79533b9698b3a40d0091fe69a86386d44bb
Author: Trond Myklebust <[EMAIL PROTECTED]>
Date:   Fri Feb 8 14:01:02 2008 -0500

    NFS: Fix a potential file corruption issue when writing
    
    patch 5d47a35600270e7115061cb1320ee60ae9bcb6b8 in mainline.
    
    If the inode is flagged as having an invalid mapping, then we can't rely on
    the PageUptodate() flag. Ensure that we don't use the "anti-fragmentation"
    write optimisation in nfs_updatepage(), since that will cause NFS to write
    out areas of the page that are no longer guaranteed to be up to date.
    
    A potential corruption could occur in the following scenario:
    
    client 1                    client 2
    ===============                     ===============
                                fd=open("f",O_CREAT|O_WRONLY,0644);
                                write(fd,"fubar\n",6);  // cache last page
                                close(fd);
    fd=open("f",O_WRONLY|O_APPEND);
    write(fd,"foo\n",4);
    close(fd);
    
                                fd=open("f",O_WRONLY|O_APPEND);
                                write(fd,"bar\n",4);
                                close(fd);
    -----
    The bug may lead to the file "f" reading 'fubar\n\0\0\0\nbar\n' because
    client 2 does not update the cached page after re-opening the file for
    write. Instead it keeps it marked as PageUptodate() until someone calls
    invalidate_inode_pages2() (typically by calling read()).
    
    The bug was introduced by commit 44b11874ff583b6e766a05856b04f3c492c32b84
    "NFS: Separate metadata and page cache revalidation mechanisms"
    
    Signed-off-by: Trond Myklebust <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>

diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 51cc1bd..855b6d5 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -701,6 +701,17 @@ int nfs_flush_incompatible(struct file *file, struct page 
*page)
 }
 
 /*
+ * If the page cache is marked as unsafe or invalid, then we can't rely on
+ * the PageUptodate() flag. In this case, we will need to turn off
+ * write optimisations that depend on the page contents being correct.
+ */
+static int nfs_write_pageuptodate(struct page *page, struct inode *inode)
+{
+       return PageUptodate(page) &&
+               !(NFS_I(inode)->cache_validity & 
(NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA));
+}
+
+/*
  * Update and possibly write a cached page of an NFS file.
  *
  * XXX: Keep an eye on generic_file_read to make sure it doesn't do bad
@@ -721,10 +732,13 @@ int nfs_updatepage(struct file *file, struct page *page,
                (long long)(page_offset(page) +offset));
 
        /* If we're not using byte range locks, and we know the page
-        * is entirely in cache, it may be more efficient to avoid
-        * fragmenting write requests.
+        * is up to date, it may be more efficient to extend the write
+        * to cover the entire page in order to avoid fragmentation
+        * inefficiencies.
         */
-       if (PageUptodate(page) && inode->i_flock == NULL && !(file->f_mode & 
O_SYNC)) {
+       if (nfs_write_pageuptodate(page, inode) &&
+                       inode->i_flock == NULL &&
+                       !(file->f_mode & O_SYNC)) {
                count = max(count + offset, nfs_page_length(page));
                offset = 0;
        }
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to