[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <7c3ec1f7c7e4098045d1e42961df8af11619089e.1717087015.git.pabeni@redhat.com>
Date: Thu, 30 May 2024 19:21:01 +0200
From: Paolo Abeni <pabeni@...hat.com>
To: netdev@...r.kernel.org
Cc: "David S. Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
David Ahern <dsahern@...nel.org>,
Jakub Kicinski <kuba@...nel.org>
Subject: [PATCH net-next 1/3] ipv6: use a new flag to indicate elevated refcount.
ip6_pol_route() can return a dst entry with elevated reference count
even when the caller ask for the RT6_LOOKUP_F_DST_NOREF flag.
Currently the caller uses the rt_uncached list entry field to detect
such scenario: the reference is elevated only for entry in the uncached
list.
Soon we are going to insert in the uncached list even entry held by
the dst_cache(s), potentially fooling the above check and causing
reference underflow.
To avoid such issue, introduce and use a new field to mark the entries
with refcount elevated. No functional change intended.
Before:
pahole -EC rt6_info
/* size: 224, cachelines: 4, members: 9 */
/* sum members: 218, holes: 1, sum holes: 4 */
After:
pahole: -EC rt6_info
/* size: 224, cachelines: 4, members: 10 */
/* sum members: 219, holes: 1, sum holes: 4 */
Signed-off-by: Paolo Abeni <pabeni@...hat.com>
---
include/net/ip6_fib.h | 3 +++
net/ipv6/route.c | 4 ++--
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index 6cb867ce4878..eb997af5523c 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -216,6 +216,9 @@ struct rt6_info {
/* more non-fragment space at head required */
unsigned short rt6i_nfheader_len;
+
+ /* route lookup always acquires a reference */
+ bool rt6i_count_held;
};
struct fib6_result {
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index bbc2a0dd9314..3b729ab86c55 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -2251,6 +2251,7 @@ struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table,
* this refcnt is always returned to the caller even
* if caller sets RT6_LOOKUP_F_DST_NOREF flag.
*/
+ rt->rt6i_count_held = true;
rt6_uncached_list_add(rt);
rcu_read_unlock();
@@ -2648,8 +2649,7 @@ struct dst_entry *ip6_route_output_flags(struct net *net,
rcu_read_lock();
dst = ip6_route_output_flags_noref(net, sk, fl6, flags);
rt6 = dst_rt6_info(dst);
- /* For dst cached in uncached_list, refcnt is already taken. */
- if (list_empty(&rt6->dst.rt_uncached) && !dst_hold_safe(dst)) {
+ if (!rt6->rt6i_count_held && !dst_hold_safe(dst)) {
dst = &net->ipv6.ip6_null_entry->dst;
dst_hold(dst);
}
--
2.43.2
Powered by blists - more mailing lists