From patchwork Mon Feb 6 14:17:57 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 724526 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id 3vH8lr02sWz9s1y; Tue, 7 Feb 2017 01:21:12 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical-com.20150623.gappssmtp.com header.i=@canonical-com.20150623.gappssmtp.com header.b="0fz3VMG3"; dkim-atps=neutral Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1cakAG-000584-Pv; Mon, 06 Feb 2017 14:21:08 +0000 Received: from mail-io0-f174.google.com ([209.85.223.174]) by huckleberry.canonical.com with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1cakA7-000568-5v for kernel-team@lists.ubuntu.com; Mon, 06 Feb 2017 14:20:59 +0000 Received: by mail-io0-f174.google.com with SMTP id j13so66270084iod.3 for ; Mon, 06 Feb 2017 06:20:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical-com.20150623.gappssmtp.com; s=20150623; h=from:to:subject:date:message-id:in-reply-to:references; bh=HmfpVFKJFVVxqJ86mFUpJM8AfWAPepSfQus0YwZfbdg=; b=0fz3VMG3Dl3Ohrx8T2fiCkDOyeSuSAa/JFrRPQ5Jn3sJFrDHThBM8qCvnMkbCkKcYg Jrg0c6IosctD+b217a5GB42MAu0aDwOkRw/RGS74HHe0Ztfiv15g19AkAyYfJTNShmyj iOvwcL0lKUfFNbX9wGS6sAYW3XA6HbRkcxMx1kBbfj+xM1ldlVmMkGU3efQNZ86fo3Ly MDvkj3y+PxtnOpdCa5vjXAUHOdLqpz4JWJbkJSWM1TGAAOB9pbIpCbQC5EfRyTnynDRN h8Jkc/CGE0MvZ9+8m5fgTgeX8mduJafTpnH3bi/j5Bm7O8v2ajxBu+fYyfBhhI4kNm6/ edZw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=HmfpVFKJFVVxqJ86mFUpJM8AfWAPepSfQus0YwZfbdg=; b=nntDRTn10JsPUTr/SM/jFJSsIpALMgzT4VuRLfKqbA7ZtG8X/VfklavmpxxTahte+K k8CxpPT3xp+Cyiq085WAgyc80BpURG/oDeoIT76XAnOuEca0vJXBB6cLHRHVctVvytH0 1mMobjJp1wFZFcTeV55eZYWPJSm9PtZmdyE2+pmAc/vZFslESOAHLoZVadpr93ZCZDkN fELZGI14egDMrhGJhmCKQhWR3pEJ03VkPBO0b2tkPqjX2nM0mX5wRJY+gUTGK4J7X9NZ c+eLsxyGVWtgxGUS/ptqoE79cJw9NnRCvLveKGELr1t56D6uLnQWCiGFBAtIG8Sdmyv2 bp3Q== X-Gm-Message-State: AMke39mMchTAmC8iX3QwXFzaDpqS15vKH+6rxZTnMby6U549Ky9DiRDBYEWVGic9gHbyvFX/ X-Received: by 10.107.185.65 with SMTP id j62mr6687175iof.3.1486390857788; Mon, 06 Feb 2017 06:20:57 -0800 (PST) Received: from localhost.localdomain (host-98-127-250-84.bln-mt.client.bresnan.net. [98.127.250.84]) by smtp.gmail.com with ESMTPSA id z42sm4307104ita.6.2017.02.06.06.20.57 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 06 Feb 2017 06:20:57 -0800 (PST) From: Tim Gardner To: kernel-team@lists.ubuntu.com Subject: [PATCH 3/3] ipv6: Avoid double dst_free Date: Mon, 6 Feb 2017 07:17:57 -0700 Message-Id: <1486390677-20555-4-git-send-email-tim.gardner@canonical.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1486390677-20555-1-git-send-email-tim.gardner@canonical.com> References: <1486390677-20555-1-git-send-email-tim.gardner@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com From: Martin KaFai Lau BugLink: http://bugs.launchpad.net/bugs/1662096 It is a prep work to get dst freeing from fib tree undergo a rcu grace period. The following is a common paradigm: if (ip6_del_rt(rt)) dst_free(rt) which means, if rt cannot be deleted from the fib tree, dst_free(rt) now. 1. We don't know the ip6_del_rt(rt) failure is because it was not managed by fib tree (e.g. DST_NOCACHE) or it had already been removed from the fib tree. 2. If rt had been managed by the fib tree, ip6_del_rt(rt) failure means dst_free(rt) has been called already. A second dst_free(rt) is not always obviously safe. The rt may have been destroyed already. 3. If rt is a DST_NOCACHE, dst_free(rt) should not be called. 4. It is a stopper to make dst freeing from fib tree undergo a rcu grace period. This patch is to use a DST_NOCACHE flag to indicate a rt is not managed by the fib tree. Signed-off-by: Martin KaFai Lau Signed-off-by: David S. Miller (back ported from commit 8e3d5be7368107f0c27a1f8126d79b01a47e9567) Signed-off-by: Tim Gardner Conflicts: net/ipv6/ip6_fib.c --- net/ipv6/addrconf.c | 7 +++---- net/ipv6/ip6_fib.c | 11 +++++++++-- net/ipv6/route.c | 7 ++++--- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 6a7e788..3ec69a5 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4578,13 +4578,12 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) rt = addrconf_get_prefix_route(&ifp->peer_addr, 128, ifp->idev->dev, 0, 0); - if (rt && ip6_del_rt(rt)) - dst_free(&rt->dst); + if (rt) + ip6_del_rt(rt); } dst_hold(&ifp->rt->dst); - if (ip6_del_rt(ifp->rt)) - dst_free(&ifp->rt->dst); + ip6_del_rt(ifp->rt); rt_genid_bump_ipv6(net); break; diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index c93b060..f29d70c 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -872,6 +872,10 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) int allow_create = 1; int replace_required = 0; + if (WARN_ON_ONCE((rt->dst.flags & DST_NOCACHE) && + !atomic_read(&rt->dst.__refcnt))) + return -EINVAL; + if (info->nlh) { if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) allow_create = 0; @@ -964,6 +968,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) fib6_start_gc(info->nl_net, rt); if (!(rt->rt6i_flags & RTF_CACHE)) fib6_prune_clones(info->nl_net, pn, rt); + rt->dst.flags &= ~DST_NOCACHE; } out: @@ -988,7 +993,8 @@ out: atomic_inc(&pn->leaf->rt6i_ref); } #endif - dst_free(&rt->dst); + if (!(rt->dst.flags & DST_NOCACHE)) + dst_free(&rt->dst); } return err; @@ -999,7 +1005,8 @@ out: st_failure: if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) fib6_repair_tree(info->nl_net, fn); - dst_free(&rt->dst); + if (!(rt->dst.flags & DST_NOCACHE)) + dst_free(&rt->dst); return err; #endif } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 11f6f8b..9091b32 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1120,8 +1120,7 @@ static void ip6_link_failure(struct sk_buff *skb) if (rt) { if (rt->rt6i_flags & RTF_CACHE) { dst_hold(&rt->dst); - if (ip6_del_rt(rt)) - dst_free(&rt->dst); + ip6_del_rt(rt); } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) { rt->rt6i_node->fn_sernum = -1; } @@ -1690,7 +1689,8 @@ static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) struct fib6_table *table; struct net *net = dev_net(rt->dst.dev); - if (rt == net->ipv6.ip6_null_entry) { + if (rt == net->ipv6.ip6_null_entry || + rt->dst.flags & DST_NOCACHE) { err = -ENOENT; goto out; } @@ -2180,6 +2180,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, rt->rt6i_dst.addr = *addr; rt->rt6i_dst.plen = 128; rt->rt6i_table = fib6_get_table(net, RT6_TABLE_LOCAL); + rt->dst.flags |= DST_NOCACHE; atomic_set(&rt->dst.__refcnt, 1);