]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net:Add sysctl_max_skb_frags
authorHans Westgaard Ry <hans.westgaard.ry@oracle.com>
Wed, 3 Feb 2016 08:26:57 +0000 (09:26 +0100)
committerLuis Henriques <luis.henriques@canonical.com>
Thu, 24 Mar 2016 10:00:44 +0000 (10:00 +0000)
commit 5f74f82ea34c0da80ea0b49192bb5ea06e063593 upstream.

Devices may have limits on the number of fragments in an skb they support.
Current codebase uses a constant as maximum for number of fragments one
skb can hold and use.
When enabling scatter/gather and running traffic with many small messages
the codebase uses the maximum number of fragments and may thereby violate
the max for certain devices.
The patch introduces a global variable as max number of fragments.

Signed-off-by: Hans Westgaard Ry <hans.westgaard.ry@oracle.com>
Reviewed-by: HÃ¥kon Bugge <haakon.bugge@oracle.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
[ luis: backported to 3.16: adjusted context ]
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
include/linux/skbuff.h
net/core/skbuff.c
net/core/sysctl_net_core.c
net/ipv4/tcp.c

index 010bc80be91c4b853c290805534680df657e6836..c046cb92172eba0a7b3b8f3d7dd75f5789b4f8a4 100644 (file)
@@ -169,6 +169,7 @@ struct sk_buff;
 #else
 #define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1)
 #endif
+extern int sysctl_max_skb_frags;
 
 typedef struct skb_frag_struct skb_frag_t;
 
index 7e31a99e0ed91655d2d1a7a5004ea5ad0522c139..8c540906793082c18614fdd7fc2fce878df724ef 100644 (file)
@@ -77,6 +77,8 @@
 
 struct kmem_cache *skbuff_head_cache __read_mostly;
 static struct kmem_cache *skbuff_fclone_cache __read_mostly;
+int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS;
+EXPORT_SYMBOL(sysctl_max_skb_frags);
 
 /**
  *     skb_panic - private function for out-of-line support
index e731c96eac4b44428f5efa38a094234deeceeeb7..cd386d2fd0399149d715ac6d1115e22106b3f651 100644 (file)
@@ -27,6 +27,7 @@ static int one = 1;
 static int ushort_max = USHRT_MAX;
 static int min_sndbuf = SOCK_MIN_SNDBUF;
 static int min_rcvbuf = SOCK_MIN_RCVBUF;
+static int max_skb_frags = MAX_SKB_FRAGS;
 
 #ifdef CONFIG_RPS
 static int rps_sock_flow_sysctl(struct ctl_table *table, int write,
@@ -363,6 +364,15 @@ static struct ctl_table net_core_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec
        },
+       {
+               .procname       = "max_skb_frags",
+               .data           = &sysctl_max_skb_frags,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &one,
+               .extra2         = &max_skb_frags,
+       },
        { }
 };
 
index 9c4f0d2f289286bbe88d78c91bad04294f9ba84c..9ee5a4bbb28944c231738057a28bbf5e95a8de10 100644 (file)
@@ -929,7 +929,7 @@ new_segment:
 
                i = skb_shinfo(skb)->nr_frags;
                can_coalesce = skb_can_coalesce(skb, i, page, offset);
-               if (!can_coalesce && i >= MAX_SKB_FRAGS) {
+               if (!can_coalesce && i >= sysctl_max_skb_frags) {
                        tcp_mark_push(tp, skb);
                        goto new_segment;
                }
@@ -1213,7 +1213,7 @@ new_segment:
 
                                if (!skb_can_coalesce(skb, i, pfrag->page,
                                                      pfrag->offset)) {
-                                       if (i == MAX_SKB_FRAGS || !sg) {
+                                       if (i == sysctl_max_skb_frags || !sg) {
                                                tcp_mark_push(tp, skb);
                                                goto new_segment;
                                        }