[pnfs] [PATCH 1/5] rpc_clnt ref count for nfs4_cb_recall

Benny Halevy bhalevy at panasas.com
Thu May 17 09:44:18 EDT 2007


This patch adds a refcount to rpc_clnt.cl_users around the call
to nfs4_cb_recall to keep the rpc_clnt around throughout the recall.
Otherwise, it could be used after free if expire_client is called
before the callback rpc starts.

Signed-off-by: Benny Halevy <bhalevy at panasas.com>
---
 fs/nfsd/nfs4callback.c   |    3 +++
 fs/nfsd/nfs4state.c      |   13 +++++++++++++
 net/sunrpc/sunrpc_syms.c |    1 +
 3 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 54b37b1..63aafd2 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -543,6 +543,9 @@ out:
 	/* Success or failure, now we're either waiting for lease expiration
 	 * or deleg_return. */
 	dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count));
+	rpc_release_client(clnt);
+	nfs4_lock_state();
 	nfs4_put_delegation(dp);
+	nfs4_unlock_state();
 	return;
 }
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2d2c85d..e2e924e 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1679,12 +1679,22 @@ static
 void nfsd_break_deleg_cb(struct file_lock *fl)
 {
 	struct nfs4_delegation *dp=  (struct nfs4_delegation *)fl->fl_owner;
+	struct rpc_clnt *clnt;
 	struct task_struct *t;
 
 	dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);
 	if (!dp)
 		return;
 
+	nfs4_lock_state();
+	clnt = dp->dl_client->cl_callback.cb_client;
+	if (!atomic_read(&dp->dl_client->cl_callback.cb_set) || !clnt) {
+		nfs4_unlock_state();
+		return;
+	}
+	atomic_inc(&clnt->cl_users);
+	nfs4_unlock_state();
+
 	/* We're assuming the state code never drops its reference
 	 * without first removing the lease.  Since we're in this lease
 	 * callback (and since the lease code is serialized by the kernel
@@ -1709,7 +1719,10 @@ void nfsd_break_deleg_cb(struct file_lock *fl)
 		printk(KERN_INFO "NFSD: Callback thread failed for "
 			"for client (clientid %08x/%08x)\n",
 			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+		rpc_release_client(clnt);
+		nfs4_lock_state();
 		nfs4_put_delegation(dp);
+		nfs4_unlock_state();
 	}
 }
 
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index f38f939..b329983 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -40,6 +40,7 @@ EXPORT_SYMBOL(rpc_create_client);
 EXPORT_SYMBOL(rpc_new_client);
 EXPORT_SYMBOL(rpc_clone_client);
 EXPORT_SYMBOL(rpc_bind_new_program);
+EXPORT_SYMBOL(rpc_release_client);
 EXPORT_SYMBOL(rpc_destroy_client);
 EXPORT_SYMBOL(rpc_shutdown_client);
 EXPORT_SYMBOL(rpc_killall_tasks);


More information about the pNFS mailing list