]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
SUNRPC: Add refcounting to the struct rpc_xprt
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Tue, 5 Sep 2006 16:55:57 +0000 (12:55 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 23 Sep 2006 03:25:01 +0000 (23:25 -0400)
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>
include/linux/sunrpc/xprt.h
net/sunrpc/clnt.c
net/sunrpc/xprt.c

index de4efea7c856da3e8de838ee504684f3e26b81f2..bdeba8538c719892407c0f112e809bb166cc179c 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/uio.h>
 #include <linux/socket.h>
 #include <linux/in.h>
+#include <linux/kref.h>
 #include <linux/sunrpc/sched.h>
 #include <linux/sunrpc/xdr.h>
 
@@ -129,6 +130,7 @@ struct rpc_xprt_ops {
 };
 
 struct rpc_xprt {
+       struct kref             kref;           /* Reference count */
        struct rpc_xprt_ops *   ops;            /* transport methods */
        struct socket *         sock;           /* BSD socket layer */
        struct sock *           inet;           /* INET layer */
@@ -248,7 +250,8 @@ int                 xprt_adjust_timeout(struct rpc_rqst *req);
 void                   xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
 void                   xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
 void                   xprt_release(struct rpc_task *task);
-int                    xprt_destroy(struct rpc_xprt *xprt);
+struct rpc_xprt *      xprt_get(struct rpc_xprt *xprt);
+void                   xprt_put(struct rpc_xprt *xprt);
 
 static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p)
 {
index ceadb728f0da2f2a8acbd145994a799575539e66..084a0ad5c64ea0752893f7ddefb95be18384a467 100644 (file)
@@ -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;
 }
index a85f82baefc127d48359f062861d34c8fd591c33..1f786f68729d465c8bc7f3fb51b45465a4c89aa2 100644 (file)
@@ -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;
 }