All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nick Piggin <npiggin@suse.de>
To: Christoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@ZenIV.linux.org.uk>,
	linux-fsdevel@vger.kernel.org, Miklos Szeredi <miklos@szeredi.hu>
Subject: [patch v2] fix truncate inode time modification breakage
Date: Thu, 3 Jun 2010 05:55:38 +1000	[thread overview]
Message-ID: <20100602195538.GG6152@laptop> (raw)
In-Reply-To: <20100601135655.GU9453@laptop>

On Tue, Jun 01, 2010 at 11:56:55PM +1000, Nick Piggin wrote:
> On Tue, Jun 01, 2010 at 03:48:01PM +0200, Christoph Hellwig wrote:
> > On Tue, Jun 01, 2010 at 11:39:23PM +1000, Nick Piggin wrote:
> > > It appears that I've broken inode time modifications on tmpfs/ext2.
> > > While ftruncate always updates these attributes, truncate must not
> > > unless size is changed. I hadn't actually understood that until
> > > Christoph told me.
> > > 
> > > Confusion is increased because other filesystems get this wrong.
> > > Those without ->setattr or ->truncate get it wrong by default.
> > > Others appear to have problems too.
> > > 
> > > I haven't gone through many yet, but is there any reason not to
> > > just do it in the vfs?
> > 
> > Doing it in the VFS is fine with me, we still have the the file
> > pointer in struct iatta to indicate a ftruncate / open O_TRUNC
> > if any filesystem really cares.  But I think you need to audit
> > all instances if they care about this.  And while you're at it
> > also remove the code handling this and the comments about it in
> > XFS.
> 
> Yes I was starting to look at that. Just want to see if I'm on the
> right track.
> 
>  
> > > -	if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
> > > -		loff_t newsize = attr->ia_size;
> > > +	if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE) &&
> > > +						newsize != inode->i_size) {
> > 
> > Btw, the S_ISREG is superflous - we only ever set ATTR_SIZE for
> > regular files from the upper layer code.
> 
> OK I'll get rid of it in the same patch.

Well I looked through filesystems and I cannot seem to find anywhere
they can use ATTR_SIZE|ATTR_[MC]TIME to do anything strange that would
let them distinguish truncate from ftruncate and O_TRUNC.

I couldn't quite understand what FUSE was trying to do, or whether I
improved it.
---

Index: linux-2.6/fs/ext2/inode.c
===================================================================
--- linux-2.6.orig/fs/ext2/inode.c
+++ linux-2.6/fs/ext2/inode.c
@@ -1203,7 +1203,6 @@ int ext2_setsize(struct inode *inode, lo
 
 	__ext2_truncate_blocks(inode, newsize);
 
-	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
 	if (inode_needs_sync(inode)) {
 		sync_mapping_buffers(inode->i_mapping);
 		ext2_sync_inode (inode);
Index: linux-2.6/fs/open.c
===================================================================
--- linux-2.6.orig/fs/open.c
+++ linux-2.6/fs/open.c
@@ -55,6 +55,9 @@ int do_truncate(struct dentry *dentry, l
 		newattrs.ia_valid |= ret | ATTR_FORCE;
 
 	mutex_lock(&dentry->d_inode->i_mutex);
+	/* Unlike ftruncate, truncate only updates times when size changes */
+	if (length != dentry->d_inode->i_size)
+		newattrs.ia_valid |= ATTR_MTIME|ATTR_CTIME;
 	ret = notify_change(dentry, &newattrs);
 	mutex_unlock(&dentry->d_inode->i_mutex);
 	return ret;
Index: linux-2.6/mm/shmem.c
===================================================================
--- linux-2.6.orig/mm/shmem.c
+++ linux-2.6/mm/shmem.c
@@ -764,10 +764,10 @@ done2:
 static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
+	loff_t newsize = attr->ia_size;
 	int error;
 
-	if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
-		loff_t newsize = attr->ia_size;
+	if ((attr->ia_valid & ATTR_SIZE) && newsize != inode->i_size) {
 		struct page *page = NULL;
 
 		if (newsize < inode->i_size) {
Index: linux-2.6/fs/ramfs/file-nommu.c
===================================================================
--- linux-2.6.orig/fs/ramfs/file-nommu.c
+++ linux-2.6/fs/ramfs/file-nommu.c
@@ -175,11 +175,6 @@ static int ramfs_nommu_setattr(struct de
 			ret = ramfs_nommu_resize(inode, ia->ia_size, size);
 			if (ret < 0 || ia->ia_valid == ATTR_SIZE)
 				goto out;
-		} else {
-			/* we skipped the truncate but must still update
-			 * timestamps
-			 */
-			ia->ia_valid |= ATTR_MTIME|ATTR_CTIME;
 		}
 	}
 
Index: linux-2.6/fs/xfs/xfs_vnodeops.c
===================================================================
--- linux-2.6.orig/fs/xfs/xfs_vnodeops.c
+++ linux-2.6/fs/xfs/xfs_vnodeops.c
@@ -286,25 +286,6 @@ xfs_setattr(
 		xfs_trans_ijoin(tp, ip, lock_flags);
 		xfs_trans_ihold(tp, ip);
 
-		/*
-		 * Only change the c/mtime if we are changing the size
-		 * or we are explicitly asked to change it. This handles
-		 * the semantic difference between truncate() and ftruncate()
-		 * as implemented in the VFS.
-		 *
-		 * The regular truncate() case without ATTR_CTIME and ATTR_MTIME
-		 * is a special case where we need to update the times despite
-		 * not having these flags set.  For all other operations the
-		 * VFS set these flags explicitly if it wants a timestamp
-		 * update.
-		 */
-		if (iattr->ia_size != ip->i_size &&
-		    (!(mask & (ATTR_CTIME | ATTR_MTIME)))) {
-			iattr->ia_ctime = iattr->ia_mtime =
-				current_fs_time(inode->i_sb);
-			mask |= ATTR_CTIME | ATTR_MTIME;
-		}
-
 		if (iattr->ia_size > ip->i_size) {
 			ip->i_d.di_size = iattr->ia_size;
 			ip->i_size = iattr->ia_size;
Index: linux-2.6/fs/fuse/dir.c
===================================================================
--- linux-2.6.orig/fs/fuse/dir.c
+++ linux-2.6/fs/fuse/dir.c
@@ -1161,20 +1161,6 @@ static int fuse_dir_fsync(struct file *f
 	return fuse_fsync_common(file, datasync, 1);
 }
 
-static bool update_mtime(unsigned ivalid)
-{
-	/* Always update if mtime is explicitly set  */
-	if (ivalid & ATTR_MTIME_SET)
-		return true;
-
-	/* If it's an open(O_TRUNC) or an ftruncate(), don't update */
-	if ((ivalid & ATTR_SIZE) && (ivalid & (ATTR_OPEN | ATTR_FILE)))
-		return false;
-
-	/* In all other cases update */
-	return true;
-}
-
 static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
 {
 	unsigned ivalid = iattr->ia_valid;
@@ -1194,7 +1180,7 @@ static void iattr_to_fattr(struct iattr
 		if (!(ivalid & ATTR_ATIME_SET))
 			arg->valid |= FATTR_ATIME_NOW;
 	}
-	if ((ivalid & ATTR_MTIME) && update_mtime(ivalid)) {
+	if (ivalid & ATTR_MTIME) {
 		arg->valid |= FATTR_MTIME;
 		arg->mtime = iattr->ia_mtime.tv_sec;
 		arg->mtimensec = iattr->ia_mtime.tv_nsec;
Index: linux-2.6/fs/ntfs/inode.c
===================================================================
--- linux-2.6.orig/fs/ntfs/inode.c
+++ linux-2.6/fs/ntfs/inode.c
@@ -2917,12 +2917,6 @@ int ntfs_setattr(struct dentry *dentry,
 				err = vmtruncate(vi, attr->ia_size);
 			if (err || ia_valid == ATTR_SIZE)
 				goto out;
-		} else {
-			/*
-			 * We skipped the truncate but must still update
-			 * timestamps.
-			 */
-			ia_valid |= ATTR_MTIME | ATTR_CTIME;
 		}
 	}
 	if (ia_valid & ATTR_ATIME)
Index: linux-2.6/fs/reiserfs/inode.c
===================================================================
--- linux-2.6.orig/fs/reiserfs/inode.c
+++ linux-2.6/fs/reiserfs/inode.c
@@ -3105,11 +3105,6 @@ int reiserfs_setattr(struct dentry *dent
 			}
 			if (error)
 				goto out;
-			/*
-			 * file size is changed, ctime and mtime are
-			 * to be updated
-			 */
-			attr->ia_valid |= (ATTR_MTIME | ATTR_CTIME);
 		}
 	}
 
Index: linux-2.6/fs/ubifs/file.c
===================================================================
--- linux-2.6.orig/fs/ubifs/file.c
+++ linux-2.6/fs/ubifs/file.c
@@ -1175,8 +1175,6 @@ static int do_truncation(struct ubifs_in
 
 	mutex_lock(&ui->ui_mutex);
 	ui->ui_size = inode->i_size;
-	/* Truncation changes inode [mc]time */
-	inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
 	/* Other attributes may be changed at the same time as well */
 	do_attr_changes(inode, attr);
 	err = ubifs_jnl_truncate(c, inode, old_size, new_size);
@@ -1224,8 +1222,6 @@ static int do_setattr(struct ubifs_info
 
 	mutex_lock(&ui->ui_mutex);
 	if (attr->ia_valid & ATTR_SIZE) {
-		/* Truncation changes inode [mc]time */
-		inode->i_mtime = inode->i_ctime = ubifs_current_time(inode);
 		/* 'simple_setsize()' changed @i_size, update @ui_size */
 		ui->ui_size = inode->i_size;
 	}

  reply	other threads:[~2010-06-02 19:55 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-06-01 13:39 [patch] fix truncate inode time modification breakage Nick Piggin
2010-06-01 13:48 ` Christoph Hellwig
2010-06-01 13:56   ` Nick Piggin
2010-06-02 19:55     ` Nick Piggin [this message]
2010-06-02 20:08       ` Filesystem setattr/truncate notes and problems Nick Piggin
2010-06-03  7:28         ` Christoph Hellwig
2010-06-03  7:32           ` Christoph Hellwig
2010-06-03  9:50             ` Nick Piggin
2010-06-03  9:18           ` Nick Piggin
2010-06-03  9:26         ` Nick Piggin
2010-06-03  8:18       ` [patch v2] fix truncate inode time modification breakage Miklos Szeredi
2010-06-03  8:40         ` Boaz Harrosh
2010-06-03  9:05           ` Miklos Szeredi
2010-06-03 12:13             ` Boaz Harrosh
2010-06-03  9:14         ` Nick Piggin
2010-06-03  9:28           ` Miklos Szeredi
2010-06-03 10:07             ` Nick Piggin
2010-06-03 10:58               ` Miklos Szeredi
2010-06-03 11:09                 ` Christoph Hellwig
2010-06-03 12:01                   ` [patch v3] " Nick Piggin
2010-06-03 11:49                 ` [patch v2] " Nick Piggin
2010-06-03 12:03                   ` Miklos Szeredi
2010-06-01 14:10 ` [patch] " Boaz Harrosh
2010-06-01 14:32   ` Nick Piggin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20100602195538.GG6152@laptop \
    --to=npiggin@suse.de \
    --cc=hch@lst.de \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=viro@ZenIV.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.