aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-26 12:06:17 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-08-07 15:13:17 -0400
commit5e11934d13c9a3bcb0cadad6c7a7de5c32660422 (patch)
tree639e5660e9081bc16afccf0c509ff41c413b483d
parentb247bbf1da69ce376aa1ceb8057331214589e366 (diff)
NFS: Fix put_nfs_open_context
We need to grab the inode->i_lock atomically with the last reference put in order to remove the open context that is being freed from the nfsi->open_files list. Fix by converting the kref to a standard atomic counter and then using atomic_dec_and_lock()... Thanks to Arnd Bergmann for pointing out the problem. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r--fs/nfs/inode.c24
-rw-r--r--include/linux/nfs_fs.h2
2 files changed, 9 insertions, 17 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index bca6cdcb9f0d..71a49c3acabd 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -468,7 +468,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
468 ctx->lockowner = current->files; 468 ctx->lockowner = current->files;
469 ctx->error = 0; 469 ctx->error = 0;
470 ctx->dir_cookie = 0; 470 ctx->dir_cookie = 0;
471 kref_init(&ctx->kref); 471 atomic_set(&ctx->count, 1);
472 } 472 }
473 return ctx; 473 return ctx;
474} 474}
@@ -476,21 +476,18 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
476struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx) 476struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
477{ 477{
478 if (ctx != NULL) 478 if (ctx != NULL)
479 kref_get(&ctx->kref); 479 atomic_inc(&ctx->count);
480 return ctx; 480 return ctx;
481} 481}
482 482
483static void nfs_free_open_context(struct kref *kref) 483void put_nfs_open_context(struct nfs_open_context *ctx)
484{ 484{
485 struct nfs_open_context *ctx = container_of(kref, 485 struct inode *inode = ctx->path.dentry->d_inode;
486 struct nfs_open_context, kref);
487 486
488 if (!list_empty(&ctx->list)) { 487 if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
489 struct inode *inode = ctx->path.dentry->d_inode; 488 return;
490 spin_lock(&inode->i_lock); 489 list_del(&ctx->list);
491 list_del(&ctx->list); 490 spin_unlock(&inode->i_lock);
492 spin_unlock(&inode->i_lock);
493 }
494 if (ctx->state != NULL) 491 if (ctx->state != NULL)
495 nfs4_close_state(&ctx->path, ctx->state, ctx->mode); 492 nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
496 if (ctx->cred != NULL) 493 if (ctx->cred != NULL)
@@ -500,11 +497,6 @@ static void nfs_free_open_context(struct kref *kref)
500 kfree(ctx); 497 kfree(ctx);
501} 498}
502 499
503void put_nfs_open_context(struct nfs_open_context *ctx)
504{
505 kref_put(&ctx->kref, nfs_free_open_context);
506}
507
508/* 500/*
509 * Ensure that mmap has a recent RPC credential for use when writing out 501 * Ensure that mmap has a recent RPC credential for use when writing out
510 * shared pages 502 * shared pages
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 9ba4aec37c50..157dcb055b5c 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -71,7 +71,7 @@ struct nfs_access_entry {
71 71
72struct nfs4_state; 72struct nfs4_state;
73struct nfs_open_context { 73struct nfs_open_context {
74 struct kref kref; 74 atomic_t count;
75 struct path path; 75 struct path path;
76 struct rpc_cred *cred; 76 struct rpc_cred *cred;
77 struct nfs4_state *state; 77 struct nfs4_state *state;