Blame view

net/core/request_sock.c 3.52 KB
0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  /*
   * NET		Generic infrastructure for Network protocols.
   *
   * Authors:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
   *
   * 		From code originally in include/net/tcp.h
   *
   *		This program is free software; you can redistribute it and/or
   *		modify it under the terms of the GNU General Public License
   *		as published by the Free Software Foundation; either version
   *		2 of the License, or (at your option) any later version.
   */
  
  #include <linux/module.h>
  #include <linux/random.h>
  #include <linux/slab.h>
  #include <linux/string.h>
72a3effaf   Eric Dumazet   [NET]: Size liste...
18
  #include <linux/vmalloc.h>
0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
19
20
  
  #include <net/request_sock.h>
e52c1f17e   David S. Miller   [NET]: Move sysct...
21
22
23
24
25
26
27
  /*
   * Maximum number of SYN_RECV sockets in queue per LISTEN socket.
   * One SYN_RECV socket costs about 80bytes on a 32bit machine.
   * It would be better to replace it with a global counter for all sockets
   * but then some measure against one socket starving all other sockets
   * would be needed.
   *
99b53bdd8   Peter Pan(潘卫平)   ipv4:correct desc...
28
   * The minimum value of it is 128. Experiments with real servers show that
e52c1f17e   David S. Miller   [NET]: Move sysct...
29
   * it is absolutely not enough even at 100conn/sec. 256 cures most
99b53bdd8   Peter Pan(潘卫平)   ipv4:correct desc...
30
31
32
   * of problems.
   * This value is adjusted to 128 for low memory machines,
   * and it will increase in proportion to the memory of machine.
72a3effaf   Eric Dumazet   [NET]: Size liste...
33
   * Note : Dont forget somaxconn that may limit backlog too.
e52c1f17e   David S. Miller   [NET]: Move sysct...
34
35
   */
  int sysctl_max_syn_backlog = 256;
493f377d6   David S. Miller   tcp: Add timewait...
36
  EXPORT_SYMBOL(sysctl_max_syn_backlog);
e52c1f17e   David S. Miller   [NET]: Move sysct...
37

0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
38
  int reqsk_queue_alloc(struct request_sock_queue *queue,
72a3effaf   Eric Dumazet   [NET]: Size liste...
39
  		      unsigned int nr_table_entries)
0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
40
  {
72a3effaf   Eric Dumazet   [NET]: Size liste...
41
42
43
44
45
46
47
48
  	size_t lopt_size = sizeof(struct listen_sock);
  	struct listen_sock *lopt;
  
  	nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog);
  	nr_table_entries = max_t(u32, nr_table_entries, 8);
  	nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);
  	lopt_size += nr_table_entries * sizeof(struct request_sock *);
  	if (lopt_size > PAGE_SIZE)
7a1c8e5ab   Eric Dumazet   net: allow GFP_HI...
49
  		lopt = vzalloc(lopt_size);
72a3effaf   Eric Dumazet   [NET]: Size liste...
50
51
  	else
  		lopt = kzalloc(lopt_size, GFP_KERNEL);
0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
52
53
  	if (lopt == NULL)
  		return -ENOMEM;
72a3effaf   Eric Dumazet   [NET]: Size liste...
54
55
  	for (lopt->max_qlen_log = 3;
  	     (1 << lopt->max_qlen_log) < nr_table_entries;
0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
56
57
58
59
  	     lopt->max_qlen_log++);
  
  	get_random_bytes(&lopt->hash_rnd, sizeof(lopt->hash_rnd));
  	rwlock_init(&queue->syn_wait_lock);
3eb4801d7   Norbert Kiesel   [NET]: drop dupli...
60
  	queue->rskq_accept_head = NULL;
83e3609eb   Arnaldo Carvalho de Melo   [REQSK]: Move the...
61
  	lopt->nr_table_entries = nr_table_entries;
0e87506fc   Arnaldo Carvalho de Melo   [NET] Generalise ...
62
63
64
65
66
67
68
  
  	write_lock_bh(&queue->syn_wait_lock);
  	queue->listen_opt = lopt;
  	write_unlock_bh(&queue->syn_wait_lock);
  
  	return 0;
  }
dab6ba368   Pavel Emelyanov   [INET]: Fix poten...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  void __reqsk_queue_destroy(struct request_sock_queue *queue)
  {
  	struct listen_sock *lopt;
  	size_t lopt_size;
  
  	/*
  	 * this is an error recovery path only
  	 * no locking needed and the lopt is not NULL
  	 */
  
  	lopt = queue->listen_opt;
  	lopt_size = sizeof(struct listen_sock) +
  		lopt->nr_table_entries * sizeof(struct request_sock *);
  
  	if (lopt_size > PAGE_SIZE)
  		vfree(lopt);
  	else
  		kfree(lopt);
  }
dab6ba368   Pavel Emelyanov   [INET]: Fix poten...
88
89
90
91
92
93
94
95
96
97
98
99
  static inline struct listen_sock *reqsk_queue_yank_listen_sk(
  		struct request_sock_queue *queue)
  {
  	struct listen_sock *lopt;
  
  	write_lock_bh(&queue->syn_wait_lock);
  	lopt = queue->listen_opt;
  	queue->listen_opt = NULL;
  	write_unlock_bh(&queue->syn_wait_lock);
  
  	return lopt;
  }
83e3609eb   Arnaldo Carvalho de Melo   [REQSK]: Move the...
100
101
102
103
  void reqsk_queue_destroy(struct request_sock_queue *queue)
  {
  	/* make all the listen_opt local to us */
  	struct listen_sock *lopt = reqsk_queue_yank_listen_sk(queue);
72a3effaf   Eric Dumazet   [NET]: Size liste...
104
105
  	size_t lopt_size = sizeof(struct listen_sock) +
  		lopt->nr_table_entries * sizeof(struct request_sock *);
83e3609eb   Arnaldo Carvalho de Melo   [REQSK]: Move the...
106
107
  
  	if (lopt->qlen != 0) {
72a3effaf   Eric Dumazet   [NET]: Size liste...
108
  		unsigned int i;
83e3609eb   Arnaldo Carvalho de Melo   [REQSK]: Move the...
109
110
111
112
113
114
115
116
117
118
119
  
  		for (i = 0; i < lopt->nr_table_entries; i++) {
  			struct request_sock *req;
  
  			while ((req = lopt->syn_table[i]) != NULL) {
  				lopt->syn_table[i] = req->dl_next;
  				lopt->qlen--;
  				reqsk_free(req);
  			}
  		}
  	}
547b792ca   Ilpo Järvinen   net: convert BUG_...
120
  	WARN_ON(lopt->qlen != 0);
72a3effaf   Eric Dumazet   [NET]: Size liste...
121
122
123
124
  	if (lopt_size > PAGE_SIZE)
  		vfree(lopt);
  	else
  		kfree(lopt);
83e3609eb   Arnaldo Carvalho de Melo   [REQSK]: Move the...
125
  }