@@ -77,8 +77,17 @@ struct sit_net {
77
77
struct net_device * fb_tunnel_dev ;
78
78
};
79
79
80
- static DEFINE_RWLOCK (ipip6_lock );
80
+ /*
81
+ * Locking : hash tables are protected by RCU and a spinlock
82
+ */
83
+ static DEFINE_SPINLOCK (ipip6_lock );
84
+
85
+ #define for_each_ip_tunnel_rcu (start ) \
86
+ for (t = rcu_dereference(start); t; t = rcu_dereference(t->next))
81
87
88
+ /*
89
+ * Must be invoked with rcu_read_lock
90
+ */
82
91
static struct ip_tunnel * ipip6_tunnel_lookup (struct net * net ,
83
92
struct net_device * dev , __be32 remote , __be32 local )
84
93
{
@@ -87,26 +96,26 @@ static struct ip_tunnel * ipip6_tunnel_lookup(struct net *net,
87
96
struct ip_tunnel * t ;
88
97
struct sit_net * sitn = net_generic (net , sit_net_id );
89
98
90
- for ( t = sitn -> tunnels_r_l [h0 ^ h1 ]; t ; t = t -> next ) {
99
+ for_each_ip_tunnel_rcu ( sitn -> tunnels_r_l [h0 ^ h1 ]) {
91
100
if (local == t -> parms .iph .saddr &&
92
101
remote == t -> parms .iph .daddr &&
93
102
(!dev || !t -> parms .link || dev -> iflink == t -> parms .link ) &&
94
103
(t -> dev -> flags & IFF_UP ))
95
104
return t ;
96
105
}
97
- for ( t = sitn -> tunnels_r [h0 ]; t ; t = t -> next ) {
106
+ for_each_ip_tunnel_rcu ( sitn -> tunnels_r [h0 ]) {
98
107
if (remote == t -> parms .iph .daddr &&
99
108
(!dev || !t -> parms .link || dev -> iflink == t -> parms .link ) &&
100
109
(t -> dev -> flags & IFF_UP ))
101
110
return t ;
102
111
}
103
- for ( t = sitn -> tunnels_l [h1 ]; t ; t = t -> next ) {
112
+ for_each_ip_tunnel_rcu ( sitn -> tunnels_l [h1 ]) {
104
113
if (local == t -> parms .iph .saddr &&
105
114
(!dev || !t -> parms .link || dev -> iflink == t -> parms .link ) &&
106
115
(t -> dev -> flags & IFF_UP ))
107
116
return t ;
108
117
}
109
- t = sitn -> tunnels_wc [0 ];
118
+ t = rcu_dereference ( sitn -> tunnels_wc [0 ]) ;
110
119
if ((t != NULL ) && (t -> dev -> flags & IFF_UP ))
111
120
return t ;
112
121
return NULL ;
@@ -143,9 +152,9 @@ static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t)
143
152
144
153
for (tp = ipip6_bucket (sitn , t ); * tp ; tp = & (* tp )-> next ) {
145
154
if (t == * tp ) {
146
- write_lock_bh (& ipip6_lock );
155
+ spin_lock_bh (& ipip6_lock );
147
156
* tp = t -> next ;
148
- write_unlock_bh (& ipip6_lock );
157
+ spin_unlock_bh (& ipip6_lock );
149
158
break ;
150
159
}
151
160
}
@@ -155,10 +164,10 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
155
164
{
156
165
struct ip_tunnel * * tp = ipip6_bucket (sitn , t );
157
166
167
+ spin_lock_bh (& ipip6_lock );
158
168
t -> next = * tp ;
159
- write_lock_bh (& ipip6_lock );
160
- * tp = t ;
161
- write_unlock_bh (& ipip6_lock );
169
+ rcu_assign_pointer (* tp , t );
170
+ spin_unlock_bh (& ipip6_lock );
162
171
}
163
172
164
173
static void ipip6_tunnel_clone_6rd (struct net_device * dev , struct sit_net * sitn )
@@ -447,9 +456,9 @@ static void ipip6_tunnel_uninit(struct net_device *dev)
447
456
struct sit_net * sitn = net_generic (net , sit_net_id );
448
457
449
458
if (dev == sitn -> fb_tunnel_dev ) {
450
- write_lock_bh (& ipip6_lock );
459
+ spin_lock_bh (& ipip6_lock );
451
460
sitn -> tunnels_wc [0 ] = NULL ;
452
- write_unlock_bh (& ipip6_lock );
461
+ spin_unlock_bh (& ipip6_lock );
453
462
dev_put (dev );
454
463
} else {
455
464
ipip6_tunnel_unlink (sitn , netdev_priv (dev ));
@@ -502,7 +511,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
502
511
503
512
err = - ENOENT ;
504
513
505
- read_lock ( & ipip6_lock );
514
+ rcu_read_lock ( );
506
515
t = ipip6_tunnel_lookup (dev_net (skb -> dev ),
507
516
skb -> dev ,
508
517
iph -> daddr ,
@@ -520,7 +529,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
520
529
t -> err_count = 1 ;
521
530
t -> err_time = jiffies ;
522
531
out :
523
- read_unlock ( & ipip6_lock );
532
+ rcu_read_unlock ( );
524
533
return err ;
525
534
}
526
535
@@ -540,7 +549,7 @@ static int ipip6_rcv(struct sk_buff *skb)
540
549
541
550
iph = ip_hdr (skb );
542
551
543
- read_lock ( & ipip6_lock );
552
+ rcu_read_lock ( );
544
553
tunnel = ipip6_tunnel_lookup (dev_net (skb -> dev ), skb -> dev ,
545
554
iph -> saddr , iph -> daddr );
546
555
if (tunnel != NULL ) {
@@ -554,7 +563,7 @@ static int ipip6_rcv(struct sk_buff *skb)
554
563
if ((tunnel -> dev -> priv_flags & IFF_ISATAP ) &&
555
564
!isatap_chksrc (skb , iph , tunnel )) {
556
565
tunnel -> dev -> stats .rx_errors ++ ;
557
- read_unlock ( & ipip6_lock );
566
+ rcu_read_unlock ( );
558
567
kfree_skb (skb );
559
568
return 0 ;
560
569
}
@@ -565,12 +574,12 @@ static int ipip6_rcv(struct sk_buff *skb)
565
574
nf_reset (skb );
566
575
ipip6_ecn_decapsulate (iph , skb );
567
576
netif_rx (skb );
568
- read_unlock ( & ipip6_lock );
577
+ rcu_read_unlock ( );
569
578
return 0 ;
570
579
}
571
580
572
581
icmp_send (skb , ICMP_DEST_UNREACH , ICMP_PORT_UNREACH , 0 );
573
- read_unlock ( & ipip6_lock );
582
+ rcu_read_unlock ( );
574
583
out :
575
584
kfree_skb (skb );
576
585
return 0 ;
0 commit comments