@@ -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 ;
@@ -1229,14 +1227,22 @@ static void l2tp_udp_encap_destroy(struct sock *sk)
12291227 l2tp_tunnel_delete (tunnel );
12301228}
12311229
1230+ static void l2tp_tunnel_remove (struct net * net , struct l2tp_tunnel * tunnel )
1231+ {
1232+ struct l2tp_net * pn = l2tp_pernet (net );
1233+
1234+ spin_lock_bh (& pn -> l2tp_tunnel_idr_lock );
1235+ idr_remove (& pn -> l2tp_tunnel_idr , tunnel -> tunnel_id );
1236+ spin_unlock_bh (& pn -> l2tp_tunnel_idr_lock );
1237+ }
1238+
12321239/* Workqueue tunnel deletion function */
12331240static void l2tp_tunnel_del_work (struct work_struct * work )
12341241{
12351242 struct l2tp_tunnel * tunnel = container_of (work , struct l2tp_tunnel ,
12361243 del_work );
12371244 struct sock * sk = tunnel -> sock ;
12381245 struct socket * sock = sk -> sk_socket ;
1239- struct l2tp_net * pn ;
12401246
12411247 l2tp_tunnel_closeall (tunnel );
12421248
@@ -1250,12 +1256,7 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
12501256 }
12511257 }
12521258
1253- /* Remove the tunnel struct from the tunnel list */
1254- pn = l2tp_pernet (tunnel -> l2tp_net );
1255- spin_lock_bh (& pn -> l2tp_tunnel_list_lock );
1256- list_del_rcu (& tunnel -> list );
1257- spin_unlock_bh (& pn -> l2tp_tunnel_list_lock );
1258-
1259+ l2tp_tunnel_remove (tunnel -> l2tp_net , tunnel );
12591260 /* drop initial ref */
12601261 l2tp_tunnel_dec_refcount (tunnel );
12611262
@@ -1457,12 +1458,19 @@ static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
14571458int l2tp_tunnel_register (struct l2tp_tunnel * tunnel , struct net * net ,
14581459 struct l2tp_tunnel_cfg * cfg )
14591460{
1460- struct l2tp_tunnel * tunnel_walk ;
1461- struct l2tp_net * pn ;
1461+ struct l2tp_net * pn = l2tp_pernet ( net ) ;
1462+ u32 tunnel_id = tunnel -> tunnel_id ;
14621463 struct socket * sock ;
14631464 struct sock * sk ;
14641465 int ret ;
14651466
1467+ spin_lock_bh (& pn -> l2tp_tunnel_idr_lock );
1468+ ret = idr_alloc_u32 (& pn -> l2tp_tunnel_idr , NULL , & tunnel_id , tunnel_id ,
1469+ GFP_ATOMIC );
1470+ spin_unlock_bh (& pn -> l2tp_tunnel_idr_lock );
1471+ if (ret )
1472+ return ret == - ENOSPC ? - EEXIST : ret ;
1473+
14661474 if (tunnel -> fd < 0 ) {
14671475 ret = l2tp_tunnel_sock_create (net , tunnel -> tunnel_id ,
14681476 tunnel -> peer_tunnel_id , cfg ,
@@ -1483,23 +1491,13 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
14831491 rcu_assign_sk_user_data (sk , tunnel );
14841492 write_unlock_bh (& sk -> sk_callback_lock );
14851493
1486- tunnel -> l2tp_net = net ;
1487- pn = l2tp_pernet (net );
1488-
14891494 sock_hold (sk );
14901495 tunnel -> sock = sk ;
1496+ tunnel -> l2tp_net = net ;
14911497
1492- spin_lock_bh (& pn -> l2tp_tunnel_list_lock );
1493- list_for_each_entry (tunnel_walk , & pn -> l2tp_tunnel_list , list ) {
1494- if (tunnel_walk -> tunnel_id == tunnel -> tunnel_id ) {
1495- spin_unlock_bh (& pn -> l2tp_tunnel_list_lock );
1496- sock_put (sk );
1497- ret = - EEXIST ;
1498- goto err_sock ;
1499- }
1500- }
1501- list_add_rcu (& tunnel -> list , & pn -> l2tp_tunnel_list );
1502- spin_unlock_bh (& pn -> l2tp_tunnel_list_lock );
1498+ spin_lock_bh (& pn -> l2tp_tunnel_idr_lock );
1499+ idr_replace (& pn -> l2tp_tunnel_idr , tunnel , tunnel -> tunnel_id );
1500+ spin_unlock_bh (& pn -> l2tp_tunnel_idr_lock );
15031501
15041502 if (tunnel -> encap == L2TP_ENCAPTYPE_UDP ) {
15051503 struct udp_tunnel_sock_cfg udp_cfg = {
@@ -1525,9 +1523,6 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15251523
15261524 return 0 ;
15271525
1528- err_sock :
1529- write_lock_bh (& sk -> sk_callback_lock );
1530- rcu_assign_sk_user_data (sk , NULL );
15311526err_inval_sock :
15321527 write_unlock_bh (& sk -> sk_callback_lock );
15331528
@@ -1536,6 +1531,7 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
15361531 else
15371532 sockfd_put (sock );
15381533err :
1534+ l2tp_tunnel_remove (net , tunnel );
15391535 return ret ;
15401536}
15411537EXPORT_SYMBOL_GPL (l2tp_tunnel_register );
@@ -1649,8 +1645,8 @@ static __net_init int l2tp_init_net(struct net *net)
16491645 struct l2tp_net * pn = net_generic (net , l2tp_net_id );
16501646 int hash ;
16511647
1652- INIT_LIST_HEAD (& pn -> l2tp_tunnel_list );
1653- spin_lock_init (& pn -> l2tp_tunnel_list_lock );
1648+ idr_init (& pn -> l2tp_tunnel_idr );
1649+ spin_lock_init (& pn -> l2tp_tunnel_idr_lock );
16541650
16551651 for (hash = 0 ; hash < L2TP_HASH_SIZE_2 ; hash ++ )
16561652 INIT_HLIST_HEAD (& pn -> l2tp_session_hlist [hash ]);
@@ -1664,11 +1660,13 @@ static __net_exit void l2tp_exit_net(struct net *net)
16641660{
16651661 struct l2tp_net * pn = l2tp_pernet (net );
16661662 struct l2tp_tunnel * tunnel = NULL ;
1663+ unsigned long tunnel_id , tmp ;
16671664 int hash ;
16681665
16691666 rcu_read_lock_bh ();
1670- list_for_each_entry_rcu (tunnel , & pn -> l2tp_tunnel_list , list ) {
1671- l2tp_tunnel_delete (tunnel );
1667+ idr_for_each_entry_ul (& pn -> l2tp_tunnel_idr , tunnel , tmp , tunnel_id ) {
1668+ if (tunnel )
1669+ l2tp_tunnel_delete (tunnel );
16721670 }
16731671 rcu_read_unlock_bh ();
16741672
@@ -1678,6 +1676,7 @@ static __net_exit void l2tp_exit_net(struct net *net)
16781676
16791677 for (hash = 0 ; hash < L2TP_HASH_SIZE_2 ; hash ++ )
16801678 WARN_ON_ONCE (!hlist_empty (& pn -> l2tp_session_hlist [hash ]));
1679+ idr_destroy (& pn -> l2tp_tunnel_idr );
16811680}
16821681
16831682static struct pernet_operations l2tp_net_ops = {
0 commit comments