Skip to content

Commit 76371d2

Browse files
tracywwnjdavem330
authored andcommitted
decnet: always not take dst->__refcnt when inserting dst into hash table
In the existing dn_route.c code, dn_route_output_slow() takes dst->__refcnt before calling dn_insert_route() while dn_route_input_slow() does not take dst->__refcnt before calling dn_insert_route(). This makes the whole routing code very buggy. In dn_dst_check_expire(), dnrt_free() is called when rt expires. This makes the routes inserted by dn_route_output_slow() not able to be freed as the refcnt is not released. In dn_dst_gc(), dnrt_drop() is called to release rt which could potentially cause the dst->__refcnt to be dropped to -1. In dn_run_flush(), dst_free() is called to release all the dst. Again, it makes the dst inserted by dn_route_output_slow() not able to be released and also, it does not wait on the rcu and could potentially cause crash in the path where other users still refer to this dst. This patch makes sure both input and output path do not take dst->__refcnt before calling dn_insert_route() and also makes sure dnrt_free()/dst_free() is called when removing dst from the hash table. The only difference between those 2 calls is that dnrt_free() waits on the rcu while dst_free() does not. Signed-off-by: Wei Wang <[email protected]> Acked-by: Martin KaFai Lau <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f1925ca commit 76371d2

File tree

1 file changed

+4
-10
lines changed

1 file changed

+4
-10
lines changed

net/decnet/dn_route.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -188,12 +188,6 @@ static inline void dnrt_free(struct dn_route *rt)
188188
call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
189189
}
190190

191-
static inline void dnrt_drop(struct dn_route *rt)
192-
{
193-
dst_release(&rt->dst);
194-
call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
195-
}
196-
197191
static void dn_dst_check_expire(unsigned long dummy)
198192
{
199193
int i;
@@ -248,7 +242,7 @@ static int dn_dst_gc(struct dst_ops *ops)
248242
}
249243
*rtp = rt->dst.dn_next;
250244
rt->dst.dn_next = NULL;
251-
dnrt_drop(rt);
245+
dnrt_free(rt);
252246
break;
253247
}
254248
spin_unlock_bh(&dn_rt_hash_table[i].lock);
@@ -350,7 +344,7 @@ static int dn_insert_route(struct dn_route *rt, unsigned int hash, struct dn_rou
350344
dst_use(&rth->dst, now);
351345
spin_unlock_bh(&dn_rt_hash_table[hash].lock);
352346

353-
dnrt_drop(rt);
347+
dst_free(&rt->dst);
354348
*rp = rth;
355349
return 0;
356350
}
@@ -380,7 +374,7 @@ static void dn_run_flush(unsigned long dummy)
380374
for(; rt; rt = next) {
381375
next = rcu_dereference_raw(rt->dst.dn_next);
382376
RCU_INIT_POINTER(rt->dst.dn_next, NULL);
383-
dst_free((struct dst_entry *)rt);
377+
dnrt_free(rt);
384378
}
385379

386380
nothing_to_declare:
@@ -1187,7 +1181,7 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowidn *o
11871181
if (dev_out->flags & IFF_LOOPBACK)
11881182
flags |= RTCF_LOCAL;
11891183

1190-
rt = dst_alloc(&dn_dst_ops, dev_out, 1, DST_OBSOLETE_NONE, DST_HOST);
1184+
rt = dst_alloc(&dn_dst_ops, dev_out, 0, DST_OBSOLETE_NONE, DST_HOST);
11911185
if (rt == NULL)
11921186
goto e_nobufs;
11931187

0 commit comments

Comments
 (0)