All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch] fix truncate inode time modification breakage
@ 2010-06-01 13:39 Nick Piggin
  2010-06-01 13:48 ` Christoph Hellwig
  2010-06-01 14:10 ` [patch] " Boaz Harrosh
  0 siblings, 2 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-01 13:39 UTC (permalink / raw)
  To: Al Viro, Christoph Hellwig, linux-fsdevel

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?

---
 fs/ext2/inode.c       |    1 -
 fs/open.c             |    3 +++
 fs/ramfs/file-nommu.c |    5 -----
 mm/shmem.c            |    5 +++--
 4 files changed, 6 insertions(+), 8 deletions(-)

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,11 @@ 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 (S_ISREG(inode->i_mode) && (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;
 		}
 	}
 


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch] fix truncate inode time modification breakage
  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-01 14:10 ` [patch] " Boaz Harrosh
  1 sibling, 1 reply; 24+ messages in thread
From: Christoph Hellwig @ 2010-06-01 13:48 UTC (permalink / raw)
  To: Nick Piggin; +Cc: Al Viro, Christoph Hellwig, linux-fsdevel

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.

> -	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.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch] fix truncate inode time modification breakage
  2010-06-01 13:48 ` Christoph Hellwig
@ 2010-06-01 13:56   ` Nick Piggin
  2010-06-02 19:55     ` [patch v2] " Nick Piggin
  0 siblings, 1 reply; 24+ messages in thread
From: Nick Piggin @ 2010-06-01 13:56 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Al Viro, linux-fsdevel

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.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch] fix truncate inode time modification breakage
  2010-06-01 13:39 [patch] fix truncate inode time modification breakage Nick Piggin
  2010-06-01 13:48 ` Christoph Hellwig
@ 2010-06-01 14:10 ` Boaz Harrosh
  2010-06-01 14:32   ` Nick Piggin
  1 sibling, 1 reply; 24+ messages in thread
From: Boaz Harrosh @ 2010-06-01 14:10 UTC (permalink / raw)
  To: Nick Piggin; +Cc: Al Viro, Christoph Hellwig, linux-fsdevel

On 06/01/2010 04:39 PM, 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?
> 
> ---
>  fs/ext2/inode.c       |    1 -
>  fs/open.c             |    3 +++
>  fs/ramfs/file-nommu.c |    5 -----
>  mm/shmem.c            |    5 +++--
>  4 files changed, 6 insertions(+), 8 deletions(-)
> 
> 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;

OK I was just investigating this. Please forgive my noviceness here:

So i_mtime is modifications time. i_ctime is creation time?

if I do ftrunc() (like dd skip=x) don't I want modification time changed
but creation time unchanged?

if I do chmod/chown do I want modification-time changed creation not?

open+truncate both m an c changed?

modification-time: is it any aspect of the file has changed? or just the actual data / size?

Confused?

Boaz

>  	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,11 @@ 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 (S_ISREG(inode->i_mode) && (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;
>  		}
>  	}
>  
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch] fix truncate inode time modification breakage
  2010-06-01 14:10 ` [patch] " Boaz Harrosh
@ 2010-06-01 14:32   ` Nick Piggin
  0 siblings, 0 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-01 14:32 UTC (permalink / raw)
  To: Boaz Harrosh; +Cc: Al Viro, Christoph Hellwig, linux-fsdevel

On Tue, Jun 01, 2010 at 05:10:05PM +0300, Boaz Harrosh wrote:
> On 06/01/2010 04:39 PM, 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?
> > 
> > ---
> >  fs/ext2/inode.c       |    1 -
> >  fs/open.c             |    3 +++
> >  fs/ramfs/file-nommu.c |    5 -----
> >  mm/shmem.c            |    5 +++--
> >  4 files changed, 6 insertions(+), 8 deletions(-)
> > 
> > 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;
> 
> OK I was just investigating this. Please forgive my noviceness here:
> 
> So i_mtime is modifications time. i_ctime is creation time?
> 
> if I do ftrunc() (like dd skip=x) don't I want modification time changed
> but creation time unchanged?

It's change time and modification time. modification time is for data
modification. change time is for data and metadata as far as I know
(with various little historic quirks like truncate/ftruncate).


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [patch v2] fix truncate inode time modification breakage
  2010-06-01 13:56   ` Nick Piggin
@ 2010-06-02 19:55     ` Nick Piggin
  2010-06-02 20:08       ` Filesystem setattr/truncate notes and problems Nick Piggin
  2010-06-03  8:18       ` [patch v2] fix truncate inode time modification breakage Miklos Szeredi
  0 siblings, 2 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-02 19:55 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Al Viro, linux-fsdevel, Miklos Szeredi

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;
 	}

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Filesystem setattr/truncate notes and problems
  2010-06-02 19:55     ` [patch v2] " Nick Piggin
@ 2010-06-02 20:08       ` Nick Piggin
  2010-06-03  7:28         ` Christoph Hellwig
  2010-06-03  9:26         ` Nick Piggin
  2010-06-03  8:18       ` [patch v2] fix truncate inode time modification breakage Miklos Szeredi
  1 sibling, 2 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-02 20:08 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Al Viro, linux-fsdevel, Miklos Szeredi

On Thu, Jun 03, 2010 at 05:55:38AM +1000, Nick Piggin wrote:
> 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.

Looking through the filesystems, I thought I found a number of issues.
I'll try to list what I understand to be important steps required in
setattr. Unless I'm way off, a lot of filesystems get these wrong, so
we may want to add some guideline to docs?

Anyway feedback on these would be appreciated. Below this there are
some questions about specific filesystems too.

Filesystems setattr methods should:

- Perform idempotent error checks as early as possible. Perform actual
  i_size change and pagecache truncation last[*]. Truncate means dirty
  pagecache is fine to be thrown out at any time[**], what is important
  is that it is not thrown out before the operation can complete (eg. by
  doing the on-disk truncation).

  [*] Pagecache truncation is irreversable unless the filesystem can
  guarantee that the page is not mapped and has no dangling
  get_user_pages references (it's almost impossible to check this
  properly unless get_user_pages is disallowed from the start) or the
  file has been readonly. Just writing back the pagecache does not
  guarantee no data loss window. So it's probably easiest to do
  pagecache truncation last.

  [**] Be careful, this might mean the page is subject to writeout
  inside i_size after the on-disk truncation. Buffer based filesystems
  will probably need rework to handle this properly.

- Update mtime and ctime IFF ATTR_MTIME and ATTR_CTIME are set in
  setattr.

- Update mode before owner or size if mode update can fail. Otherwise
  killing of suid could fail after owner/size has changed (ideally
  these would be all done atomically). Although we do already have weird
  races in permission checking in core vfs code anyway.

- Perform time modifications iff others have/will succeeded (these are
  applicable for chmod, chown, etc too). Do not succeed a truncate and
  then error out because the time cannot be set. Do not set the time but
  fail the truncate or chown etc.

- If ATTR_SIZE change cannot succeed, don't ignore it, return something
  (like -EPERM or -EINVAL), right? (lots of filesystems just mask it
  off, maybe that is preferable behaviour sometimes?)

- Remember to actually trim off disk blocks or underlying object past
  i_size in response to setattr shrinking the file.

- In case of write_begin/write_end/direct_IO failure, trim object past
  i_size if it was possible to have been allocated before the operation
  fails.


Interesting specific filesystem questions: (not comprehensive)

ecryptfs improve mtime/ctime handling for truncate of lower inode

fuse, should be setting ctime on truncate?

gfs2, mtime and ctime should only be set in truncate if the ATTR_?TIME
are set.

hostfs, don't ignore ATTR_SIZE. ftruncate/truncate have interesting
different semantics for timestamp updates, so don't use fd != -1 for
these (could use utimes for this, but it causes an atomicity/error
handling issue).

hpfs could use cont_expand to do expanding truncates?

ncpfs, nfs smbfs, cifs seems to perform inode size checks
(inode_newsize_ok) after truncating the file on the server??

ntfs does not do inode size checks properly.

logfs logfs_truncate without doing inode_change_ok, inode_newsize_ok etc
can fail inode_setattr after successful truncate (truncate(2) would
return failure and yet the file would be truncated).

procfs why not return -EPERM rather than setting size?

reiserfs should do all setattr checks early as possible
(inode_change_ok, inode_newsize_ok).

ubifs should not update access times unconditionally when ATTR_SIZE is
set

ufs simple_setsize still destroys the pagecache and causes concurrent
reads to go EOF past updated i_size. Restoring old i_size is too late
I think. Should do those checks first (in fairness lots of filesystems
have bit problems with error handling, but ufs attempts a little bit and
gets it wrong).

xfs in the 0 length file shortcut, isn't this missing suid kill case?
(ftruncate mandatory mtime update seems like it wasn't working right
there either before this patch).

nfsd should not change attributes in the case of truncated file with no
size change?


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Filesystem setattr/truncate notes and problems
  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:18           ` Nick Piggin
  2010-06-03  9:26         ` Nick Piggin
  1 sibling, 2 replies; 24+ messages in thread
From: Christoph Hellwig @ 2010-06-03  7:28 UTC (permalink / raw)
  To: Nick Piggin; +Cc: Christoph Hellwig, Al Viro, linux-fsdevel, Miklos Szeredi

On Thu, Jun 03, 2010 at 06:08:55AM +1000, Nick Piggin wrote:
> xfs in the 0 length file shortcut, isn't this missing suid kill case?
> (ftruncate mandatory mtime update seems like it wasn't working right
> there either before this patch).

The wording from Posix for truncate is:

"Upon successful completion, if the file size is changed, this function
 shall mark for update the st_ctime and st_mtime fields of the file, and
 the S_ISUID and S_ISGID bits of the file mode may be cleared."

and for truncate:

"Upon successful completion, if fildes refers to a regular file, the
 ftruncate() function shall mark for update the st_ctime and st_mtime
 fields of the file and the S_ISUID and S_ISGID bits of the file mode
 may be cleared."

Which translates to me that the suid/sgid clearing behaviour is
exactly the same as the c/mtime update and it can be skipped for
truncate only if there is no size change.  Except that the wording
is rather nasty as the suid/sgid bits are only accepted into Posix
as an ugly headed stepchild and may not actually be present on
some systems.

Which means XFS behaviour for truncate while not strictly against
Posix is at least unexpected.  I'll fix it up.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Filesystem setattr/truncate notes and problems
  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
  1 sibling, 1 reply; 24+ messages in thread
From: Christoph Hellwig @ 2010-06-03  7:32 UTC (permalink / raw)
  To: Nick Piggin; +Cc: Christoph Hellwig, Al Viro, linux-fsdevel, Miklos Szeredi

On Thu, Jun 03, 2010 at 09:28:12AM +0200, Christoph Hellwig wrote:
> Which means XFS behaviour for truncate while not strictly against
> Posix is at least unexpected.  I'll fix it up.

Actually I'd prefer if you could throw this into your do_truncate
patch so that filesystems don't get the clear suid request if
the file size doesn't change.  That way I can just change XFS
to do everything requested but the actual size update for that case.
In fact just clearing out ATTR_SIZE in that case in do_truncate would
be nice.

Which brings up the question: are we guaranteed to have stable
and uptodate i_size in do_truncate?  I think normally we'd need
a ->getattr first to stabilize it.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-02 19:55     ` [patch v2] " Nick Piggin
  2010-06-02 20:08       ` Filesystem setattr/truncate notes and problems Nick Piggin
@ 2010-06-03  8:18       ` Miklos Szeredi
  2010-06-03  8:40         ` Boaz Harrosh
  2010-06-03  9:14         ` Nick Piggin
  1 sibling, 2 replies; 24+ messages in thread
From: Miklos Szeredi @ 2010-06-03  8:18 UTC (permalink / raw)
  To: Nick Piggin; +Cc: hch, viro, linux-fsdevel, miklos

On Thu, 3 Jun 2010, Nick Piggin wrote:
> 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;
> -}
> -

Fuse philosophy is: each operation itself has to update times on files
if necessary.  So it basically moves the responsibility to update
[amc]time from the VFS into the filesystem.

This means the only place fuse is interested in ATTR_ATIME or
ATTR_MTIME is for the utime* syscalls.

It also means that fuse always ignores ATTR_CTIME which is never set
explicitly.

So I believe the current fuse code is correct.

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  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  9:14         ` Nick Piggin
  1 sibling, 1 reply; 24+ messages in thread
From: Boaz Harrosh @ 2010-06-03  8:40 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Nick Piggin, hch, viro, linux-fsdevel

On 06/03/2010 11:18 AM, Miklos Szeredi wrote:
> On Thu, 3 Jun 2010, Nick Piggin wrote:
>> 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;
>> -}
>> -
> 
> Fuse philosophy is: each operation itself has to update times on files
> if necessary.  So it basically moves the responsibility to update
> [amc]time from the VFS into the filesystem.
> 
> This means the only place fuse is interested in ATTR_ATIME or
> ATTR_MTIME is for the utime* syscalls.
> 
> It also means that fuse always ignores ATTR_CTIME which is never set
> explicitly.
> 
> So I believe the current fuse code is correct.
> 

It might be correct, but there were reports it has problems with NFS export.
Why let the filesystems be broken? Why not do the common stuff common? (In VFS)

Boaz

> Thanks,
> Miklos
> --
> To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03  8:40         ` Boaz Harrosh
@ 2010-06-03  9:05           ` Miklos Szeredi
  2010-06-03 12:13             ` Boaz Harrosh
  0 siblings, 1 reply; 24+ messages in thread
From: Miklos Szeredi @ 2010-06-03  9:05 UTC (permalink / raw)
  To: Boaz Harrosh; +Cc: miklos, npiggin, hch, viro, linux-fsdevel

On Thu, 03 Jun 2010, Boaz Harrosh wrote:
> > Fuse philosophy is: each operation itself has to update times on files
> > if necessary.  So it basically moves the responsibility to update
> > [amc]time from the VFS into the filesystem.
> > 
> > This means the only place fuse is interested in ATTR_ATIME or
> > ATTR_MTIME is for the utime* syscalls.
> > 
> > It also means that fuse always ignores ATTR_CTIME which is never set
> > explicitly.
> > 
> > So I believe the current fuse code is correct.
> > 
> 
> It might be correct, but there were reports it has problems with NFS export.

Do you have details?  I can't remember any report related to time
modification and NFS export.

> Why let the filesystems be broken? Why not do the common stuff
> common? (In VFS)

For consistency and simplicity.  The fuse API looks much like the
syscall API, which means that for a truncate() call on a fuse file the
truncate() method will be called in the filesystem, not a truncate() +
utimes().  And so on...

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  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:14         ` Nick Piggin
  2010-06-03  9:28           ` Miklos Szeredi
  1 sibling, 1 reply; 24+ messages in thread
From: Nick Piggin @ 2010-06-03  9:14 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: hch, viro, linux-fsdevel

On Thu, Jun 03, 2010 at 10:18:24AM +0200, Miklos Szeredi wrote:
> On Thu, 3 Jun 2010, Nick Piggin wrote:
> > 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;
> > -}
> > -
> 
> Fuse philosophy is: each operation itself has to update times on files
> if necessary.  So it basically moves the responsibility to update
> [amc]time from the VFS into the filesystem.
> 
> This means the only place fuse is interested in ATTR_ATIME or
> ATTR_MTIME is for the utime* syscalls.

OK, makes sense. I wonder why you do ATTR_ATIME changes, though,
rather than just getting those too back from the filesystem?

Do you ever have a problem with inode's atime going backwards due
to differences between touch_atime and reading the atime from the
server?


> It also means that fuse always ignores ATTR_CTIME which is never set
> explicitly.
> 
> So I believe the current fuse code is correct.

After my patch to pass ATTR_MTIME|ATTR_CTIME from truncate(2), it is
not (because above won't return false, ie. it will change the mtime
for truncate).

Why not avoid all mtime updates except MTIME_SET?



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Filesystem setattr/truncate notes and problems
  2010-06-03  7:28         ` Christoph Hellwig
  2010-06-03  7:32           ` Christoph Hellwig
@ 2010-06-03  9:18           ` Nick Piggin
  1 sibling, 0 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-03  9:18 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Al Viro, linux-fsdevel, Miklos Szeredi

On Thu, Jun 03, 2010 at 09:28:12AM +0200, Christoph Hellwig wrote:
> On Thu, Jun 03, 2010 at 06:08:55AM +1000, Nick Piggin wrote:
> > xfs in the 0 length file shortcut, isn't this missing suid kill case?
> > (ftruncate mandatory mtime update seems like it wasn't working right
> > there either before this patch).
> 
> The wording from Posix for truncate is:
> 
> "Upon successful completion, if the file size is changed, this function
>  shall mark for update the st_ctime and st_mtime fields of the file, and
>  the S_ISUID and S_ISGID bits of the file mode may be cleared."
> 
> and for truncate:
> 
> "Upon successful completion, if fildes refers to a regular file, the
>  ftruncate() function shall mark for update the st_ctime and st_mtime
>  fields of the file and the S_ISUID and S_ISGID bits of the file mode
>  may be cleared."
> 
> Which translates to me that the suid/sgid clearing behaviour is
> exactly the same as the c/mtime update and it can be skipped for
> truncate only if there is no size change.  Except that the wording
> is rather nasty as the suid/sgid bits are only accepted into Posix
> as an ugly headed stepchild and may not actually be present on
> some systems.

Well at least we should do suid bit clearing consistently with ctime/mtime
updates if we do them at all, that part of the wording seems clear.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Filesystem setattr/truncate notes and problems
  2010-06-02 20:08       ` Filesystem setattr/truncate notes and problems Nick Piggin
  2010-06-03  7:28         ` Christoph Hellwig
@ 2010-06-03  9:26         ` Nick Piggin
  1 sibling, 0 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-03  9:26 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Al Viro, linux-fsdevel, Miklos Szeredi

On Thu, Jun 03, 2010 at 06:08:55AM +1000, Nick Piggin wrote:
> Interesting specific filesystem questions: (not comprehensive)
> 
> ecryptfs improve mtime/ctime handling for truncate of lower inode
> 
> fuse, should be setting ctime on truncate?
> 
> gfs2, mtime and ctime should only be set in truncate if the ATTR_?TIME
> are set.
> 
> hostfs, don't ignore ATTR_SIZE. ftruncate/truncate have interesting
> different semantics for timestamp updates, so don't use fd != -1 for
> these (could use utimes for this, but it causes an atomicity/error
> handling issue).
> 
> hpfs could use cont_expand to do expanding truncates?
> 
> ncpfs, nfs smbfs, cifs seems to perform inode size checks
> (inode_newsize_ok) after truncating the file on the server??
> 
> ntfs does not do inode size checks properly.
> 
> logfs logfs_truncate without doing inode_change_ok, inode_newsize_ok etc
> can fail inode_setattr after successful truncate (truncate(2) would
> return failure and yet the file would be truncated).
> 
> procfs why not return -EPERM rather than setting size?
> 
> reiserfs should do all setattr checks early as possible
> (inode_change_ok, inode_newsize_ok).
> 
> ubifs should not update access times unconditionally when ATTR_SIZE is
> set
> 
> ufs simple_setsize still destroys the pagecache and causes concurrent
> reads to go EOF past updated i_size. Restoring old i_size is too late
> I think. Should do those checks first (in fairness lots of filesystems
> have bit problems with error handling, but ufs attempts a little bit and
> gets it wrong).
> 
> xfs in the 0 length file shortcut, isn't this missing suid kill case?
> (ftruncate mandatory mtime update seems like it wasn't working right
> there either before this patch).
> 
> nfsd should not change attributes in the case of truncated file with no
> size change?

ceph doesn't seem to call inode_newsize_ok (so it's missing the rlimit
check).

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03  9:14         ` Nick Piggin
@ 2010-06-03  9:28           ` Miklos Szeredi
  2010-06-03 10:07             ` Nick Piggin
  0 siblings, 1 reply; 24+ messages in thread
From: Miklos Szeredi @ 2010-06-03  9:28 UTC (permalink / raw)
  To: Nick Piggin; +Cc: miklos, hch, viro, linux-fsdevel

On Thu, 3 Jun 2010, Nick Piggin wrote:
> > Fuse philosophy is: each operation itself has to update times on files
> > if necessary.  So it basically moves the responsibility to update
> > [amc]time from the VFS into the filesystem.
> > 
> > This means the only place fuse is interested in ATTR_ATIME or
> > ATTR_MTIME is for the utime* syscalls.
> 
> OK, makes sense. I wonder why you do ATTR_ATIME changes, though,
> rather than just getting those too back from the filesystem?

It does that, through setting S_NOATIME and invalidating attributes
after each op.

> > It also means that fuse always ignores ATTR_CTIME which is never set
> > explicitly.
> > 
> > So I believe the current fuse code is correct.
> 
> After my patch to pass ATTR_MTIME|ATTR_CTIME from truncate(2), it is
> not (because above won't return false, ie. it will change the mtime
> for truncate).
> 
> Why not avoid all mtime updates except MTIME_SET?

Because utimes(NULL) will supply only ATTR_ATIME | ATTR_MTIME.

I guess fuse should do something like this:

	if (valid ^ (ATTR_MTIME | ATTR_CTIME | ATTR_SIZE) == 0)
		valid = ATTR_SIZE;

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: Filesystem setattr/truncate notes and problems
  2010-06-03  7:32           ` Christoph Hellwig
@ 2010-06-03  9:50             ` Nick Piggin
  0 siblings, 0 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-03  9:50 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Al Viro, linux-fsdevel, Miklos Szeredi

On Thu, Jun 03, 2010 at 09:32:38AM +0200, Christoph Hellwig wrote:
> On Thu, Jun 03, 2010 at 09:28:12AM +0200, Christoph Hellwig wrote:
> > Which means XFS behaviour for truncate while not strictly against
> > Posix is at least unexpected.  I'll fix it up.
> 
> Actually I'd prefer if you could throw this into your do_truncate
> patch so that filesystems don't get the clear suid request if
> the file size doesn't change.

Yes it should be done the same way as mtime/ctime updates are
done.


>  That way I can just change XFS
> to do everything requested but the actual size update for that case.
> In fact just clearing out ATTR_SIZE in that case in do_truncate would
> be nice.

I thought I spotted a reason why why should not do that... I guess it
is because some filesystems were choosing to do things like update ctime
even when file size does not change. But if those all get stamped out,
it can probably go away.

 
> Which brings up the question: are we guaranteed to have stable
> and uptodate i_size in do_truncate?  I think normally we'd need
> a ->getattr first to stabilize it.

Good point actually. I wonder if it would be better then to pass down
specific flags from the truncate code, where filesystems can call a
helper to turn them into CTIME|MTIME|MODE flags when they have a
stable i_size?


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03  9:28           ` Miklos Szeredi
@ 2010-06-03 10:07             ` Nick Piggin
  2010-06-03 10:58               ` Miklos Szeredi
  0 siblings, 1 reply; 24+ messages in thread
From: Nick Piggin @ 2010-06-03 10:07 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: hch, viro, linux-fsdevel

On Thu, Jun 03, 2010 at 11:28:25AM +0200, Miklos Szeredi wrote:
> On Thu, 3 Jun 2010, Nick Piggin wrote:
> > > Fuse philosophy is: each operation itself has to update times on files
> > > if necessary.  So it basically moves the responsibility to update
> > > [amc]time from the VFS into the filesystem.
> > > 
> > > This means the only place fuse is interested in ATTR_ATIME or
> > > ATTR_MTIME is for the utime* syscalls.
> > 
> > OK, makes sense. I wonder why you do ATTR_ATIME changes, though,
> > rather than just getting those too back from the filesystem?
> 
> It does that, through setting S_NOATIME and invalidating attributes
> after each op.

Oh ok.

 
> > > It also means that fuse always ignores ATTR_CTIME which is never set
> > > explicitly.
> > > 
> > > So I believe the current fuse code is correct.
> > 
> > After my patch to pass ATTR_MTIME|ATTR_CTIME from truncate(2), it is
> > not (because above won't return false, ie. it will change the mtime
> > for truncate).
> > 
> > Why not avoid all mtime updates except MTIME_SET?
> 
> Because utimes(NULL) will supply only ATTR_ATIME | ATTR_MTIME.

Good answer.

 
> I guess fuse should do something like this:
> 
> 	if (valid ^ (ATTR_MTIME | ATTR_CTIME | ATTR_SIZE) == 0)
> 		valid = ATTR_SIZE;

You'll have to be careful, truncate will pass other things down like
mode to get rid of suid.

If you just wanted to ignore mtime changes on truncate, then masking
it off would be the way to go I think.

if (valid & ATTR_SIZE)
  valid &= ~ATTR_SIZE;

Would you also want to do the same thing with suid kill bits from
truncate, then? Mask off ATTR_MODE and just read it back from the
server too?


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03 10:07             ` Nick Piggin
@ 2010-06-03 10:58               ` Miklos Szeredi
  2010-06-03 11:09                 ` Christoph Hellwig
  2010-06-03 11:49                 ` [patch v2] " Nick Piggin
  0 siblings, 2 replies; 24+ messages in thread
From: Miklos Szeredi @ 2010-06-03 10:58 UTC (permalink / raw)
  To: Nick Piggin; +Cc: miklos, hch, viro, linux-fsdevel

On Thu, 3 Jun 2010, Nick Piggin wrote:
> You'll have to be careful, truncate will pass other things down like
> mode to get rid of suid.

Oh, right.

> If you just wanted to ignore mtime changes on truncate, then masking
> it off would be the way to go I think.
> 
> if (valid & ATTR_SIZE)
>   valid &= ~ATTR_SIZE;
> 
> Would you also want to do the same thing with suid kill bits from
> truncate, then? Mask off ATTR_MODE and just read it back from the
> server too?

That would be logical, but no, it didn't used to do that, and now it
can't start doing it for fear of creating a security hole.

Also suid removal happens very rarely compared to mtime update, so a
rare additional chmod request (which might be superfluous for some
filesystems) in addition to write and truncate is I think acceptable.

(In fact I think it would be cleanest if truncate/ftruncate was a
separate operation from setattr on all levels, but that's a different
story.)

So for now something like

	if (valid & ATTR_SIZE)
		valid &= ~(ATTR_MTIME | ATTR_CTIME);

would work?

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  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
  1 sibling, 1 reply; 24+ messages in thread
From: Christoph Hellwig @ 2010-06-03 11:09 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: Nick Piggin, hch, viro, linux-fsdevel

On Thu, Jun 03, 2010 at 12:58:22PM +0200, Miklos Szeredi wrote:
> (In fact I think it would be cleanest if truncate/ftruncate was a
> separate operation from setattr on all levels, but that's a different
> story.)

It might be.  Let's finish off the current transition after which
we should have all truncate code in a clean

	if (valid & ATTR_SIZE)

inside the setattr method.  We can think about re-introducing a
proper truncate method after that, although I'm not sure how much
duplication the timestamp and mode updates will mean.  The upside
of it is that many filesystems could remove the setattr method
after this, though.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03 10:58               ` Miklos Szeredi
  2010-06-03 11:09                 ` Christoph Hellwig
@ 2010-06-03 11:49                 ` Nick Piggin
  2010-06-03 12:03                   ` Miklos Szeredi
  1 sibling, 1 reply; 24+ messages in thread
From: Nick Piggin @ 2010-06-03 11:49 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: hch, viro, linux-fsdevel

On Thu, Jun 03, 2010 at 12:58:22PM +0200, Miklos Szeredi wrote:
> On Thu, 3 Jun 2010, Nick Piggin wrote:
> > You'll have to be careful, truncate will pass other things down like
> > mode to get rid of suid.
> 
> Oh, right.
> 
> > If you just wanted to ignore mtime changes on truncate, then masking
> > it off would be the way to go I think.
> > 
> > if (valid & ATTR_SIZE)
> >   valid &= ~ATTR_SIZE;
> > 
> > Would you also want to do the same thing with suid kill bits from
> > truncate, then? Mask off ATTR_MODE and just read it back from the
> > server too?
> 
> That would be logical, but no, it didn't used to do that, and now it
> can't start doing it for fear of creating a security hole.

OK.

 
> Also suid removal happens very rarely compared to mtime update, so a
> rare additional chmod request (which might be superfluous for some
> filesystems) in addition to write and truncate is I think acceptable.

Yeah no big deal. One little thing to put on the list if you ever need
bump the protocol version.

 
> (In fact I think it would be cleanest if truncate/ftruncate was a
> separate operation from setattr on all levels, but that's a different
> story.)

Well it's possible. It is a combination of inode and address space
operation really. Because you really want to update mtime/ctime and
suid bits iff the truncate succeeds.

We did consider a new API for it, but it didn't seem to be an
obvious improvement. A filesystem can easily branch into another
function for ATTR_SIZE immediately on setattr entry.

 
> So for now something like
> 
> 	if (valid & ATTR_SIZE)
> 		valid &= ~(ATTR_MTIME | ATTR_CTIME);
> 
> would work?

That should do the trick, yes. But I think CTIME would just confuse
things seeing as you ignore it everywhere else.


^ permalink raw reply	[flat|nested] 24+ messages in thread

* [patch v3] fix truncate inode time modification breakage
  2010-06-03 11:09                 ` Christoph Hellwig
@ 2010-06-03 12:01                   ` Nick Piggin
  0 siblings, 0 replies; 24+ messages in thread
From: Nick Piggin @ 2010-06-03 12:01 UTC (permalink / raw)
  To: Al Viro, Christoph Hellwig
  Cc: Miklos Szeredi, linux-fsdevel, linux-ext4, Hugh Dickins

I think this should be the best way to fix 2.6.35. I'll look at what
it takes to completely direct truncate time/mode changes from the vfs
probably on top of Christophs latest truncate patchsets.

--

mtime and ctime should be changed only if the file size has actually
changed. Patches changing ext2 and tmpfs from vmtruncate to new truncate
sequence has caused regressions where they always update timestamps.

There is some strange cases in POSIX where truncate(2) must not update
times unless the size has acutally changed, see 6e656be89.

This area is all still rather buggy in different ways in a lot of
filesystems and needs a cleanup and audit (ideally the vfs will provide
a simple attribute or call to direct all filesystems exactly which
attributes to change). But coming up with the best solution will take a
while and is not appropriate for rc anyway.

So fix recent regression for now.

Signed-off-by: Nick Piggin <npiggin@suse.de>

---
 fs/ext2/inode.c |    2 +-
 mm/shmem.c      |    5 +++--
 2 files changed, 4 insertions(+), 3 deletions(-)

Index: linux-2.6/mm/shmem.c
===================================================================
--- linux-2.6.orig/mm/shmem.c
+++ linux-2.6/mm/shmem.c
@@ -764,10 +764,11 @@ 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 (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)
+					&& newsize != inode->i_size) {
 		struct page *page = NULL;
 
 		if (newsize < inode->i_size) {
Index: linux-2.6/fs/ext2/inode.c
===================================================================
--- linux-2.6.orig/fs/ext2/inode.c
+++ linux-2.6/fs/ext2/inode.c
@@ -1552,7 +1552,7 @@ int ext2_setattr(struct dentry *dentry,
 		if (error)
 			return error;
 	}
-	if (iattr->ia_valid & ATTR_SIZE) {
+	if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) {
 		error = ext2_setsize(inode, iattr->ia_size);
 		if (error)
 			return error;

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03 11:49                 ` [patch v2] " Nick Piggin
@ 2010-06-03 12:03                   ` Miklos Szeredi
  0 siblings, 0 replies; 24+ messages in thread
From: Miklos Szeredi @ 2010-06-03 12:03 UTC (permalink / raw)
  To: Nick Piggin; +Cc: miklos, hch, viro, linux-fsdevel

On Thu, 3 Jun 2010, Nick Piggin wrote:
> > (In fact I think it would be cleanest if truncate/ftruncate was a
> > separate operation from setattr on all levels, but that's a different
> > story.)
> 
> Well it's possible. It is a combination of inode and address space
> operation really. Because you really want to update mtime/ctime and
> suid bits iff the truncate succeeds.

Well, same as write() really.  Except truncate is an inode op, while
ftruncate is a file op just like write.

> We did consider a new API for it, but it didn't seem to be an
> obvious improvement. A filesystem can easily branch into another
> function for ATTR_SIZE immediately on setattr entry.
> 
>  
> > So for now something like
> > 
> > 	if (valid & ATTR_SIZE)
> > 		valid &= ~(ATTR_MTIME | ATTR_CTIME);
> > 
> > would work?
> 
> That should do the trick, yes. But I think CTIME would just confuse
> things seeing as you ignore it everywhere else.

Yes.

Thanks,
Miklos




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [patch v2] fix truncate inode time modification breakage
  2010-06-03  9:05           ` Miklos Szeredi
@ 2010-06-03 12:13             ` Boaz Harrosh
  0 siblings, 0 replies; 24+ messages in thread
From: Boaz Harrosh @ 2010-06-03 12:13 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: npiggin, hch, viro, linux-fsdevel

On 06/03/2010 12:05 PM, Miklos Szeredi wrote:
> On Thu, 03 Jun 2010, Boaz Harrosh wrote:
>>> Fuse philosophy is: each operation itself has to update times on files
>>> if necessary.  So it basically moves the responsibility to update
>>> [amc]time from the VFS into the filesystem.
>>>
>>> This means the only place fuse is interested in ATTR_ATIME or
>>> ATTR_MTIME is for the utime* syscalls.
>>>
>>> It also means that fuse always ignores ATTR_CTIME which is never set
>>> explicitly.
>>>
>>> So I believe the current fuse code is correct.
>>>
>>
>> It might be correct, but there were reports it has problems with NFS export.
> 
> Do you have details?  I can't remember any report related to time
> modification and NFS export.
> 
>> Why let the filesystems be broken? Why not do the common stuff
>> common? (In VFS)
> 
> For consistency and simplicity.  The fuse API looks much like the
> syscall API, which means that for a truncate() call on a fuse file the
> truncate() method will be called in the filesystem, not a truncate() +
> utimes().  And so on...
> 

OK So that has now changed there is a ->setattr from VFS ->truncate is
been killed. And the VFS could be trusted to do what it knows how to do?
(I think)

> Thanks,
> Miklos

Boaz

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2010-06-03 12:13 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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     ` [patch v2] " Nick Piggin
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

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.