diff options
Diffstat (limited to 'net/core/dst.c')
-rw-r--r-- | net/core/dst.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/net/core/dst.c b/net/core/dst.c index b99c7c7ffce2..578893505702 100644 --- a/net/core/dst.c +++ b/net/core/dst.c | |||
@@ -164,6 +164,8 @@ int dst_discard(struct sk_buff *skb) | |||
164 | } | 164 | } |
165 | EXPORT_SYMBOL(dst_discard); | 165 | EXPORT_SYMBOL(dst_discard); |
166 | 166 | ||
167 | static const u32 dst_default_metrics[RTAX_MAX]; | ||
168 | |||
167 | void *dst_alloc(struct dst_ops *ops) | 169 | void *dst_alloc(struct dst_ops *ops) |
168 | { | 170 | { |
169 | struct dst_entry *dst; | 171 | struct dst_entry *dst; |
@@ -180,6 +182,7 @@ void *dst_alloc(struct dst_ops *ops) | |||
180 | dst->lastuse = jiffies; | 182 | dst->lastuse = jiffies; |
181 | dst->path = dst; | 183 | dst->path = dst; |
182 | dst->input = dst->output = dst_discard; | 184 | dst->input = dst->output = dst_discard; |
185 | dst_init_metrics(dst, dst_default_metrics, true); | ||
183 | #if RT_CACHE_DEBUG >= 2 | 186 | #if RT_CACHE_DEBUG >= 2 |
184 | atomic_inc(&dst_total); | 187 | atomic_inc(&dst_total); |
185 | #endif | 188 | #endif |
@@ -282,6 +285,42 @@ void dst_release(struct dst_entry *dst) | |||
282 | } | 285 | } |
283 | EXPORT_SYMBOL(dst_release); | 286 | EXPORT_SYMBOL(dst_release); |
284 | 287 | ||
288 | u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old) | ||
289 | { | ||
290 | u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); | ||
291 | |||
292 | if (p) { | ||
293 | u32 *old_p = __DST_METRICS_PTR(old); | ||
294 | unsigned long prev, new; | ||
295 | |||
296 | memcpy(p, old_p, sizeof(u32) * RTAX_MAX); | ||
297 | |||
298 | new = (unsigned long) p; | ||
299 | prev = cmpxchg(&dst->_metrics, old, new); | ||
300 | |||
301 | if (prev != old) { | ||
302 | kfree(p); | ||
303 | p = __DST_METRICS_PTR(prev); | ||
304 | if (prev & DST_METRICS_READ_ONLY) | ||
305 | p = NULL; | ||
306 | } | ||
307 | } | ||
308 | return p; | ||
309 | } | ||
310 | EXPORT_SYMBOL(dst_cow_metrics_generic); | ||
311 | |||
312 | /* Caller asserts that dst_metrics_read_only(dst) is false. */ | ||
313 | void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old) | ||
314 | { | ||
315 | unsigned long prev, new; | ||
316 | |||
317 | new = (unsigned long) dst_default_metrics; | ||
318 | prev = cmpxchg(&dst->_metrics, old, new); | ||
319 | if (prev == old) | ||
320 | kfree(__DST_METRICS_PTR(old)); | ||
321 | } | ||
322 | EXPORT_SYMBOL(__dst_destroy_metrics_generic); | ||
323 | |||
285 | /** | 324 | /** |
286 | * skb_dst_set_noref - sets skb dst, without a reference | 325 | * skb_dst_set_noref - sets skb dst, without a reference |
287 | * @skb: buffer | 326 | * @skb: buffer |