aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-06-05 10:31:33 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-10 23:40:24 -0400
commit4a35bd41aff5714deb41c8f14766df3871e2e8f7 (patch)
tree3542c76b1e0aabcd0ee6bb76fdd8228e6f3b5479 /fs
parentad389da79f7bf9dc12dbc79c9c2740f9ed2f13d1 (diff)
NFSv4: Ensure that nfs4_do_close() doesn't race with umount
nfs4_do_close() does not currently have any way to ensure that the user won't attempt to unmount the partition while the asynchronous RPC call is completing. This again may cause Oopses in nfs_update_inode(). Add a vfsmount argument to nfs4_close_state to ensure that the partition remains mounted while we're closing the file. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/inode.c19
-rw-r--r--fs/nfs/nfs4_fs.h6
-rw-r--r--fs/nfs/nfs4proc.c35
-rw-r--r--fs/nfs/nfs4state.c4
4 files changed, 26 insertions, 38 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index cc7a9064be90..23ecf0334a18 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -490,7 +490,7 @@ void put_nfs_open_context(struct nfs_open_context *ctx)
490 spin_unlock(&inode->i_lock); 490 spin_unlock(&inode->i_lock);
491 } 491 }
492 if (ctx->state != NULL) 492 if (ctx->state != NULL)
493 nfs4_close_state(ctx->state, ctx->mode); 493 nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
494 if (ctx->cred != NULL) 494 if (ctx->cred != NULL)
495 put_rpccred(ctx->cred); 495 put_rpccred(ctx->cred);
496 dput(ctx->path.dentry); 496 dput(ctx->path.dentry);
@@ -1103,27 +1103,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1103 */ 1103 */
1104void nfs4_clear_inode(struct inode *inode) 1104void nfs4_clear_inode(struct inode *inode)
1105{ 1105{
1106 struct nfs_inode *nfsi = NFS_I(inode);
1107
1108 /* If we are holding a delegation, return it! */ 1106 /* If we are holding a delegation, return it! */
1109 nfs_inode_return_delegation(inode); 1107 nfs_inode_return_delegation(inode);
1110 /* First call standard NFS clear_inode() code */ 1108 /* First call standard NFS clear_inode() code */
1111 nfs_clear_inode(inode); 1109 nfs_clear_inode(inode);
1112 /* Now clear out any remaining state */
1113 while (!list_empty(&nfsi->open_states)) {
1114 struct nfs4_state *state;
1115
1116 state = list_entry(nfsi->open_states.next,
1117 struct nfs4_state,
1118 inode_states);
1119 dprintk("%s(%s/%Ld): found unclaimed NFSv4 state %p\n",
1120 __FUNCTION__,
1121 inode->i_sb->s_id,
1122 (long long)NFS_FILEID(inode),
1123 state);
1124 BUG_ON(atomic_read(&state->count) != 1);
1125 nfs4_close_state(state, state->state);
1126 }
1127} 1110}
1128#endif 1111#endif
1129 1112
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index cf3a17eb5c09..c97a0ad8430e 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -165,7 +165,7 @@ extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, struc
165extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *); 165extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct rpc_cred *);
166extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *); 166extern int nfs4_proc_async_renew(struct nfs_client *, struct rpc_cred *);
167extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *); 167extern int nfs4_proc_renew(struct nfs_client *, struct rpc_cred *);
168extern int nfs4_do_close(struct inode *inode, struct nfs4_state *state); 168extern int nfs4_do_close(struct path *path, struct nfs4_state *state);
169extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *); 169extern struct dentry *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
170extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *); 170extern int nfs4_open_revalidate(struct inode *, struct dentry *, int, struct nameidata *);
171extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle); 171extern int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle);
@@ -196,7 +196,7 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *);
196extern void nfs4_drop_state_owner(struct nfs4_state_owner *); 196extern void nfs4_drop_state_owner(struct nfs4_state_owner *);
197extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *); 197extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
198extern void nfs4_put_open_state(struct nfs4_state *); 198extern void nfs4_put_open_state(struct nfs4_state *);
199extern void nfs4_close_state(struct nfs4_state *, mode_t); 199extern void nfs4_close_state(struct path *, struct nfs4_state *, mode_t);
200extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t); 200extern void nfs4_state_set_mode_locked(struct nfs4_state *, mode_t);
201extern void nfs4_schedule_state_recovery(struct nfs_client *); 201extern void nfs4_schedule_state_recovery(struct nfs_client *);
202extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); 202extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
@@ -222,7 +222,7 @@ extern struct svc_version nfs4_callback_version1;
222 222
223#else 223#else
224 224
225#define nfs4_close_state(a, b) do { } while (0) 225#define nfs4_close_state(a, b, c) do { } while (0)
226 226
227#endif /* CONFIG_NFS_V4 */ 227#endif /* CONFIG_NFS_V4 */
228#endif /* __LINUX_FS_NFS_NFS4_FS.H */ 228#endif /* __LINUX_FS_NFS_NFS4_FS.H */
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 895e8e649c91..8feaf232f2e4 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -453,7 +453,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
453 opendata->owner->so_cred, 453 opendata->owner->so_cred,
454 &opendata->o_res); 454 &opendata->o_res);
455 } 455 }
456 nfs4_close_state(newstate, opendata->o_arg.open_flags); 456 nfs4_close_state(&opendata->path, newstate, opendata->o_arg.open_flags);
457 } 457 }
458 if (newstate != state) 458 if (newstate != state)
459 return -ESTALE; 459 return -ESTALE;
@@ -603,7 +603,7 @@ static void nfs4_open_confirm_release(void *calldata)
603 nfs_confirm_seqid(&data->owner->so_seqid, 0); 603 nfs_confirm_seqid(&data->owner->so_seqid, 0);
604 state = nfs4_opendata_to_nfs4_state(data); 604 state = nfs4_opendata_to_nfs4_state(data);
605 if (state != NULL) 605 if (state != NULL)
606 nfs4_close_state(state, data->o_arg.open_flags); 606 nfs4_close_state(&data->path, state, data->o_arg.open_flags);
607out_free: 607out_free:
608 nfs4_opendata_free(data); 608 nfs4_opendata_free(data);
609} 609}
@@ -706,7 +706,7 @@ static void nfs4_open_release(void *calldata)
706 nfs_confirm_seqid(&data->owner->so_seqid, 0); 706 nfs_confirm_seqid(&data->owner->so_seqid, 0);
707 state = nfs4_opendata_to_nfs4_state(data); 707 state = nfs4_opendata_to_nfs4_state(data);
708 if (state != NULL) 708 if (state != NULL)
709 nfs4_close_state(state, data->o_arg.open_flags); 709 nfs4_close_state(&data->path, state, data->o_arg.open_flags);
710out_free: 710out_free:
711 nfs4_opendata_free(data); 711 nfs4_opendata_free(data);
712} 712}
@@ -1103,6 +1103,7 @@ static int nfs4_do_setattr(struct inode *inode, struct nfs_fattr *fattr,
1103} 1103}
1104 1104
1105struct nfs4_closedata { 1105struct nfs4_closedata {
1106 struct path path;
1106 struct inode *inode; 1107 struct inode *inode;
1107 struct nfs4_state *state; 1108 struct nfs4_state *state;
1108 struct nfs_closeargs arg; 1109 struct nfs_closeargs arg;
@@ -1119,6 +1120,8 @@ static void nfs4_free_closedata(void *data)
1119 nfs4_put_open_state(calldata->state); 1120 nfs4_put_open_state(calldata->state);
1120 nfs_free_seqid(calldata->arg.seqid); 1121 nfs_free_seqid(calldata->arg.seqid);
1121 nfs4_put_state_owner(sp); 1122 nfs4_put_state_owner(sp);
1123 dput(calldata->path.dentry);
1124 mntput(calldata->path.mnt);
1122 kfree(calldata); 1125 kfree(calldata);
1123} 1126}
1124 1127
@@ -1211,18 +1214,18 @@ static const struct rpc_call_ops nfs4_close_ops = {
1211 * 1214 *
1212 * NOTE: Caller must be holding the sp->so_owner semaphore! 1215 * NOTE: Caller must be holding the sp->so_owner semaphore!
1213 */ 1216 */
1214int nfs4_do_close(struct inode *inode, struct nfs4_state *state) 1217int nfs4_do_close(struct path *path, struct nfs4_state *state)
1215{ 1218{
1216 struct nfs_server *server = NFS_SERVER(inode); 1219 struct nfs_server *server = NFS_SERVER(state->inode);
1217 struct nfs4_closedata *calldata; 1220 struct nfs4_closedata *calldata;
1218 int status = -ENOMEM; 1221 int status = -ENOMEM;
1219 1222
1220 calldata = kmalloc(sizeof(*calldata), GFP_KERNEL); 1223 calldata = kmalloc(sizeof(*calldata), GFP_KERNEL);
1221 if (calldata == NULL) 1224 if (calldata == NULL)
1222 goto out; 1225 goto out;
1223 calldata->inode = inode; 1226 calldata->inode = state->inode;
1224 calldata->state = state; 1227 calldata->state = state;
1225 calldata->arg.fh = NFS_FH(inode); 1228 calldata->arg.fh = NFS_FH(state->inode);
1226 calldata->arg.stateid = &state->stateid; 1229 calldata->arg.stateid = &state->stateid;
1227 /* Serialization for the sequence id */ 1230 /* Serialization for the sequence id */
1228 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid); 1231 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid);
@@ -1231,6 +1234,8 @@ int nfs4_do_close(struct inode *inode, struct nfs4_state *state)
1231 calldata->arg.bitmask = server->attr_bitmask; 1234 calldata->arg.bitmask = server->attr_bitmask;
1232 calldata->res.fattr = &calldata->fattr; 1235 calldata->res.fattr = &calldata->fattr;
1233 calldata->res.server = server; 1236 calldata->res.server = server;
1237 calldata->path.mnt = mntget(path->mnt);
1238 calldata->path.dentry = dget(path->dentry);
1234 1239
1235 status = nfs4_call_async(server->client, &nfs4_close_ops, calldata); 1240 status = nfs4_call_async(server->client, &nfs4_close_ops, calldata);
1236 if (status == 0) 1241 if (status == 0)
@@ -1243,18 +1248,18 @@ out:
1243 return status; 1248 return status;
1244} 1249}
1245 1250
1246static int nfs4_intent_set_file(struct nameidata *nd, struct dentry *dentry, struct nfs4_state *state) 1251static int nfs4_intent_set_file(struct nameidata *nd, struct path *path, struct nfs4_state *state)
1247{ 1252{
1248 struct file *filp; 1253 struct file *filp;
1249 1254
1250 filp = lookup_instantiate_filp(nd, dentry, NULL); 1255 filp = lookup_instantiate_filp(nd, path->dentry, NULL);
1251 if (!IS_ERR(filp)) { 1256 if (!IS_ERR(filp)) {
1252 struct nfs_open_context *ctx; 1257 struct nfs_open_context *ctx;
1253 ctx = (struct nfs_open_context *)filp->private_data; 1258 ctx = (struct nfs_open_context *)filp->private_data;
1254 ctx->state = state; 1259 ctx->state = state;
1255 return 0; 1260 return 0;
1256 } 1261 }
1257 nfs4_close_state(state, nd->intent.open.flags); 1262 nfs4_close_state(path, state, nd->intent.open.flags);
1258 return PTR_ERR(filp); 1263 return PTR_ERR(filp);
1259} 1264}
1260 1265
@@ -1293,7 +1298,7 @@ nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
1293 res = d_add_unique(dentry, igrab(state->inode)); 1298 res = d_add_unique(dentry, igrab(state->inode));
1294 if (res != NULL) 1299 if (res != NULL)
1295 dentry = res; 1300 dentry = res;
1296 nfs4_intent_set_file(nd, dentry, state); 1301 nfs4_intent_set_file(nd, &path, state);
1297 return res; 1302 return res;
1298} 1303}
1299 1304
@@ -1328,10 +1333,10 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
1328 } 1333 }
1329 } 1334 }
1330 if (state->inode == dentry->d_inode) { 1335 if (state->inode == dentry->d_inode) {
1331 nfs4_intent_set_file(nd, dentry, state); 1336 nfs4_intent_set_file(nd, &path, state);
1332 return 1; 1337 return 1;
1333 } 1338 }
1334 nfs4_close_state(state, openflags); 1339 nfs4_close_state(&path, state, openflags);
1335out_drop: 1340out_drop:
1336 d_drop(dentry); 1341 d_drop(dentry);
1337 return 0; 1342 return 0;
@@ -1789,9 +1794,9 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
1789 nfs_setattr_update_inode(state->inode, sattr); 1794 nfs_setattr_update_inode(state->inode, sattr);
1790 } 1795 }
1791 if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0) 1796 if (status == 0 && (nd->flags & LOOKUP_OPEN) != 0)
1792 status = nfs4_intent_set_file(nd, dentry, state); 1797 status = nfs4_intent_set_file(nd, &path, state);
1793 else 1798 else
1794 nfs4_close_state(state, flags); 1799 nfs4_close_state(&path, state, flags);
1795out: 1800out:
1796 return status; 1801 return status;
1797} 1802}
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 8ed79d5c54f9..a85138ef67ad 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -341,7 +341,7 @@ void nfs4_put_open_state(struct nfs4_state *state)
341/* 341/*
342 * Close the current file. 342 * Close the current file.
343 */ 343 */
344void nfs4_close_state(struct nfs4_state *state, mode_t mode) 344void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
345{ 345{
346 struct inode *inode = state->inode; 346 struct inode *inode = state->inode;
347 struct nfs4_state_owner *owner = state->owner; 347 struct nfs4_state_owner *owner = state->owner;
@@ -375,7 +375,7 @@ void nfs4_close_state(struct nfs4_state *state, mode_t mode)
375 spin_unlock(&inode->i_lock); 375 spin_unlock(&inode->i_lock);
376 spin_unlock(&owner->so_lock); 376 spin_unlock(&owner->so_lock);
377 377
378 if (oldstate != newstate && nfs4_do_close(inode, state) == 0) 378 if (oldstate != newstate && nfs4_do_close(path, state) == 0)
379 return; 379 return;
380 nfs4_put_open_state(state); 380 nfs4_put_open_state(state);
381 nfs4_put_state_owner(owner); 381 nfs4_put_state_owner(owner);