mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-14 12:37:32 +00:00
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>
This commit is contained in:
parent
b247bbf1da
commit
5e11934d13
2 changed files with 9 additions and 17 deletions
|
@ -468,7 +468,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
|
||||||
ctx->lockowner = current->files;
|
ctx->lockowner = current->files;
|
||||||
ctx->error = 0;
|
ctx->error = 0;
|
||||||
ctx->dir_cookie = 0;
|
ctx->dir_cookie = 0;
|
||||||
kref_init(&ctx->kref);
|
atomic_set(&ctx->count, 1);
|
||||||
}
|
}
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
@ -476,21 +476,18 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
|
||||||
struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
|
struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
|
||||||
{
|
{
|
||||||
if (ctx != NULL)
|
if (ctx != NULL)
|
||||||
kref_get(&ctx->kref);
|
atomic_inc(&ctx->count);
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nfs_free_open_context(struct kref *kref)
|
void put_nfs_open_context(struct nfs_open_context *ctx)
|
||||||
{
|
{
|
||||||
struct nfs_open_context *ctx = container_of(kref,
|
|
||||||
struct nfs_open_context, kref);
|
|
||||||
|
|
||||||
if (!list_empty(&ctx->list)) {
|
|
||||||
struct inode *inode = ctx->path.dentry->d_inode;
|
struct inode *inode = ctx->path.dentry->d_inode;
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
|
if (!atomic_dec_and_lock(&ctx->count, &inode->i_lock))
|
||||||
|
return;
|
||||||
list_del(&ctx->list);
|
list_del(&ctx->list);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
}
|
|
||||||
if (ctx->state != NULL)
|
if (ctx->state != NULL)
|
||||||
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
nfs4_close_state(&ctx->path, ctx->state, ctx->mode);
|
||||||
if (ctx->cred != NULL)
|
if (ctx->cred != NULL)
|
||||||
|
@ -500,11 +497,6 @@ static void nfs_free_open_context(struct kref *kref)
|
||||||
kfree(ctx);
|
kfree(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void put_nfs_open_context(struct nfs_open_context *ctx)
|
|
||||||
{
|
|
||||||
kref_put(&ctx->kref, nfs_free_open_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that mmap has a recent RPC credential for use when writing out
|
* Ensure that mmap has a recent RPC credential for use when writing out
|
||||||
* shared pages
|
* shared pages
|
||||||
|
|
|
@ -71,7 +71,7 @@ struct nfs_access_entry {
|
||||||
|
|
||||||
struct nfs4_state;
|
struct nfs4_state;
|
||||||
struct nfs_open_context {
|
struct nfs_open_context {
|
||||||
struct kref kref;
|
atomic_t count;
|
||||||
struct path path;
|
struct path path;
|
||||||
struct rpc_cred *cred;
|
struct rpc_cred *cred;
|
||||||
struct nfs4_state *state;
|
struct nfs4_state *state;
|
||||||
|
|
Loading…
Reference in a new issue