aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:17 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2005-10-18 17:20:17 -0400
commit02a913a73b52071e93f4b76db3e86138d19efffd (patch)
tree1dc1abbd2d8f57a6fd593dd252d6d7ecc7c811c5 /fs/nfs/nfs4proc.c
parent834f2a4a1554dc5b2598038b3fe8703defcbe467 (diff)
NFSv4: Eliminate nfsv4 open race...
Make NFSv4 return the fully initialized file pointer with the stateid that it created in the lookup w/intent. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c137
1 files changed, 56 insertions, 81 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 35da15342e05..c9ecb8119632 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -47,6 +47,7 @@
47#include <linux/nfs_page.h> 47#include <linux/nfs_page.h>
48#include <linux/smp_lock.h> 48#include <linux/smp_lock.h>
49#include <linux/namei.h> 49#include <linux/namei.h>
50#include <linux/mount.h>
50 51
51#include "nfs4_fs.h" 52#include "nfs4_fs.h"
52#include "delegation.h" 53#include "delegation.h"
@@ -947,12 +948,26 @@ out:
947 return status; 948 return status;
948} 949}
949 950
950struct inode * 951static void nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state)
952{
953 struct file *filp;
954
955 filp = lookup_instantiate_filp(nd, dentry, NULL);
956 if (!IS_ERR(filp)) {
957 struct nfs_open_context *ctx;
958 ctx = (struct nfs_open_context *)filp->private_data;
959 ctx->state = state;
960 } else
961 nfs4_close_state(state, nd->intent.open.flags);
962}
963
964struct dentry *
951nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 965nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
952{ 966{
953 struct iattr attr; 967 struct iattr attr;
954 struct rpc_cred *cred; 968 struct rpc_cred *cred;
955 struct nfs4_state *state; 969 struct nfs4_state *state;
970 struct dentry *res;
956 971
957 if (nd->flags & LOOKUP_CREATE) { 972 if (nd->flags & LOOKUP_CREATE) {
958 attr.ia_mode = nd->intent.open.create_mode; 973 attr.ia_mode = nd->intent.open.create_mode;
@@ -966,16 +981,23 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
966 981
967 cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); 982 cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
968 if (IS_ERR(cred)) 983 if (IS_ERR(cred))
969 return (struct inode *)cred; 984 return (struct dentry *)cred;
970 state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); 985 state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred);
971 put_rpccred(cred); 986 put_rpccred(cred);
972 if (IS_ERR(state)) 987 if (IS_ERR(state)) {
973 return (struct inode *)state; 988 if (PTR_ERR(state) == -ENOENT)
974 return state->inode; 989 d_add(dentry, NULL);
990 return (struct dentry *)state;
991 }
992 res = d_add_unique(dentry, state->inode);
993 if (res != NULL)
994 dentry = res;
995 nfs4_intent_set_file(nd, dentry, state);
996 return res;
975} 997}
976 998
977int 999int
978nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags) 1000nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd)
979{ 1001{
980 struct rpc_cred *cred; 1002 struct rpc_cred *cred;
981 struct nfs4_state *state; 1003 struct nfs4_state *state;
@@ -988,18 +1010,30 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags)
988 if (IS_ERR(state)) 1010 if (IS_ERR(state))
989 state = nfs4_do_open(dir, dentry, openflags, NULL, cred); 1011 state = nfs4_do_open(dir, dentry, openflags, NULL, cred);
990 put_rpccred(cred); 1012 put_rpccred(cred);
991 if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0) 1013 if (IS_ERR(state)) {
992 return 1; 1014 switch (PTR_ERR(state)) {
993 if (IS_ERR(state)) 1015 case -EPERM:
994 return 0; 1016 case -EACCES:
1017 case -EDQUOT:
1018 case -ENOSPC:
1019 case -EROFS:
1020 lookup_instantiate_filp(nd, (struct dentry *)state, NULL);
1021 return 1;
1022 case -ENOENT:
1023 if (dentry->d_inode == NULL)
1024 return 1;
1025 }
1026 goto out_drop;
1027 }
995 inode = state->inode; 1028 inode = state->inode;
1029 iput(inode);
996 if (inode == dentry->d_inode) { 1030 if (inode == dentry->d_inode) {
997 iput(inode); 1031 nfs4_intent_set_file(nd, dentry, state);
998 return 1; 1032 return 1;
999 } 1033 }
1000 d_drop(dentry);
1001 nfs4_close_state(state, openflags); 1034 nfs4_close_state(state, openflags);
1002 iput(inode); 1035out_drop:
1036 d_drop(dentry);
1003 return 0; 1037 return 0;
1004} 1038}
1005 1039
@@ -1500,7 +1534,7 @@ static int nfs4_proc_commit(struct nfs_write_data *cdata)
1500 1534
1501static int 1535static int
1502nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, 1536nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1503 int flags) 1537 int flags, struct nameidata *nd)
1504{ 1538{
1505 struct nfs4_state *state; 1539 struct nfs4_state *state;
1506 struct rpc_cred *cred; 1540 struct rpc_cred *cred;
@@ -1522,13 +1556,13 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1522 struct nfs_fattr fattr; 1556 struct nfs_fattr fattr;
1523 status = nfs4_do_setattr(NFS_SERVER(dir), &fattr, 1557 status = nfs4_do_setattr(NFS_SERVER(dir), &fattr,
1524 NFS_FH(state->inode), sattr, state); 1558 NFS_FH(state->inode), sattr, state);
1525 if (status == 0) { 1559 if (status == 0)
1526 nfs_setattr_update_inode(state->inode, sattr); 1560 nfs_setattr_update_inode(state->inode, sattr);
1527 goto out; 1561 }
1528 } 1562 if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN))
1529 } else if (flags != 0) 1563 nfs4_intent_set_file(nd, dentry, state);
1530 goto out; 1564 else
1531 nfs4_close_state(state, flags); 1565 nfs4_close_state(state, flags);
1532out: 1566out:
1533 return status; 1567 return status;
1534} 1568}
@@ -2175,65 +2209,6 @@ nfs4_proc_renew(struct nfs4_client *clp)
2175 return 0; 2209 return 0;
2176} 2210}
2177 2211
2178/*
2179 * We will need to arrange for the VFS layer to provide an atomic open.
2180 * Until then, this open method is prone to inefficiency and race conditions
2181 * due to the lookup, potential create, and open VFS calls from sys_open()
2182 * placed on the wire.
2183 */
2184static int
2185nfs4_proc_file_open(struct inode *inode, struct file *filp)
2186{
2187 struct dentry *dentry = filp->f_dentry;
2188 struct nfs_open_context *ctx;
2189 struct nfs4_state *state = NULL;
2190 struct rpc_cred *cred;
2191 int status = -ENOMEM;
2192
2193 dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n",
2194 (int)dentry->d_parent->d_name.len,
2195 dentry->d_parent->d_name.name,
2196 (int)dentry->d_name.len, dentry->d_name.name);
2197
2198
2199 /* Find our open stateid */
2200 cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
2201 if (IS_ERR(cred))
2202 return PTR_ERR(cred);
2203 ctx = alloc_nfs_open_context(dentry, cred);
2204 put_rpccred(cred);
2205 if (unlikely(ctx == NULL))
2206 return -ENOMEM;
2207 status = -EIO; /* ERACE actually */
2208 state = nfs4_find_state(inode, cred, filp->f_mode);
2209 if (unlikely(state == NULL))
2210 goto no_state;
2211 ctx->state = state;
2212 nfs4_close_state(state, filp->f_mode);
2213 ctx->mode = filp->f_mode;
2214 nfs_file_set_open_context(filp, ctx);
2215 put_nfs_open_context(ctx);
2216 if (filp->f_mode & FMODE_WRITE)
2217 nfs_begin_data_update(inode);
2218 return 0;
2219no_state:
2220 printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__);
2221 put_nfs_open_context(ctx);
2222 return status;
2223}
2224
2225/*
2226 * Release our state
2227 */
2228static int
2229nfs4_proc_file_release(struct inode *inode, struct file *filp)
2230{
2231 if (filp->f_mode & FMODE_WRITE)
2232 nfs_end_data_update(inode);
2233 nfs_file_clear_open_context(filp);
2234 return 0;
2235}
2236
2237static inline int nfs4_server_supports_acls(struct nfs_server *server) 2212static inline int nfs4_server_supports_acls(struct nfs_server *server)
2238{ 2213{
2239 return (server->caps & NFS_CAP_ACLS) 2214 return (server->caps & NFS_CAP_ACLS)
@@ -3145,8 +3120,8 @@ struct nfs_rpc_ops nfs_v4_clientops = {
3145 .read_setup = nfs4_proc_read_setup, 3120 .read_setup = nfs4_proc_read_setup,
3146 .write_setup = nfs4_proc_write_setup, 3121 .write_setup = nfs4_proc_write_setup,
3147 .commit_setup = nfs4_proc_commit_setup, 3122 .commit_setup = nfs4_proc_commit_setup,
3148 .file_open = nfs4_proc_file_open, 3123 .file_open = nfs_open,
3149 .file_release = nfs4_proc_file_release, 3124 .file_release = nfs_release,
3150 .lock = nfs4_proc_lock, 3125 .lock = nfs4_proc_lock,
3151 .clear_acl_cache = nfs4_zap_acl_attr, 3126 .clear_acl_cache = nfs4_zap_acl_attr,
3152}; 3127};