diff options
author | J. Bruce Fields <bfields@redhat.com> | 2019-03-20 20:03:02 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2019-07-03 17:52:49 -0400 |
commit | 59f8e91b75ecf16f22d62eca0659c13901eff5f3 (patch) | |
tree | 71be0a7af288721f33e8c34e5ff6691d9c200098 | |
parent | 14ed14cc7c062bbed7821be0a93938dc78a49803 (diff) |
nfsd4: use reference count to free client
Keep a second reference count which is what is really used to decide
when to free the client's memory.
Next I'm going to add an nfsd/clients/ directory with a subdirectory for
each NFSv4 client. File objects under nfsd/clients/ will hold these
references.
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r-- | fs/nfsd/nfs4state.c | 26 | ||||
-rw-r--r-- | fs/nfsd/state.h | 1 |
2 files changed, 22 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 194da1700cc4..de68c3cbea2b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1879,6 +1879,24 @@ err_no_name: return NULL; } +static void __free_client(struct kref *k) +{ + struct nfs4_client *clp = container_of(k, struct nfs4_client, cl_ref); + + free_svc_cred(&clp->cl_cred); + kfree(clp->cl_ownerstr_hashtbl); + kfree(clp->cl_name.data); + idr_destroy(&clp->cl_stateids); + if (clp->cl_nfsd_dentry) + nfsd_client_rmdir(clp->cl_nfsd_dentry); + kmem_cache_free(client_slab, clp); +} + +void drop_client(struct nfs4_client *clp) +{ + kref_put(&clp->cl_ref, __free_client); +} + static void free_client(struct nfs4_client *clp) { @@ -1891,11 +1909,7 @@ free_client(struct nfs4_client *clp) free_session(ses); } rpc_destroy_wait_queue(&clp->cl_cb_waitq); - free_svc_cred(&clp->cl_cred); - kfree(clp->cl_ownerstr_hashtbl); - kfree(clp->cl_name.data); - idr_destroy(&clp->cl_stateids); - kmem_cache_free(client_slab, clp); + drop_client(clp); } /* must be called under the client_lock */ @@ -2216,6 +2230,8 @@ static struct nfs4_client *create_client(struct xdr_netobj name, free_client(clp); return NULL; } + + kref_init(&clp->cl_ref); nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); clp->cl_time = get_seconds(); clear_bit(0, &clp->cl_cb_slot_busy); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index f79ad7202e82..8eacdbc50cd7 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -348,6 +348,7 @@ struct nfs4_client { u32 cl_exchange_flags; /* number of rpc's in progress over an associated session: */ atomic_t cl_rpc_users; + struct kref cl_ref; struct nfs4_op_map cl_spo_must_allow; /* for nfs41 callbacks */ |