summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-05 12:55:57 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:25:01 -0400
commit6b6ca86b77b62b798cf9ca2599036420abce7796 (patch)
treecf631a3c293be45fa4bed54bca5dcbfc96a57df1 /net
parentda45828e2835057045150b318c4fbe9bb91f18dd (diff)
downloadlwn-6b6ca86b77b62b798cf9ca2599036420abce7796.tar.gz
lwn-6b6ca86b77b62b798cf9ca2599036420abce7796.zip
SUNRPC: Add refcounting to the struct rpc_xprt
In a subsequent patch, this will allow the portmapper to take a reference to the rpc_xprt for which it is updating the port number, fixing an Oops. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/clnt.c8
-rw-r--r--net/sunrpc/xprt.c28
2 files changed, 28 insertions, 8 deletions
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index ceadb728f0da..084a0ad5c64e 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -177,7 +177,7 @@ out_no_path:
kfree(clnt->cl_server);
kfree(clnt);
out_err:
- xprt_destroy(xprt);
+ xprt_put(xprt);
out_no_xprt:
return ERR_PTR(err);
}
@@ -261,6 +261,7 @@ rpc_clone_client(struct rpc_clnt *clnt)
atomic_set(&new->cl_users, 0);
new->cl_parent = clnt;
atomic_inc(&clnt->cl_count);
+ new->cl_xprt = xprt_get(clnt->cl_xprt);
/* Turn off autobind on clones */
new->cl_autobind = 0;
new->cl_oneshot = 0;
@@ -337,15 +338,12 @@ rpc_destroy_client(struct rpc_clnt *clnt)
rpc_rmdir(clnt->cl_dentry);
rpc_put_mount();
}
- if (clnt->cl_xprt) {
- xprt_destroy(clnt->cl_xprt);
- clnt->cl_xprt = NULL;
- }
if (clnt->cl_server != clnt->cl_inline_name)
kfree(clnt->cl_server);
out_free:
rpc_free_iostats(clnt->cl_metrics);
clnt->cl_metrics = NULL;
+ xprt_put(clnt->cl_xprt);
kfree(clnt);
return 0;
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index a85f82baefc1..1f786f68729d 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -926,6 +926,7 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si
return ERR_PTR(result);
}
+ kref_init(&xprt->kref);
spin_lock_init(&xprt->transport_lock);
spin_lock_init(&xprt->reserve_lock);
@@ -958,16 +959,37 @@ struct rpc_xprt *xprt_create_transport(int proto, struct sockaddr *ap, size_t si
/**
* xprt_destroy - destroy an RPC transport, killing off all requests.
- * @xprt: transport to destroy
+ * @kref: kref for the transport to destroy
*
*/
-int xprt_destroy(struct rpc_xprt *xprt)
+static void xprt_destroy(struct kref *kref)
{
+ struct rpc_xprt *xprt = container_of(kref, struct rpc_xprt, kref);
+
dprintk("RPC: destroying transport %p\n", xprt);
xprt->shutdown = 1;
del_timer_sync(&xprt->timer);
xprt->ops->destroy(xprt);
kfree(xprt);
+}
- return 0;
+/**
+ * xprt_put - release a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+void xprt_put(struct rpc_xprt *xprt)
+{
+ kref_put(&xprt->kref, xprt_destroy);
+}
+
+/**
+ * xprt_get - return a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
+{
+ kref_get(&xprt->kref);
+ return xprt;
}