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 /fs | |
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>
Diffstat (limited to 'fs')
-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 */ |