aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/inqueue.c
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>2016-06-02 14:05:42 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-03 19:37:21 -0400
commit3acb50c18d8d6650f10919464ade4dcdaf41d62f (patch)
tree174b8c7ef21aaa3e2cddecd81a286976649bd6af /net/sctp/inqueue.c
parentae7ef81ef000adeee7a87585b9135ff8a8064acc (diff)
sctp: delay as much as possible skb_linearize
This patch is a preparation for the GSO one. In order to successfully handle GSO packets on rx path we must not call skb_linearize, otherwise it defeats any gain GSO may have had. This patch thus delays as much as possible the call to skb_linearize, leaving it to sctp_inq_pop() moment. For that the sanity checks performed now know how to deal with fragments. One positive side-effect of this is that if the socket is backlogged it will have the chance of doing it on backlog processing instead of during softirq. With this move, it's evident that a check for non-linearity in sctp_inq_pop was ineffective and is now removed. Note that a similar check is performed a bit below this one. Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Tested-by: Xin Long <lucien.xin@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/inqueue.c')
-rw-r--r--net/sctp/inqueue.c29
1 files changed, 18 insertions, 11 deletions
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index 9d87bba0ff1d..5ba08ceda3ab 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -130,7 +130,8 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
130 * at this time. 130 * at this time.
131 */ 131 */
132 132
133 if ((chunk = queue->in_progress)) { 133 chunk = queue->in_progress;
134 if (chunk) {
134 /* There is a packet that we have been working on. 135 /* There is a packet that we have been working on.
135 * Any post processing work to do before we move on? 136 * Any post processing work to do before we move on?
136 */ 137 */
@@ -152,15 +153,29 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
152 if (!chunk) { 153 if (!chunk) {
153 struct list_head *entry; 154 struct list_head *entry;
154 155
156next_chunk:
155 /* Is the queue empty? */ 157 /* Is the queue empty? */
156 if (list_empty(&queue->in_chunk_list)) 158 if (list_empty(&queue->in_chunk_list))
157 return NULL; 159 return NULL;
158 160
159 entry = queue->in_chunk_list.next; 161 entry = queue->in_chunk_list.next;
160 chunk = queue->in_progress = 162 chunk = list_entry(entry, struct sctp_chunk, list);
161 list_entry(entry, struct sctp_chunk, list);
162 list_del_init(entry); 163 list_del_init(entry);
163 164
165 /* Linearize if it's not GSO */
166 if (skb_is_nonlinear(chunk->skb)) {
167 if (skb_linearize(chunk->skb)) {
168 __SCTP_INC_STATS(dev_net(chunk->skb->dev), SCTP_MIB_IN_PKT_DISCARDS);
169 sctp_chunk_free(chunk);
170 goto next_chunk;
171 }
172
173 /* Update sctp_hdr as it probably changed */
174 chunk->sctp_hdr = sctp_hdr(chunk->skb);
175 }
176
177 queue->in_progress = chunk;
178
164 /* This is the first chunk in the packet. */ 179 /* This is the first chunk in the packet. */
165 chunk->singleton = 1; 180 chunk->singleton = 1;
166 ch = (sctp_chunkhdr_t *) chunk->skb->data; 181 ch = (sctp_chunkhdr_t *) chunk->skb->data;
@@ -172,14 +187,6 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
172 187
173 chunk->chunk_hdr = ch; 188 chunk->chunk_hdr = ch;
174 chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length)); 189 chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
175 /* In the unlikely case of an IP reassembly, the skb could be
176 * non-linear. If so, update chunk_end so that it doesn't go past
177 * the skb->tail.
178 */
179 if (unlikely(skb_is_nonlinear(chunk->skb))) {
180 if (chunk->chunk_end > skb_tail_pointer(chunk->skb))
181 chunk->chunk_end = skb_tail_pointer(chunk->skb);
182 }
183 skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); 190 skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
184 chunk->subh.v = NULL; /* Subheader is no longer valid. */ 191 chunk->subh.v = NULL; /* Subheader is no longer valid. */
185 192