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: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Родитель
48c22eb210
Коммит
536e43d12b
25
fs/nfs/dir.c
25
fs/nfs/dir.c
|
@ -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) {
|
||||
|
|
|
@ -402,7 +402,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)
|
||||
|
@ -424,7 +424,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 */
|
||||
|
|
|
@ -828,7 +828,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;
|
||||
|
@ -885,7 +885,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:
|
||||
|
@ -1033,7 +1033,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;
|
||||
|
@ -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);
|
||||
if (status == 0)
|
||||
nfs_setattr_update_inode(inode, sattr);
|
||||
|
|
Загрузка…
Ссылка в новой задаче