aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/client.c51
-rw-r--r--fs/nfs/inode.c1
-rw-r--r--fs/nfs/internal.h1
-rw-r--r--fs/nfs/nfs4proc.c1
-rw-r--r--include/linux/nfs_fs_sb.h1
5 files changed, 55 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));
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index e67e31c7341..c7782b278e8 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1612,6 +1612,7 @@ static void __exit exit_nfs_fs(void)
1612#ifdef CONFIG_PROC_FS 1612#ifdef CONFIG_PROC_FS
1613 rpc_proc_unregister("nfs"); 1613 rpc_proc_unregister("nfs");
1614#endif 1614#endif
1615 nfs_cleanup_cb_ident_idr();
1615 unregister_nfs_fs(); 1616 unregister_nfs_fs();
1616 nfs_fs_proc_exit(); 1617 nfs_fs_proc_exit();
1617 nfsiod_stop(); 1618 nfsiod_stop();
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 435eae3666b..7c803c91657 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -128,6 +128,7 @@ extern void nfs_umount(const struct nfs_mount_request *info);
128/* client.c */ 128/* client.c */
129extern struct rpc_program nfs_program; 129extern struct rpc_program nfs_program;
130 130
131extern void nfs_cleanup_cb_ident_idr(void);
131extern void nfs_put_client(struct nfs_client *); 132extern void nfs_put_client(struct nfs_client *);
132extern struct nfs_client *nfs_find_client(const struct sockaddr *, u32); 133extern struct nfs_client *nfs_find_client(const struct sockaddr *, u32);
133extern struct nfs_client *nfs_find_client_next(struct nfs_client *); 134extern struct nfs_client *nfs_find_client_next(struct nfs_client *);
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 82f3a82b711..e165c53db08 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3484,6 +3484,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
3484 struct nfs4_setclientid setclientid = { 3484 struct nfs4_setclientid setclientid = {
3485 .sc_verifier = &sc_verifier, 3485 .sc_verifier = &sc_verifier,
3486 .sc_prog = program, 3486 .sc_prog = program,
3487 .sc_cb_ident = clp->cl_cb_ident,
3487 }; 3488 };
3488 struct rpc_message msg = { 3489 struct rpc_message msg = {
3489 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID], 3490 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index 452d96436d2..1eaa054a2c7 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -71,6 +71,7 @@ struct nfs_client {
71 */ 71 */
72 char cl_ipaddr[48]; 72 char cl_ipaddr[48];
73 unsigned char cl_id_uniquifier; 73 unsigned char cl_id_uniquifier;
74 u32 cl_cb_ident; /* v4.0 callback identifier */
74 const struct nfs4_minor_version_ops *cl_mvops; 75 const struct nfs4_minor_version_ops *cl_mvops;
75#endif /* CONFIG_NFS_V4 */ 76#endif /* CONFIG_NFS_V4 */
76 77