Commit 52d1430d authored by Trond Myklebust's avatar Trond Myklebust

[PATCH] Use the intents in 'nameidata' to improve NFS close-to-open consistency

  - Make use of the open intents to improve close-to-open
    cache consistency. Only force data cache revalidation when
    we're doing an open().

  - Add true exclusive create to NFSv3.

  - Optimize away the redundant ->lookup() to check for an
    existing file when we know that we're doing NFSv3 exclusive
    create.

  - Optimize away all ->permission() checks other than those for
    path traversal, open(), and sys_access().
parent a574f324
......@@ -78,13 +78,9 @@ struct inode_operations nfs_dir_inode_operations = {
static int
nfs_opendir(struct inode *inode, struct file *filp)
{
struct nfs_server *server = NFS_SERVER(inode);
int res = 0;
lock_kernel();
/* Do cto revalidation */
if (!(server->flags & NFS_MOUNT_NOCTO))
res = __nfs_revalidate_inode(server, inode);
/* Call generic open code in order to cache credentials */
if (!res)
res = nfs_open(inode, filp);
......@@ -485,9 +481,13 @@ static inline void nfs_renew_times(struct dentry * dentry)
}
static inline
int nfs_lookup_verify_inode(struct inode *inode)
int nfs_lookup_verify_inode(struct inode *inode, int isopen)
{
return nfs_revalidate_inode(NFS_SERVER(inode), inode);
struct nfs_server *server = NFS_SERVER(inode);
if (isopen && !(server->flags & NFS_MOUNT_NOCTO))
return __nfs_revalidate_inode(server, inode);
return nfs_revalidate_inode(server, inode);
}
/*
......@@ -497,8 +497,17 @@ int nfs_lookup_verify_inode(struct inode *inode)
* If parent mtime has changed, we revalidate, else we wait for a
* period corresponding to the parent's attribute cache timeout value.
*/
static inline int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry)
static inline
int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
struct nameidata *nd)
{
int ndflags = 0;
if (nd)
ndflags = nd->flags;
/* Don't revalidate a negative dentry if we're creating a new file */
if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
return 0;
if (!nfs_check_verifier(dir, dentry))
return 1;
return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
......@@ -523,14 +532,18 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
int error;
struct nfs_fh fhandle;
struct nfs_fattr fattr;
int isopen = 0;
parent = dget_parent(dentry);
lock_kernel();
dir = parent->d_inode;
inode = dentry->d_inode;
if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN))
isopen = 1;
if (!inode) {
if (nfs_neg_need_reval(dir, dentry))
if (nfs_neg_need_reval(dir, dentry, nd))
goto out_bad;
goto out_valid;
}
......@@ -543,7 +556,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
/* Force a full look up iff the parent directory has changed */
if (nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode))
if (nfs_lookup_verify_inode(inode, isopen))
goto out_bad;
goto out_valid;
}
......@@ -552,7 +565,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if (!error) {
if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
goto out_bad;
if (nfs_lookup_verify_inode(inode))
if (nfs_lookup_verify_inode(inode, isopen))
goto out_bad;
goto out_valid_renew;
}
......@@ -630,6 +643,16 @@ struct dentry_operations nfs_dentry_operations = {
.d_iput = nfs_dentry_iput,
};
static inline
int nfs_is_exclusive_create(struct inode *dir, struct nameidata *nd)
{
if (NFS_PROTO(dir)->version == 2)
return 0;
if (!nd || (nd->flags & LOOKUP_CONTINUE) || !(nd->flags & LOOKUP_CREATE))
return 0;
return (nd->intent.open.flags & O_EXCL) != 0;
}
static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct inode *inode = NULL;
......@@ -647,6 +670,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
error = -ENOMEM;
dentry->d_op = &nfs_dentry_operations;
/* If we're doing an exclusive create, optimize away the lookup */
if (nfs_is_exclusive_create(dir, nd))
return NULL;
lock_kernel();
error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
if (!error) {
......@@ -794,6 +821,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nfs_fattr fattr;
struct nfs_fh fhandle;
int error;
int open_flags = 0;
dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name);
......@@ -801,6 +829,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;
if (nd && (nd->flags & LOOKUP_CREATE))
open_flags = nd->intent.open.flags;
/*
* The 0 argument passed into the create function should one day
* contain the O_EXCL flag if requested. This allows NFSv3 to
......@@ -810,7 +841,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
lock_kernel();
nfs_zap_caches(dir);
error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
&attr, 0, &fhandle, &fattr);
&attr, open_flags, &fhandle, &fattr);
if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr);
else
......@@ -1247,6 +1278,13 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
int mode = inode->i_mode;
int res;
/* Are we checking permissions on anything other than lookup? */
if (!(mask & MAY_EXEC)) {
/* We only need to check permissions on file open() and access() */
if (!nd || !(nd->flags & (LOOKUP_OPEN|LOOKUP_ACCESS)))
return 0;
}
if (mask & MAY_WRITE) {
/*
*
......
......@@ -82,9 +82,6 @@ nfs_file_open(struct inode *inode, struct file *filp)
/* Do NFSv4 open() call */
if ((open = server->rpc_ops->file_open) != NULL)
res = open(inode, filp);
/* Do cto revalidation */
else if (!(server->flags & NFS_MOUNT_NOCTO))
res = __nfs_revalidate_inode(server, inode);
/* Call generic open code in order to cache credentials */
if (!res)
res = nfs_open(inode, filp);
......
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