]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
rds: fix list corruption and tx hang when netfilter is used
authorshamir rabinovitch <shamir.rabinovitch@oracle.com>
Sun, 21 Sep 2014 21:00:59 +0000 (00:00 +0300)
committerMukesh Kacker <mukesh.kacker@oracle.com>
Wed, 8 Jul 2015 21:00:10 +0000 (14:00 -0700)
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 <shamir.rabinovitch@oracle.com>
Tested-by: jun yang <jun.yang@oracle.com>
Tested-by: denise iguma <denise.iguma@oracle.com>
Acked-by: chien yen <chien.yen@oracle.com>
Signed-off-by: Guangyu Sun <guangyu.sun@oracle.com>
(cherry picked from commit 61b5557dde8366245a58402f76d8e2d9f8a18b7d)

net/rds/recv.c
net/rds/send.c

index d2fa84bf8d81f45613c50ffbc2473a3178b50034..b103976a20903943828bbfd2fce2f96c5984217b 100644 (file)
@@ -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);
        }
index 4376e0a459b67f4b79f0ec77e8b597f0290fbaec..e339615694700fa5048bd167b9bb5e8ecda1f0fc 100644 (file)
@@ -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);