| From: Trond Myklebust <Trond.Myklebust@netapp.com> |
| |
| Currently, we will correctly optimise away a truncate that doesn't |
| change the file size. However, in the case of open(O_TRUNC), we |
| also want to optimise away the time changes. |
| |
| Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> |
| |
| fs/nfs/dir.c | 25 +++++++++++++++++++------ |
| fs/nfs/inode.c | 4 ++-- |
| fs/nfs/nfs4proc.c | 10 +++++++--- |
| 3 files changed, 28 insertions(+), 11 deletions(-) |
| |
| diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c |
| index fd9a872..bb132a8 100644 |
| |
| |
| @@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry |
| } |
| |
| open_flags = nd->intent.open.flags; |
| + attr.ia_valid = 0; |
| |
| ctx = create_nfs_open_context(dentry, open_flags); |
| res = ERR_CAST(ctx); |
| @@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry |
| |
| if (nd->flags & LOOKUP_CREATE) { |
| attr.ia_mode = nd->intent.open.create_mode; |
| - attr.ia_valid = ATTR_MODE; |
| + attr.ia_valid |= ATTR_MODE; |
| attr.ia_mode &= ~current_umask(); |
| - } else { |
| + } else |
| open_flags &= ~(O_EXCL | O_CREAT); |
| - attr.ia_valid = 0; |
| + |
| + if (open_flags & O_TRUNC) { |
| + attr.ia_valid |= ATTR_SIZE; |
| + attr.ia_size = 0; |
| } |
| |
| /* Open the file on the server */ |
| @@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) |
| struct inode *inode; |
| struct inode *dir; |
| struct nfs_open_context *ctx; |
| + struct iattr attr; |
| int openflags, ret = 0; |
| |
| if (nd->flags & LOOKUP_RCU) |
| @@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) |
| /* We cannot do exclusive creation on a positive dentry */ |
| if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) |
| goto no_open_dput; |
| - /* We can't create new files, or truncate existing ones here */ |
| - openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); |
| + /* We can't create new files here */ |
| + openflags &= ~(O_CREAT|O_EXCL); |
| |
| ctx = create_nfs_open_context(dentry, openflags); |
| ret = PTR_ERR(ctx); |
| if (IS_ERR(ctx)) |
| goto out; |
| + |
| + attr.ia_valid = 0; |
| + if (openflags & O_TRUNC) { |
| + attr.ia_valid |= ATTR_SIZE; |
| + attr.ia_size = 0; |
| + nfs_wb_all(inode); |
| + } |
| + |
| /* |
| * Note: we're not holding inode->i_mutex and so may be racing with |
| * operations that change the directory. We therefore save the |
| * change attribute *before* we do the RPC call. |
| */ |
| - inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, NULL); |
| + inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr); |
| if (IS_ERR(inode)) { |
| ret = PTR_ERR(inode); |
| switch (ret) { |
| diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c |
| index f649fba..57d0abb 100644 |
| |
| |
| @@ -401,7 +401,7 @@ out_no_inode: |
| goto out; |
| } |
| |
| -#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE) |
| +#define NFS_VALID_ATTRS (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_ATIME_SET|ATTR_MTIME|ATTR_MTIME_SET|ATTR_FILE|ATTR_OPEN) |
| |
| int |
| nfs_setattr(struct dentry *dentry, struct iattr *attr) |
| @@ -423,7 +423,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) |
| |
| /* Optimization: if the end result is no change, don't RPC */ |
| attr->ia_valid &= NFS_VALID_ATTRS; |
| - if ((attr->ia_valid & ~ATTR_FILE) == 0) |
| + if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0) |
| return 0; |
| |
| /* Write all dirty data */ |
| diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c |
| index 1515e45..c4c6b48 100644 |
| |
| |
| @@ -833,7 +833,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, |
| p->o_arg.bitmask = server->attr_bitmask; |
| p->o_arg.dir_bitmask = server->cache_consistency_bitmask; |
| p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; |
| - if (flags & O_CREAT) { |
| + if (attrs != NULL && attrs->ia_valid != 0) { |
| u32 *s; |
| |
| p->o_arg.u.attrs = &p->attrs; |
| @@ -890,7 +890,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode |
| { |
| int ret = 0; |
| |
| - if (open_mode & O_EXCL) |
| + if (open_mode & (O_EXCL|O_TRUNC)) |
| goto out; |
| switch (mode & (FMODE_READ|FMODE_WRITE)) { |
| case FMODE_READ: |
| @@ -1038,7 +1038,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) |
| struct nfs4_state *state = opendata->state; |
| struct nfs_inode *nfsi = NFS_I(state->inode); |
| struct nfs_delegation *delegation; |
| - int open_mode = opendata->o_arg.open_flags & O_EXCL; |
| + int open_mode = opendata->o_arg.open_flags & (O_EXCL|O_TRUNC); |
| fmode_t fmode = opendata->o_arg.fmode; |
| nfs4_stateid stateid; |
| int ret = -EAGAIN; |
| @@ -2439,6 +2439,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, |
| } |
| } |
| |
| + /* Deal with open(O_TRUNC) */ |
| + if (sattr->ia_valid & ATTR_OPEN) |
| + sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME|ATTR_OPEN); |
| + |
| status = nfs4_do_setattr(inode, cred, fattr, sattr, state); |
| if (status == 0) |
| nfs_setattr_update_inode(inode, sattr); |
| -- |
| 1.7.7.6 |
| |
| _______________________________________________ |
| kernel mailing list |
| kernel@lists.fedoraproject.org |
| https://admin.fedoraproject.org/mailman/listinfo/kernel |