Skip to content

Commit 15e36f5

Browse files
wdebruijdavem330
authored andcommitted
udp: paged allocation with gso
When sending large datagrams that are later segmented, store data in page frags to avoid copying from linear in skb_segment. Signed-off-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent ad40585 commit 15e36f5

File tree

2 files changed

+25
-9
lines changed

2 files changed

+25
-9
lines changed

net/ipv4/ip_output.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -878,11 +878,13 @@ static int __ip_append_data(struct sock *sk,
878878
struct rtable *rt = (struct rtable *)cork->dst;
879879
unsigned int wmem_alloc_delta = 0;
880880
u32 tskey = 0;
881+
bool paged;
881882

882883
skb = skb_peek_tail(queue);
883884

884885
exthdrlen = !skb ? rt->dst.header_len : 0;
885886
mtu = cork->gso_size ? IP_MAX_MTU : cork->fragsize;
887+
paged = !!cork->gso_size;
886888

887889
if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP &&
888890
sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)
@@ -934,6 +936,7 @@ static int __ip_append_data(struct sock *sk,
934936
unsigned int fraglen;
935937
unsigned int fraggap;
936938
unsigned int alloclen;
939+
unsigned int pagedlen = 0;
937940
struct sk_buff *skb_prev;
938941
alloc_new_skb:
939942
skb_prev = skb;
@@ -954,8 +957,12 @@ static int __ip_append_data(struct sock *sk,
954957
if ((flags & MSG_MORE) &&
955958
!(rt->dst.dev->features&NETIF_F_SG))
956959
alloclen = mtu;
957-
else
960+
else if (!paged)
958961
alloclen = fraglen;
962+
else {
963+
alloclen = min_t(int, fraglen, MAX_HEADER);
964+
pagedlen = fraglen - alloclen;
965+
}
959966

960967
alloclen += exthdrlen;
961968

@@ -999,7 +1006,7 @@ static int __ip_append_data(struct sock *sk,
9991006
/*
10001007
* Find where to start putting bytes.
10011008
*/
1002-
data = skb_put(skb, fraglen + exthdrlen);
1009+
data = skb_put(skb, fraglen + exthdrlen - pagedlen);
10031010
skb_set_network_header(skb, exthdrlen);
10041011
skb->transport_header = (skb->network_header +
10051012
fragheaderlen);
@@ -1015,15 +1022,15 @@ static int __ip_append_data(struct sock *sk,
10151022
pskb_trim_unique(skb_prev, maxfraglen);
10161023
}
10171024

1018-
copy = datalen - transhdrlen - fraggap;
1025+
copy = datalen - transhdrlen - fraggap - pagedlen;
10191026
if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) {
10201027
err = -EFAULT;
10211028
kfree_skb(skb);
10221029
goto error;
10231030
}
10241031

10251032
offset += copy;
1026-
length -= datalen - fraggap;
1033+
length -= copy + transhdrlen;
10271034
transhdrlen = 0;
10281035
exthdrlen = 0;
10291036
csummode = CHECKSUM_NONE;

net/ipv6/ip6_output.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,13 +1276,15 @@ static int __ip6_append_data(struct sock *sk,
12761276
int csummode = CHECKSUM_NONE;
12771277
unsigned int maxnonfragsize, headersize;
12781278
unsigned int wmem_alloc_delta = 0;
1279+
bool paged;
12791280

12801281
skb = skb_peek_tail(queue);
12811282
if (!skb) {
12821283
exthdrlen = opt ? opt->opt_flen : 0;
12831284
dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len;
12841285
}
12851286

1287+
paged = !!cork->gso_size;
12861288
mtu = cork->gso_size ? IP6_MAX_MTU : cork->fragsize;
12871289
orig_mtu = mtu;
12881290

@@ -1374,6 +1376,7 @@ static int __ip6_append_data(struct sock *sk,
13741376
unsigned int fraglen;
13751377
unsigned int fraggap;
13761378
unsigned int alloclen;
1379+
unsigned int pagedlen = 0;
13771380
alloc_new_skb:
13781381
/* There's no room in the current skb */
13791382
if (skb)
@@ -1396,11 +1399,17 @@ static int __ip6_append_data(struct sock *sk,
13961399

13971400
if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen)
13981401
datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len;
1402+
fraglen = datalen + fragheaderlen;
1403+
13991404
if ((flags & MSG_MORE) &&
14001405
!(rt->dst.dev->features&NETIF_F_SG))
14011406
alloclen = mtu;
1402-
else
1403-
alloclen = datalen + fragheaderlen;
1407+
else if (!paged)
1408+
alloclen = fraglen;
1409+
else {
1410+
alloclen = min_t(int, fraglen, MAX_HEADER);
1411+
pagedlen = fraglen - alloclen;
1412+
}
14041413

14051414
alloclen += dst_exthdrlen;
14061415

@@ -1422,7 +1431,7 @@ static int __ip6_append_data(struct sock *sk,
14221431
*/
14231432
alloclen += sizeof(struct frag_hdr);
14241433

1425-
copy = datalen - transhdrlen - fraggap;
1434+
copy = datalen - transhdrlen - fraggap - pagedlen;
14261435
if (copy < 0) {
14271436
err = -EINVAL;
14281437
goto error;
@@ -1461,7 +1470,7 @@ static int __ip6_append_data(struct sock *sk,
14611470
/*
14621471
* Find where to start putting bytes
14631472
*/
1464-
data = skb_put(skb, fraglen);
1473+
data = skb_put(skb, fraglen - pagedlen);
14651474
skb_set_network_header(skb, exthdrlen);
14661475
data += fragheaderlen;
14671476
skb->transport_header = (skb->network_header +
@@ -1484,7 +1493,7 @@ static int __ip6_append_data(struct sock *sk,
14841493
}
14851494

14861495
offset += copy;
1487-
length -= datalen - fraggap;
1496+
length -= copy + transhdrlen;
14881497
transhdrlen = 0;
14891498
exthdrlen = 0;
14901499
dst_exthdrlen = 0;

0 commit comments

Comments
 (0)