aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@primarydata.com>2014-07-29 21:34:26 -0400
committerJ. Bruce Fields <bfields@redhat.com>2014-07-31 14:20:18 -0400
commit6b180f0b57af0295e8dc2602a7a4781241766340 (patch)
treecd27ba1d399d67714df6b3798f1512f2a3ef2504
parent2d3f96689ffc757628c6d4038cacaaeb72a03345 (diff)
nfsd: Add reference counting to state owners
The way stateowners are managed today is somewhat awkward. They need to be explicitly destroyed, even though the stateids reference them. This will be particularly problematic when we remove the client_mutex. We may create a new stateowner and attempt to open a file or set a lock, and have that fail. In the meantime, another RPC may come in that uses that same stateowner and succeed. We can't have the first task tearing down the stateowner in that situation. To fix this, we need to change how stateowners are tracked altogether. Refcount them and only destroy them once all stateids that reference them have been destroyed. This patch starts by adding the refcounting necessary to do that. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Signed-off-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c49
-rw-r--r--fs/nfsd/state.h22
2 files changed, 50 insertions, 21 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 653de6b14665..5a93e5fafd4a 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -890,6 +890,14 @@ release_all_access(struct nfs4_ol_stateid *stp)
890 } 890 }
891} 891}
892 892
893static void nfs4_put_stateowner(struct nfs4_stateowner *sop)
894{
895 if (!atomic_dec_and_test(&sop->so_count))
896 return;
897 kfree(sop->so_owner.data);
898 sop->so_ops->so_free(sop);
899}
900
893static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) 901static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
894{ 902{
895 struct nfs4_file *fp = stp->st_stid.sc_file; 903 struct nfs4_file *fp = stp->st_stid.sc_file;
@@ -946,16 +954,10 @@ static void unhash_lockowner(struct nfs4_lockowner *lo)
946 } 954 }
947} 955}
948 956
949static void nfs4_free_lockowner(struct nfs4_lockowner *lo)
950{
951 kfree(lo->lo_owner.so_owner.data);
952 kmem_cache_free(lockowner_slab, lo);
953}
954
955static void release_lockowner(struct nfs4_lockowner *lo) 957static void release_lockowner(struct nfs4_lockowner *lo)
956{ 958{
957 unhash_lockowner(lo); 959 unhash_lockowner(lo);
958 nfs4_free_lockowner(lo); 960 nfs4_put_stateowner(&lo->lo_owner);
959} 961}
960 962
961static void release_lockowner_if_empty(struct nfs4_lockowner *lo) 963static void release_lockowner_if_empty(struct nfs4_lockowner *lo)
@@ -1025,18 +1027,12 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo)
1025 } 1027 }
1026} 1028}
1027 1029
1028static void nfs4_free_openowner(struct nfs4_openowner *oo)
1029{
1030 kfree(oo->oo_owner.so_owner.data);
1031 kmem_cache_free(openowner_slab, oo);
1032}
1033
1034static void release_openowner(struct nfs4_openowner *oo) 1030static void release_openowner(struct nfs4_openowner *oo)
1035{ 1031{
1036 unhash_openowner(oo); 1032 unhash_openowner(oo);
1037 list_del(&oo->oo_close_lru); 1033 list_del(&oo->oo_close_lru);
1038 release_last_closed_stateid(oo); 1034 release_last_closed_stateid(oo);
1039 nfs4_free_openowner(oo); 1035 nfs4_put_stateowner(&oo->oo_owner);
1040} 1036}
1041 1037
1042static inline int 1038static inline int
@@ -2964,6 +2960,7 @@ static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj
2964 INIT_LIST_HEAD(&sop->so_stateids); 2960 INIT_LIST_HEAD(&sop->so_stateids);
2965 sop->so_client = clp; 2961 sop->so_client = clp;
2966 init_nfs4_replay(&sop->so_replay); 2962 init_nfs4_replay(&sop->so_replay);
2963 atomic_set(&sop->so_count, 1);
2967 return sop; 2964 return sop;
2968} 2965}
2969 2966
@@ -2975,6 +2972,17 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u
2975 list_add(&oo->oo_perclient, &clp->cl_openowners); 2972 list_add(&oo->oo_perclient, &clp->cl_openowners);
2976} 2973}
2977 2974
2975static void nfs4_free_openowner(struct nfs4_stateowner *so)
2976{
2977 struct nfs4_openowner *oo = openowner(so);
2978
2979 kmem_cache_free(openowner_slab, oo);
2980}
2981
2982static const struct nfs4_stateowner_operations openowner_ops = {
2983 .so_free = nfs4_free_openowner,
2984};
2985
2978static struct nfs4_openowner * 2986static struct nfs4_openowner *
2979alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 2987alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
2980 struct nfsd4_compound_state *cstate) 2988 struct nfsd4_compound_state *cstate)
@@ -2985,6 +2993,7 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
2985 oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); 2993 oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
2986 if (!oo) 2994 if (!oo)
2987 return NULL; 2995 return NULL;
2996 oo->oo_owner.so_ops = &openowner_ops;
2988 oo->oo_owner.so_is_open_owner = 1; 2997 oo->oo_owner.so_is_open_owner = 1;
2989 oo->oo_owner.so_seqid = open->op_seqid; 2998 oo->oo_owner.so_seqid = open->op_seqid;
2990 oo->oo_flags = NFS4_OO_NEW; 2999 oo->oo_flags = NFS4_OO_NEW;
@@ -4729,6 +4738,17 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner,
4729 return NULL; 4738 return NULL;
4730} 4739}
4731 4740
4741static void nfs4_free_lockowner(struct nfs4_stateowner *sop)
4742{
4743 struct nfs4_lockowner *lo = lockowner(sop);
4744
4745 kmem_cache_free(lockowner_slab, lo);
4746}
4747
4748static const struct nfs4_stateowner_operations lockowner_ops = {
4749 .so_free = nfs4_free_lockowner,
4750};
4751
4732/* 4752/*
4733 * Alloc a lock owner structure. 4753 * Alloc a lock owner structure.
4734 * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 4754 * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has
@@ -4749,6 +4769,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
4749 /* It is the openowner seqid that will be incremented in encode in the 4769 /* It is the openowner seqid that will be incremented in encode in the
4750 * case of new lockowners; so increment the lock seqid manually: */ 4770 * case of new lockowners; so increment the lock seqid manually: */
4751 lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1; 4771 lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
4772 lo->lo_owner.so_ops = &lockowner_ops;
4752 list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); 4773 list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]);
4753 return lo; 4774 return lo;
4754} 4775}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index af1d9c42e939..dc725deb4aa8 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -331,16 +331,24 @@ struct nfs4_replay {
331 char rp_ibuf[NFSD4_REPLAY_ISIZE]; 331 char rp_ibuf[NFSD4_REPLAY_ISIZE];
332}; 332};
333 333
334struct nfs4_stateowner;
335
336struct nfs4_stateowner_operations {
337 void (*so_free)(struct nfs4_stateowner *);
338};
339
334struct nfs4_stateowner { 340struct nfs4_stateowner {
335 struct list_head so_strhash; /* hash by op_name */ 341 struct list_head so_strhash;
336 struct list_head so_stateids; 342 struct list_head so_stateids;
337 struct nfs4_client * so_client; 343 struct nfs4_client *so_client;
344 const struct nfs4_stateowner_operations *so_ops;
338 /* after increment in ENCODE_SEQID_OP_TAIL, represents the next 345 /* after increment in ENCODE_SEQID_OP_TAIL, represents the next
339 * sequence id expected from the client: */ 346 * sequence id expected from the client: */
340 u32 so_seqid; 347 atomic_t so_count;
341 struct xdr_netobj so_owner; /* open owner name */ 348 u32 so_seqid;
342 struct nfs4_replay so_replay; 349 struct xdr_netobj so_owner; /* open owner name */
343 bool so_is_open_owner; 350 struct nfs4_replay so_replay;
351 bool so_is_open_owner;
344}; 352};
345 353
346struct nfs4_openowner { 354struct nfs4_openowner {