All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH ] Fix some problems with truncate and mtime semantics.
       [not found] <20051115125657.9403.patches@notabene>
@ 2005-11-15  2:00 ` NeilBrown
  2005-11-15  2:03   ` Trond Myklebust
                     ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: NeilBrown @ 2005-11-15  2:00 UTC (permalink / raw)
  To: Andrew Morton; +Cc: linux-kernel, Trond Myklebust

Resubmitting this patch to fix truncate/mtime semantics.  

It is against 2.6.14-mm2 and is probably suitable for 2.6.15, but can
be held over to 2.6.16 if you are feeling cautious.

NeilBrown

### Comments for Changeset

SUS requires that when truncating a file to the size that it currently
is:
  truncate and ftruncate should NOT modify ctime or mtime
  O_EXCL SHOULD modify ctime and mtime.

Currently mtime and ctime are always modified on most local
filesystems (side effect of ->truncate) or never modified (on NFS).

With this patch:
  ATTR_CTIME|ATTR_MTIME are sent with ATTR_SIZE precisely when 
    an update of these times is required whether size changes or not 
    (via a new argument to do_truncate).  This allows NFS to do
    the right thing for O_EXCL.
  inode_setattr nolonger forces ATTR_MTIME|ATTR_CTIME when the ATTR_SIZE
    sets the size to it's current value.  This allows local filesystems
    to do the right thing for f?truncate.
  
Also, the logic in inode_setattr is changed a bit so there are two
return points.  One returns the error from vmtruncate if it failed,
the other returns 0 (there can be no other failure).

Finally, if vmtruncate succeeds, and ATTR_SIZE is the only change
requested, we now fall-through and mark_inode_dirty.  If a filesystem
did not have a ->truncate function, then vmtruncate will have changed
i_size, without marking the inode as 'dirty', and I think this is wrong.


Signed-off-by: Neil Brown <neilb@suse.de>

### Diffstat output
 ./fs/attr.c          |   22 +++++++---------------
 ./fs/exec.c          |    2 +-
 ./fs/namei.c         |    2 +-
 ./fs/open.c          |    9 +++++----
 ./include/linux/fs.h |    3 ++-
 5 files changed, 16 insertions(+), 22 deletions(-)

diff ./fs/attr.c~current~ ./fs/attr.c
--- ./fs/attr.c~current~	2005-11-15 10:29:55.000000000 +1100
+++ ./fs/attr.c	2005-11-15 10:29:55.000000000 +1100
@@ -67,20 +67,12 @@ EXPORT_SYMBOL(inode_change_ok);
 int inode_setattr(struct inode * inode, struct iattr * attr)
 {
 	unsigned int ia_valid = attr->ia_valid;
-	int error = 0;
 
-	if (ia_valid & ATTR_SIZE) {
-		if (attr->ia_size != i_size_read(inode)) {
-			error = vmtruncate(inode, attr->ia_size);
-			if (error || (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_SIZE &&
+	    attr->ia_size != i_size_read(inode)) {
+		int error = vmtruncate(inode, attr->ia_size);
+		if (error)
+			return error;
 	}
 
 	if (ia_valid & ATTR_UID)
@@ -104,8 +96,8 @@ int inode_setattr(struct inode * inode, 
 		inode->i_mode = mode;
 	}
 	mark_inode_dirty(inode);
-out:
-	return error;
+
+	return 0;
 }
 EXPORT_SYMBOL(inode_setattr);
 

diff ./fs/exec.c~current~ ./fs/exec.c
--- ./fs/exec.c~current~	2005-11-15 10:29:55.000000000 +1100
+++ ./fs/exec.c	2005-11-15 10:29:55.000000000 +1100
@@ -1516,7 +1516,7 @@ int do_coredump(long signr, int exit_cod
 		goto close_fail;
 	if (!file->f_op->write)
 		goto close_fail;
-	if (do_truncate(file->f_dentry, 0, file) != 0)
+	if (do_truncate(file->f_dentry, 0, 0, file) != 0)
 		goto close_fail;
 
 	retval = binfmt->core_dump(signr, regs, file);

diff ./fs/namei.c~current~ ./fs/namei.c
--- ./fs/namei.c~current~	2005-11-15 10:29:55.000000000 +1100
+++ ./fs/namei.c	2005-11-15 10:29:55.000000000 +1100
@@ -1491,7 +1491,7 @@ int may_open(struct nameidata *nd, int a
 		if (!error) {
 			DQUOT_INIT(inode);
 			
-			error = do_truncate(dentry, 0, NULL);
+			error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL);
 		}
 		put_write_access(inode);
 		if (error)

diff ./fs/open.c~current~ ./fs/open.c
--- ./fs/open.c~current~	2005-11-15 10:29:55.000000000 +1100
+++ ./fs/open.c	2005-11-15 10:29:55.000000000 +1100
@@ -194,7 +194,8 @@ out:
 	return error;
 }
 
-int do_truncate(struct dentry *dentry, loff_t length, struct file *filp)
+int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
+	struct file *filp)
 {
 	int err;
 	struct iattr newattrs;
@@ -204,7 +205,7 @@ int do_truncate(struct dentry *dentry, l
 		return -EINVAL;
 
 	newattrs.ia_size = length;
-	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+	newattrs.ia_valid = ATTR_SIZE | time_attrs;
 	if (filp) {
 		newattrs.ia_file = filp;
 		newattrs.ia_valid |= ATTR_FILE;
@@ -266,7 +267,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, NULL);
+		error = do_truncate(nd.dentry, length, 0, NULL);
 	}
 	put_write_access(inode);
 
@@ -318,7 +319,7 @@ static inline long do_sys_ftruncate(unsi
 
 	error = locks_verify_truncate(inode, file, length);
 	if (!error)
-		error = do_truncate(dentry, length, file);
+		error = do_truncate(dentry, length, 0, file);
 out_putf:
 	fput(file);
 out:

diff ./include/linux/fs.h~current~ ./include/linux/fs.h
--- ./include/linux/fs.h~current~	2005-11-15 10:29:55.000000000 +1100
+++ ./include/linux/fs.h	2005-11-15 10:29:55.000000000 +1100
@@ -1340,7 +1340,8 @@ static inline int break_lease(struct ino
 
 /* fs/open.c */
 
-extern int do_truncate(struct dentry *, loff_t start, struct file *filp);
+extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs,
+		       struct file *filp);
 extern long do_sys_open(const char __user *filename, int flags, int mode);
 extern struct file *filp_open(const char *, int, int);
 extern struct file * dentry_open(struct dentry *, struct vfsmount *, int);

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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15  2:00 ` [PATCH ] Fix some problems with truncate and mtime semantics NeilBrown
@ 2005-11-15  2:03   ` Trond Myklebust
  2005-11-15  2:09     ` Neil Brown
  2005-11-15 11:15     ` Anton Altaparmakov
  2005-11-15  9:56   ` Christoph Hellwig
  2005-11-15 10:13   ` Miklos Szeredi
  2 siblings, 2 replies; 9+ messages in thread
From: Trond Myklebust @ 2005-11-15  2:03 UTC (permalink / raw)
  To: NeilBrown; +Cc: Andrew Morton, linux-kernel

On Tue, 2005-11-15 at 13:00 +1100, NeilBrown wrote:
> Resubmitting this patch to fix truncate/mtime semantics.  
> 
> It is against 2.6.14-mm2 and is probably suitable for 2.6.15, but can
> be held over to 2.6.16 if you are feeling cautious.
> 
> NeilBrown
> 
> ### Comments for Changeset
> 
> SUS requires that when truncating a file to the size that it currently
> is:
>   truncate and ftruncate should NOT modify ctime or mtime
>   O_EXCL SHOULD modify ctime and mtime.
    ^^^^^ O_CREAT ;-)

> Currently mtime and ctime are always modified on most local
> filesystems (side effect of ->truncate) or never modified (on NFS).
> 
> With this patch:
>   ATTR_CTIME|ATTR_MTIME are sent with ATTR_SIZE precisely when 
>     an update of these times is required whether size changes or not 
>     (via a new argument to do_truncate).  This allows NFS to do
>     the right thing for O_EXCL.
                          ^^^^^

Cheers,
  Trond


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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15  2:03   ` Trond Myklebust
@ 2005-11-15  2:09     ` Neil Brown
  2005-11-15 11:15     ` Anton Altaparmakov
  1 sibling, 0 replies; 9+ messages in thread
From: Neil Brown @ 2005-11-15  2:09 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: Andrew Morton, linux-kernel

On Monday November 14, trond.myklebust@fys.uio.no wrote:
> On Tue, 2005-11-15 at 13:00 +1100, NeilBrown wrote:
> > Resubmitting this patch to fix truncate/mtime semantics.  
> > 
> > It is against 2.6.14-mm2 and is probably suitable for 2.6.15, but can
> > be held over to 2.6.16 if you are feeling cautious.
> > 
> > NeilBrown
> > 
> > ### Comments for Changeset
> > 
> > SUS requires that when truncating a file to the size that it currently
> > is:
> >   truncate and ftruncate should NOT modify ctime or mtime
> >   O_EXCL SHOULD modify ctime and mtime.
>     ^^^^^ O_CREAT ;-)

Groan... thanks Trond.
Andrew .. if you could just do a little edit there for me, I'd really
appreciate it :-(

NeilBrown

> 
> > Currently mtime and ctime are always modified on most local
> > filesystems (side effect of ->truncate) or never modified (on NFS).
> > 
> > With this patch:
> >   ATTR_CTIME|ATTR_MTIME are sent with ATTR_SIZE precisely when 
> >     an update of these times is required whether size changes or not 
> >     (via a new argument to do_truncate).  This allows NFS to do
> >     the right thing for O_EXCL.
>                           ^^^^^
> 
> Cheers,
>   Trond

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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15  2:00 ` [PATCH ] Fix some problems with truncate and mtime semantics NeilBrown
  2005-11-15  2:03   ` Trond Myklebust
@ 2005-11-15  9:56   ` Christoph Hellwig
  2005-11-15 10:16     ` Andrew Morton
  2005-11-15 10:13   ` Miklos Szeredi
  2 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2005-11-15  9:56 UTC (permalink / raw)
  To: NeilBrown; +Cc: Andrew Morton, linux-kernel, Trond Myklebust

> -int do_truncate(struct dentry *dentry, loff_t length, struct file *filp)
> +int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
> +	struct file *filp)
>  {
>  	int err;
>  	struct iattr newattrs;
> @@ -204,7 +205,7 @@ int do_truncate(struct dentry *dentry, l
>  		return -EINVAL;
>  
>  	newattrs.ia_size = length;
> -	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
> +	newattrs.ia_valid = ATTR_SIZE | time_attrs;

I'd rather make the argument and boolean update_times flag and this:


	newattrs.ia_valid = ATTR_SIZE;
	if (update_times)
		newattrs.ia_valid |= ATTR_CTIME|ATTR_MTIME;

but except for that little nitpick the patch looks good.  thanks.


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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15  2:00 ` [PATCH ] Fix some problems with truncate and mtime semantics NeilBrown
  2005-11-15  2:03   ` Trond Myklebust
  2005-11-15  9:56   ` Christoph Hellwig
@ 2005-11-15 10:13   ` Miklos Szeredi
  2005-11-15 10:41     ` Neil Brown
  2 siblings, 1 reply; 9+ messages in thread
From: Miklos Szeredi @ 2005-11-15 10:13 UTC (permalink / raw)
  To: neilb; +Cc: akpm, linux-kernel, trond.myklebust

> Finally, if vmtruncate succeeds, and ATTR_SIZE is the only change
> requested, we now fall-through and mark_inode_dirty.  If a filesystem
> did not have a ->truncate function, then vmtruncate will have changed
> i_size, without marking the inode as 'dirty', and I think this is wrong.

And if filesystem does not have a ->truncate() function and it caller
was [f]truncate(), ctime and mtime won't be set.

That's wrong too, isn't it?

Miklos

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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15  9:56   ` Christoph Hellwig
@ 2005-11-15 10:16     ` Andrew Morton
  0 siblings, 0 replies; 9+ messages in thread
From: Andrew Morton @ 2005-11-15 10:16 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: neilb, linux-kernel, trond.myklebust

Christoph Hellwig <hch@infradead.org> wrote:
>
> > -int do_truncate(struct dentry *dentry, loff_t length, struct file *filp)
> > +int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
> > +	struct file *filp)
> >  {
> >  	int err;
> >  	struct iattr newattrs;
> > @@ -204,7 +205,7 @@ int do_truncate(struct dentry *dentry, l
> >  		return -EINVAL;
> >  
> >  	newattrs.ia_size = length;
> > -	newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
> > +	newattrs.ia_valid = ATTR_SIZE | time_attrs;
> 
> I'd rather make the argument and boolean update_times flag and this:
> 

That sentence is incomprehensible.  Want to have another go?


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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15 10:13   ` Miklos Szeredi
@ 2005-11-15 10:41     ` Neil Brown
  2005-11-15 12:48       ` Miklos Szeredi
  0 siblings, 1 reply; 9+ messages in thread
From: Neil Brown @ 2005-11-15 10:41 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linux-kernel, trond.myklebust

On Tuesday November 15, miklos@szeredi.hu wrote:
> > Finally, if vmtruncate succeeds, and ATTR_SIZE is the only change
> > requested, we now fall-through and mark_inode_dirty.  If a filesystem
> > did not have a ->truncate function, then vmtruncate will have changed
> > i_size, without marking the inode as 'dirty', and I think this is wrong.
> 
> And if filesystem does not have a ->truncate() function and it caller
> was [f]truncate(), ctime and mtime won't be set.
> 
> That's wrong too, isn't it?

I don't think that is a problem.  
The filesystem would have had a ->setattr function which would have
been told that the size had changed, and it would have had to change
the inode, and so would have updated the ctime and probably mtime.

Changing i_size without marking the inode dirty is an issue of
consistency of common data structures and inode_setattr should be
careful about that.

Changing ctime/mtime when the isize changes is an issue of filesystem
correctness, and the filesystem callbacks should handle that.

Changing mtime when isize DOESN'T change is an issue of obscure
POSIX/SUS semantics.  It was less clear where this should be handled.
I think the handle of this is now better.

NeilBrown

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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15  2:03   ` Trond Myklebust
  2005-11-15  2:09     ` Neil Brown
@ 2005-11-15 11:15     ` Anton Altaparmakov
  1 sibling, 0 replies; 9+ messages in thread
From: Anton Altaparmakov @ 2005-11-15 11:15 UTC (permalink / raw)
  To: Trond Myklebust; +Cc: NeilBrown, Andrew Morton, linux-kernel

On Mon, 14 Nov 2005, Trond Myklebust wrote:
> On Tue, 2005-11-15 at 13:00 +1100, NeilBrown wrote:
> > Resubmitting this patch to fix truncate/mtime semantics.  
> > 
> > It is against 2.6.14-mm2 and is probably suitable for 2.6.15, but can
> > be held over to 2.6.16 if you are feeling cautious.
> > 
> > NeilBrown
> > 
> > ### Comments for Changeset
> > 
> > SUS requires that when truncating a file to the size that it currently
> > is:
> >   truncate and ftruncate should NOT modify ctime or mtime
> >   O_EXCL SHOULD modify ctime and mtime.
>     ^^^^^ O_CREAT ;-)

O_TRUNC actually ;-)  See:

	http://www.opengroup.org/onlinepubs/009695399/functions/open.html

<quote>
If O_CREAT is set and the file did not previously exist, upon successful 
completion, open() shall mark for update the st_atime, st_ctime, and 
st_mtime fields of the file and the st_ctime and st_mtime fields of the 
parent directory.

If O_TRUNC is set and the file did previously exist, upon successful 
completion, open() shall mark for update the st_ctime and st_mtime fields 
of the file.
</quote>

Given we are talking about truncate, we only care about O_TRUNC.  
O_CREAT/O_EXCL of course set A/C/M time as the file is newly created and 
hence all three values are set to the current system time!

> > Currently mtime and ctime are always modified on most local
> > filesystems (side effect of ->truncate) or never modified (on NFS).
> > 
> > With this patch:
> >   ATTR_CTIME|ATTR_MTIME are sent with ATTR_SIZE precisely when 
> >     an update of these times is required whether size changes or not 
> >     (via a new argument to do_truncate).  This allows NFS to do
> >     the right thing for O_EXCL.
>                           ^^^^^

O_TRUNC...

Best regards,

	Anton
-- 
Anton Altaparmakov <aia21 at cam.ac.uk> (replace at with @)
Unix Support, Computing Service, University of Cambridge, CB2 3QH, UK
Linux NTFS maintainer / IRC: #ntfs on irc.freenode.net
WWW: http://linux-ntfs.sf.net/ & http://www-stu.christs.cam.ac.uk/~aia21/

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

* Re: [PATCH ] Fix some problems with truncate and mtime semantics.
  2005-11-15 10:41     ` Neil Brown
@ 2005-11-15 12:48       ` Miklos Szeredi
  0 siblings, 0 replies; 9+ messages in thread
From: Miklos Szeredi @ 2005-11-15 12:48 UTC (permalink / raw)
  To: neilb; +Cc: akpm, linux-kernel, trond.myklebust

> > > Finally, if vmtruncate succeeds, and ATTR_SIZE is the only change
> > > requested, we now fall-through and mark_inode_dirty.  If a filesystem
> > > did not have a ->truncate function, then vmtruncate will have changed
> > > i_size, without marking the inode as 'dirty', and I think this is wrong.
> > 
> > And if filesystem does not have a ->truncate() function and it caller
> > was [f]truncate(), ctime and mtime won't be set.
> > 
> > That's wrong too, isn't it?
> 
> I don't think that is a problem.  
> The filesystem would have had a ->setattr function which would have
> been told that the size had changed, and it would have had to change
> the inode, and so would have updated the ctime and probably mtime.

What if filesystem has neither ->truncate() nor ->setattr()?
E.g. ramfs and derivatives.

> Changing i_size without marking the inode dirty is an issue of
> consistency of common data structures and inode_setattr should be
> careful about that.
> 
> Changing ctime/mtime when the isize changes is an issue of filesystem
> correctness, and the filesystem callbacks should handle that.

Yes, but VFS should have a sane default when filesystem doesn't have
the methods.  It's the same with all the other methods.

Miklos


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

end of thread, other threads:[~2005-11-15 12:49 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20051115125657.9403.patches@notabene>
2005-11-15  2:00 ` [PATCH ] Fix some problems with truncate and mtime semantics NeilBrown
2005-11-15  2:03   ` Trond Myklebust
2005-11-15  2:09     ` Neil Brown
2005-11-15 11:15     ` Anton Altaparmakov
2005-11-15  9:56   ` Christoph Hellwig
2005-11-15 10:16     ` Andrew Morton
2005-11-15 10:13   ` Miklos Szeredi
2005-11-15 10:41     ` Neil Brown
2005-11-15 12:48       ` Miklos Szeredi

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.