From: shamir rabinovitch Date: Sun, 21 Sep 2014 21:00:59 +0000 (+0300) Subject: rds: fix list corruption and tx hang when netfilter is used X-Git-Tag: v4.1.12-92~293^2^2~19 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=2864ecb83de9541296c309d32b4a82ca68c8e95d;p=users%2Fjedix%2Flinux-maple.git rds: fix list corruption and tx hang when netfilter is used when rds netfilter enabled the below issues can happen and this patch solve them: 1. rds socket rds-incoming list corruption. this issue happen when the below code path is executed: * rds_recv_incoming -> NF_HOOK { nf hook decide to send packet to local and to origin } -> * { send to local } -> rds_recv_local -> list_add_tail { rds-incoming is queued on the rds socket rs_recv_queue list } * { send to origin } -> rds_recv_route -> rds_recv_forward -> { rds_send_internal failed! } -> rds_recv_local -> list_add_tail { rds-incoming is queued on the rds socket rs_recv_queue list } 2. rds rx tasklet forced to tx the incoming packet and so is un able to process acks from remote and free space in the rds sendbuf: * rds_recv_incoming -> NF_HOOK { nf hook decide to send packet to origin } -> rds_recv_route -> rds_recv_forward -> rds_send_internal -> rds_send_xmit { rx tasklet now do the tx! } Orabug: 18963548 Signed-off-by: shamir rabinovitch Tested-by: jun yang Tested-by: denise iguma Acked-by: chien yen Signed-off-by: Guangyu Sun (cherry picked from commit 61b5557dde8366245a58402f76d8e2d9f8a18b7d) --- diff --git a/net/rds/recv.c b/net/rds/recv.c index d2fa84bf8d81f..b103976a20903 100644 --- a/net/rds/recv.c +++ b/net/rds/recv.c @@ -513,14 +513,26 @@ rds_recv_local(struct rds_connection *conn, __be32 saddr, __be32 daddr, /* serialize with rds_release -> sock_orphan */ write_lock_irqsave(&rs->rs_recv_lock, flags); if (!sock_flag(sk, SOCK_DEAD)) { - rdsdebug("adding inc %p to rs %p's recv queue\n", inc, rs); - rds_stats_inc(s_recv_queued); - rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong, + /* only queue the incoming once. when rds netfilter hook + * is enabled, the follow code path can cause us to send + * rds_incoming twice to rds_recv_local: rds_recv_incoming + * call NF_HOOK, hook decide to send rds incoming to both, + * local & remote, rds_recv_local queue the inc msg, + * rds_recv_forward fail to send the inc to remote & call + * rds_recv_local again with the same rds inc. calling list + * on alredy added list item w/o calling list_del_init in + * between cause list corruption */ + if (list_empty(&inc->i_item)) { + rdsdebug("adding inc %p to rs %p's recv queue\n", + inc, rs); + rds_stats_inc(s_recv_queued); + rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong, be32_to_cpu(inc->i_hdr.h_len), inc->i_hdr.h_dport); - rds_inc_addref(inc); - list_add_tail(&inc->i_item, &rs->rs_recv_queue); - __rds_wake_sk_sleep(sk); + rds_inc_addref(inc); + list_add_tail(&inc->i_item, &rs->rs_recv_queue); + __rds_wake_sk_sleep(sk); + } } else { rds_stats_inc(s_recv_drop_dead_sock); } diff --git a/net/rds/send.c b/net/rds/send.c index 4376e0a459b67..e339615694700 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1484,18 +1484,8 @@ int rds_send_internal(struct rds_connection *conn, struct rds_sock *rs, */ rds_stats_inc(s_send_queued); -/* Set this to 1 for normal testing but 0 when building the TCP version - * of the code. The TCP version has hang issues otherwise. */ -#if 1 - /* for the time being it looks like the send_xmit code may lead to a - * deadlock/hang, so we are not going to use it yet */ - ret = rds_send_xmit(conn); - if (ret == -ENOMEM || ret == -EAGAIN) - queue_delayed_work(rds_wq, &conn->c_send_w, 1); -#else /* always hand the send off to the worker thread */ queue_delayed_work(rds_wq, &conn->c_send_w, 0); -#endif rdsdebug("message sent for rs %p, conn %p, len %d, %u.%u.%u.%u : %u -> %u.%u.%u.%u : %u\n", rs, conn, skb->len, NIPQUAD(dst->saddr), dst->sport, NIPQUAD(dst->daddr), dst->dport);