NFSv4: Fix up stateid locking...
We really don't need to grab both the state->so_owner and the inode->i_lock. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
1ac7e2fd35
commit
8bda4e4c98
@ -139,9 +139,11 @@ struct nfs4_state {
|
|||||||
unsigned long flags; /* Do we hold any locks? */
|
unsigned long flags; /* Do we hold any locks? */
|
||||||
spinlock_t state_lock; /* Protects the lock_states list */
|
spinlock_t state_lock; /* Protects the lock_states list */
|
||||||
|
|
||||||
|
seqlock_t seqlock; /* Protects the stateid/open_stateid */
|
||||||
nfs4_stateid stateid; /* Current stateid: may be delegation */
|
nfs4_stateid stateid; /* Current stateid: may be delegation */
|
||||||
nfs4_stateid open_stateid; /* OPEN stateid */
|
nfs4_stateid open_stateid; /* OPEN stateid */
|
||||||
|
|
||||||
|
/* The following 3 fields are protected by owner->so_lock */
|
||||||
unsigned int n_rdonly; /* Number of read-only references */
|
unsigned int n_rdonly; /* Number of read-only references */
|
||||||
unsigned int n_wronly; /* Number of write-only references */
|
unsigned int n_wronly; /* Number of write-only references */
|
||||||
unsigned int n_rdwr; /* Number of read/write references */
|
unsigned int n_rdwr; /* Number of read/write references */
|
||||||
|
@ -385,29 +385,28 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
|
|||||||
|
|
||||||
static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
|
static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags)
|
||||||
{
|
{
|
||||||
spin_lock(&state->owner->so_lock);
|
write_seqlock(&state->seqlock);
|
||||||
spin_lock(&state->inode->i_lock);
|
|
||||||
nfs_set_open_stateid_locked(state, stateid, open_flags);
|
nfs_set_open_stateid_locked(state, stateid, open_flags);
|
||||||
spin_unlock(&state->inode->i_lock);
|
write_sequnlock(&state->seqlock);
|
||||||
spin_unlock(&state->owner->so_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
|
static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags)
|
||||||
{
|
{
|
||||||
struct inode *inode = state->inode;
|
|
||||||
|
|
||||||
open_flags &= (FMODE_READ|FMODE_WRITE);
|
open_flags &= (FMODE_READ|FMODE_WRITE);
|
||||||
/* Protect against nfs4_find_state_byowner() */
|
/*
|
||||||
spin_lock(&state->owner->so_lock);
|
* Protect the call to nfs4_state_set_mode_locked and
|
||||||
spin_lock(&inode->i_lock);
|
* serialise the stateid update
|
||||||
|
*/
|
||||||
|
write_seqlock(&state->seqlock);
|
||||||
if (deleg_stateid != NULL) {
|
if (deleg_stateid != NULL) {
|
||||||
memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
|
memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
|
||||||
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
||||||
}
|
}
|
||||||
if (open_stateid != NULL)
|
if (open_stateid != NULL)
|
||||||
nfs_set_open_stateid_locked(state, open_stateid, open_flags);
|
nfs_set_open_stateid_locked(state, open_stateid, open_flags);
|
||||||
|
write_sequnlock(&state->seqlock);
|
||||||
|
spin_lock(&state->owner->so_lock);
|
||||||
update_open_stateflags(state, open_flags);
|
update_open_stateflags(state, open_flags);
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
spin_unlock(&state->owner->so_lock);
|
spin_unlock(&state->owner->so_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,12 +607,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|||||||
*/
|
*/
|
||||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
|
||||||
memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
|
memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
|
||||||
spin_lock(&state->owner->so_lock);
|
write_seqlock(&state->seqlock);
|
||||||
spin_lock(&state->inode->i_lock);
|
|
||||||
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
||||||
memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
|
memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
|
||||||
spin_unlock(&state->inode->i_lock);
|
write_sequnlock(&state->seqlock);
|
||||||
spin_unlock(&state->owner->so_lock);
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1280,7 +1277,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||||||
mode = FMODE_READ|FMODE_WRITE;
|
mode = FMODE_READ|FMODE_WRITE;
|
||||||
clear_rd = clear_wr = clear_rdwr = 0;
|
clear_rd = clear_wr = clear_rdwr = 0;
|
||||||
spin_lock(&state->owner->so_lock);
|
spin_lock(&state->owner->so_lock);
|
||||||
spin_lock(&calldata->inode->i_lock);
|
|
||||||
/* Calculate the change in open mode */
|
/* Calculate the change in open mode */
|
||||||
if (state->n_rdwr == 0) {
|
if (state->n_rdwr == 0) {
|
||||||
if (state->n_rdonly == 0) {
|
if (state->n_rdonly == 0) {
|
||||||
@ -1294,7 +1290,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
|
|||||||
clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&calldata->inode->i_lock);
|
|
||||||
spin_unlock(&state->owner->so_lock);
|
spin_unlock(&state->owner->so_lock);
|
||||||
if (!clear_rd && !clear_wr && !clear_rdwr) {
|
if (!clear_rd && !clear_wr && !clear_rdwr) {
|
||||||
/* Note: exit _without_ calling nfs4_close_done */
|
/* Note: exit _without_ calling nfs4_close_done */
|
||||||
|
@ -307,6 +307,7 @@ nfs4_alloc_open_state(void)
|
|||||||
atomic_set(&state->count, 1);
|
atomic_set(&state->count, 1);
|
||||||
INIT_LIST_HEAD(&state->lock_states);
|
INIT_LIST_HEAD(&state->lock_states);
|
||||||
spin_lock_init(&state->state_lock);
|
spin_lock_init(&state->state_lock);
|
||||||
|
seqlock_init(&state->seqlock);
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,7 +412,6 @@ void nfs4_put_open_state(struct nfs4_state *state)
|
|||||||
*/
|
*/
|
||||||
void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
||||||
{
|
{
|
||||||
struct inode *inode = state->inode;
|
|
||||||
struct nfs4_state_owner *owner = state->owner;
|
struct nfs4_state_owner *owner = state->owner;
|
||||||
int call_close = 0;
|
int call_close = 0;
|
||||||
int newstate;
|
int newstate;
|
||||||
@ -419,7 +419,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
|||||||
atomic_inc(&owner->so_count);
|
atomic_inc(&owner->so_count);
|
||||||
/* Protect against nfs4_find_state() */
|
/* Protect against nfs4_find_state() */
|
||||||
spin_lock(&owner->so_lock);
|
spin_lock(&owner->so_lock);
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
switch (mode & (FMODE_READ | FMODE_WRITE)) {
|
switch (mode & (FMODE_READ | FMODE_WRITE)) {
|
||||||
case FMODE_READ:
|
case FMODE_READ:
|
||||||
state->n_rdonly--;
|
state->n_rdonly--;
|
||||||
@ -446,7 +445,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode)
|
|||||||
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
clear_bit(NFS_DELEGATED_STATE, &state->flags);
|
||||||
}
|
}
|
||||||
nfs4_state_set_mode_locked(state, newstate);
|
nfs4_state_set_mode_locked(state, newstate);
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
spin_unlock(&owner->so_lock);
|
spin_unlock(&owner->so_lock);
|
||||||
|
|
||||||
if (!call_close) {
|
if (!call_close) {
|
||||||
@ -599,8 +597,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
|
|||||||
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
|
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
|
||||||
{
|
{
|
||||||
struct nfs4_lock_state *lsp;
|
struct nfs4_lock_state *lsp;
|
||||||
|
int seq;
|
||||||
|
|
||||||
memcpy(dst, &state->stateid, sizeof(*dst));
|
do {
|
||||||
|
seq = read_seqbegin(&state->seqlock);
|
||||||
|
memcpy(dst, &state->stateid, sizeof(*dst));
|
||||||
|
} while (read_seqretry(&state->seqlock, seq));
|
||||||
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
|
if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user