@@ -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