diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 855add62abc1..bc3a8620e8c3 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -56,6 +56,30 @@ static DEFINE_SPINLOCK(nfs_client_lock); | |||
56 | static LIST_HEAD(nfs_client_list); | 56 | static LIST_HEAD(nfs_client_list); |
57 | static LIST_HEAD(nfs_volume_list); | 57 | static LIST_HEAD(nfs_volume_list); |
58 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); | 58 | static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); |
59 | #ifdef CONFIG_NFS_V4 | ||
60 | static 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 | */ | ||
66 | static 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; | ||
72 | retry: | ||
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 */ | ||
235 | void nfs_cleanup_cb_ident_idr(void) | ||
236 | { | ||
237 | idr_destroy(&cb_ident_idr); | ||
238 | } | ||
239 | |||
240 | /* nfs_client_lock held */ | ||
241 | static 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 |
206 | static void nfs4_shutdown_client(struct nfs_client *clp) | 248 | static void nfs4_shutdown_client(struct nfs_client *clp) |
207 | { | 249 | { |
208 | } | 250 | } |
251 | |||
252 | void nfs_cleanup_cb_ident_idr(void) | ||
253 | { | ||
254 | } | ||
255 | |||
256 | static 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)); |