static void
rds_recv_local(struct rds_connection *conn, __be32 saddr, __be32 daddr,
- struct rds_incoming *inc, gfp_t gfp);
+ struct rds_incoming *inc, gfp_t gfp, struct rds_sock *rs);
static int
rds_recv_ok(struct sock *sk, struct sk_buff *skb)
/* pass it on locally if there is no socket bound, or if netfilter is
* disabled for this socket */
if (NULL == rs || !rs->rs_netfilter_enabled) {
+ rds_recv_local(conn, saddr, daddr, inc, gfp, rs);
+
/* drop the reference if we had taken one */
if (NULL != rs)
rds_sock_put(rs);
- rds_recv_local(conn, saddr, daddr, inc, gfp);
return;
}
rds_rtd(RDS_RTD_ERR,
"failure to allocate space for inc %p, %u.%u.%u.%u -> %u.%d.%u.%u tos %d\n",
inc, NIPQUAD(saddr), NIPQUAD(daddr), conn->c_tos);
- rds_recv_local(conn, saddr, daddr, inc, gfp);
+ rds_recv_local(conn, saddr, daddr, inc, gfp, rs);
+ /* drop the reference if we had taken one */
+ if (NULL != rs)
+ rds_sock_put(rs);
return;
}
/* cleanup any references taken */
if (NULL != rs)
rds_sock_put(rs);
+ rs = NULL;
/* the original info is just a copy */
memcpy(org, dst, sizeof(struct rds_nf_hdr));
/* check the original header and if changed do the needful */
if (dst->saddr == org->saddr && dst->daddr == org->daddr &&
conn->c_trans->skb_local(skb)) {
- rds_recv_local(conn, saddr, daddr, inc, gfp);
+ rds_recv_local(conn, saddr, daddr, inc, gfp, NULL);
}
/* the send both case does both a local recv and a reroute */
else if (dst->flags & RDS_NF_HDR_FLAG_BOTH) {
rds_inc_addref(inc);
/* send it up the stream locally */
- rds_recv_local(conn, saddr, daddr, inc, gfp);
+ rds_recv_local(conn, saddr, daddr, inc, gfp, NULL);
/* and also reroute the request */
rds_recv_route(conn, inc, gfp);
/* this is a request for our local node, but potentially a different source
* either way we process it locally */
else if (conn->c_trans->skb_local(inc->i_skb)) {
- rds_recv_local(nconn, dst->saddr, dst->daddr, inc, gfp);
+ rds_recv_local(nconn, dst->saddr, dst->daddr, inc, gfp, NULL);
}
/* looks like this request is going out to another node */
else {
NF_HOOK(PF_RDS_HOOK, NF_RDS_FORWARD_ERROR, sk, inc->i_skb, NULL, NULL, rds_recv_ok);
/* then hand the request off to normal local processing on the old connection */
- rds_recv_local(inc->i_oconn, org->saddr, org->daddr, inc, gfp);
+ rds_recv_local(inc->i_oconn, org->saddr, org->daddr, inc, gfp, NULL);
}
static void
rds_recv_local(struct rds_connection *conn, __be32 saddr, __be32 daddr,
- struct rds_incoming *inc, gfp_t gfp)
+ struct rds_incoming *inc, gfp_t gfp, struct rds_sock *rs)
{
- struct rds_sock *rs = NULL;
struct sock *sk;
unsigned long flags;
u64 inc_hdr_h_sequence = 0;
+ bool rs_local = (!rs);
inc->i_conn = conn;
inc->i_rx_jiffies = jiffies;
goto out;
}
- rs = rds_find_bound(daddr, inc->i_hdr.h_dport);
+ if (!rs)
+ rs = rds_find_bound(daddr, inc->i_hdr.h_dport);
if (!rs) {
rds_stats_inc(s_recv_drop_no_sock);
goto out;
write_unlock_irqrestore(&rs->rs_recv_lock, flags);
out:
- if (rs)
+ if (rs_local && rs)
rds_sock_put(rs);
}