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 = { ...@@ -78,13 +78,9 @@ struct inode_operations nfs_dir_inode_operations = {
static int static int
nfs_opendir(struct inode *inode, struct file *filp) nfs_opendir(struct inode *inode, struct file *filp)
{ {
struct nfs_server *server = NFS_SERVER(inode);
int res = 0; int res = 0;
lock_kernel(); 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 */ /* Call generic open code in order to cache credentials */
if (!res) if (!res)
res = nfs_open(inode, filp); res = nfs_open(inode, filp);
...@@ -485,9 +481,13 @@ static inline void nfs_renew_times(struct dentry * dentry) ...@@ -485,9 +481,13 @@ static inline void nfs_renew_times(struct dentry * dentry)
} }
static inline 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) ...@@ -497,8 +497,17 @@ int nfs_lookup_verify_inode(struct inode *inode)
* If parent mtime has changed, we revalidate, else we wait for a * If parent mtime has changed, we revalidate, else we wait for a
* period corresponding to the parent's attribute cache timeout value. * 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)) if (!nfs_check_verifier(dir, dentry))
return 1; return 1;
return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir)); 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) ...@@ -523,14 +532,18 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
int error; int error;
struct nfs_fh fhandle; struct nfs_fh fhandle;
struct nfs_fattr fattr; struct nfs_fattr fattr;
int isopen = 0;
parent = dget_parent(dentry); parent = dget_parent(dentry);
lock_kernel(); lock_kernel();
dir = parent->d_inode; dir = parent->d_inode;
inode = dentry->d_inode; inode = dentry->d_inode;
if (nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_OPEN))
isopen = 1;
if (!inode) { if (!inode) {
if (nfs_neg_need_reval(dir, dentry)) if (nfs_neg_need_reval(dir, dentry, nd))
goto out_bad; goto out_bad;
goto out_valid; goto out_valid;
} }
...@@ -543,7 +556,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) ...@@ -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 */ /* Force a full look up iff the parent directory has changed */
if (nfs_check_verifier(dir, dentry)) { if (nfs_check_verifier(dir, dentry)) {
if (nfs_lookup_verify_inode(inode)) if (nfs_lookup_verify_inode(inode, isopen))
goto out_bad; goto out_bad;
goto out_valid; goto out_valid;
} }
...@@ -552,7 +565,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) ...@@ -552,7 +565,7 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd)
if (!error) { if (!error) {
if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0) if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
goto out_bad; goto out_bad;
if (nfs_lookup_verify_inode(inode)) if (nfs_lookup_verify_inode(inode, isopen))
goto out_bad; goto out_bad;
goto out_valid_renew; goto out_valid_renew;
} }
...@@ -630,6 +643,16 @@ struct dentry_operations nfs_dentry_operations = { ...@@ -630,6 +643,16 @@ struct dentry_operations nfs_dentry_operations = {
.d_iput = nfs_dentry_iput, .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) static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{ {
struct inode *inode = NULL; struct inode *inode = NULL;
...@@ -647,6 +670,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru ...@@ -647,6 +670,10 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
error = -ENOMEM; error = -ENOMEM;
dentry->d_op = &nfs_dentry_operations; 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(); lock_kernel();
error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr); error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
if (!error) { if (!error) {
...@@ -794,6 +821,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -794,6 +821,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct nfs_fh fhandle; struct nfs_fh fhandle;
int error; int error;
int open_flags = 0;
dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id, dfprintk(VFS, "NFS: create(%s/%ld, %s\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name); dir->i_ino, dentry->d_name.name);
...@@ -801,6 +829,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode, ...@@ -801,6 +829,9 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
attr.ia_mode = mode; attr.ia_mode = mode;
attr.ia_valid = ATTR_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 * The 0 argument passed into the create function should one day
* contain the O_EXCL flag if requested. This allows NFSv3 to * 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, ...@@ -810,7 +841,7 @@ static int nfs_create(struct inode *dir, struct dentry *dentry, int mode,
lock_kernel(); lock_kernel();
nfs_zap_caches(dir); nfs_zap_caches(dir);
error = NFS_PROTO(dir)->create(dir, &dentry->d_name, error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
&attr, 0, &fhandle, &fattr); &attr, open_flags, &fhandle, &fattr);
if (!error) if (!error)
error = nfs_instantiate(dentry, &fhandle, &fattr); error = nfs_instantiate(dentry, &fhandle, &fattr);
else else
...@@ -1247,6 +1278,13 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd) ...@@ -1247,6 +1278,13 @@ nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
int mode = inode->i_mode; int mode = inode->i_mode;
int res; 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) { if (mask & MAY_WRITE) {
/* /*
* *
......
...@@ -82,9 +82,6 @@ nfs_file_open(struct inode *inode, struct file *filp) ...@@ -82,9 +82,6 @@ nfs_file_open(struct inode *inode, struct file *filp)
/* Do NFSv4 open() call */ /* Do NFSv4 open() call */
if ((open = server->rpc_ops->file_open) != NULL) if ((open = server->rpc_ops->file_open) != NULL)
res = open(inode, filp); 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 */ /* Call generic open code in order to cache credentials */
if (!res) if (!res)
res = nfs_open(inode, filp); 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