aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4proc.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-06-05 12:30:00 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:24 -0400
commitad389da79f7bf9dc12dbc79c9c2740f9ed2f13d1 (patch)
tree9fd51d8a43aaba790a87f721d2796e36ab9f66e7 /fs/nfs/nfs4proc.c
parent539cd03a5708c9861a3e738e6f363ad743c85ddf (diff)
NFSv4: Ensure asynchronous open() calls always pin the mountpoint
A number of race conditions may currently ensue if the user presses ^C and then unmounts the partition while an asynchronous open() is in progress. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4proc.c')
-rw-r--r--fs/nfs/nfs4proc.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index c83db9def0fe..895e8e649c91 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -221,7 +221,7 @@ struct nfs4_opendata {
221 struct nfs_open_confirmres c_res; 221 struct nfs_open_confirmres c_res;
222 struct nfs_fattr f_attr; 222 struct nfs_fattr f_attr;
223 struct nfs_fattr dir_attr; 223 struct nfs_fattr dir_attr;
224 struct dentry *dentry; 224 struct path path;
225 struct dentry *dir; 225 struct dentry *dir;
226 struct nfs4_state_owner *owner; 226 struct nfs4_state_owner *owner;
227 struct iattr attrs; 227 struct iattr attrs;
@@ -230,11 +230,11 @@ struct nfs4_opendata {
230 int cancelled; 230 int cancelled;
231}; 231};
232 232
233static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, 233static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
234 struct nfs4_state_owner *sp, int flags, 234 struct nfs4_state_owner *sp, int flags,
235 const struct iattr *attrs) 235 const struct iattr *attrs)
236{ 236{
237 struct dentry *parent = dget_parent(dentry); 237 struct dentry *parent = dget_parent(path->dentry);
238 struct inode *dir = parent->d_inode; 238 struct inode *dir = parent->d_inode;
239 struct nfs_server *server = NFS_SERVER(dir); 239 struct nfs_server *server = NFS_SERVER(dir);
240 struct nfs4_opendata *p; 240 struct nfs4_opendata *p;
@@ -246,7 +246,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
246 if (p->o_arg.seqid == NULL) 246 if (p->o_arg.seqid == NULL)
247 goto err_free; 247 goto err_free;
248 atomic_set(&p->count, 1); 248 atomic_set(&p->count, 1);
249 p->dentry = dget(dentry); 249 p->path.mnt = mntget(path->mnt);
250 p->path.dentry = dget(path->dentry);
250 p->dir = parent; 251 p->dir = parent;
251 p->owner = sp; 252 p->owner = sp;
252 atomic_inc(&sp->so_count); 253 atomic_inc(&sp->so_count);
@@ -254,7 +255,7 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
254 p->o_arg.open_flags = flags, 255 p->o_arg.open_flags = flags,
255 p->o_arg.clientid = server->nfs_client->cl_clientid; 256 p->o_arg.clientid = server->nfs_client->cl_clientid;
256 p->o_arg.id = sp->so_id; 257 p->o_arg.id = sp->so_id;
257 p->o_arg.name = &dentry->d_name; 258 p->o_arg.name = &p->path.dentry->d_name;
258 p->o_arg.server = server; 259 p->o_arg.server = server;
259 p->o_arg.bitmask = server->attr_bitmask; 260 p->o_arg.bitmask = server->attr_bitmask;
260 p->o_arg.claim = NFS4_OPEN_CLAIM_NULL; 261 p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
@@ -288,7 +289,8 @@ static void nfs4_opendata_free(struct nfs4_opendata *p)
288 nfs_free_seqid(p->o_arg.seqid); 289 nfs_free_seqid(p->o_arg.seqid);
289 nfs4_put_state_owner(p->owner); 290 nfs4_put_state_owner(p->owner);
290 dput(p->dir); 291 dput(p->dir);
291 dput(p->dentry); 292 dput(p->path.dentry);
293 mntput(p->path.mnt);
292 kfree(p); 294 kfree(p);
293 } 295 }
294} 296}
@@ -478,7 +480,7 @@ static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
478 } 480 }
479 delegation_type = delegation->type; 481 delegation_type = delegation->type;
480 } 482 }
481 opendata = nfs4_opendata_alloc(ctx->path.dentry, state->owner, 0, NULL); 483 opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL);
482 if (opendata == NULL) 484 if (opendata == NULL)
483 return -ENOMEM; 485 return -ENOMEM;
484 opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; 486 opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
@@ -525,7 +527,7 @@ static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs
525 527
526 if (!test_bit(NFS_DELEGATED_STATE, &state->flags)) 528 if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
527 return 0; 529 return 0;
528 opendata = nfs4_opendata_alloc(ctx->path.dentry, sp, 0, NULL); 530 opendata = nfs4_opendata_alloc(&ctx->path, sp, 0, NULL);
529 if (opendata == NULL) 531 if (opendata == NULL)
530 return -ENOMEM; 532 return -ENOMEM;
531 opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; 533 opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
@@ -827,7 +829,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
827 set_bit(NFS_DELEGATED_STATE, &state->flags); 829 set_bit(NFS_DELEGATED_STATE, &state->flags);
828 return 0; 830 return 0;
829 } 831 }
830 opendata = nfs4_opendata_alloc(ctx->path.dentry, state->owner, openflags, NULL); 832 opendata = nfs4_opendata_alloc(&ctx->path, state->owner, openflags, NULL);
831 if (opendata == NULL) 833 if (opendata == NULL)
832 return -ENOMEM; 834 return -ENOMEM;
833 ret = nfs4_open_recover(opendata, state); 835 ret = nfs4_open_recover(opendata, state);
@@ -955,7 +957,7 @@ static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, st
955/* 957/*
956 * Returns a referenced nfs4_state 958 * Returns a referenced nfs4_state
957 */ 959 */
958static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) 960static int _nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
959{ 961{
960 struct nfs4_state_owner *sp; 962 struct nfs4_state_owner *sp;
961 struct nfs4_state *state = NULL; 963 struct nfs4_state *state = NULL;
@@ -975,7 +977,7 @@ static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, st
975 goto err_put_state_owner; 977 goto err_put_state_owner;
976 down_read(&clp->cl_sem); 978 down_read(&clp->cl_sem);
977 status = -ENOMEM; 979 status = -ENOMEM;
978 opendata = nfs4_opendata_alloc(dentry, sp, flags, sattr); 980 opendata = nfs4_opendata_alloc(path, sp, flags, sattr);
979 if (opendata == NULL) 981 if (opendata == NULL)
980 goto err_release_rwsem; 982 goto err_release_rwsem;
981 983
@@ -1006,14 +1008,14 @@ out_err:
1006} 1008}
1007 1009
1008 1010
1009static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) 1011static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred)
1010{ 1012{
1011 struct nfs4_exception exception = { }; 1013 struct nfs4_exception exception = { };
1012 struct nfs4_state *res; 1014 struct nfs4_state *res;
1013 int status; 1015 int status;
1014 1016
1015 do { 1017 do {
1016 status = _nfs4_do_open(dir, dentry, flags, sattr, cred, &res); 1018 status = _nfs4_do_open(dir, path, flags, sattr, cred, &res);
1017 if (status == 0) 1019 if (status == 0)
1018 break; 1020 break;
1019 /* NOTE: BAD_SEQID means the server and client disagree about the 1021 /* NOTE: BAD_SEQID means the server and client disagree about the
@@ -1259,6 +1261,10 @@ static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, str
1259struct dentry * 1261struct dentry *
1260nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 1262nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1261{ 1263{
1264 struct path path = {
1265 .mnt = nd->mnt,
1266 .dentry = dentry,
1267 };
1262 struct iattr attr; 1268 struct iattr attr;
1263 struct rpc_cred *cred; 1269 struct rpc_cred *cred;
1264 struct nfs4_state *state; 1270 struct nfs4_state *state;
@@ -1277,7 +1283,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1277 cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0); 1283 cred = rpcauth_lookupcred(NFS_CLIENT(dir)->cl_auth, 0);
1278 if (IS_ERR(cred)) 1284 if (IS_ERR(cred))
1279 return (struct dentry *)cred; 1285 return (struct dentry *)cred;
1280 state = nfs4_do_open(dir, dentry, nd->intent.open.flags, &attr, cred); 1286 state = nfs4_do_open(dir, &path, nd->intent.open.flags, &attr, cred);
1281 put_rpccred(cred); 1287 put_rpccred(cred);
1282 if (IS_ERR(state)) { 1288 if (IS_ERR(state)) {
1283 if (PTR_ERR(state) == -ENOENT) 1289 if (PTR_ERR(state) == -ENOENT)
@@ -1294,6 +1300,10 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1294int 1300int
1295nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) 1301nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd)
1296{ 1302{
1303 struct path path = {
1304 .mnt = nd->mnt,
1305 .dentry = dentry,
1306 };
1297 struct rpc_cred *cred; 1307 struct rpc_cred *cred;
1298 struct nfs4_state *state; 1308 struct nfs4_state *state;
1299 1309
@@ -1302,7 +1312,7 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
1302 return PTR_ERR(cred); 1312 return PTR_ERR(cred);
1303 state = nfs4_open_delegated(dentry->d_inode, openflags, cred); 1313 state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
1304 if (IS_ERR(state)) 1314 if (IS_ERR(state))
1305 state = nfs4_do_open(dir, dentry, openflags, NULL, cred); 1315 state = nfs4_do_open(dir, &path, openflags, NULL, cred);
1306 put_rpccred(cred); 1316 put_rpccred(cred);
1307 if (IS_ERR(state)) { 1317 if (IS_ERR(state)) {
1308 switch (PTR_ERR(state)) { 1318 switch (PTR_ERR(state)) {
@@ -1752,6 +1762,10 @@ static int
1752nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, 1762nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1753 int flags, struct nameidata *nd) 1763 int flags, struct nameidata *nd)
1754{ 1764{
1765 struct path path = {
1766 .mnt = nd->mnt,
1767 .dentry = dentry,
1768 };
1755 struct nfs4_state *state; 1769 struct nfs4_state *state;
1756 struct rpc_cred *cred; 1770 struct rpc_cred *cred;
1757 int status = 0; 1771 int status = 0;
@@ -1761,7 +1775,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1761 status = PTR_ERR(cred); 1775 status = PTR_ERR(cred);
1762 goto out; 1776 goto out;
1763 } 1777 }
1764 state = nfs4_do_open(dir, dentry, flags, sattr, cred); 1778 state = nfs4_do_open(dir, &path, flags, sattr, cred);
1765 put_rpccred(cred); 1779 put_rpccred(cred);
1766 if (IS_ERR(state)) { 1780 if (IS_ERR(state)) {
1767 status = PTR_ERR(state); 1781 status = PTR_ERR(state);
@@ -1774,7 +1788,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1774 if (status == 0) 1788 if (status == 0)
1775 nfs_setattr_update_inode(state->inode, sattr); 1789 nfs_setattr_update_inode(state->inode, sattr);
1776 } 1790 }
1777 if (status == 0 && nd != NULL && (nd->flags & LOOKUP_OPEN)) 1791 if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
1778 status = nfs4_intent_set_file(nd, dentry, state); 1792 status = nfs4_intent_set_file(nd, dentry, state);
1779 else 1793 else
1780 nfs4_close_state(state, flags); 1794 nfs4_close_state(state, flags);