@@ -1007,27 +1007,39 @@ static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt)
1007
1007
1008
1008
static struct rt6_info * rt6_make_pcpu_route (struct rt6_info * rt )
1009
1009
{
1010
+ struct fib6_table * table = rt -> rt6i_table ;
1010
1011
struct rt6_info * pcpu_rt , * prev , * * p ;
1011
1012
1012
1013
pcpu_rt = ip6_rt_pcpu_alloc (rt );
1013
1014
if (!pcpu_rt ) {
1014
1015
struct net * net = dev_net (rt -> dst .dev );
1015
1016
1016
- pcpu_rt = net -> ipv6 .ip6_null_entry ;
1017
- goto done ;
1017
+ dst_hold ( & net -> ipv6 .ip6_null_entry -> dst ) ;
1018
+ return net -> ipv6 . ip6_null_entry ;
1018
1019
}
1019
1020
1020
- p = this_cpu_ptr (rt -> rt6i_pcpu );
1021
- prev = cmpxchg (p , NULL , pcpu_rt );
1022
- if (prev ) {
1023
- /* If someone did it before us, return prev instead */
1021
+ read_lock_bh (& table -> tb6_lock );
1022
+ if (rt -> rt6i_pcpu ) {
1023
+ p = this_cpu_ptr (rt -> rt6i_pcpu );
1024
+ prev = cmpxchg (p , NULL , pcpu_rt );
1025
+ if (prev ) {
1026
+ /* If someone did it before us, return prev instead */
1027
+ dst_destroy (& pcpu_rt -> dst );
1028
+ pcpu_rt = prev ;
1029
+ }
1030
+ } else {
1031
+ /* rt has been removed from the fib6 tree
1032
+ * before we have a chance to acquire the read_lock.
1033
+ * In this case, don't brother to create a pcpu rt
1034
+ * since rt is going away anyway. The next
1035
+ * dst_check() will trigger a re-lookup.
1036
+ */
1024
1037
dst_destroy (& pcpu_rt -> dst );
1025
- pcpu_rt = prev ;
1038
+ pcpu_rt = rt ;
1026
1039
}
1027
-
1028
- done :
1029
1040
dst_hold (& pcpu_rt -> dst );
1030
1041
rt6_dst_from_metrics_check (pcpu_rt );
1042
+ read_unlock_bh (& table -> tb6_lock );
1031
1043
return pcpu_rt ;
1032
1044
}
1033
1045
@@ -1103,11 +1115,21 @@ static struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
1103
1115
rt -> dst .__use ++ ;
1104
1116
pcpu_rt = rt6_get_pcpu_route (rt );
1105
1117
1106
- if (!pcpu_rt )
1118
+ if (pcpu_rt ) {
1119
+ read_unlock_bh (& table -> tb6_lock );
1120
+ } else {
1121
+ /* We have to do the read_unlock first
1122
+ * because rt6_make_pcpu_route() may trigger
1123
+ * ip6_dst_gc() which will take the write_lock.
1124
+ */
1125
+ dst_hold (& rt -> dst );
1126
+ read_unlock_bh (& table -> tb6_lock );
1107
1127
pcpu_rt = rt6_make_pcpu_route (rt );
1128
+ dst_release (& rt -> dst );
1129
+ }
1108
1130
1109
- read_unlock_bh (& table -> tb6_lock );
1110
1131
return pcpu_rt ;
1132
+
1111
1133
}
1112
1134
}
1113
1135
0 commit comments