aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/inet_common.h1
-rw-r--r--include/net/ipv6.h1
-rw-r--r--include/net/sock.h32
-rw-r--r--include/net/tcp.h2
-rw-r--r--net/core/sock.c6
-rw-r--r--net/ipv4/af_inet.c18
-rw-r--r--net/ipv4/tcp.c7
-rw-r--r--net/ipv4/tcp_minisocks.c20
-rw-r--r--net/ipv6/af_inet6.c31
-rw-r--r--net/ipv6/ipv6_sockglue.c15
-rw-r--r--net/ipv6/tcp_ipv6.c18
-rw-r--r--net/sctp/ipv6.c5
-rw-r--r--net/sctp/protocol.c4
13 files changed, 86 insertions, 74 deletions
diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index fbc1f4d140d8..1fbd94d8a316 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -29,7 +29,6 @@ extern unsigned int inet_poll(struct file * file, struct socket *sock, struct p
29extern int inet_listen(struct socket *sock, int backlog); 29extern int inet_listen(struct socket *sock, int backlog);
30 30
31extern void inet_sock_destruct(struct sock *sk); 31extern void inet_sock_destruct(struct sock *sk);
32extern atomic_t inet_sock_nr;
33 32
34extern int inet_bind(struct socket *sock, 33extern int inet_bind(struct socket *sock,
35 struct sockaddr *uaddr, int addr_len); 34 struct sockaddr *uaddr, int addr_len);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 533fc074ed90..c5a02ddc594a 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -145,7 +145,6 @@ DECLARE_SNMP_STAT(struct udp_mib, udp_stats_in6);
145#define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field) 145#define UDP6_INC_STATS(field) SNMP_INC_STATS(udp_stats_in6, field)
146#define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field) 146#define UDP6_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_stats_in6, field)
147#define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field) 147#define UDP6_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_stats_in6, field)
148extern atomic_t inet6_sock_nr;
149 148
150int snmp6_register_dev(struct inet6_dev *idev); 149int snmp6_register_dev(struct inet6_dev *idev);
151int snmp6_unregister_dev(struct inet6_dev *idev); 150int snmp6_unregister_dev(struct inet6_dev *idev);
diff --git a/include/net/sock.h b/include/net/sock.h
index e9b1dbab90d0..11b81551041e 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -491,6 +491,9 @@ extern int sk_wait_data(struct sock *sk, long *timeo);
491 491
492struct request_sock_ops; 492struct request_sock_ops;
493 493
494/* Here is the right place to enable sock refcounting debugging */
495#define SOCK_REFCNT_DEBUG
496
494/* Networking protocol blocks we attach to sockets. 497/* Networking protocol blocks we attach to sockets.
495 * socket layer -> transport layer interface 498 * socket layer -> transport layer interface
496 * transport -> network interface is defined by struct inet_proto 499 * transport -> network interface is defined by struct inet_proto
@@ -561,7 +564,9 @@ struct proto {
561 char name[32]; 564 char name[32];
562 565
563 struct list_head node; 566 struct list_head node;
564 567#ifdef SOCK_REFCNT_DEBUG
568 atomic_t socks;
569#endif
565 struct { 570 struct {
566 int inuse; 571 int inuse;
567 u8 __pad[SMP_CACHE_BYTES - sizeof(int)]; 572 u8 __pad[SMP_CACHE_BYTES - sizeof(int)];
@@ -571,6 +576,31 @@ struct proto {
571extern int proto_register(struct proto *prot, int alloc_slab); 576extern int proto_register(struct proto *prot, int alloc_slab);
572extern void proto_unregister(struct proto *prot); 577extern void proto_unregister(struct proto *prot);
573 578
579#ifdef SOCK_REFCNT_DEBUG
580static inline void sk_refcnt_debug_inc(struct sock *sk)
581{
582 atomic_inc(&sk->sk_prot->socks);
583}
584
585static inline void sk_refcnt_debug_dec(struct sock *sk)
586{
587 atomic_dec(&sk->sk_prot->socks);
588 printk(KERN_DEBUG "%s socket %p released, %d are still alive\n",
589 sk->sk_prot->name, sk, atomic_read(&sk->sk_prot->socks));
590}
591
592static inline void sk_refcnt_debug_release(const struct sock *sk)
593{
594 if (atomic_read(&sk->sk_refcnt) != 1)
595 printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n",
596 sk->sk_prot->name, sk, atomic_read(&sk->sk_refcnt));
597}
598#else /* SOCK_REFCNT_DEBUG */
599#define sk_refcnt_debug_inc(sk) do { } while (0)
600#define sk_refcnt_debug_dec(sk) do { } while (0)
601#define sk_refcnt_debug_release(sk) do { } while (0)
602#endif /* SOCK_REFCNT_DEBUG */
603
574/* Called with local bh disabled */ 604/* Called with local bh disabled */
575static __inline__ void sock_prot_inc_use(struct proto *prot) 605static __inline__ void sock_prot_inc_use(struct proto *prot)
576{ 606{
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 5010f0c5a56e..31984733777b 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -306,7 +306,7 @@ extern kmem_cache_t *tcp_timewait_cachep;
306static inline void tcp_tw_put(struct tcp_tw_bucket *tw) 306static inline void tcp_tw_put(struct tcp_tw_bucket *tw)
307{ 307{
308 if (atomic_dec_and_test(&tw->tw_refcnt)) { 308 if (atomic_dec_and_test(&tw->tw_refcnt)) {
309#ifdef INET_REFCNT_DEBUG 309#ifdef SOCK_REFCNT_DEBUG
310 printk(KERN_DEBUG "tw_bucket %p released\n", tw); 310 printk(KERN_DEBUG "tw_bucket %p released\n", tw);
311#endif 311#endif
312 kmem_cache_free(tcp_timewait_cachep, tw); 312 kmem_cache_free(tcp_timewait_cachep, tw);
diff --git a/net/core/sock.c b/net/core/sock.c
index 51a5e7ddee85..a1a23be10aa3 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -1367,11 +1367,7 @@ void sk_common_release(struct sock *sk)
1367 1367
1368 xfrm_sk_free_policy(sk); 1368 xfrm_sk_free_policy(sk);
1369 1369
1370#ifdef INET_REFCNT_DEBUG 1370 sk_refcnt_debug_release(sk);
1371 if (atomic_read(&sk->sk_refcnt) != 1)
1372 printk(KERN_DEBUG "Destruction of the socket %p delayed, c=%d\n",
1373 sk, atomic_read(&sk->sk_refcnt));
1374#endif
1375 sock_put(sk); 1371 sock_put(sk);
1376} 1372}
1377 1373
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 163ae4068b5f..9e83d7773d8f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -114,10 +114,6 @@
114 114
115DEFINE_SNMP_STAT(struct linux_mib, net_statistics); 115DEFINE_SNMP_STAT(struct linux_mib, net_statistics);
116 116
117#ifdef INET_REFCNT_DEBUG
118atomic_t inet_sock_nr;
119#endif
120
121extern void ip_mc_drop_socket(struct sock *sk); 117extern void ip_mc_drop_socket(struct sock *sk);
122 118
123/* The inetsw table contains everything that inet_create needs to 119/* The inetsw table contains everything that inet_create needs to
@@ -153,11 +149,7 @@ void inet_sock_destruct(struct sock *sk)
153 if (inet->opt) 149 if (inet->opt)
154 kfree(inet->opt); 150 kfree(inet->opt);
155 dst_release(sk->sk_dst_cache); 151 dst_release(sk->sk_dst_cache);
156#ifdef INET_REFCNT_DEBUG 152 sk_refcnt_debug_dec(sk);
157 atomic_dec(&inet_sock_nr);
158 printk(KERN_DEBUG "INET socket %p released, %d are still alive\n",
159 sk, atomic_read(&inet_sock_nr));
160#endif
161} 153}
162 154
163/* 155/*
@@ -317,9 +309,7 @@ static int inet_create(struct socket *sock, int protocol)
317 inet->mc_index = 0; 309 inet->mc_index = 0;
318 inet->mc_list = NULL; 310 inet->mc_list = NULL;
319 311
320#ifdef INET_REFCNT_DEBUG 312 sk_refcnt_debug_inc(sk);
321 atomic_inc(&inet_sock_nr);
322#endif
323 313
324 if (inet->num) { 314 if (inet->num) {
325 /* It assumes that any protocol which allows 315 /* It assumes that any protocol which allows
@@ -1205,7 +1195,3 @@ EXPORT_SYMBOL(inet_stream_ops);
1205EXPORT_SYMBOL(inet_unregister_protosw); 1195EXPORT_SYMBOL(inet_unregister_protosw);
1206EXPORT_SYMBOL(net_statistics); 1196EXPORT_SYMBOL(net_statistics);
1207EXPORT_SYMBOL(sysctl_ip_nonlocal_bind); 1197EXPORT_SYMBOL(sysctl_ip_nonlocal_bind);
1208
1209#ifdef INET_REFCNT_DEBUG
1210EXPORT_SYMBOL(inet_sock_nr);
1211#endif
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 42a2e2ccd430..20159a3dafb3 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -1580,12 +1580,7 @@ void tcp_destroy_sock(struct sock *sk)
1580 1580
1581 xfrm_sk_free_policy(sk); 1581 xfrm_sk_free_policy(sk);
1582 1582
1583#ifdef INET_REFCNT_DEBUG 1583 sk_refcnt_debug_release(sk);
1584 if (atomic_read(&sk->sk_refcnt) != 1) {
1585 printk(KERN_DEBUG "Destruction TCP %p delayed, c=%d\n",
1586 sk, atomic_read(&sk->sk_refcnt));
1587 }
1588#endif
1589 1584
1590 atomic_dec(&tcp_orphan_count); 1585 atomic_dec(&tcp_orphan_count);
1591 sock_put(sk); 1586 sock_put(sk);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index f42a284164b7..f8e288c8d693 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -84,7 +84,7 @@ static void tcp_timewait_kill(struct tcp_tw_bucket *tw)
84 tcp_bucket_destroy(tb); 84 tcp_bucket_destroy(tb);
85 spin_unlock(&bhead->lock); 85 spin_unlock(&bhead->lock);
86 86
87#ifdef INET_REFCNT_DEBUG 87#ifdef SOCK_REFCNT_DEBUG
88 if (atomic_read(&tw->tw_refcnt) != 1) { 88 if (atomic_read(&tw->tw_refcnt) != 1) {
89 printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, 89 printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw,
90 atomic_read(&tw->tw_refcnt)); 90 atomic_read(&tw->tw_refcnt));
@@ -799,9 +799,21 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
799 newsk->sk_err = 0; 799 newsk->sk_err = 0;
800 newsk->sk_priority = 0; 800 newsk->sk_priority = 0;
801 atomic_set(&newsk->sk_refcnt, 2); 801 atomic_set(&newsk->sk_refcnt, 2);
802#ifdef INET_REFCNT_DEBUG 802
803 atomic_inc(&inet_sock_nr); 803 /*
804#endif 804 * Increment the counter in the same struct proto as the master
805 * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that
806 * is the same as sk->sk_prot->socks, as this field was copied
807 * with memcpy), same rationale as the first comment in this
808 * function.
809 *
810 * This _changes_ the previous behaviour, where
811 * tcp_create_openreq_child always was incrementing the
812 * equivalent to tcp_prot->socks (inet_sock_nr), so this have
813 * to be taken into account in all callers. -acme
814 */
815 sk_refcnt_debug_inc(newsk);
816
805 atomic_inc(&tcp_sockets_allocated); 817 atomic_inc(&tcp_sockets_allocated);
806 818
807 if (sock_flag(newsk, SOCK_KEEPOPEN)) 819 if (sock_flag(newsk, SOCK_KEEPOPEN))
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 574047353628..7df2ccb380d9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -86,26 +86,12 @@ extern void if6_proc_exit(void);
86 86
87int sysctl_ipv6_bindv6only; 87int sysctl_ipv6_bindv6only;
88 88
89#ifdef INET_REFCNT_DEBUG
90atomic_t inet6_sock_nr;
91EXPORT_SYMBOL(inet6_sock_nr);
92#endif
93
94/* The inetsw table contains everything that inet_create needs to 89/* The inetsw table contains everything that inet_create needs to
95 * build a new socket. 90 * build a new socket.
96 */ 91 */
97static struct list_head inetsw6[SOCK_MAX]; 92static struct list_head inetsw6[SOCK_MAX];
98static DEFINE_SPINLOCK(inetsw6_lock); 93static DEFINE_SPINLOCK(inetsw6_lock);
99 94
100static void inet6_sock_destruct(struct sock *sk)
101{
102 inet_sock_destruct(sk);
103
104#ifdef INET_REFCNT_DEBUG
105 atomic_dec(&inet6_sock_nr);
106#endif
107}
108
109static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) 95static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
110{ 96{
111 const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo); 97 const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo);
@@ -186,7 +172,7 @@ static int inet6_create(struct socket *sock, int protocol)
186 inet->hdrincl = 1; 172 inet->hdrincl = 1;
187 } 173 }
188 174
189 sk->sk_destruct = inet6_sock_destruct; 175 sk->sk_destruct = inet_sock_destruct;
190 sk->sk_family = PF_INET6; 176 sk->sk_family = PF_INET6;
191 sk->sk_protocol = protocol; 177 sk->sk_protocol = protocol;
192 178
@@ -213,12 +199,17 @@ static int inet6_create(struct socket *sock, int protocol)
213 inet->pmtudisc = IP_PMTUDISC_DONT; 199 inet->pmtudisc = IP_PMTUDISC_DONT;
214 else 200 else
215 inet->pmtudisc = IP_PMTUDISC_WANT; 201 inet->pmtudisc = IP_PMTUDISC_WANT;
202 /*
203 * Increment only the relevant sk_prot->socks debug field, this changes
204 * the previous behaviour of incrementing both the equivalent to
205 * answer->prot->socks (inet6_sock_nr) and inet_sock_nr.
206 *
207 * This allows better debug granularity as we'll know exactly how many
208 * UDPv6, TCPv6, etc socks were allocated, not the sum of all IPv6
209 * transport protocol socks. -acme
210 */
211 sk_refcnt_debug_inc(sk);
216 212
217
218#ifdef INET_REFCNT_DEBUG
219 atomic_inc(&inet6_sock_nr);
220 atomic_inc(&inet_sock_nr);
221#endif
222 if (inet->num) { 213 if (inet->num) {
223 /* It assumes that any protocol which allows 214 /* It assumes that any protocol which allows
224 * the user to assign a number at socket 215 * the user to assign a number at socket
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 3bc144a79fa5..76fe23925d77 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -163,6 +163,13 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
163 fl6_free_socklist(sk); 163 fl6_free_socklist(sk);
164 ipv6_sock_mc_close(sk); 164 ipv6_sock_mc_close(sk);
165 165
166 /*
167 * Sock is moving from IPv6 to IPv4 (sk_prot), so
168 * remove it from the refcnt debug socks count in the
169 * original family...
170 */
171 sk_refcnt_debug_dec(sk);
172
166 if (sk->sk_protocol == IPPROTO_TCP) { 173 if (sk->sk_protocol == IPPROTO_TCP) {
167 struct tcp_sock *tp = tcp_sk(sk); 174 struct tcp_sock *tp = tcp_sk(sk);
168 175
@@ -192,9 +199,11 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname,
192 kfree_skb(pktopt); 199 kfree_skb(pktopt);
193 200
194 sk->sk_destruct = inet_sock_destruct; 201 sk->sk_destruct = inet_sock_destruct;
195#ifdef INET_REFCNT_DEBUG 202 /*
196 atomic_dec(&inet6_sock_nr); 203 * ... and add it to the refcnt debug socks count
197#endif 204 * in the new family. -acme
205 */
206 sk_refcnt_debug_inc(sk);
198 module_put(THIS_MODULE); 207 module_put(THIS_MODULE);
199 retv = 0; 208 retv = 0;
200 break; 209 break;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ef29cfd936d3..885e05bd99f6 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1407,12 +1407,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1407 newnp->mcast_oif = tcp_v6_iif(skb); 1407 newnp->mcast_oif = tcp_v6_iif(skb);
1408 newnp->mcast_hops = skb->nh.ipv6h->hop_limit; 1408 newnp->mcast_hops = skb->nh.ipv6h->hop_limit;
1409 1409
1410 /* Charge newly allocated IPv6 socket. Though it is mapped, 1410 /*
1411 * it is IPv6 yet. 1411 * No need to charge this sock to the relevant IPv6 refcnt debug socks count
1412 * here, tcp_create_openreq_child now does this for us, see the comment in
1413 * that function for the gory details. -acme
1412 */ 1414 */
1413#ifdef INET_REFCNT_DEBUG
1414 atomic_inc(&inet6_sock_nr);
1415#endif
1416 1415
1417 /* It is tricky place. Until this moment IPv4 tcp 1416 /* It is tricky place. Until this moment IPv4 tcp
1418 worked with IPv6 af_tcp.af_specific. 1417 worked with IPv6 af_tcp.af_specific.
@@ -1467,10 +1466,11 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
1467 if (newsk == NULL) 1466 if (newsk == NULL)
1468 goto out; 1467 goto out;
1469 1468
1470 /* Charge newly allocated IPv6 socket */ 1469 /*
1471#ifdef INET_REFCNT_DEBUG 1470 * No need to charge this sock to the relevant IPv6 refcnt debug socks
1472 atomic_inc(&inet6_sock_nr); 1471 * count here, tcp_create_openreq_child now does this for us, see the
1473#endif 1472 * comment in that function for the gory details. -acme
1473 */
1474 1474
1475 ip6_dst_store(newsk, dst, NULL); 1475 ip6_dst_store(newsk, dst, NULL);
1476 newsk->sk_route_caps = dst->dev->features & 1476 newsk->sk_route_caps = dst->dev->features &
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e9b2fd480d61..4a6421a9fcab 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -641,10 +641,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
641 else 641 else
642 newinet->pmtudisc = IP_PMTUDISC_WANT; 642 newinet->pmtudisc = IP_PMTUDISC_WANT;
643 643
644#ifdef INET_REFCNT_DEBUG 644 sk_refcnt_debug_inc(newsk);
645 atomic_inc(&inet6_sock_nr);
646 atomic_inc(&inet_sock_nr);
647#endif
648 645
649 if (newsk->sk_prot->init(newsk)) { 646 if (newsk->sk_prot->init(newsk)) {
650 sk_common_release(newsk); 647 sk_common_release(newsk);
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index ce9245e71fca..8d3f8096b873 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -593,9 +593,7 @@ static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
593 newinet->mc_index = 0; 593 newinet->mc_index = 0;
594 newinet->mc_list = NULL; 594 newinet->mc_list = NULL;
595 595
596#ifdef INET_REFCNT_DEBUG 596 sk_refcnt_debug_inc(newsk);
597 atomic_inc(&inet_sock_nr);
598#endif
599 597
600 if (newsk->sk_prot->init(newsk)) { 598 if (newsk->sk_prot->init(newsk)) {
601 sk_common_release(newsk); 599 sk_common_release(newsk);