@@ -110,11 +110,25 @@ static void mlx5e_rep_neigh_stats_work(struct work_struct *work)
110
110
rtnl_unlock ();
111
111
}
112
112
113
+ struct neigh_update_work {
114
+ struct work_struct work ;
115
+ struct neighbour * n ;
116
+ struct mlx5e_neigh_hash_entry * nhe ;
117
+ };
118
+
119
+ static void mlx5e_release_neigh_update_work (struct neigh_update_work * update_work )
120
+ {
121
+ neigh_release (update_work -> n );
122
+ mlx5e_rep_neigh_entry_release (update_work -> nhe );
123
+ kfree (update_work );
124
+ }
125
+
113
126
static void mlx5e_rep_neigh_update (struct work_struct * work )
114
127
{
115
- struct mlx5e_neigh_hash_entry * nhe =
116
- container_of (work , struct mlx5e_neigh_hash_entry , neigh_update_work );
117
- struct neighbour * n = nhe -> n ;
128
+ struct neigh_update_work * update_work = container_of (work , struct neigh_update_work ,
129
+ work );
130
+ struct mlx5e_neigh_hash_entry * nhe = update_work -> nhe ;
131
+ struct neighbour * n = update_work -> n ;
118
132
struct mlx5e_encap_entry * e ;
119
133
unsigned char ha [ETH_ALEN ];
120
134
struct mlx5e_priv * priv ;
@@ -146,30 +160,42 @@ static void mlx5e_rep_neigh_update(struct work_struct *work)
146
160
mlx5e_rep_update_flows (priv , e , neigh_connected , ha );
147
161
mlx5e_encap_put (priv , e );
148
162
}
149
- mlx5e_rep_neigh_entry_release (nhe );
150
163
rtnl_unlock ();
151
- neigh_release ( n );
164
+ mlx5e_release_neigh_update_work ( update_work );
152
165
}
153
166
154
- static void mlx5e_rep_queue_neigh_update_work (struct mlx5e_priv * priv ,
155
- struct mlx5e_neigh_hash_entry * nhe ,
156
- struct neighbour * n )
167
+ static struct neigh_update_work * mlx5e_alloc_neigh_update_work (struct mlx5e_priv * priv ,
168
+ struct neighbour * n )
157
169
{
158
- /* Take a reference to ensure the neighbour and mlx5 encap
159
- * entry won't be destructed until we drop the reference in
160
- * delayed work.
161
- */
162
- neigh_hold (n );
170
+ struct neigh_update_work * update_work ;
171
+ struct mlx5e_neigh_hash_entry * nhe ;
172
+ struct mlx5e_neigh m_neigh = {};
163
173
164
- /* This assignment is valid as long as the the neigh reference
165
- * is taken
166
- */
167
- nhe -> n = n ;
174
+ update_work = kzalloc (sizeof (* update_work ), GFP_ATOMIC );
175
+ if (WARN_ON (!update_work ))
176
+ return NULL ;
168
177
169
- if (!queue_work (priv -> wq , & nhe -> neigh_update_work )) {
170
- mlx5e_rep_neigh_entry_release (nhe );
171
- neigh_release (n );
178
+ m_neigh .dev = n -> dev ;
179
+ m_neigh .family = n -> ops -> family ;
180
+ memcpy (& m_neigh .dst_ip , n -> primary_key , n -> tbl -> key_len );
181
+
182
+ /* Obtain reference to nhe as last step in order not to release it in
183
+ * atomic context.
184
+ */
185
+ rcu_read_lock ();
186
+ nhe = mlx5e_rep_neigh_entry_lookup (priv , & m_neigh );
187
+ rcu_read_unlock ();
188
+ if (!nhe ) {
189
+ kfree (update_work );
190
+ return NULL ;
172
191
}
192
+
193
+ INIT_WORK (& update_work -> work , mlx5e_rep_neigh_update );
194
+ neigh_hold (n );
195
+ update_work -> n = n ;
196
+ update_work -> nhe = nhe ;
197
+
198
+ return update_work ;
173
199
}
174
200
175
201
static int mlx5e_rep_netevent_event (struct notifier_block * nb ,
@@ -181,7 +207,7 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
181
207
struct net_device * netdev = rpriv -> netdev ;
182
208
struct mlx5e_priv * priv = netdev_priv (netdev );
183
209
struct mlx5e_neigh_hash_entry * nhe = NULL ;
184
- struct mlx5e_neigh m_neigh = {} ;
210
+ struct neigh_update_work * update_work ;
185
211
struct neigh_parms * p ;
186
212
struct neighbour * n ;
187
213
bool found = false;
@@ -196,17 +222,11 @@ static int mlx5e_rep_netevent_event(struct notifier_block *nb,
196
222
#endif
197
223
return NOTIFY_DONE ;
198
224
199
- m_neigh .dev = n -> dev ;
200
- m_neigh .family = n -> ops -> family ;
201
- memcpy (& m_neigh .dst_ip , n -> primary_key , n -> tbl -> key_len );
202
-
203
- rcu_read_lock ();
204
- nhe = mlx5e_rep_neigh_entry_lookup (priv , & m_neigh );
205
- rcu_read_unlock ();
206
- if (!nhe )
225
+ update_work = mlx5e_alloc_neigh_update_work (priv , n );
226
+ if (!update_work )
207
227
return NOTIFY_DONE ;
208
228
209
- mlx5e_rep_queue_neigh_update_work (priv , nhe , n );
229
+ queue_work (priv -> wq , & update_work -> work );
210
230
break ;
211
231
212
232
case NETEVENT_DELAY_PROBE_TIME_UPDATE :
@@ -352,7 +372,6 @@ int mlx5e_rep_neigh_entry_create(struct mlx5e_priv *priv,
352
372
353
373
(* nhe )-> priv = priv ;
354
374
memcpy (& (* nhe )-> m_neigh , & e -> m_neigh , sizeof (e -> m_neigh ));
355
- INIT_WORK (& (* nhe )-> neigh_update_work , mlx5e_rep_neigh_update );
356
375
spin_lock_init (& (* nhe )-> encap_list_lock );
357
376
INIT_LIST_HEAD (& (* nhe )-> encap_list );
358
377
refcount_set (& (* nhe )-> refcnt , 1 );
0 commit comments