diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-06-05 12:30:00 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:24 -0400 |
commit | ad389da79f7bf9dc12dbc79c9c2740f9ed2f13d1 (patch) | |
tree | 9fd51d8a43aaba790a87f721d2796e36ab9f66e7 /fs/nfs/nfs4proc.c | |
parent | 539cd03a5708c9861a3e738e6f363ad743c85ddf (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.c | 48 |
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 | ||
233 | static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry, | 233 | static 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 | */ |
958 | static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res) | 960 | static 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 | ||
1009 | static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, int flags, struct iattr *sattr, struct rpc_cred *cred) | 1011 | static 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 | |||
1259 | struct dentry * | 1261 | struct dentry * |
1260 | nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 1262 | nfs4_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) | |||
1294 | int | 1300 | int |
1295 | nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, struct nameidata *nd) | 1301 | nfs4_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 | |||
1752 | nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, | 1762 | nfs4_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); |