diff options
| author | J. Bruce Fields <bfields@redhat.com> | 2011-09-16 17:42:48 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@redhat.com> | 2011-09-17 10:01:54 -0400 |
| commit | 38c387b52d8404f8fd29d8c26bebc83a80733657 (patch) | |
| tree | 41879d4c05ef03368856439f232df7ac1fcc2b0b | |
| parent | dad1c067eb42ec8bedadd64f681056914547d22e (diff) | |
nfsd4: match close replays on stateid, not open owner id
Keep around an unhashed copy of the final stateid after the last close
using an openowner, and when identifying a replay, match against that
stateid instead of just against the open owner id. Free it the next
time the seqid is bumped or the stateowner is destroyed.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
| -rw-r--r-- | fs/nfsd/nfs4state.c | 47 | ||||
| -rw-r--r-- | fs/nfsd/nfs4xdr.c | 1 | ||||
| -rw-r--r-- | fs/nfsd/state.h | 3 |
3 files changed, 44 insertions, 7 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 59b70afdc884..a174841b262e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
| @@ -438,7 +438,6 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp) | |||
| 438 | 438 | ||
| 439 | static void free_generic_stateid(struct nfs4_ol_stateid *stp) | 439 | static void free_generic_stateid(struct nfs4_ol_stateid *stp) |
| 440 | { | 440 | { |
| 441 | close_generic_stateid(stp); | ||
| 442 | kmem_cache_free(stateid_slab, stp); | 441 | kmem_cache_free(stateid_slab, stp); |
| 443 | } | 442 | } |
| 444 | 443 | ||
| @@ -450,6 +449,7 @@ static void release_lock_stateid(struct nfs4_ol_stateid *stp) | |||
| 450 | file = find_any_file(stp->st_file); | 449 | file = find_any_file(stp->st_file); |
| 451 | if (file) | 450 | if (file) |
| 452 | locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); | 451 | locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); |
| 452 | close_generic_stateid(stp); | ||
| 453 | free_generic_stateid(stp); | 453 | free_generic_stateid(stp); |
| 454 | } | 454 | } |
| 455 | 455 | ||
| @@ -485,10 +485,16 @@ release_stateid_lockowners(struct nfs4_ol_stateid *open_stp) | |||
| 485 | } | 485 | } |
| 486 | } | 486 | } |
| 487 | 487 | ||
| 488 | static void release_open_stateid(struct nfs4_ol_stateid *stp) | 488 | static void unhash_open_stateid(struct nfs4_ol_stateid *stp) |
| 489 | { | 489 | { |
| 490 | unhash_generic_stateid(stp); | 490 | unhash_generic_stateid(stp); |
| 491 | release_stateid_lockowners(stp); | 491 | release_stateid_lockowners(stp); |
| 492 | close_generic_stateid(stp); | ||
| 493 | } | ||
| 494 | |||
| 495 | static void release_open_stateid(struct nfs4_ol_stateid *stp) | ||
| 496 | { | ||
| 497 | unhash_open_stateid(stp); | ||
| 492 | free_generic_stateid(stp); | 498 | free_generic_stateid(stp); |
| 493 | } | 499 | } |
| 494 | 500 | ||
| @@ -510,6 +516,8 @@ static void release_openowner(struct nfs4_openowner *oo) | |||
| 510 | { | 516 | { |
| 511 | unhash_openowner(oo); | 517 | unhash_openowner(oo); |
| 512 | list_del(&oo->oo_close_lru); | 518 | list_del(&oo->oo_close_lru); |
| 519 | if (oo->oo_last_closed_stid) | ||
| 520 | free_generic_stateid(oo->oo_last_closed_stid); | ||
| 513 | nfs4_free_openowner(oo); | 521 | nfs4_free_openowner(oo); |
| 514 | } | 522 | } |
| 515 | 523 | ||
| @@ -2324,6 +2332,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
| 2324 | oo->oo_owner.so_seqid = open->op_seqid; | 2332 | oo->oo_owner.so_seqid = open->op_seqid; |
| 2325 | oo->oo_flags = 0; | 2333 | oo->oo_flags = 0; |
| 2326 | oo->oo_time = 0; | 2334 | oo->oo_time = 0; |
| 2335 | oo->oo_last_closed_stid = NULL; | ||
| 2327 | INIT_LIST_HEAD(&oo->oo_close_lru); | 2336 | INIT_LIST_HEAD(&oo->oo_close_lru); |
| 2328 | hash_openowner(oo, clp, strhashval); | 2337 | hash_openowner(oo, clp, strhashval); |
| 2329 | return oo; | 2338 | return oo; |
| @@ -3120,12 +3129,14 @@ laundromat_main(struct work_struct *not_used) | |||
| 3120 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); | 3129 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); |
| 3121 | } | 3130 | } |
| 3122 | 3131 | ||
| 3123 | static struct nfs4_openowner * search_close_lru(u32 st_id) | 3132 | static struct nfs4_openowner * search_close_lru(stateid_t *s) |
| 3124 | { | 3133 | { |
| 3125 | struct nfs4_openowner *local; | 3134 | struct nfs4_openowner *local; |
| 3135 | struct nfs4_ol_stateid *os; | ||
| 3126 | 3136 | ||
| 3127 | list_for_each_entry(local, &close_lru, oo_close_lru) { | 3137 | list_for_each_entry(local, &close_lru, oo_close_lru) { |
| 3128 | if (local->oo_owner.so_id == st_id) | 3138 | os = local->oo_last_closed_stid; |
| 3139 | if (same_stateid(&os->st_stid.sc_stateid, s)) | ||
| 3129 | return local; | 3140 | return local; |
| 3130 | } | 3141 | } |
| 3131 | return NULL; | 3142 | return NULL; |
| @@ -3589,6 +3600,27 @@ out: | |||
| 3589 | return status; | 3600 | return status; |
| 3590 | } | 3601 | } |
| 3591 | 3602 | ||
| 3603 | void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so) | ||
| 3604 | { | ||
| 3605 | struct nfs4_openowner *oo; | ||
| 3606 | struct nfs4_ol_stateid *s; | ||
| 3607 | |||
| 3608 | if (!so->so_is_open_owner) | ||
| 3609 | return; | ||
| 3610 | oo = openowner(so); | ||
| 3611 | s = oo->oo_last_closed_stid; | ||
| 3612 | if (!s) | ||
| 3613 | return; | ||
| 3614 | if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) { | ||
| 3615 | /* Release the last_closed_stid on the next seqid bump: */ | ||
| 3616 | oo->oo_flags |= NFS4_OO_PURGE_CLOSE; | ||
| 3617 | return; | ||
| 3618 | } | ||
| 3619 | oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE; | ||
| 3620 | free_generic_stateid(oo->oo_last_closed_stid); | ||
| 3621 | oo->oo_last_closed_stid = NULL; | ||
| 3622 | } | ||
| 3623 | |||
| 3592 | /* | 3624 | /* |
| 3593 | * nfs4_unlock_state() called after encode | 3625 | * nfs4_unlock_state() called after encode |
| 3594 | */ | 3626 | */ |
| @@ -3613,7 +3645,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3613 | * Also, we should make sure this isn't just the result of | 3645 | * Also, we should make sure this isn't just the result of |
| 3614 | * a replayed close: | 3646 | * a replayed close: |
| 3615 | */ | 3647 | */ |
| 3616 | oo = search_close_lru(close->cl_stateid.si_stateownerid); | 3648 | oo = search_close_lru(&close->cl_stateid); |
| 3617 | /* It's not stale; let's assume it's expired: */ | 3649 | /* It's not stale; let's assume it's expired: */ |
| 3618 | if (oo == NULL) | 3650 | if (oo == NULL) |
| 3619 | goto out; | 3651 | goto out; |
| @@ -3630,8 +3662,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
| 3630 | update_stateid(&stp->st_stid.sc_stateid); | 3662 | update_stateid(&stp->st_stid.sc_stateid); |
| 3631 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3663 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); |
| 3632 | 3664 | ||
| 3633 | /* release_stateid() calls nfsd_close() if needed */ | 3665 | /* unhash_open_stateid() calls nfsd_close() if needed */ |
| 3634 | release_open_stateid(stp); | 3666 | oo->oo_last_closed_stid = stp; |
| 3667 | unhash_open_stateid(stp); | ||
| 3635 | 3668 | ||
| 3636 | /* place unused nfs4_stateowners on so_close_lru list to be | 3669 | /* place unused nfs4_stateowners on so_close_lru list to be |
| 3637 | * released by the laundromat service after the lease period | 3670 | * released by the laundromat service after the lease period |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f4116cf16595..7bd57c2dbc4d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -1636,6 +1636,7 @@ static void encode_seqid_op_tail(struct nfsd4_compoundres *resp, __be32 *save, _ | |||
| 1636 | (char *)resp->p - (char *)save; | 1636 | (char *)resp->p - (char *)save; |
| 1637 | memcpy(stateowner->so_replay.rp_buf, save, | 1637 | memcpy(stateowner->so_replay.rp_buf, save, |
| 1638 | stateowner->so_replay.rp_buflen); | 1638 | stateowner->so_replay.rp_buflen); |
| 1639 | nfsd4_purge_closed_stateid(stateowner); | ||
| 1639 | } | 1640 | } |
| 1640 | } | 1641 | } |
| 1641 | 1642 | ||
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index a8324b868a36..e807abb116f6 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
| @@ -370,8 +370,10 @@ struct nfs4_openowner { | |||
| 370 | struct nfs4_stateowner oo_owner; /* must be first field */ | 370 | struct nfs4_stateowner oo_owner; /* must be first field */ |
| 371 | struct list_head oo_perclient; | 371 | struct list_head oo_perclient; |
| 372 | struct list_head oo_close_lru; /* tail queue */ | 372 | struct list_head oo_close_lru; /* tail queue */ |
| 373 | struct nfs4_ol_stateid *oo_last_closed_stid; | ||
| 373 | time_t oo_time; /* time of placement on so_close_lru */ | 374 | time_t oo_time; /* time of placement on so_close_lru */ |
| 374 | #define NFS4_OO_CONFIRMED 1 | 375 | #define NFS4_OO_CONFIRMED 1 |
| 376 | #define NFS4_OO_PURGE_CLOSE 2 | ||
| 375 | unsigned char oo_flags; | 377 | unsigned char oo_flags; |
| 376 | }; | 378 | }; |
| 377 | 379 | ||
| @@ -514,5 +516,6 @@ extern int nfsd4_create_clid_dir(struct nfs4_client *clp); | |||
| 514 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); | 516 | extern void nfsd4_remove_clid_dir(struct nfs4_client *clp); |
| 515 | extern void release_session_client(struct nfsd4_session *); | 517 | extern void release_session_client(struct nfsd4_session *); |
| 516 | extern __be32 nfs4_validate_stateid(stateid_t *, bool); | 518 | extern __be32 nfs4_validate_stateid(stateid_t *, bool); |
| 519 | extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); | ||
| 517 | 520 | ||
| 518 | #endif /* NFSD4_STATE_H */ | 521 | #endif /* NFSD4_STATE_H */ |
