diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2012-11-16 00:31:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-11-16 13:36:27 -0500 |
commit | 976a702ac9eeacea09e588456ab165dc06f9ee83 (patch) | |
tree | c7373df6e09bc8b43c2000f4de940b0573e888ea /net | |
parent | 6fc4adca6ce3e1d57a42707019dddcb883578a91 (diff) |
tcp: handle tcp_net_metrics_init() order-5 memory allocation failures
order-5 allocations can fail with current kernels, we should
try vmalloc() as well.
Reported-by: Julien Tinnes <jln@google.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/tcp_metrics.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 53bc5847bfa8..f696d7c2e9fa 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c | |||
@@ -1,7 +1,6 @@ | |||
1 | #include <linux/rcupdate.h> | 1 | #include <linux/rcupdate.h> |
2 | #include <linux/spinlock.h> | 2 | #include <linux/spinlock.h> |
3 | #include <linux/jiffies.h> | 3 | #include <linux/jiffies.h> |
4 | #include <linux/bootmem.h> | ||
5 | #include <linux/module.h> | 4 | #include <linux/module.h> |
6 | #include <linux/cache.h> | 5 | #include <linux/cache.h> |
7 | #include <linux/slab.h> | 6 | #include <linux/slab.h> |
@@ -9,6 +8,7 @@ | |||
9 | #include <linux/tcp.h> | 8 | #include <linux/tcp.h> |
10 | #include <linux/hash.h> | 9 | #include <linux/hash.h> |
11 | #include <linux/tcp_metrics.h> | 10 | #include <linux/tcp_metrics.h> |
11 | #include <linux/vmalloc.h> | ||
12 | 12 | ||
13 | #include <net/inet_connection_sock.h> | 13 | #include <net/inet_connection_sock.h> |
14 | #include <net/net_namespace.h> | 14 | #include <net/net_namespace.h> |
@@ -1034,7 +1034,10 @@ static int __net_init tcp_net_metrics_init(struct net *net) | |||
1034 | net->ipv4.tcp_metrics_hash_log = order_base_2(slots); | 1034 | net->ipv4.tcp_metrics_hash_log = order_base_2(slots); |
1035 | size = sizeof(struct tcpm_hash_bucket) << net->ipv4.tcp_metrics_hash_log; | 1035 | size = sizeof(struct tcpm_hash_bucket) << net->ipv4.tcp_metrics_hash_log; |
1036 | 1036 | ||
1037 | net->ipv4.tcp_metrics_hash = kzalloc(size, GFP_KERNEL); | 1037 | net->ipv4.tcp_metrics_hash = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); |
1038 | if (!net->ipv4.tcp_metrics_hash) | ||
1039 | net->ipv4.tcp_metrics_hash = vzalloc(size); | ||
1040 | |||
1038 | if (!net->ipv4.tcp_metrics_hash) | 1041 | if (!net->ipv4.tcp_metrics_hash) |
1039 | return -ENOMEM; | 1042 | return -ENOMEM; |
1040 | 1043 | ||
@@ -1055,7 +1058,10 @@ static void __net_exit tcp_net_metrics_exit(struct net *net) | |||
1055 | tm = next; | 1058 | tm = next; |
1056 | } | 1059 | } |
1057 | } | 1060 | } |
1058 | kfree(net->ipv4.tcp_metrics_hash); | 1061 | if (is_vmalloc_addr(net->ipv4.tcp_metrics_hash)) |
1062 | vfree(net->ipv4.tcp_metrics_hash); | ||
1063 | else | ||
1064 | kfree(net->ipv4.tcp_metrics_hash); | ||
1059 | } | 1065 | } |
1060 | 1066 | ||
1061 | static __net_initdata struct pernet_operations tcp_net_metrics_ops = { | 1067 | static __net_initdata struct pernet_operations tcp_net_metrics_ops = { |