diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-09 10:45:42 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2007-07-10 23:40:43 -0400 |
commit | 8bda4e4c98d14566fc1a354c62fb59d70cc49b97 (patch) | |
tree | d137e784db33d1347a6b03d22044e9a41e10967f | |
parent | 1ac7e2fd35905f3d44df06568bca5f9d140369b3 (diff) |
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>
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 27 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 10 |
3 files changed, 19 insertions, 20 deletions
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index 4a1c4d80a577..dd1aa2b598ce 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -139,9 +139,11 @@ struct nfs4_state { | |||
139 | unsigned long flags; /* Do we hold any locks? */ | 139 | unsigned long flags; /* Do we hold any locks? */ |
140 | spinlock_t state_lock; /* Protects the lock_states list */ | 140 | spinlock_t state_lock; /* Protects the lock_states list */ |
141 | 141 | ||
142 | seqlock_t seqlock; /* Protects the stateid/open_stateid */ | ||
142 | nfs4_stateid stateid; /* Current stateid: may be delegation */ | 143 | nfs4_stateid stateid; /* Current stateid: may be delegation */ |
143 | nfs4_stateid open_stateid; /* OPEN stateid */ | 144 | nfs4_stateid open_stateid; /* OPEN stateid */ |
144 | 145 | ||
146 | /* The following 3 fields are protected by owner->so_lock */ | ||
145 | unsigned int n_rdonly; /* Number of read-only references */ | 147 | unsigned int n_rdonly; /* Number of read-only references */ |
146 | unsigned int n_wronly; /* Number of write-only references */ | 148 | unsigned int n_wronly; /* Number of write-only references */ |
147 | unsigned int n_rdwr; /* Number of read/write references */ | 149 | unsigned int n_rdwr; /* Number of read/write references */ |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3a2af8053767..ba86ec654c2e 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -385,29 +385,28 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid * | |||
385 | 385 | ||
386 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) | 386 | static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, int open_flags) |
387 | { | 387 | { |
388 | spin_lock(&state->owner->so_lock); | 388 | write_seqlock(&state->seqlock); |
389 | spin_lock(&state->inode->i_lock); | ||
390 | nfs_set_open_stateid_locked(state, stateid, open_flags); | 389 | nfs_set_open_stateid_locked(state, stateid, open_flags); |
391 | spin_unlock(&state->inode->i_lock); | 390 | write_sequnlock(&state->seqlock); |
392 | spin_unlock(&state->owner->so_lock); | ||
393 | } | 391 | } |
394 | 392 | ||
395 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) | 393 | static void update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *deleg_stateid, int open_flags) |
396 | { | 394 | { |
397 | struct inode *inode = state->inode; | ||
398 | |||
399 | open_flags &= (FMODE_READ|FMODE_WRITE); | 395 | open_flags &= (FMODE_READ|FMODE_WRITE); |
400 | /* Protect against nfs4_find_state_byowner() */ | 396 | /* |
401 | spin_lock(&state->owner->so_lock); | 397 | * Protect the call to nfs4_state_set_mode_locked and |
402 | spin_lock(&inode->i_lock); | 398 | * serialise the stateid update |
399 | */ | ||
400 | write_seqlock(&state->seqlock); | ||
403 | if (deleg_stateid != NULL) { | 401 | if (deleg_stateid != NULL) { |
404 | memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); | 402 | memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data)); |
405 | set_bit(NFS_DELEGATED_STATE, &state->flags); | 403 | set_bit(NFS_DELEGATED_STATE, &state->flags); |
406 | } | 404 | } |
407 | if (open_stateid != NULL) | 405 | if (open_stateid != NULL) |
408 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); | 406 | nfs_set_open_stateid_locked(state, open_stateid, open_flags); |
407 | write_sequnlock(&state->seqlock); | ||
408 | spin_lock(&state->owner->so_lock); | ||
409 | update_open_stateflags(state, open_flags); | 409 | update_open_stateflags(state, open_flags); |
410 | spin_unlock(&inode->i_lock); | ||
411 | spin_unlock(&state->owner->so_lock); | 410 | spin_unlock(&state->owner->so_lock); |
412 | } | 411 | } |
413 | 412 | ||
@@ -608,12 +607,10 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state * | |||
608 | */ | 607 | */ |
609 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && | 608 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && |
610 | memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { | 609 | memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { |
611 | spin_lock(&state->owner->so_lock); | 610 | write_seqlock(&state->seqlock); |
612 | spin_lock(&state->inode->i_lock); | ||
613 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) | 611 | if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) |
614 | memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); | 612 | memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); |
615 | spin_unlock(&state->inode->i_lock); | 613 | write_sequnlock(&state->seqlock); |
616 | spin_unlock(&state->owner->so_lock); | ||
617 | } | 614 | } |
618 | return 0; | 615 | return 0; |
619 | } | 616 | } |
@@ -1280,7 +1277,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1280 | mode = FMODE_READ|FMODE_WRITE; | 1277 | mode = FMODE_READ|FMODE_WRITE; |
1281 | clear_rd = clear_wr = clear_rdwr = 0; | 1278 | clear_rd = clear_wr = clear_rdwr = 0; |
1282 | spin_lock(&state->owner->so_lock); | 1279 | spin_lock(&state->owner->so_lock); |
1283 | spin_lock(&calldata->inode->i_lock); | ||
1284 | /* Calculate the change in open mode */ | 1280 | /* Calculate the change in open mode */ |
1285 | if (state->n_rdwr == 0) { | 1281 | if (state->n_rdwr == 0) { |
1286 | if (state->n_rdonly == 0) { | 1282 | if (state->n_rdonly == 0) { |
@@ -1294,7 +1290,6 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data) | |||
1294 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); | 1290 | clear_rdwr |= test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags); |
1295 | } | 1291 | } |
1296 | } | 1292 | } |
1297 | spin_unlock(&calldata->inode->i_lock); | ||
1298 | spin_unlock(&state->owner->so_lock); | 1293 | spin_unlock(&state->owner->so_lock); |
1299 | if (!clear_rd && !clear_wr && !clear_rdwr) { | 1294 | if (!clear_rd && !clear_wr && !clear_rdwr) { |
1300 | /* Note: exit _without_ calling nfs4_close_done */ | 1295 | /* Note: exit _without_ calling nfs4_close_done */ |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 4fa4054cdf34..523cc2cbb5e1 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -307,6 +307,7 @@ nfs4_alloc_open_state(void) | |||
307 | atomic_set(&state->count, 1); | 307 | atomic_set(&state->count, 1); |
308 | INIT_LIST_HEAD(&state->lock_states); | 308 | INIT_LIST_HEAD(&state->lock_states); |
309 | spin_lock_init(&state->state_lock); | 309 | spin_lock_init(&state->state_lock); |
310 | seqlock_init(&state->seqlock); | ||
310 | return state; | 311 | return state; |
311 | } | 312 | } |
312 | 313 | ||
@@ -411,7 +412,6 @@ void nfs4_put_open_state(struct nfs4_state *state) | |||
411 | */ | 412 | */ |
412 | void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | 413 | void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) |
413 | { | 414 | { |
414 | struct inode *inode = state->inode; | ||
415 | struct nfs4_state_owner *owner = state->owner; | 415 | struct nfs4_state_owner *owner = state->owner; |
416 | int call_close = 0; | 416 | int call_close = 0; |
417 | int newstate; | 417 | int newstate; |
@@ -419,7 +419,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | |||
419 | atomic_inc(&owner->so_count); | 419 | atomic_inc(&owner->so_count); |
420 | /* Protect against nfs4_find_state() */ | 420 | /* Protect against nfs4_find_state() */ |
421 | spin_lock(&owner->so_lock); | 421 | spin_lock(&owner->so_lock); |
422 | spin_lock(&inode->i_lock); | ||
423 | switch (mode & (FMODE_READ | FMODE_WRITE)) { | 422 | switch (mode & (FMODE_READ | FMODE_WRITE)) { |
424 | case FMODE_READ: | 423 | case FMODE_READ: |
425 | state->n_rdonly--; | 424 | state->n_rdonly--; |
@@ -446,7 +445,6 @@ void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode) | |||
446 | clear_bit(NFS_DELEGATED_STATE, &state->flags); | 445 | clear_bit(NFS_DELEGATED_STATE, &state->flags); |
447 | } | 446 | } |
448 | nfs4_state_set_mode_locked(state, newstate); | 447 | nfs4_state_set_mode_locked(state, newstate); |
449 | spin_unlock(&inode->i_lock); | ||
450 | spin_unlock(&owner->so_lock); | 448 | spin_unlock(&owner->so_lock); |
451 | 449 | ||
452 | if (!call_close) { | 450 | if (!call_close) { |
@@ -599,8 +597,12 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
599 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) | 597 | void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner) |
600 | { | 598 | { |
601 | struct nfs4_lock_state *lsp; | 599 | struct nfs4_lock_state *lsp; |
600 | int seq; | ||
602 | 601 | ||
603 | memcpy(dst, &state->stateid, sizeof(*dst)); | 602 | do { |
603 | seq = read_seqbegin(&state->seqlock); | ||
604 | memcpy(dst, &state->stateid, sizeof(*dst)); | ||
605 | } while (read_seqretry(&state->seqlock, seq)); | ||
604 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) | 606 | if (test_bit(LK_STATE_IN_USE, &state->flags) == 0) |
605 | return; | 607 | return; |
606 | 608 | ||