| From foo@baz Thu Jul 19 08:32:33 CEST 2018 |
| From: Doron Roberts-Kedes <doronrk@fb.com> |
| Date: Tue, 26 Jun 2018 18:33:33 -0700 |
| Subject: strparser: Remove early eaten to fix full tcp receive buffer stall |
| |
| From: Doron Roberts-Kedes <doronrk@fb.com> |
| |
| [ Upstream commit 977c7114ebda2e746a114840d3a875e0cdb826fb ] |
| |
| On receving an incomplete message, the existing code stores the |
| remaining length of the cloned skb in the early_eaten field instead of |
| incrementing the value returned by __strp_recv. This defers invocation |
| of sock_rfree for the current skb until the next invocation of |
| __strp_recv, which returns early_eaten if early_eaten is non-zero. |
| |
| This behavior causes a stall when the current message occupies the very |
| tail end of a massive skb, and strp_peek/need_bytes indicates that the |
| remainder of the current message has yet to arrive on the socket. The |
| TCP receive buffer is totally full, causing the TCP window to go to |
| zero, so the remainder of the message will never arrive. |
| |
| Incrementing the value returned by __strp_recv by the amount otherwise |
| stored in early_eaten prevents stalls of this nature. |
| |
| Signed-off-by: Doron Roberts-Kedes <doronrk@fb.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/strparser/strparser.c | 17 +---------------- |
| 1 file changed, 1 insertion(+), 16 deletions(-) |
| |
| --- a/net/strparser/strparser.c |
| +++ b/net/strparser/strparser.c |
| @@ -35,7 +35,6 @@ struct _strp_msg { |
| */ |
| struct strp_msg strp; |
| int accum_len; |
| - int early_eaten; |
| }; |
| |
| static inline struct _strp_msg *_strp_msg(struct sk_buff *skb) |
| @@ -115,20 +114,6 @@ static int __strp_recv(read_descriptor_t |
| head = strp->skb_head; |
| if (head) { |
| /* Message already in progress */ |
| - |
| - stm = _strp_msg(head); |
| - if (unlikely(stm->early_eaten)) { |
| - /* Already some number of bytes on the receive sock |
| - * data saved in skb_head, just indicate they |
| - * are consumed. |
| - */ |
| - eaten = orig_len <= stm->early_eaten ? |
| - orig_len : stm->early_eaten; |
| - stm->early_eaten -= eaten; |
| - |
| - return eaten; |
| - } |
| - |
| if (unlikely(orig_offset)) { |
| /* Getting data with a non-zero offset when a message is |
| * in progress is not expected. If it does happen, we |
| @@ -297,9 +282,9 @@ static int __strp_recv(read_descriptor_t |
| } |
| |
| stm->accum_len += cand_len; |
| + eaten += cand_len; |
| strp->need_bytes = stm->strp.full_len - |
| stm->accum_len; |
| - stm->early_eaten = cand_len; |
| STRP_STATS_ADD(strp->stats.bytes, cand_len); |
| desc->count = 0; /* Stop reading socket */ |
| break; |