With struct sock and ax25_cb in a unified data structure it now is possible to fix the reference counting by using the sk_reset_timer and sk_stop_timer helper function - the previous implementation was based simply on "principle hope".
Signed-off-by: Ralf Baechle <[EMAIL PROTECTED]> include/net/ax25.h | 5 +++ include/net/rose.h | 1 net/ax25/af_ax25.c | 55 ++++++++++++++++++--------------- net/ax25/ax25_timer.c | 82 ++++++++++++++++++++------------------------------ net/netrom/nr_timer.c | 29 +++++++++-------- net/rose/af_rose.c | 6 +-- net/rose/rose_timer.c | 79 +++++++++++++++++++----------------------------- 7 files changed, 120 insertions(+), 137 deletions(-) Index: linux-net/net/ax25/af_ax25.c =================================================================== --- linux-net.orig/net/ax25/af_ax25.c 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/net/ax25/af_ax25.c 2006-07-14 01:36:04.000000000 +0100 @@ -49,8 +49,6 @@ #include <net/ip.h> #include <net/arp.h> - - HLIST_HEAD(ax25_list); DEFINE_SPINLOCK(ax25_list_lock); @@ -261,13 +259,10 @@ void ax25_destroy_socket(struct ax25_soc */ static void ax25_destroy_timer(unsigned long data) { - struct ax25_sock *ax25 = (struct ax25_sock *)data; - struct sock *sk; - - sk=ax25->sk; - + struct ax25_sock *ax25 = (struct ax25_sock *) data; + struct sock *sk = ax25->sk; + bh_lock_sock(sk); - sock_hold(sk); ax25_destroy_socket(ax25); bh_unlock_sock(sk); sock_put(sk); @@ -281,6 +276,7 @@ static void ax25_destroy_timer(unsigned */ void ax25_destroy_socket(struct ax25_sock *ax25) { + struct sock *sk = ax25->sk; struct sk_buff *skb; ax25_cb_del(ax25); @@ -293,9 +289,9 @@ void ax25_destroy_socket(struct ax25_soc ax25_clear_queues(ax25); /* Flush the queues */ - if (ax25->sk != NULL) { + if (sk) { while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) { - if (skb->sk != ax25->sk) { + if (skb->sk != sk) { /* A pending connection */ struct ax25_sock *sax25 = ax25_sk(skb->sk); @@ -308,23 +304,14 @@ void ax25_destroy_socket(struct ax25_soc kfree_skb(skb); } - skb_queue_purge(&ax25->sk->sk_write_queue); - } + skb_queue_purge(&sk->sk_write_queue); - if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->sk_wmem_alloc) || - atomic_read(&ax25->sk->sk_rmem_alloc)) { + if (atomic_read(&sk->sk_wmem_alloc) || + atomic_read(&sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ - init_timer(&ax25->dtimer); - ax25->dtimer.expires = jiffies + 2 * HZ; - ax25->dtimer.function = ax25_destroy_timer; - ax25->dtimer.data = (unsigned long)ax25; - add_timer(&ax25->dtimer); - } else { - struct sock *sk=ax25->sk; - ax25->sk=NULL; + sk_reset_timer(sk, &ax25->dtimer, jiffies + 2 * HZ); + } else sock_put(sk); - } } else { sock_put(&ax25->sock); } @@ -497,11 +484,29 @@ struct ax25_sock *ax25_alloc_sock(struct skb_queue_head_init(&ax25->ack_queue); skb_queue_head_init(&ax25->reseq_queue); - init_timer(&ax25->timer); init_timer(&ax25->t1timer); + ax25->t1timer.function = &ax25_t1timer_expiry; + ax25->t1timer.data = (unsigned long) ax25; + init_timer(&ax25->t2timer); + ax25->t2timer.function = &ax25_t2timer_expiry; + ax25->t2timer.data = (unsigned long) ax25; + init_timer(&ax25->t3timer); + ax25->t3timer.function = &ax25_t3timer_expiry; + ax25->t3timer.data = (unsigned long) ax25; + init_timer(&ax25->idletimer); + ax25->idletimer.function= &ax25_idletimer_expiry; + ax25->idletimer.data = (unsigned long) ax25; + + init_timer(&ax25->timer); + ax25->timer.function = &ax25_heartbeat_expiry; + ax25->timer.data = (unsigned long) ax25; + + init_timer(&ax25->dtimer); + ax25->dtimer.function = ax25_destroy_timer; + ax25->dtimer.data = (unsigned long)ax25; ax25_fillin_cb(ax25, NULL); Index: linux-net/net/ax25/ax25_timer.c =================================================================== --- linux-net.orig/net/ax25/ax25_timer.c 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/net/ax25/ax25_timer.c 2006-07-14 01:36:04.000000000 +0100 @@ -34,94 +34,70 @@ #include <linux/mm.h> #include <linux/interrupt.h> -static void ax25_heartbeat_expiry(unsigned long); -static void ax25_t1timer_expiry(unsigned long); -static void ax25_t2timer_expiry(unsigned long); -static void ax25_t3timer_expiry(unsigned long); -static void ax25_idletimer_expiry(unsigned long); - void ax25_start_heartbeat(struct ax25_sock *ax25) { - del_timer(&ax25->timer); - - ax25->timer.data = (unsigned long)ax25; - ax25->timer.function = &ax25_heartbeat_expiry; - ax25->timer.expires = jiffies + 5 * HZ; + struct sock *sk = &ax25->sock; - add_timer(&ax25->timer); + sk_reset_timer(sk, &ax25->timer, jiffies + 5 * HZ); } void ax25_start_t1timer(struct ax25_sock *ax25) { - del_timer(&ax25->t1timer); - - ax25->t1timer.data = (unsigned long)ax25; - ax25->t1timer.function = &ax25_t1timer_expiry; - ax25->t1timer.expires = jiffies + ax25->t1; + struct sock *sk = &ax25->sock; - add_timer(&ax25->t1timer); + sk_reset_timer(sk, &ax25->t1timer, jiffies + ax25->t1); } void ax25_start_t2timer(struct ax25_sock *ax25) { - del_timer(&ax25->t2timer); + struct sock *sk = &ax25->sock; - ax25->t2timer.data = (unsigned long)ax25; - ax25->t2timer.function = &ax25_t2timer_expiry; - ax25->t2timer.expires = jiffies + ax25->t2; - - add_timer(&ax25->t2timer); + sk_reset_timer(sk, &ax25->t2timer, jiffies + ax25->t2); } void ax25_start_t3timer(struct ax25_sock *ax25) { - del_timer(&ax25->t3timer); + struct sock *sk = &ax25->sock; - if (ax25->t3 > 0) { - ax25->t3timer.data = (unsigned long)ax25; - ax25->t3timer.function = &ax25_t3timer_expiry; - ax25->t3timer.expires = jiffies + ax25->t3; + sk_stop_timer(sk, &ax25->t3timer); - add_timer(&ax25->t3timer); - } + if (ax25->t3 > 0) + sk_reset_timer(sk, &ax25->t3timer, jiffies + ax25->t3); } void ax25_start_idletimer(struct ax25_sock *ax25) { - del_timer(&ax25->idletimer); + struct sock *sk = &ax25->sock; - if (ax25->idle > 0) { - ax25->idletimer.data = (unsigned long)ax25; - ax25->idletimer.function = &ax25_idletimer_expiry; - ax25->idletimer.expires = jiffies + ax25->idle; + sk_stop_timer(sk, &ax25->idletimer); - add_timer(&ax25->idletimer); - } + if (ax25->idle > 0) + sk_reset_timer(sk, &ax25->idletimer, jiffies + ax25->idle); } void ax25_stop_heartbeat(struct ax25_sock *ax25) { - del_timer(&ax25->timer); + sk_stop_timer(&ax25->sock, &ax25->timer); } void ax25_stop_t1timer(struct ax25_sock *ax25) { - del_timer(&ax25->t1timer); + sk_stop_timer(&ax25->sock, &ax25->t1timer); } void ax25_stop_t2timer(struct ax25_sock *ax25) { - del_timer(&ax25->t2timer); + sk_stop_timer(&ax25->sock, &ax25->t2timer); } void ax25_stop_t3timer(struct ax25_sock *ax25) { - del_timer(&ax25->t3timer); + sk_stop_timer(&ax25->sock, &ax25->t3timer); } void ax25_stop_idletimer(struct ax25_sock *ax25) { - del_timer(&ax25->idletimer); + sk_stop_timer(&ax25->sock, &ax25->idletimer); } int ax25_t1timer_running(struct ax25_sock *ax25) @@ -139,7 +115,7 @@ unsigned long ax25_display_timer(struct EXPORT_SYMBOL(ax25_display_timer); -static void ax25_heartbeat_expiry(unsigned long param) +void ax25_heartbeat_expiry(unsigned long param) { int proto = AX25_PROTO_STD_SIMPLEX; struct ax25_sock *ax25 = (struct ax25_sock *)param; @@ -162,9 +138,11 @@ static void ax25_heartbeat_expiry(unsign break; #endif } + + sock_put(&ax25->sock); } -static void ax25_t1timer_expiry(unsigned long param) +void ax25_t1timer_expiry(unsigned long param) { struct ax25_sock *ax25 = (struct ax25_sock *)param; @@ -181,9 +159,11 @@ static void ax25_t1timer_expiry(unsigned break; #endif } + + sock_put(&ax25->sock); } -static void ax25_t2timer_expiry(unsigned long param) +void ax25_t2timer_expiry(unsigned long param) { struct ax25_sock *ax25 = (struct ax25_sock *)param; @@ -200,9 +180,11 @@ static void ax25_t2timer_expiry(unsigned break; #endif } + + sock_put(&ax25->sock); } -static void ax25_t3timer_expiry(unsigned long param) +void ax25_t3timer_expiry(unsigned long param) { struct ax25_sock *ax25 = (struct ax25_sock *)param; @@ -221,9 +203,11 @@ static void ax25_t3timer_expiry(unsigned break; #endif } + + sock_put(&ax25->sock); } -static void ax25_idletimer_expiry(unsigned long param) +void ax25_idletimer_expiry(unsigned long param) { struct ax25_sock *ax25 = (struct ax25_sock *)param; @@ -242,4 +226,6 @@ static void ax25_idletimer_expiry(unsign break; #endif } + + sock_put(&ax25->sock); } Index: linux-net/include/net/ax25.h =================================================================== --- linux-net.orig/include/net/ax25.h 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/include/net/ax25.h 2006-07-14 01:36:04.000000000 +0100 @@ -395,6 +395,11 @@ extern void ax25_stop_t1timer(struct ax2 extern void ax25_stop_t2timer(struct ax25_sock *); extern void ax25_stop_t3timer(struct ax25_sock *); extern void ax25_stop_idletimer(struct ax25_sock *); +extern void ax25_heartbeat_expiry(unsigned long); +extern void ax25_t1timer_expiry(unsigned long); +extern void ax25_t2timer_expiry(unsigned long); +extern void ax25_t3timer_expiry(unsigned long); +extern void ax25_idletimer_expiry(unsigned long); extern int ax25_t1timer_running(struct ax25_sock *); extern unsigned long ax25_display_timer(struct timer_list *); Index: linux-net/net/netrom/nr_timer.c =================================================================== --- linux-net.orig/net/netrom/nr_timer.c 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/net/netrom/nr_timer.c 2006-07-14 01:37:19.000000000 +0100 @@ -65,21 +65,21 @@ void nr_start_t1timer(struct sock *sk) { struct nr_sock *nr = nr_sk(sk); - mod_timer(&nr->t1timer, jiffies + nr->t1); + sk_reset_timer(sk, &nr->t1timer, jiffies + nr->t1); } void nr_start_t2timer(struct sock *sk) { struct nr_sock *nr = nr_sk(sk); - mod_timer(&nr->t2timer, jiffies + nr->t2); + sk_reset_timer(sk, &nr->t2timer, jiffies + nr->t2); } void nr_start_t4timer(struct sock *sk) { struct nr_sock *nr = nr_sk(sk); - mod_timer(&nr->t4timer, jiffies + nr->t4); + sk_reset_timer(sk, &nr->t4timer, jiffies + nr->t4); } void nr_start_idletimer(struct sock *sk) @@ -87,37 +87,37 @@ void nr_start_idletimer(struct sock *sk) struct nr_sock *nr = nr_sk(sk); if (nr->idle > 0) - mod_timer(&nr->idletimer, jiffies + nr->idle); + sk_reset_timer(sk, &nr->idletimer, jiffies + nr->idle); } void nr_start_heartbeat(struct sock *sk) { - mod_timer(&sk->sk_timer, jiffies + 5 * HZ); + sk_reset_timer(sk, &sk->sk_timer, jiffies + 5 * HZ); } void nr_stop_t1timer(struct sock *sk) { - del_timer(&nr_sk(sk)->t1timer); + sk_stop_timer(sk, &nr_sk(sk)->t1timer); } void nr_stop_t2timer(struct sock *sk) { - del_timer(&nr_sk(sk)->t2timer); + sk_stop_timer(sk, &nr_sk(sk)->t2timer); } void nr_stop_t4timer(struct sock *sk) { - del_timer(&nr_sk(sk)->t4timer); + sk_stop_timer(sk, &nr_sk(sk)->t4timer); } void nr_stop_idletimer(struct sock *sk) { - del_timer(&nr_sk(sk)->idletimer); + sk_stop_timer(sk, &nr_sk(sk)->idletimer); } void nr_stop_heartbeat(struct sock *sk) { - del_timer(&sk->sk_timer); + sk_stop_timer(sk, &sk->sk_timer); } int nr_t1timer_running(struct sock *sk) @@ -137,10 +137,7 @@ static void nr_heartbeat_expiry(unsigned is accepted() it isn't 'dead' so doesn't get removed. */ if (sock_flag(sk, SOCK_DESTROY) || (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { - sock_hold(sk); - bh_unlock_sock(sk); nr_destroy_socket(sk); - sock_put(sk); return; } break; @@ -161,7 +158,9 @@ static void nr_heartbeat_expiry(unsigned } nr_start_heartbeat(sk); + bh_unlock_sock(sk); + sock_put(sk); } static void nr_t2timer_expiry(unsigned long param) @@ -175,6 +174,7 @@ static void nr_t2timer_expiry(unsigned l nr_enquiry_response(sk); } bh_unlock_sock(sk); + sock_put(sk); } static void nr_t4timer_expiry(unsigned long param) @@ -184,6 +184,7 @@ static void nr_t4timer_expiry(unsigned l bh_lock_sock(sk); nr_sk(sk)->condition &= ~NR_COND_PEER_RX_BUSY; bh_unlock_sock(sk); + sock_put(sk); } static void nr_idletimer_expiry(unsigned long param) @@ -212,6 +213,7 @@ static void nr_idletimer_expiry(unsigned sock_set_flag(sk, SOCK_DEAD); } bh_unlock_sock(sk); + sock_put(sk); } static void nr_t1timer_expiry(unsigned long param) @@ -257,4 +259,5 @@ static void nr_t1timer_expiry(unsigned l nr_start_t1timer(sk); bh_unlock_sock(sk); + sock_put(sk); } Index: linux-net/include/net/rose.h =================================================================== --- linux-net.orig/include/net/rose.h 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/include/net/rose.h 2006-07-14 01:36:04.000000000 +0100 @@ -218,6 +218,7 @@ extern int rose_parse_facilities(unsign extern void rose_disconnect(struct sock *, int, int, int); /* rose_timer.c */ +extern void rose_init_timers(struct sock *sk); extern void rose_start_heartbeat(struct sock *); extern void rose_start_t1timer(struct sock *); extern void rose_start_t2timer(struct sock *); Index: linux-net/net/rose/af_rose.c =================================================================== --- linux-net.orig/net/rose/af_rose.c 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/net/rose/af_rose.c 2006-07-14 01:36:04.000000000 +0100 @@ -522,8 +522,7 @@ static int rose_create(struct socket *so sock->ops = &rose_proto_ops; sk->sk_protocol = protocol; - init_timer(&rose->timer); - init_timer(&rose->idletimer); + rose_init_timers(sk); rose->t1 = msecs_to_jiffies(sysctl_rose_call_request_timeout); rose->t2 = msecs_to_jiffies(sysctl_rose_reset_request_timeout); @@ -567,8 +566,7 @@ static struct sock *rose_make_new(struct sk->sk_sleep = osk->sk_sleep; sock_copy_flags(sk, osk); - init_timer(&rose->timer); - init_timer(&rose->idletimer); + rose_init_timers(sk); orose = rose_sk(osk); rose->t1 = orose->t1; Index: linux-net/net/rose/rose_timer.c =================================================================== --- linux-net.orig/net/rose/rose_timer.c 2006-07-14 01:34:39.000000000 +0100 +++ linux-net/net/rose/rose_timer.c 2006-07-14 01:36:04.000000000 +0100 @@ -5,7 +5,7 @@ * (at your option) any later version. * * Copyright (C) Jonathan Naylor G4KLX ([EMAIL PROTECTED]) - * Copyright (C) 2002 Ralf Baechle DO1GRB ([EMAIL PROTECTED]) + * Copyright (C) 2002, 06 Ralf Baechle DL5RB ([EMAIL PROTECTED]) */ #include <linux/errno.h> #include <linux/types.h> @@ -33,97 +33,78 @@ static void rose_heartbeat_expiry(unsign static void rose_timer_expiry(unsigned long); static void rose_idletimer_expiry(unsigned long); -void rose_start_heartbeat(struct sock *sk) +void rose_init_timers(struct sock *sk) { - del_timer(&sk->sk_timer); + struct rose_sock *rose = rose_sk(sk); - sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.data = (unsigned long) sk; sk->sk_timer.function = &rose_heartbeat_expiry; - sk->sk_timer.expires = jiffies + 5 * HZ; - add_timer(&sk->sk_timer); + init_timer(&rose->timer); + rose->timer.data = (unsigned long) sk; + rose->timer.function = &rose_timer_expiry; + + init_timer(&rose->idletimer); + rose->idletimer.data = (unsigned long) sk; + rose->idletimer.function = &rose_idletimer_expiry; +} + +void rose_start_heartbeat(struct sock *sk) +{ + sk_reset_timer(sk, &sk->sk_timer, jiffies + 5 * HZ); } void rose_start_t1timer(struct sock *sk) { struct rose_sock *rose = rose_sk(sk); - del_timer(&rose->timer); - - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; - rose->timer.expires = jiffies + rose->t1; - - add_timer(&rose->timer); + sk_reset_timer(sk, &rose->timer, jiffies + rose->t1); } void rose_start_t2timer(struct sock *sk) { struct rose_sock *rose = rose_sk(sk); - del_timer(&rose->timer); - - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; - rose->timer.expires = jiffies + rose->t2; - - add_timer(&rose->timer); + sk_reset_timer(sk, &rose->timer, jiffies + rose->t2); } void rose_start_t3timer(struct sock *sk) { struct rose_sock *rose = rose_sk(sk); - del_timer(&rose->timer); - - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; - rose->timer.expires = jiffies + rose->t3; - - add_timer(&rose->timer); + sk_reset_timer(sk, &rose->timer, jiffies + rose->t3); } void rose_start_hbtimer(struct sock *sk) { struct rose_sock *rose = rose_sk(sk); - del_timer(&rose->timer); - - rose->timer.data = (unsigned long)sk; - rose->timer.function = &rose_timer_expiry; - rose->timer.expires = jiffies + rose->hb; - - add_timer(&rose->timer); + sk_reset_timer(sk, &rose->timer, jiffies + rose->hb); } void rose_start_idletimer(struct sock *sk) { struct rose_sock *rose = rose_sk(sk); - del_timer(&rose->idletimer); - - if (rose->idle > 0) { - rose->idletimer.data = (unsigned long)sk; - rose->idletimer.function = &rose_idletimer_expiry; - rose->idletimer.expires = jiffies + rose->idle; + sk_stop_timer(sk, &rose->idletimer); - add_timer(&rose->idletimer); - } + if (rose->idle > 0) + sk_reset_timer(sk, &rose->idletimer, jiffies + rose->idle); } void rose_stop_heartbeat(struct sock *sk) { - del_timer(&sk->sk_timer); + sk_stop_timer(sk, &sk->sk_timer); } void rose_stop_timer(struct sock *sk) { - del_timer(&rose_sk(sk)->timer); + sk_stop_timer(sk, &rose_sk(sk)->timer); } void rose_stop_idletimer(struct sock *sk) { - del_timer(&rose_sk(sk)->idletimer); + sk_stop_timer(sk, &rose_sk(sk)->idletimer); } static void rose_heartbeat_expiry(unsigned long param) @@ -138,9 +119,8 @@ static void rose_heartbeat_expiry(unsign is accepted() it isn't 'dead' so doesn't get removed. */ if (sock_flag(sk, SOCK_DESTROY) || (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { - bh_unlock_sock(sk); rose_destroy_socket(sk); - return; + goto out_unlock; } break; @@ -161,7 +141,10 @@ static void rose_heartbeat_expiry(unsign } rose_start_heartbeat(sk); + +out_unlock: bh_unlock_sock(sk); + sock_put(sk); } static void rose_timer_expiry(unsigned long param) @@ -191,6 +174,7 @@ static void rose_timer_expiry(unsigned l break; } bh_unlock_sock(sk); + sock_put(sk); } static void rose_idletimer_expiry(unsigned long param) @@ -214,4 +198,5 @@ static void rose_idletimer_expiry(unsign sock_set_flag(sk, SOCK_DEAD); } bh_unlock_sock(sk); + sock_put(sk); } - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html