--- x/include/net/rose.h +++ y/include/net/rose.h @@ -98,6 +98,7 @@ struct rose_neigh { unsigned short count; unsigned short use; unsigned int number; + atomic_t ref; char restarted; char dce_mode; char loopback; @@ -214,6 +215,7 @@ void rose_link_device_down(struct net_de struct net_device *rose_dev_first(void); struct net_device *rose_dev_get(rose_address *); struct rose_route *rose_route_free_lci(unsigned int, struct rose_neigh *); +void rose_put_neigh(struct rose_neigh *); struct rose_neigh *rose_get_neigh(rose_address *, unsigned char *, unsigned char *, int); int rose_rt_ioctl(unsigned int, void __user *); --- x/net/rose/af_rose.c +++ y/net/rose/af_rose.c @@ -171,6 +171,7 @@ void rose_kill_by_neigh(struct rose_neig if (rose->neighbour == neigh) { rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0); rose->neighbour->use--; + rose_put_neigh(rose->neighbour); rose->neighbour = NULL; } } @@ -383,8 +384,10 @@ void rose_destroy_socket(struct sock *sk timer_setup(&sk->sk_timer, rose_destroy_timer, 0); sk->sk_timer.expires = jiffies + 10 * HZ; add_timer(&sk->sk_timer); - } else + } else { + rose_put_neigh(rose_sk(sk)->neighbour); sock_put(sk); + } } /* --- x/net/rose/rose_route.c +++ y/net/rose/rose_route.c @@ -97,6 +97,7 @@ static int __must_check rose_add_node(st rose_neigh->dce_mode = 0; rose_neigh->loopback = 0; rose_neigh->number = rose_neigh_no++; + atomic_set(&rose_neigh->ref, 1); rose_neigh->restarted = 0; skb_queue_head_init(&rose_neigh->queue); @@ -237,7 +238,7 @@ static void rose_remove_neigh(struct ros if (rose_neigh->ax25) ax25_cb_put(rose_neigh->ax25); kfree(rose_neigh->digipeat); - kfree(rose_neigh); + rose_put_neigh(rose_neigh); return; } @@ -247,7 +248,7 @@ static void rose_remove_neigh(struct ros if (rose_neigh->ax25) ax25_cb_put(rose_neigh->ax25); kfree(rose_neigh->digipeat); - kfree(rose_neigh); + rose_put_neigh(rose_neigh); return; } @@ -265,8 +266,10 @@ static void rose_remove_route(struct ros if (rose_route->neigh1 != NULL) rose_route->neigh1->use--; - if (rose_route->neigh2 != NULL) + if (rose_route->neigh2 != NULL) { rose_route->neigh2->use--; + rose_put_neigh(rose_route->neigh2); + } if ((s = rose_route_list) == rose_route) { rose_route_list = rose_route->next; @@ -667,6 +670,11 @@ struct rose_route *rose_route_free_lci(u return NULL; } +void rose_put_neigh(struct rose_neigh *n) +{ + if (n && atomic_dec_and_test(&n->ref)) + kfree(n); +} /* * Find a neighbour or a route given a ROSE address. */ @@ -712,6 +720,8 @@ struct rose_neigh *rose_get_neigh(rose_a } out: + if (res) + atomic_inc(&res->ref); if (!route_frame) spin_unlock_bh(&rose_node_list_lock); return res; } @@ -1061,6 +1071,7 @@ int rose_route_frame(struct sk_buff *skb rose_route->neigh1 = rose_neigh; rose_route->lci2 = new_lci; rose_route->neigh2 = new_neigh; + new_neigh = NULL; rose_route->neigh1->use++; rose_route->neigh2->use++; @@ -1076,6 +1087,8 @@ int rose_route_frame(struct sk_buff *skb res = 1; out: + if (new_neigh) + rose_put_neigh(new_neigh); spin_unlock_bh(&rose_route_list_lock); spin_unlock_bh(&rose_neigh_list_lock);