to den 01.09.2005 Klokka 19:38 (-0400) skreiv Trond Myklebust:
> This is a consequence of 2.6 NFS clients optimising away unnecessary
> truncate calls. Whereas this is correct behaviour for truncate(), it
> appears to be incorrect for open(O_TRUNC).
> 
> In fact, local filesystems like xfs and ext3 appear to have the opposite
> problem: they change ctime if you call ftruncate(0) on the zero-length
> file, as the attached test shows.

Rob,

Could you please check if the following patch fixes NFS (and also the
local filesystems) for you?

Cheers,
  Trond

VFS/NFS: Fix up behaviour w.r.t. truncate() and open(O_TRUNC)

 POSIX and the SUSv3 specify that open(O_TRUNC) should always bump ctime/mtime
 whereas truncate() should only do so if the file size actually changes.

 Fix the behaviour of NFS, which currently is broken w.r.t. open(), and fix
 the VFS truncate() so that it no enforces the POSIX rules.

 Signed-off-by: Trond Myklebust <[EMAIL PROTECTED]>
---
 nfs/inode.c |    5 -----
 open.c      |   12 ++++++++++--
 2 files changed, 10 insertions(+), 7 deletions(-)

Index: linux-2.6.13/fs/nfs/inode.c
===================================================================
--- linux-2.6.13.orig/fs/nfs/inode.c
+++ linux-2.6.13/fs/nfs/inode.c
@@ -833,11 +833,6 @@ nfs_setattr(struct dentry *dentry, struc
        struct nfs_fattr fattr;
        int error;
 
-       if (attr->ia_valid & ATTR_SIZE) {
-               if (!S_ISREG(inode->i_mode) || attr->ia_size == 
i_size_read(inode))
-                       attr->ia_valid &= ~ATTR_SIZE;
-       }
-
        /* Optimization: if the end result is no change, don't RPC */
        attr->ia_valid &= NFS_VALID_ATTRS;
        if (attr->ia_valid == 0)
Index: linux-2.6.13/fs/open.c
===================================================================
--- linux-2.6.13.orig/fs/open.c
+++ linux-2.6.13/fs/open.c
@@ -211,6 +211,14 @@ int do_truncate(struct dentry *dentry, l
        return err;
 }
 
+static inline int do_posix_truncate(struct dentry *dentry, loff_t length)
+{
+       /* In SuS/Posix lore, truncate to the current file size is a no-op */
+       if (length == i_size_read(dentry->d_inode))
+               return 0;
+       return do_truncate(dentry, length);
+}
+
 static inline long do_sys_truncate(const char __user * path, loff_t length)
 {
        struct nameidata nd;
@@ -261,7 +269,7 @@ static inline long do_sys_truncate(const
        error = locks_verify_truncate(inode, NULL, length);
        if (!error) {
                DQUOT_INIT(inode);
-               error = do_truncate(nd.dentry, length);
+               error = do_posix_truncate(nd.dentry, length);
        }
        put_write_access(inode);
 
@@ -313,7 +321,7 @@ static inline long do_sys_ftruncate(unsi
 
        error = locks_verify_truncate(inode, file, length);
        if (!error)
-               error = do_truncate(dentry, length);
+               error = do_posix_truncate(dentry, length);
 out_putf:
        fput(file);
 out:

Reply via email to