@@ -56,6 +56,8 @@ static DEFINE_SPINLOCK(nfs_client_lock);
static LIST_HEAD(nfs_client_list);
static LIST_HEAD(nfs_volume_list);
static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
+/* NFSv4.0 callback identifier */
+static DEFINE_IDR(cb_ident_idr);
/*
* RPC cruft for NFS
@@ -359,6 +361,30 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1,
return 0;
}
+/* idr_remove_all is not needed as all id's are removed by nfs_put_client */
+void nfs_cleanup_cb_ident_idr(void)
+{
+ idr_destroy(&cb_ident_idr);
+}
+
+/*
+ * Get a unique NFSv4.0 callback identifier which will be used
+ * by the V4.0 callback service to lookup the nfs_client struct
+ */
+int nfs_get_cb_ident(struct nfs_client *clp, int *cb_ident)
+{
+ int ret;
+retry:
+ if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL))
+ return -ENOMEM;
+ spin_lock(&nfs_client_lock);
+ ret = idr_get_new(&cb_ident_idr, clp, cb_ident);
+ spin_unlock(&nfs_client_lock);
+ if (ret == -EAGAIN)
+ goto retry;
+ return ret;
+}
+
/*
* Find a client by IP address and protocol version
* - returns NULL if no such client
@@ -1612,6 +1612,7 @@ static void __exit exit_nfs_fs(void)
#ifdef CONFIG_PROC_FS
rpc_proc_unregister("nfs");
#endif
+ nfs_cleanup_cb_ident_idr();
unregister_nfs_fs();
nfs_fs_proc_exit();
nfsiod_stop();
@@ -128,6 +128,8 @@ extern void nfs_umount(const struct nfs_mount_request *info);
/* client.c */
extern struct rpc_program nfs_program;
+extern void nfs_cleanup_cb_ident_idr(void);
+extern int nfs_get_cb_ident(struct nfs_client *, int *);
extern void nfs_put_client(struct nfs_client *);
extern struct nfs_client *nfs_find_client(const struct sockaddr *, u32);
extern struct nfs_client *nfs_find_client_next(struct nfs_client *);
@@ -3489,6 +3489,11 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
int loop = 0;
int status;
+ /* get a unique callback identifier */
+ status = nfs_get_cb_ident(clp, &setclientid.sc_cb_ident);
+ if (status)
+ return status;
+
p = (__be32*)sc_verifier.data;
*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
*p = htonl((u32)clp->cl_boot_time.tv_nsec);
@@ -3522,6 +3527,8 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
if (++clp->cl_id_uniquifier == 0)
break;
}
+ if (status == NFS_OK)
+ res->cb_ident = setclientid.sc_cb_ident;
return status;
}
@@ -79,6 +79,7 @@ int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
if (status != 0)
goto out;
clp->cl_clientid = clid.clientid;
+ clp->cl_cb_ident = clid.cb_ident;
nfs4_schedule_state_renewal(clp);
out:
return status;
@@ -71,6 +71,7 @@ struct nfs_client {
*/
char cl_ipaddr[48];
unsigned char cl_id_uniquifier;
+ u32 cl_cb_ident; /* v4.0 callback identifier */
const struct nfs4_minor_version_ops *cl_mvops;
#endif /* CONFIG_NFS_V4 */
@@ -869,6 +869,7 @@ struct nfs4_setclientid {
struct nfs4_setclientid_res {
u64 clientid;
nfs4_verifier confirm;
+ u32 cb_ident;
};
struct nfs4_statfs_arg {