aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/xprt.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/xprt.c')
-rw-r--r--net/sunrpc/xprt.c42
1 files changed, 27 insertions, 15 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 37edea6fa92d..216a1385718a 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -48,6 +48,7 @@
48#include <linux/sunrpc/clnt.h> 48#include <linux/sunrpc/clnt.h>
49#include <linux/sunrpc/metrics.h> 49#include <linux/sunrpc/metrics.h>
50#include <linux/sunrpc/bc_xprt.h> 50#include <linux/sunrpc/bc_xprt.h>
51#include <linux/rcupdate.h>
51 52
52#include <trace/events/sunrpc.h> 53#include <trace/events/sunrpc.h>
53 54
@@ -1166,7 +1167,7 @@ void xprt_free(struct rpc_xprt *xprt)
1166{ 1167{
1167 put_net(xprt->xprt_net); 1168 put_net(xprt->xprt_net);
1168 xprt_free_all_slots(xprt); 1169 xprt_free_all_slots(xprt);
1169 kfree(xprt); 1170 kfree_rcu(xprt, rcu);
1170} 1171}
1171EXPORT_SYMBOL_GPL(xprt_free); 1172EXPORT_SYMBOL_GPL(xprt_free);
1172 1173
@@ -1180,7 +1181,7 @@ EXPORT_SYMBOL_GPL(xprt_free);
1180 */ 1181 */
1181void xprt_reserve(struct rpc_task *task) 1182void xprt_reserve(struct rpc_task *task)
1182{ 1183{
1183 struct rpc_xprt *xprt; 1184 struct rpc_xprt *xprt = task->tk_xprt;
1184 1185
1185 task->tk_status = 0; 1186 task->tk_status = 0;
1186 if (task->tk_rqstp != NULL) 1187 if (task->tk_rqstp != NULL)
@@ -1188,11 +1189,8 @@ void xprt_reserve(struct rpc_task *task)
1188 1189
1189 task->tk_timeout = 0; 1190 task->tk_timeout = 0;
1190 task->tk_status = -EAGAIN; 1191 task->tk_status = -EAGAIN;
1191 rcu_read_lock();
1192 xprt = rcu_dereference(task->tk_client->cl_xprt);
1193 if (!xprt_throttle_congested(xprt, task)) 1192 if (!xprt_throttle_congested(xprt, task))
1194 xprt->ops->alloc_slot(xprt, task); 1193 xprt->ops->alloc_slot(xprt, task);
1195 rcu_read_unlock();
1196} 1194}
1197 1195
1198/** 1196/**
@@ -1206,7 +1204,7 @@ void xprt_reserve(struct rpc_task *task)
1206 */ 1204 */
1207void xprt_retry_reserve(struct rpc_task *task) 1205void xprt_retry_reserve(struct rpc_task *task)
1208{ 1206{
1209 struct rpc_xprt *xprt; 1207 struct rpc_xprt *xprt = task->tk_xprt;
1210 1208
1211 task->tk_status = 0; 1209 task->tk_status = 0;
1212 if (task->tk_rqstp != NULL) 1210 if (task->tk_rqstp != NULL)
@@ -1214,10 +1212,7 @@ void xprt_retry_reserve(struct rpc_task *task)
1214 1212
1215 task->tk_timeout = 0; 1213 task->tk_timeout = 0;
1216 task->tk_status = -EAGAIN; 1214 task->tk_status = -EAGAIN;
1217 rcu_read_lock();
1218 xprt = rcu_dereference(task->tk_client->cl_xprt);
1219 xprt->ops->alloc_slot(xprt, task); 1215 xprt->ops->alloc_slot(xprt, task);
1220 rcu_read_unlock();
1221} 1216}
1222 1217
1223static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) 1218static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
@@ -1264,11 +1259,9 @@ void xprt_release(struct rpc_task *task)
1264 1259
1265 if (req == NULL) { 1260 if (req == NULL) {
1266 if (task->tk_client) { 1261 if (task->tk_client) {
1267 rcu_read_lock(); 1262 xprt = task->tk_xprt;
1268 xprt = rcu_dereference(task->tk_client->cl_xprt);
1269 if (xprt->snd_task == task) 1263 if (xprt->snd_task == task)
1270 xprt_release_write(xprt, task); 1264 xprt_release_write(xprt, task);
1271 rcu_read_unlock();
1272 } 1265 }
1273 return; 1266 return;
1274 } 1267 }
@@ -1307,7 +1300,7 @@ void xprt_release(struct rpc_task *task)
1307 1300
1308static void xprt_init(struct rpc_xprt *xprt, struct net *net) 1301static void xprt_init(struct rpc_xprt *xprt, struct net *net)
1309{ 1302{
1310 atomic_set(&xprt->count, 1); 1303 kref_init(&xprt->kref);
1311 1304
1312 spin_lock_init(&xprt->transport_lock); 1305 spin_lock_init(&xprt->transport_lock);
1313 spin_lock_init(&xprt->reserve_lock); 1306 spin_lock_init(&xprt->reserve_lock);
@@ -1318,6 +1311,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
1318 spin_lock_init(&xprt->bc_pa_lock); 1311 spin_lock_init(&xprt->bc_pa_lock);
1319 INIT_LIST_HEAD(&xprt->bc_pa_list); 1312 INIT_LIST_HEAD(&xprt->bc_pa_list);
1320#endif /* CONFIG_SUNRPC_BACKCHANNEL */ 1313#endif /* CONFIG_SUNRPC_BACKCHANNEL */
1314 INIT_LIST_HEAD(&xprt->xprt_switch);
1321 1315
1322 xprt->last_used = jiffies; 1316 xprt->last_used = jiffies;
1323 xprt->cwnd = RPC_INITCWND; 1317 xprt->cwnd = RPC_INITCWND;
@@ -1415,6 +1409,24 @@ static void xprt_destroy(struct rpc_xprt *xprt)
1415 xprt->ops->destroy(xprt); 1409 xprt->ops->destroy(xprt);
1416} 1410}
1417 1411
1412static void xprt_destroy_kref(struct kref *kref)
1413{
1414 xprt_destroy(container_of(kref, struct rpc_xprt, kref));
1415}
1416
1417/**
1418 * xprt_get - return a reference to an RPC transport.
1419 * @xprt: pointer to the transport
1420 *
1421 */
1422struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
1423{
1424 if (xprt != NULL && kref_get_unless_zero(&xprt->kref))
1425 return xprt;
1426 return NULL;
1427}
1428EXPORT_SYMBOL_GPL(xprt_get);
1429
1418/** 1430/**
1419 * xprt_put - release a reference to an RPC transport. 1431 * xprt_put - release a reference to an RPC transport.
1420 * @xprt: pointer to the transport 1432 * @xprt: pointer to the transport
@@ -1422,7 +1434,7 @@ static void xprt_destroy(struct rpc_xprt *xprt)
1422 */ 1434 */
1423void xprt_put(struct rpc_xprt *xprt) 1435void xprt_put(struct rpc_xprt *xprt)
1424{ 1436{
1425 if (atomic_dec_and_test(&xprt->count)) 1437 if (xprt != NULL)
1426 xprt_destroy(xprt); 1438 kref_put(&xprt->kref, xprt_destroy_kref);
1427} 1439}
1428EXPORT_SYMBOL_GPL(xprt_put); 1440EXPORT_SYMBOL_GPL(xprt_put);