aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/dst.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dst.c')
-rw-r--r--net/core/dst.c25
1 files changed, 4 insertions, 21 deletions
diff --git a/net/core/dst.c b/net/core/dst.c
index 43d94cedbf7c..069d51d29414 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -94,7 +94,7 @@ loop:
94 * But we do not have state "obsoleted, but 94 * But we do not have state "obsoleted, but
95 * referenced by parent", so it is right. 95 * referenced by parent", so it is right.
96 */ 96 */
97 if (dst->obsolete > 1) 97 if (dst->obsolete > 0)
98 continue; 98 continue;
99 99
100 ___dst_free(dst); 100 ___dst_free(dst);
@@ -152,7 +152,7 @@ EXPORT_SYMBOL(dst_discard);
152const u32 dst_default_metrics[RTAX_MAX]; 152const u32 dst_default_metrics[RTAX_MAX];
153 153
154void *dst_alloc(struct dst_ops *ops, struct net_device *dev, 154void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
155 int initial_ref, int initial_obsolete, int flags) 155 int initial_ref, int initial_obsolete, unsigned short flags)
156{ 156{
157 struct dst_entry *dst; 157 struct dst_entry *dst;
158 158
@@ -171,7 +171,6 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
171 dst_init_metrics(dst, dst_default_metrics, true); 171 dst_init_metrics(dst, dst_default_metrics, true);
172 dst->expires = 0UL; 172 dst->expires = 0UL;
173 dst->path = dst; 173 dst->path = dst;
174 RCU_INIT_POINTER(dst->_neighbour, NULL);
175#ifdef CONFIG_XFRM 174#ifdef CONFIG_XFRM
176 dst->xfrm = NULL; 175 dst->xfrm = NULL;
177#endif 176#endif
@@ -188,6 +187,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
188 dst->__use = 0; 187 dst->__use = 0;
189 dst->lastuse = jiffies; 188 dst->lastuse = jiffies;
190 dst->flags = flags; 189 dst->flags = flags;
190 dst->pending_confirm = 0;
191 dst->next = NULL; 191 dst->next = NULL;
192 if (!(flags & DST_NOCOUNT)) 192 if (!(flags & DST_NOCOUNT))
193 dst_entries_add(ops, 1); 193 dst_entries_add(ops, 1);
@@ -202,7 +202,7 @@ static void ___dst_free(struct dst_entry *dst)
202 */ 202 */
203 if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) 203 if (dst->dev == NULL || !(dst->dev->flags&IFF_UP))
204 dst->input = dst->output = dst_discard; 204 dst->input = dst->output = dst_discard;
205 dst->obsolete = 2; 205 dst->obsolete = DST_OBSOLETE_DEAD;
206} 206}
207 207
208void __dst_free(struct dst_entry *dst) 208void __dst_free(struct dst_entry *dst)
@@ -224,19 +224,12 @@ EXPORT_SYMBOL(__dst_free);
224struct dst_entry *dst_destroy(struct dst_entry * dst) 224struct dst_entry *dst_destroy(struct dst_entry * dst)
225{ 225{
226 struct dst_entry *child; 226 struct dst_entry *child;
227 struct neighbour *neigh;
228 227
229 smp_rmb(); 228 smp_rmb();
230 229
231again: 230again:
232 neigh = rcu_dereference_protected(dst->_neighbour, 1);
233 child = dst->child; 231 child = dst->child;
234 232
235 if (neigh) {
236 RCU_INIT_POINTER(dst->_neighbour, NULL);
237 neigh_release(neigh);
238 }
239
240 if (!(dst->flags & DST_NOCOUNT)) 233 if (!(dst->flags & DST_NOCOUNT))
241 dst_entries_add(dst->ops, -1); 234 dst_entries_add(dst->ops, -1);
242 235
@@ -360,19 +353,9 @@ static void dst_ifdown(struct dst_entry *dst, struct net_device *dev,
360 if (!unregister) { 353 if (!unregister) {
361 dst->input = dst->output = dst_discard; 354 dst->input = dst->output = dst_discard;
362 } else { 355 } else {
363 struct neighbour *neigh;
364
365 dst->dev = dev_net(dst->dev)->loopback_dev; 356 dst->dev = dev_net(dst->dev)->loopback_dev;
366 dev_hold(dst->dev); 357 dev_hold(dst->dev);
367 dev_put(dev); 358 dev_put(dev);
368 rcu_read_lock();
369 neigh = dst_get_neighbour_noref(dst);
370 if (neigh && neigh->dev == dev) {
371 neigh->dev = dst->dev;
372 dev_hold(dst->dev);
373 dev_put(dev);
374 }
375 rcu_read_unlock();
376 } 359 }
377} 360}
378 361