Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[deliverable/linux.git] / net / sunrpc / xprt.c
index 37edea6fa92d9685570ad3c1b37cb5fda5c0b9b3..216a1385718a27e9f86516720d28d61b9aaac609 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/metrics.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/rcupdate.h>
 
 #include <trace/events/sunrpc.h>
 
@@ -1166,7 +1167,7 @@ void xprt_free(struct rpc_xprt *xprt)
 {
        put_net(xprt->xprt_net);
        xprt_free_all_slots(xprt);
-       kfree(xprt);
+       kfree_rcu(xprt, rcu);
 }
 EXPORT_SYMBOL_GPL(xprt_free);
 
@@ -1180,7 +1181,7 @@ EXPORT_SYMBOL_GPL(xprt_free);
  */
 void xprt_reserve(struct rpc_task *task)
 {
-       struct rpc_xprt *xprt;
+       struct rpc_xprt *xprt = task->tk_xprt;
 
        task->tk_status = 0;
        if (task->tk_rqstp != NULL)
@@ -1188,11 +1189,8 @@ void xprt_reserve(struct rpc_task *task)
 
        task->tk_timeout = 0;
        task->tk_status = -EAGAIN;
-       rcu_read_lock();
-       xprt = rcu_dereference(task->tk_client->cl_xprt);
        if (!xprt_throttle_congested(xprt, task))
                xprt->ops->alloc_slot(xprt, task);
-       rcu_read_unlock();
 }
 
 /**
@@ -1206,7 +1204,7 @@ void xprt_reserve(struct rpc_task *task)
  */
 void xprt_retry_reserve(struct rpc_task *task)
 {
-       struct rpc_xprt *xprt;
+       struct rpc_xprt *xprt = task->tk_xprt;
 
        task->tk_status = 0;
        if (task->tk_rqstp != NULL)
@@ -1214,10 +1212,7 @@ void xprt_retry_reserve(struct rpc_task *task)
 
        task->tk_timeout = 0;
        task->tk_status = -EAGAIN;
-       rcu_read_lock();
-       xprt = rcu_dereference(task->tk_client->cl_xprt);
        xprt->ops->alloc_slot(xprt, task);
-       rcu_read_unlock();
 }
 
 static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
@@ -1264,11 +1259,9 @@ void xprt_release(struct rpc_task *task)
 
        if (req == NULL) {
                if (task->tk_client) {
-                       rcu_read_lock();
-                       xprt = rcu_dereference(task->tk_client->cl_xprt);
+                       xprt = task->tk_xprt;
                        if (xprt->snd_task == task)
                                xprt_release_write(xprt, task);
-                       rcu_read_unlock();
                }
                return;
        }
@@ -1307,7 +1300,7 @@ void xprt_release(struct rpc_task *task)
 
 static void xprt_init(struct rpc_xprt *xprt, struct net *net)
 {
-       atomic_set(&xprt->count, 1);
+       kref_init(&xprt->kref);
 
        spin_lock_init(&xprt->transport_lock);
        spin_lock_init(&xprt->reserve_lock);
@@ -1318,6 +1311,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
        spin_lock_init(&xprt->bc_pa_lock);
        INIT_LIST_HEAD(&xprt->bc_pa_list);
 #endif /* CONFIG_SUNRPC_BACKCHANNEL */
+       INIT_LIST_HEAD(&xprt->xprt_switch);
 
        xprt->last_used = jiffies;
        xprt->cwnd = RPC_INITCWND;
@@ -1415,6 +1409,24 @@ static void xprt_destroy(struct rpc_xprt *xprt)
        xprt->ops->destroy(xprt);
 }
 
+static void xprt_destroy_kref(struct kref *kref)
+{
+       xprt_destroy(container_of(kref, struct rpc_xprt, kref));
+}
+
+/**
+ * xprt_get - return a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
+{
+       if (xprt != NULL && kref_get_unless_zero(&xprt->kref))
+               return xprt;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(xprt_get);
+
 /**
  * xprt_put - release a reference to an RPC transport.
  * @xprt: pointer to the transport
@@ -1422,7 +1434,7 @@ static void xprt_destroy(struct rpc_xprt *xprt)
  */
 void xprt_put(struct rpc_xprt *xprt)
 {
-       if (atomic_dec_and_test(&xprt->count))
-               xprt_destroy(xprt);
+       if (xprt != NULL)
+               kref_put(&xprt->kref, xprt_destroy_kref);
 }
 EXPORT_SYMBOL_GPL(xprt_put);
This page took 0.051679 seconds and 5 git commands to generate.