aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r--fs/nfs/client.c51
1 files changed, 51 insertions, 0 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 855add62abc..bc3a8620e8c 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -56,6 +56,30 @@ static DEFINE_SPINLOCK(nfs_client_lock);
56static LIST_HEAD(nfs_client_list); 56static LIST_HEAD(nfs_client_list);
57static LIST_HEAD(nfs_volume_list); 57static LIST_HEAD(nfs_volume_list);
58static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); 58static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
59#ifdef CONFIG_NFS_V4
60static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */
61
62/*
63 * Get a unique NFSv4.0 callback identifier which will be used
64 * by the V4.0 callback service to lookup the nfs_client struct
65 */
66static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
67{
68 int ret = 0;
69
70 if (clp->rpc_ops->version != 4 || minorversion != 0)
71 return ret;
72retry:
73 if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL))
74 return -ENOMEM;
75 spin_lock(&nfs_client_lock);
76 ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident);
77 spin_unlock(&nfs_client_lock);
78 if (ret == -EAGAIN)
79 goto retry;
80 return ret;
81}
82#endif /* CONFIG_NFS_V4 */
59 83
60/* 84/*
61 * RPC cruft for NFS 85 * RPC cruft for NFS
@@ -144,6 +168,10 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_
144 clp->cl_proto = cl_init->proto; 168 clp->cl_proto = cl_init->proto;
145 169
146#ifdef CONFIG_NFS_V4 170#ifdef CONFIG_NFS_V4
171 err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
172 if (err)
173 goto error_cleanup;
174
147 INIT_LIST_HEAD(&clp->cl_delegations); 175 INIT_LIST_HEAD(&clp->cl_delegations);
148 spin_lock_init(&clp->cl_lock); 176 spin_lock_init(&clp->cl_lock);
149 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); 177 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
@@ -202,10 +230,32 @@ static void nfs4_shutdown_client(struct nfs_client *clp)
202 230
203 rpc_destroy_wait_queue(&clp->cl_rpcwaitq); 231 rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
204} 232}
233
234/* idr_remove_all is not needed as all id's are removed by nfs_put_client */
235void nfs_cleanup_cb_ident_idr(void)
236{
237 idr_destroy(&cb_ident_idr);
238}
239
240/* nfs_client_lock held */
241static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
242{
243 if (clp->cl_cb_ident)
244 idr_remove(&cb_ident_idr, clp->cl_cb_ident);
245}
246
205#else 247#else
206static void nfs4_shutdown_client(struct nfs_client *clp) 248static void nfs4_shutdown_client(struct nfs_client *clp)
207{ 249{
208} 250}
251
252void nfs_cleanup_cb_ident_idr(void)
253{
254}
255
256static void nfs_cb_idr_remove_locked(struct nfs_client *clp)
257{
258}
209#endif /* CONFIG_NFS_V4 */ 259#endif /* CONFIG_NFS_V4 */
210 260
211/* 261/*
@@ -244,6 +294,7 @@ void nfs_put_client(struct nfs_client *clp)
244 294
245 if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { 295 if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) {
246 list_del(&clp->cl_share_link); 296 list_del(&clp->cl_share_link);
297 nfs_cb_idr_remove_locked(clp);
247 spin_unlock(&nfs_client_lock); 298 spin_unlock(&nfs_client_lock);
248 299
249 BUG_ON(!list_empty(&clp->cl_superblocks)); 300 BUG_ON(!list_empty(&clp->cl_superblocks));