@@ -104,9 +104,9 @@ static struct workqueue_struct *l2tp_wq;
104104/* per-net private data for this module */ 
105105static  unsigned int   l2tp_net_id ;
106106struct  l2tp_net  {
107- 	struct   list_head   l2tp_tunnel_list ; 
108- 	/* Lock for write access to l2tp_tunnel_list */ 
109- 	spinlock_t   l2tp_tunnel_list_lock ;
107+ 	/* Lock for write access to l2tp_tunnel_idr */ 
108+ 	spinlock_t   l2tp_tunnel_idr_lock ; 
109+ 	struct   idr   l2tp_tunnel_idr ;
110110	struct  hlist_head  l2tp_session_hlist [L2TP_HASH_SIZE_2 ];
111111	/* Lock for write access to l2tp_session_hlist */ 
112112	spinlock_t  l2tp_session_hlist_lock ;
@@ -208,13 +208,10 @@ struct l2tp_tunnel *l2tp_tunnel_get(const struct net *net, u32 tunnel_id)
208208	struct  l2tp_tunnel  * tunnel ;
209209
210210	rcu_read_lock_bh ();
211- 	list_for_each_entry_rcu (tunnel , & pn -> l2tp_tunnel_list , list ) {
212- 		if  (tunnel -> tunnel_id  ==  tunnel_id  && 
213- 		    refcount_inc_not_zero (& tunnel -> ref_count )) {
214- 			rcu_read_unlock_bh ();
215- 
216- 			return  tunnel ;
217- 		}
211+ 	tunnel  =  idr_find (& pn -> l2tp_tunnel_idr , tunnel_id );
212+ 	if  (tunnel  &&  refcount_inc_not_zero (& tunnel -> ref_count )) {
213+ 		rcu_read_unlock_bh ();
214+ 		return  tunnel ;
218215	}
219216	rcu_read_unlock_bh ();
220217
@@ -224,13 +221,14 @@ EXPORT_SYMBOL_GPL(l2tp_tunnel_get);
224221
225222struct  l2tp_tunnel  * l2tp_tunnel_get_nth (const  struct  net  * net , int  nth )
226223{
227- 	const  struct  l2tp_net  * pn  =  l2tp_pernet (net );
224+ 	struct  l2tp_net  * pn  =  l2tp_pernet (net );
225+ 	unsigned long  tunnel_id , tmp ;
228226	struct  l2tp_tunnel  * tunnel ;
229227	int  count  =  0 ;
230228
231229	rcu_read_lock_bh ();
232- 	list_for_each_entry_rcu ( tunnel ,  & pn -> l2tp_tunnel_list ,  list ) {
233- 		if  (++ count  >  nth  && 
230+ 	idr_for_each_entry_ul ( & pn -> l2tp_tunnel_idr ,  tunnel ,  tmp ,  tunnel_id ) {
231+ 		if  (tunnel   &&   ++ count  >  nth  && 
234232		    refcount_inc_not_zero (& tunnel -> ref_count )) {
235233			rcu_read_unlock_bh ();
236234			return  tunnel ;
@@ -1227,14 +1225,22 @@ static void l2tp_udp_encap_destroy(struct sock *sk)
12271225		l2tp_tunnel_delete (tunnel );
12281226}
12291227
1228+ static  void  l2tp_tunnel_remove (struct  net  * net , struct  l2tp_tunnel  * tunnel )
1229+ {
1230+ 	struct  l2tp_net  * pn  =  l2tp_pernet (net );
1231+ 
1232+ 	spin_lock_bh (& pn -> l2tp_tunnel_idr_lock );
1233+ 	idr_remove (& pn -> l2tp_tunnel_idr , tunnel -> tunnel_id );
1234+ 	spin_unlock_bh (& pn -> l2tp_tunnel_idr_lock );
1235+ }
1236+ 
12301237/* Workqueue tunnel deletion function */ 
12311238static  void  l2tp_tunnel_del_work (struct  work_struct  * work )
12321239{
12331240	struct  l2tp_tunnel  * tunnel  =  container_of (work , struct  l2tp_tunnel ,
12341241						  del_work );
12351242	struct  sock  * sk  =  tunnel -> sock ;
12361243	struct  socket  * sock  =  sk -> sk_socket ;
1237- 	struct  l2tp_net  * pn ;
12381244
12391245	l2tp_tunnel_closeall (tunnel );
12401246
@@ -1248,12 +1254,7 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
12481254		}
12491255	}
12501256
1251- 	/* Remove the tunnel struct from the tunnel list */ 
1252- 	pn  =  l2tp_pernet (tunnel -> l2tp_net );
1253- 	spin_lock_bh (& pn -> l2tp_tunnel_list_lock );
1254- 	list_del_rcu (& tunnel -> list );
1255- 	spin_unlock_bh (& pn -> l2tp_tunnel_list_lock );
1256- 
1257+ 	l2tp_tunnel_remove (tunnel -> l2tp_net , tunnel );
12571258	/* drop initial ref */ 
12581259	l2tp_tunnel_dec_refcount (tunnel );
12591260
@@ -1455,12 +1456,19 @@ static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
14551456int  l2tp_tunnel_register (struct  l2tp_tunnel  * tunnel , struct  net  * net ,
14561457			 struct  l2tp_tunnel_cfg  * cfg )
14571458{
1458- 	struct  l2tp_tunnel   * tunnel_walk ;
1459- 	struct   l2tp_net   * pn ;
1459+ 	struct  l2tp_net   * pn   =   l2tp_pernet ( net ) ;
1460+ 	u32   tunnel_id   =   tunnel -> tunnel_id ;
14601461	struct  socket  * sock ;
14611462	struct  sock  * sk ;
14621463	int  ret ;
14631464
1465+ 	spin_lock_bh (& pn -> l2tp_tunnel_idr_lock );
1466+ 	ret  =  idr_alloc_u32 (& pn -> l2tp_tunnel_idr , NULL , & tunnel_id , tunnel_id ,
1467+ 			    GFP_ATOMIC );
1468+ 	spin_unlock_bh (& pn -> l2tp_tunnel_idr_lock );
1469+ 	if  (ret )
1470+ 		return  ret  ==  - ENOSPC  ? - EEXIST  : ret ;
1471+ 
14641472	if  (tunnel -> fd  <  0 ) {
14651473		ret  =  l2tp_tunnel_sock_create (net , tunnel -> tunnel_id ,
14661474					      tunnel -> peer_tunnel_id , cfg ,
@@ -1481,23 +1489,13 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14811489	rcu_assign_sk_user_data (sk , tunnel );
14821490	write_unlock_bh (& sk -> sk_callback_lock );
14831491
1484- 	tunnel -> l2tp_net  =  net ;
1485- 	pn  =  l2tp_pernet (net );
1486- 
14871492	sock_hold (sk );
14881493	tunnel -> sock  =  sk ;
1494+ 	tunnel -> l2tp_net  =  net ;
14891495
1490- 	spin_lock_bh (& pn -> l2tp_tunnel_list_lock );
1491- 	list_for_each_entry (tunnel_walk , & pn -> l2tp_tunnel_list , list ) {
1492- 		if  (tunnel_walk -> tunnel_id  ==  tunnel -> tunnel_id ) {
1493- 			spin_unlock_bh (& pn -> l2tp_tunnel_list_lock );
1494- 			sock_put (sk );
1495- 			ret  =  - EEXIST ;
1496- 			goto err_sock ;
1497- 		}
1498- 	}
1499- 	list_add_rcu (& tunnel -> list , & pn -> l2tp_tunnel_list );
1500- 	spin_unlock_bh (& pn -> l2tp_tunnel_list_lock );
1496+ 	spin_lock_bh (& pn -> l2tp_tunnel_idr_lock );
1497+ 	idr_replace (& pn -> l2tp_tunnel_idr , tunnel , tunnel -> tunnel_id );
1498+ 	spin_unlock_bh (& pn -> l2tp_tunnel_idr_lock );
15011499
15021500	if  (tunnel -> encap  ==  L2TP_ENCAPTYPE_UDP ) {
15031501		struct  udp_tunnel_sock_cfg  udp_cfg  =  {
@@ -1523,9 +1521,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15231521
15241522	return  0 ;
15251523
1526- err_sock :
1527- 	write_lock_bh (& sk -> sk_callback_lock );
1528- 	rcu_assign_sk_user_data (sk , NULL );
15291524err_inval_sock :
15301525	write_unlock_bh (& sk -> sk_callback_lock );
15311526
@@ -1534,6 +1529,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15341529	else 
15351530		sockfd_put (sock );
15361531err :
1532+ 	l2tp_tunnel_remove (net , tunnel );
15371533	return  ret ;
15381534}
15391535EXPORT_SYMBOL_GPL (l2tp_tunnel_register );
@@ -1647,8 +1643,8 @@ static __net_init int l2tp_init_net(struct net *net)
16471643	struct  l2tp_net  * pn  =  net_generic (net , l2tp_net_id );
16481644	int  hash ;
16491645
1650- 	INIT_LIST_HEAD (& pn -> l2tp_tunnel_list );
1651- 	spin_lock_init (& pn -> l2tp_tunnel_list_lock );
1646+ 	idr_init (& pn -> l2tp_tunnel_idr );
1647+ 	spin_lock_init (& pn -> l2tp_tunnel_idr_lock );
16521648
16531649	for  (hash  =  0 ; hash  <  L2TP_HASH_SIZE_2 ; hash ++ )
16541650		INIT_HLIST_HEAD (& pn -> l2tp_session_hlist [hash ]);
@@ -1662,11 +1658,13 @@ static __net_exit void l2tp_exit_net(struct net *net)
16621658{
16631659	struct  l2tp_net  * pn  =  l2tp_pernet (net );
16641660	struct  l2tp_tunnel  * tunnel  =  NULL ;
1661+ 	unsigned long  tunnel_id , tmp ;
16651662	int  hash ;
16661663
16671664	rcu_read_lock_bh ();
1668- 	list_for_each_entry_rcu (tunnel , & pn -> l2tp_tunnel_list , list ) {
1669- 		l2tp_tunnel_delete (tunnel );
1665+ 	idr_for_each_entry_ul (& pn -> l2tp_tunnel_idr , tunnel , tmp , tunnel_id ) {
1666+ 		if  (tunnel )
1667+ 			l2tp_tunnel_delete (tunnel );
16701668	}
16711669	rcu_read_unlock_bh ();
16721670
@@ -1676,6 +1674,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
16761674
16771675	for  (hash  =  0 ; hash  <  L2TP_HASH_SIZE_2 ; hash ++ )
16781676		WARN_ON_ONCE (!hlist_empty (& pn -> l2tp_session_hlist [hash ]));
1677+ 	idr_destroy (& pn -> l2tp_tunnel_idr );
16791678}
16801679
16811680static  struct  pernet_operations  l2tp_net_ops  =  {
0 commit comments