diff options
author | David S. Miller <davem@davemloft.net> | 2017-06-17 22:54:01 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-06-17 22:54:01 -0400 |
commit | ffe95ecf3a2e060cc95ad8835a71273a4a3b3923 (patch) | |
tree | 84d1cd1b7a6b3990749e2423a6a2a38a2478acd7 /net/decnet/dn_route.c | |
parent | 273889e306256e95ea55d5ebaef99310cf589def (diff) | |
parent | 44ebe79149ff415e810529bf192faa5c38d4a0de (diff) | |
download | blackbird-obmc-linux-ffe95ecf3a2e060cc95ad8835a71273a4a3b3923.tar.gz blackbird-obmc-linux-ffe95ecf3a2e060cc95ad8835a71273a4a3b3923.zip |
Merge branch 'net-remove-dst-garbage-collector-logic'
Wei Wang says:
====================
remove dst garbage collector logic
The current mechanism of dst release is a bit complicated. It is because
the users of dst get divided into 2 situations:
1. Most users take the reference count when using a dst and release the
reference count when done.
2. Exceptional users like IPv4/IPv6/decnet/xfrm routing code do not take
reference count when referencing to a dst due to some histotic reasons.
Due to those exceptional use cases in 2, reference count being 0 is not an
adequate evidence to indicate that no user is using this dst. So users in 1
can't free the dst simply based on reference count being 0 because users in
2 might still hold reference to it.
Instead, a dst garbage list is needed to hold the dst entries that already
get removed by the users in 2 but are still held by users in 1. And a periodic
garbage collector task is run to check all the dst entries in the list to see
if the users in 1 have released the reference to those dst entries.
If so, the dst is now ready to be freed.
This logic introduces unnecessary complications in the dst code which makes it
hard to understand and to debug.
In order to get rid of the whole dst garbage collector (gc) and make the dst
code more unified and simplified, we can make the users in 2 also take reference
count on the dst and release it properly when done.
This way, dst can be safely freed once the refcount drops to 0 and no gc
thread is needed anymore.
This patch series' target is to completely get rid of dst gc logic and free
dst based on reference count only.
Patch 1-3 are preparation patches to do some cleanup/improvement on the existing
code to make later work easier.
Patch 4-21 are real implementations.
In these patches, a temporary flag DST_NOGC is used to help transition
those exceptional users one by one. Once every component is transitioned,
this temporary flag is removed.
By the end of this patch series, all dst are refcounted when being used
and released when done. And dst will be freed when its refcount drops to 0.
No dst gc task is running anymore.
Note: This patch series depends on the decnet fix that was sent right before:
"decnet: always not take dst->__refcnt when inserting dst into hash table"
v2:
add curly braces in udp_v4/6_early_demux() in patch 02
add EXPORT_SYMBOL() for dst_dev_put() in patch 05
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/decnet/dn_route.c')
-rw-r--r-- | net/decnet/dn_route.c | 34 |
1 files changed, 17 insertions, 17 deletions
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 6f95612b4d32..5d17d843ac86 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -183,11 +183,6 @@ static __inline__ unsigned int dn_hash(__le16 src, __le16 dst) return dn_rt_hash_mask & (unsigned int)tmp; } -static inline void dnrt_free(struct dn_route *rt) -{ - call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free); -} - static void dn_dst_check_expire(unsigned long dummy) { int i; @@ -202,14 +197,15 @@ static void dn_dst_check_expire(unsigned long dummy) spin_lock(&dn_rt_hash_table[i].lock); while ((rt = rcu_dereference_protected(*rtp, lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) { - if (atomic_read(&rt->dst.__refcnt) || - (now - rt->dst.lastuse) < expire) { + if (atomic_read(&rt->dst.__refcnt) > 1 || + (now - rt->dst.lastuse) < expire) { rtp = &rt->dst.dn_next; continue; } *rtp = rt->dst.dn_next; rt->dst.dn_next = NULL; - dnrt_free(rt); + dst_dev_put(&rt->dst); + dst_release(&rt->dst); } spin_unlock(&dn_rt_hash_table[i].lock); @@ -235,14 +231,15 @@ static int dn_dst_gc(struct dst_ops *ops) while ((rt = rcu_dereference_protected(*rtp, lockdep_is_held(&dn_rt_hash_table[i].lock))) != NULL) { - if (atomic_read(&rt->dst.__refcnt) || - (now - rt->dst.lastuse) < expire) { + if (atomic_read(&rt->dst.__refcnt) > 1 || + (now - rt->dst.lastuse) < expire) { rtp = &rt->dst.dn_next; continue; } *rtp = rt->dst.dn_next; rt->dst.dn_next = NULL; - dnrt_free(rt); + dst_dev_put(&rt->dst); + dst_release(&rt->dst); break; } spin_unlock_bh(&dn_rt_hash_table[i].lock); @@ -344,7 +341,7 @@ static int dn_insert_route(struct dn_route *rt, unsigned int hash, struct dn_rou dst_use(&rth->dst, now); spin_unlock_bh(&dn_rt_hash_table[hash].lock); - dst_free(&rt->dst); + dst_release_immediate(&rt->dst); *rp = rth; return 0; } @@ -374,7 +371,8 @@ static void dn_run_flush(unsigned long dummy) for(; rt; rt = next) { next = rcu_dereference_raw(rt->dst.dn_next); RCU_INIT_POINTER(rt->dst.dn_next, NULL); - dnrt_free(rt); + dst_dev_put(&rt->dst); + dst_release(&rt->dst); } nothing_to_declare: @@ -1181,7 +1179,7 @@ make_route: if (dev_out->flags & IFF_LOOPBACK) flags |= RTCF_LOCAL; - rt = dst_alloc(&dn_dst_ops, dev_out, 0, DST_OBSOLETE_NONE, DST_HOST); + rt = dst_alloc(&dn_dst_ops, dev_out, 1, DST_OBSOLETE_NONE, DST_HOST); if (rt == NULL) goto e_nobufs; @@ -1215,6 +1213,7 @@ make_route: goto e_neighbour; hash = dn_hash(rt->fld.saddr, rt->fld.daddr); + /* dn_insert_route() increments dst->__refcnt */ dn_insert_route(rt, hash, (struct dn_route **)pprt); done: @@ -1237,7 +1236,7 @@ e_nobufs: err = -ENOBUFS; goto done; e_neighbour: - dst_free(&rt->dst); + dst_release_immediate(&rt->dst); goto e_nobufs; } @@ -1445,7 +1444,7 @@ static int dn_route_input_slow(struct sk_buff *skb) } make_route: - rt = dst_alloc(&dn_dst_ops, out_dev, 0, DST_OBSOLETE_NONE, DST_HOST); + rt = dst_alloc(&dn_dst_ops, out_dev, 1, DST_OBSOLETE_NONE, DST_HOST); if (rt == NULL) goto e_nobufs; @@ -1491,6 +1490,7 @@ make_route: goto e_neighbour; hash = dn_hash(rt->fld.saddr, rt->fld.daddr); + /* dn_insert_route() increments dst->__refcnt */ dn_insert_route(rt, hash, &rt); skb_dst_set(skb, &rt->dst); @@ -1514,7 +1514,7 @@ e_nobufs: goto done; e_neighbour: - dst_free(&rt->dst); + dst_release_immediate(&rt->dst); goto done; } |