Commit 536e43d1 authored by Trond Myklebust's avatar Trond Myklebust

NFS: Optimise away unnecessary setattrs for open(O_TRUNC);

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: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 48c22eb2
...@@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry ...@@ -1429,6 +1429,7 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
} }
open_flags = nd->intent.open.flags; open_flags = nd->intent.open.flags;
attr.ia_valid = 0;
ctx = create_nfs_open_context(dentry, open_flags); ctx = create_nfs_open_context(dentry, open_flags);
res = ERR_CAST(ctx); res = ERR_CAST(ctx);
...@@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry ...@@ -1437,11 +1438,14 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry
if (nd->flags & LOOKUP_CREATE) { if (nd->flags & LOOKUP_CREATE) {
attr.ia_mode = nd->intent.open.create_mode; attr.ia_mode = nd->intent.open.create_mode;
attr.ia_valid = ATTR_MODE; attr.ia_valid |= ATTR_MODE;
attr.ia_mode &= ~current_umask(); attr.ia_mode &= ~current_umask();
} else { } else
open_flags &= ~(O_EXCL | O_CREAT); 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 */ /* Open the file on the server */
...@@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -1495,6 +1499,7 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
struct inode *inode; struct inode *inode;
struct inode *dir; struct inode *dir;
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
struct iattr attr;
int openflags, ret = 0; int openflags, ret = 0;
if (nd->flags & LOOKUP_RCU) if (nd->flags & LOOKUP_RCU)
...@@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd) ...@@ -1523,19 +1528,27 @@ static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
/* We cannot do exclusive creation on a positive dentry */ /* We cannot do exclusive creation on a positive dentry */
if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL)) if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
goto no_open_dput; goto no_open_dput;
/* We can't create new files, or truncate existing ones here */ /* We can't create new files here */
openflags &= ~(O_CREAT|O_EXCL|O_TRUNC); openflags &= ~(O_CREAT|O_EXCL);
ctx = create_nfs_open_context(dentry, openflags); ctx = create_nfs_open_context(dentry, openflags);
ret = PTR_ERR(ctx); ret = PTR_ERR(ctx);
if (IS_ERR(ctx)) if (IS_ERR(ctx))
goto out; 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 * Note: we're not holding inode->i_mutex and so may be racing with
* operations that change the directory. We therefore save the * operations that change the directory. We therefore save the
* change attribute *before* we do the RPC call. * 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)) { if (IS_ERR(inode)) {
ret = PTR_ERR(inode); ret = PTR_ERR(inode);
switch (ret) { switch (ret) {
......
...@@ -402,7 +402,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr) ...@@ -402,7 +402,7 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
goto out; 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 int
nfs_setattr(struct dentry *dentry, struct iattr *attr) nfs_setattr(struct dentry *dentry, struct iattr *attr)
...@@ -424,7 +424,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -424,7 +424,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr)
/* Optimization: if the end result is no change, don't RPC */ /* Optimization: if the end result is no change, don't RPC */
attr->ia_valid &= NFS_VALID_ATTRS; attr->ia_valid &= NFS_VALID_ATTRS;
if ((attr->ia_valid & ~ATTR_FILE) == 0) if ((attr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
return 0; return 0;
/* Write all dirty data */ /* Write all dirty data */
......
...@@ -828,7 +828,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, ...@@ -828,7 +828,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
p->o_arg.bitmask = server->attr_bitmask; p->o_arg.bitmask = server->attr_bitmask;
p->o_arg.dir_bitmask = server->cache_consistency_bitmask; p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
if (flags & O_CREAT) { if (attrs != NULL && attrs->ia_valid != 0) {
u32 *s; u32 *s;
p->o_arg.u.attrs = &p->attrs; p->o_arg.u.attrs = &p->attrs;
...@@ -885,7 +885,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode ...@@ -885,7 +885,7 @@ static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode
{ {
int ret = 0; int ret = 0;
if (open_mode & O_EXCL) if (open_mode & (O_EXCL|O_TRUNC))
goto out; goto out;
switch (mode & (FMODE_READ|FMODE_WRITE)) { switch (mode & (FMODE_READ|FMODE_WRITE)) {
case FMODE_READ: case FMODE_READ:
...@@ -1033,7 +1033,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata) ...@@ -1033,7 +1033,7 @@ static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
struct nfs4_state *state = opendata->state; struct nfs4_state *state = opendata->state;
struct nfs_inode *nfsi = NFS_I(state->inode); struct nfs_inode *nfsi = NFS_I(state->inode);
struct nfs_delegation *delegation; 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; fmode_t fmode = opendata->o_arg.fmode;
nfs4_stateid stateid; nfs4_stateid stateid;
int ret = -EAGAIN; int ret = -EAGAIN;
...@@ -2431,6 +2431,10 @@ nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr, ...@@ -2431,6 +2431,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); status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
if (status == 0) if (status == 0)
nfs_setattr_update_inode(inode, sattr); nfs_setattr_update_inode(inode, sattr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment