NFSv4: Fix up locking for nfs4_state_owner Signed-off-by: Trond Myklebust --- fs/nfs/nfs4_fs.h | 1 + fs/nfs/nfs4proc.c | 2 ++ fs/nfs/nfs4state.c | 20 +++++++++++++++----- 3 files changed, 18 insertions(+), 5 deletions(-) Index: linux-2.6/fs/nfs/nfs4_fs.h =================================================================== --- linux-2.6.orig/fs/nfs/nfs4_fs.h +++ linux-2.6/fs/nfs/nfs4_fs.h @@ -126,6 +126,7 @@ static inline void nfs_confirm_seqid(str * semantics by allowing the server to identify replayed requests. */ struct nfs4_state_owner { + spinlock_t so_lock; struct list_head so_list; /* per-clientid list of state_owners */ struct nfs4_client *so_client; u32 so_id; /* 32-bit identifier, unique */ Index: linux-2.6/fs/nfs/nfs4state.c =================================================================== --- linux-2.6.orig/fs/nfs/nfs4state.c +++ linux-2.6/fs/nfs/nfs4state.c @@ -267,6 +267,7 @@ nfs4_alloc_state_owner(void) sp = kzalloc(sizeof(*sp),GFP_KERNEL); if (!sp) return NULL; + spin_lock_init(&sp->so_lock); INIT_LIST_HEAD(&sp->so_states); INIT_LIST_HEAD(&sp->so_delegations); rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue"); @@ -438,20 +439,23 @@ nfs4_get_open_state(struct inode *inode, if (state) goto out; new = nfs4_alloc_open_state(); + spin_lock(&owner->so_lock); spin_lock(&inode->i_lock); state = __nfs4_find_state_byowner(inode, owner); if (state == NULL && new != NULL) { state = new; - /* Note: The reclaim code dictates that we add stateless - * and read-only stateids to the end of the list */ - list_add_tail(&state->open_states, &owner->so_states); state->owner = owner; atomic_inc(&owner->so_count); list_add(&state->inode_states, &nfsi->open_states); state->inode = igrab(inode); spin_unlock(&inode->i_lock); + /* Note: The reclaim code dictates that we add stateless + * and read-only stateids to the end of the list */ + list_add_tail(&state->open_states, &owner->so_states); + spin_unlock(&owner->so_lock); } else { spin_unlock(&inode->i_lock); + spin_unlock(&owner->so_lock); if (new) nfs4_free_open_state(new); } @@ -468,12 +472,14 @@ void nfs4_put_open_state(struct nfs4_sta struct inode *inode = state->inode; struct nfs4_state_owner *owner = state->owner; - if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) + if (!atomic_dec_and_lock(&state->count, &owner->so_lock)) return; + spin_lock(&inode->i_lock); if (!list_empty(&state->inode_states)) list_del(&state->inode_states); - spin_unlock(&inode->i_lock); list_del(&state->open_states); + spin_unlock(&inode->i_lock); + spin_unlock(&owner->so_lock); iput(inode); BUG_ON (state->state != 0); nfs4_free_open_state(state); @@ -491,6 +497,7 @@ void nfs4_close_state(struct nfs4_state atomic_inc(&owner->so_count); /* Protect against nfs4_find_state() */ + spin_lock(&owner->so_lock); spin_lock(&inode->i_lock); if (mode & FMODE_READ) state->nreaders--; @@ -503,6 +510,7 @@ void nfs4_close_state(struct nfs4_state list_move_tail(&state->open_states, &owner->so_states); } spin_unlock(&inode->i_lock); + spin_unlock(&owner->so_lock); newstate = 0; if (state->state != 0) { if (state->nreaders) @@ -899,6 +907,7 @@ static void nfs4_state_mark_reclaim(stru list_for_each_entry(sp, &clp->cl_state_owners, so_list) { sp->so_seqid.counter = 0; sp->so_seqid.flags = 0; + spin_lock(&sp->so_lock); list_for_each_entry(state, &sp->so_states, open_states) { list_for_each_entry(lock, &state->lock_states, ls_locks) { lock->ls_seqid.counter = 0; @@ -906,6 +915,7 @@ static void nfs4_state_mark_reclaim(stru lock->ls_flags &= ~NFS_LOCK_INITIALIZED; } } + spin_unlock(&sp->so_lock); } } Index: linux-2.6/fs/nfs/nfs4proc.c =================================================================== --- linux-2.6.orig/fs/nfs/nfs4proc.c +++ linux-2.6/fs/nfs/nfs4proc.c @@ -212,6 +212,7 @@ static void update_open_stateid(struct n open_flags &= (FMODE_READ|FMODE_WRITE); /* Protect against nfs4_find_state() */ + spin_lock(&state->owner->so_lock); spin_lock(&inode->i_lock); state->state |= open_flags; /* NB! List reordering - see the reclaim code for why. */ @@ -221,6 +222,7 @@ static void update_open_stateid(struct n state->nreaders++; memcpy(&state->stateid, stateid, sizeof(state->stateid)); spin_unlock(&inode->i_lock); + spin_unlock(&state->owner->so_lock); } /*