From: NeilBrown Reference-counting the nfsd4 stateowner structs will let us fix a race and simplify some of the xdr code a bit, and may also help us make the nfsd4 locking a little more fine-grained in the future. Signed-off-by: J. Bruce Fields Signed-off-by: Neil Brown Signed-off-by: Andrew Morton --- 25-akpm/fs/nfsd/nfs4state.c | 27 ++++++++++++++------------- 25-akpm/include/linux/nfsd/state.h | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 13 deletions(-) diff -puN fs/nfsd/nfs4state.c~nfsd4-reference-count-stateowners fs/nfsd/nfs4state.c --- 25/fs/nfsd/nfs4state.c~nfsd4-reference-count-stateowners 2004-09-23 22:06:21.650797200 -0700 +++ 25-akpm/fs/nfsd/nfs4state.c 2004-09-23 22:09:46.582642824 -0700 @@ -833,6 +833,17 @@ release_all_files(void) } } +/* should use a slab cache */ +void +nfs4_free_stateowner(struct kref *kref) +{ + struct nfs4_stateowner *sop = + container_of(kref, struct nfs4_stateowner, so_ref); + kfree(sop->so_owner.data); + kfree(sop); + free_sowner++; +} + static inline struct nfs4_stateowner * alloc_stateowner(struct xdr_netobj *owner) { @@ -842,6 +853,7 @@ alloc_stateowner(struct xdr_netobj *owne if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) { memcpy(sop->so_owner.data, owner->data, owner->len); sop->so_owner.len = owner->len; + kref_init(&sop->so_ref); return sop; } kfree(sop); @@ -849,17 +861,6 @@ alloc_stateowner(struct xdr_netobj *owne return NULL; } -/* should use a slab cache */ -static void -free_stateowner(struct nfs4_stateowner *sop) { - if (sop) { - kfree(sop->so_owner.data); - kfree(sop); - sop = NULL; - free_sowner++; - } -} - static struct nfs4_stateowner * alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { struct nfs4_stateowner *sop; @@ -932,7 +933,7 @@ release_stateowner(struct nfs4_stateowne { unhash_stateowner(sop); list_del(&sop->so_close_lru); - free_stateowner(sop); + nfs4_put_stateowner(sop); } static inline void @@ -1460,7 +1461,7 @@ nfs4_laundromat(void) dprintk("NFSD: purging unused open stateowner (so_id %d)\n", sop->so_id); list_del(&sop->so_close_lru); - free_stateowner(sop); + nfs4_put_stateowner(sop); } if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; diff -puN include/linux/nfsd/state.h~nfsd4-reference-count-stateowners include/linux/nfsd/state.h --- 25/include/linux/nfsd/state.h~nfsd4-reference-count-stateowners 2004-09-23 22:06:21.663795224 -0700 +++ 25-akpm/include/linux/nfsd/state.h 2004-09-23 22:06:21.669794312 -0700 @@ -38,6 +38,7 @@ #define _NFSD4_STATE_H #include +#include #include #define NFS4_OPAQUE_LIMIT 1024 @@ -168,6 +169,7 @@ struct nfs4_replay { * reaped by laundramat thread after lease period. */ struct nfs4_stateowner { + struct kref so_ref; struct list_head so_idhash; /* hash by so_id */ struct list_head so_strhash; /* hash by op_name */ struct list_head so_perclient; /* nfs4_client->cl_perclient */ @@ -248,4 +250,18 @@ extern void nfs4_lock_state(void); extern void nfs4_unlock_state(void); extern int nfs4_in_grace(void); extern int nfs4_check_open_reclaim(clientid_t *clid); +extern void nfs4_free_stateowner(struct kref *kref); + +static inline void +nfs4_put_stateowner(struct nfs4_stateowner *so) +{ + kref_put(&so->so_ref, nfs4_free_stateowner); +} + +static inline void +nfs4_get_stateowner(struct nfs4_stateowner *so) +{ + kref_get(&so->so_ref); +} + #endif /* NFSD4_STATE_H */ _