summaryrefslogtreecommitdiffstats
path: root/net/strparser
diff options
context:
space:
mode:
authorDoron Roberts-Kedes <doronrk@fb.com>2018-06-26 21:33:33 -0400
committerDavid S. Miller <davem@davemloft.net>2018-06-28 08:37:26 -0400
commit977c7114ebda2e746a114840d3a875e0cdb826fb (patch)
tree68e42d70c25e7ee758a2b5bf7d4231fa4aa7fc8d /net/strparser
parent04c6faa17558b1c044524e24d86adf1400f2017f (diff)
strparser: Remove early eaten to fix full tcp receive buffer stall
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>
Diffstat (limited to 'net/strparser')
-rw-r--r--net/strparser/strparser.c17
1 files changed, 1 insertions, 16 deletions
diff --git a/net/strparser/strparser.c b/net/strparser/strparser.c
index 373836615c57..625acb27efcc 100644
--- a/net/strparser/strparser.c
+++ b/net/strparser/strparser.c
@@ -35,7 +35,6 @@ struct _strp_msg {
35 */ 35 */
36 struct strp_msg strp; 36 struct strp_msg strp;
37 int accum_len; 37 int accum_len;
38 int early_eaten;
39}; 38};
40 39
41static inline struct _strp_msg *_strp_msg(struct sk_buff *skb) 40static inline struct _strp_msg *_strp_msg(struct sk_buff *skb)
@@ -115,20 +114,6 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
115 head = strp->skb_head; 114 head = strp->skb_head;
116 if (head) { 115 if (head) {
117 /* Message already in progress */ 116 /* Message already in progress */
118
119 stm = _strp_msg(head);
120 if (unlikely(stm->early_eaten)) {
121 /* Already some number of bytes on the receive sock
122 * data saved in skb_head, just indicate they
123 * are consumed.
124 */
125 eaten = orig_len <= stm->early_eaten ?
126 orig_len : stm->early_eaten;
127 stm->early_eaten -= eaten;
128
129 return eaten;
130 }
131
132 if (unlikely(orig_offset)) { 117 if (unlikely(orig_offset)) {
133 /* Getting data with a non-zero offset when a message is 118 /* Getting data with a non-zero offset when a message is
134 * in progress is not expected. If it does happen, we 119 * in progress is not expected. If it does happen, we
@@ -297,9 +282,9 @@ static int __strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
297 } 282 }
298 283
299 stm->accum_len += cand_len; 284 stm->accum_len += cand_len;
285 eaten += cand_len;
300 strp->need_bytes = stm->strp.full_len - 286 strp->need_bytes = stm->strp.full_len -
301 stm->accum_len; 287 stm->accum_len;
302 stm->early_eaten = cand_len;
303 STRP_STATS_ADD(strp->stats.bytes, cand_len); 288 STRP_STATS_ADD(strp->stats.bytes, cand_len);
304 desc->count = 0; /* Stop reading socket */ 289 desc->count = 0; /* Stop reading socket */
305 break; 290 break;