From: NeilBrown <neilb@suse.de>
To: Andrew Morton <akpm@osdl.org>
Cc: linux-kernel@vger.kernel.org,
Trond Myklebust <trond.myklebust@fys.uio.no>
Subject: [PATCH ] Fix some problems with truncate and mtime semantics.
Date: Tue, 15 Nov 2005 13:00:02 +1100 [thread overview]
Message-ID: <1051115020002.9459@suse.de> (raw)
In-Reply-To: 20051115125657.9403.patches@notabene
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);
next parent reply other threads:[~2005-11-15 2:00 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20051115125657.9403.patches@notabene>
2005-11-15 2:00 ` NeilBrown [this message]
2005-11-15 2:03 ` [PATCH ] Fix some problems with truncate and mtime semantics 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
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=1051115020002.9459@suse.de \
--to=neilb@suse.de \
--cc=akpm@osdl.org \
--cc=linux-kernel@vger.kernel.org \
--cc=trond.myklebust@fys.uio.no \
/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.