diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-19 20:04:20 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2008-02-26 00:40:33 -0500 |
commit | 383ba71938519959be8e0b598ec658f0c211ff45 (patch) | |
tree | 01eb0155676fe69d40f01dc137ea3be952d88997 /fs/nfs/inode.c | |
parent | 4b5621f6b127bce9218998c187bd25bf7f9fc371 (diff) |
NFS: Fix a deadlock with lazy umount
We can't allow rpc callback functions like task->tk_ops->rpc_call_prepare()
and task->tk_ops->rpc_call_done() to call mntput() in any way, since
that will cause a deadlock when the call to rpc_shutdown_client() attempts
to wait on 'task' to complete.
We can avoid the above deadlock by moving calls to mntput to
task->tk_ops->rpc_release() callback, since at that time the task will be
marked as completed, and so rpc_shutdown_client won't attempt to wait on
it.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/inode.c')
-rw-r--r-- | fs/nfs/inode.c | 6 |
1 files changed, 5 insertions, 1 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 966a8850aa30..a499fb58d858 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -521,8 +521,12 @@ struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) | |||
521 | 521 | ||
522 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) | 522 | static void __put_nfs_open_context(struct nfs_open_context *ctx, int wait) |
523 | { | 523 | { |
524 | struct inode *inode = ctx->path.dentry->d_inode; | 524 | struct inode *inode; |
525 | 525 | ||
526 | if (ctx == NULL) | ||
527 | return; | ||
528 | |||
529 | inode = ctx->path.dentry->d_inode; | ||
526 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) | 530 | if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock)) |
527 | return; | 531 | return; |
528 | list_del(&ctx->list); | 532 | list_del(&ctx->list); |