[SRU][Artful][PATCH 0/2][v3] Fixes for LP:1746474

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[SRU][Artful][PATCH 0/2][v3] Fixes for LP:1746474

Joseph Salisbury-3
BugLink: http://bugs.launchpad.net/bugs/1746474

== SRU Justification ==
Commit 52df157f17e5 introduced a regression in v4.13-rc1.  This regression
causes a stack trace to occur when tearing down an LXD container.  The process
hangs with the following message:

"unregister_netdevice: waiting for eth0 to become free. Usage count = 5"

This regression is fixed by commit 510c321b5571, which is in mainline as of
v4.16-rc7.  The fix is needed in Artful and Bionic.  However, Artful needs
commit 9620fef27ed2 as a prereq commit, so it's SRU request es beinsss sent separately.


== Fixes ==
9620fef27ed2 ("ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t")
510c321b5571 ("xfrm: reuse uncached_list to track xdsts")

== Regression Potential ==
Low.  This commit is to fix a current regression.

== Test Case ==
A test kernel was built with these patches and tested by the original bug reporter.
The bug reporter states the test kernel resolved the bug.



Eric Dumazet (1):
  ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t

Xin Long (1):
  xfrm: reuse uncached_list to track xdsts

 include/net/dst.h        |  3 ++-
 include/net/ip6_route.h  |  2 ++
 include/net/route.h      |  3 +++
 net/core/dst.c           |  6 +++---
 net/ipv4/fib_semantics.c |  4 ++--
 net/ipv4/route.c         | 23 ++++++++++++++---------
 net/ipv4/xfrm4_policy.c  |  4 +++-
 net/ipv6/route.c         |  4 ++--
 net/ipv6/xfrm6_policy.c  |  4 ++++
 9 files changed, 35 insertions(+), 18 deletions(-)

--
2.7.4


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[SRU][Artful][PATCH 1/2][v3] ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t

Joseph Salisbury-3
From: Eric Dumazet <[hidden email]>

BugLink: http://bugs.launchpad.net/bugs/1746474

refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.

Signed-off-by: Eric Dumazet <[hidden email]>
Signed-off-by: David S. Miller <[hidden email]>
(cherry picked from commit 9620fef27ed2cdb37bf6fd028f32bea2ef5119a8)
Signed-off-by: Joseph Salisbury <[hidden email]>
---
 include/net/dst.h        | 3 ++-
 net/core/dst.c           | 6 +++---
 net/ipv4/fib_semantics.c | 4 ++--
 net/ipv4/route.c         | 4 ++--
 4 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/include/net/dst.h b/include/net/dst.h
index f73611e..93568bd 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -14,6 +14,7 @@
 #include <linux/rcupdate.h>
 #include <linux/bug.h>
 #include <linux/jiffies.h>
+#include <linux/refcount.h>
 #include <net/neighbour.h>
 #include <asm/processor.h>
 
@@ -107,7 +108,7 @@ struct dst_entry {
 
 struct dst_metrics {
  u32 metrics[RTAX_MAX];
- atomic_t refcnt;
+ refcount_t refcnt;
 };
 extern const struct dst_metrics dst_default_metrics;
 
diff --git a/net/core/dst.c b/net/core/dst.c
index 00aa972..d6ead75 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -55,7 +55,7 @@ const struct dst_metrics dst_default_metrics = {
  * We really want to avoid false sharing on this variable, and catch
  * any writes on it.
  */
- .refcnt = ATOMIC_INIT(1),
+ .refcnt = REFCOUNT_INIT(1),
 };
 
 void dst_init(struct dst_entry *dst, struct dst_ops *ops,
@@ -213,7 +213,7 @@ u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
  struct dst_metrics *old_p = (struct dst_metrics *)__DST_METRICS_PTR(old);
  unsigned long prev, new;
 
- atomic_set(&p->refcnt, 1);
+ refcount_set(&p->refcnt, 1);
  memcpy(p->metrics, old_p->metrics, sizeof(p->metrics));
 
  new = (unsigned long) p;
@@ -225,7 +225,7 @@ u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
  if (prev & DST_METRICS_READ_ONLY)
  p = NULL;
  } else if (prev & DST_METRICS_REFCOUNTED) {
- if (atomic_dec_and_test(&old_p->refcnt))
+ if (refcount_dec_and_test(&old_p->refcnt))
  kfree(old_p);
  }
  }
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index ec3a9ce..a663c09 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -219,7 +219,7 @@ static void free_fib_info_rcu(struct rcu_head *head)
  } endfor_nexthops(fi);
 
  m = fi->fib_metrics;
- if (m != &dst_default_metrics && atomic_dec_and_test(&m->refcnt))
+ if (m != &dst_default_metrics && refcount_dec_and_test(&m->refcnt))
  kfree(m);
  kfree(fi);
 }
@@ -1089,7 +1089,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg,
  kfree(fi);
  return ERR_PTR(err);
  }
- atomic_set(&fi->fib_metrics->refcnt, 1);
+ refcount_set(&fi->fib_metrics->refcnt, 1);
  } else {
  fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics;
  }
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 72afa4c..83a2c494 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1398,7 +1398,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
  struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
  struct rtable *rt = (struct rtable *) dst;
 
- if (p != &dst_default_metrics && atomic_dec_and_test(&p->refcnt))
+ if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
  kfree(p);
 
  if (!list_empty(&rt->rt_uncached)) {
@@ -1456,7 +1456,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
  dst_init_metrics(&rt->dst, fi->fib_metrics->metrics, true);
  if (fi->fib_metrics != &dst_default_metrics) {
  rt->dst._metrics |= DST_METRICS_REFCOUNTED;
- atomic_inc(&fi->fib_metrics->refcnt);
+ refcount_inc(&fi->fib_metrics->refcnt);
  }
 #ifdef CONFIG_IP_ROUTE_CLASSID
  rt->dst.tclassid = nh->nh_tclassid;
--
2.7.4


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

[SRU][Artful][PATCH 2/2][v3] xfrm: reuse uncached_list to track xdsts

Joseph Salisbury-3
In reply to this post by Joseph Salisbury-3
From: Xin Long <[hidden email]>

BugLink: http://bugs.launchpad.net/bugs/1746474

In early time, when freeing a xdst, it would be inserted into
dst_garbage.list first. Then if it's refcnt was still held
somewhere, later it would be put into dst_busy_list in
dst_gc_task().

When one dev was being unregistered, the dev of these dsts in
dst_busy_list would be set with loopback_dev and put this dev.
So that this dev's removal wouldn't get blocked, and avoid the
kmsg warning:

  kernel:unregister_netdevice: waiting for veth0 to become \
  free. Usage count = 2

However after Commit 52df157f17e5 ("xfrm: take refcnt of dst
when creating struct xfrm_dst bundle"), the xdst will not be
freed with dst gc, and this warning happens.

To fix it, we need to find these xdsts that are still held by
others when removing the dev, and free xdst's dev and set it
with loopback_dev.

But unfortunately after flow_cache for xfrm was deleted, no
list tracks them anymore. So we need to save these xdsts
somewhere to release the xdst's dev later.

To make this easier, this patch is to reuse uncached_list to
track xdsts, so that the dev refcnt can be released in the
event NETDEV_UNREGISTER process of fib_netdev_notifier.

Thanks to Florian, we could move forward this fix quickly.

Fixes: 52df157f17e5 ("xfrm: take refcnt of dst when creating struct xfrm_dst bundle")
Reported-by: Jianlin Shi <[hidden email]>
Reported-by: Hangbin Liu <[hidden email]>
Tested-by: Eyal Birger <[hidden email]>
Signed-off-by: Xin Long <[hidden email]>
Signed-off-by: Steffen Klassert <[hidden email]>
(back ported from commit 510c321b557121861601f9d259aadd65aa274f35)
Signed-off-by: Joseph Salisbury <[hidden email]>
---
 include/net/ip6_route.h |  2 ++
 include/net/route.h     |  3 +++
 net/ipv4/route.c        | 21 +++++++++++++--------
 net/ipv4/xfrm4_policy.c |  4 +++-
 net/ipv6/route.c        |  4 ++--
 net/ipv6/xfrm6_policy.c |  4 ++++
 6 files changed, 27 insertions(+), 11 deletions(-)

diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 1990569..7721693 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -163,6 +163,8 @@ void rt6_mtu_change(struct net_device *dev, unsigned int mtu);
 void rt6_remove_prefsrc(struct inet6_ifaddr *ifp);
 void rt6_clean_tohost(struct net *net, struct in6_addr *gateway);
 
+void rt6_uncached_list_add(struct rt6_info *rt);
+void rt6_uncached_list_del(struct rt6_info *rt);
 
 /*
  * Store a destination cache entry in a socket
diff --git a/include/net/route.h b/include/net/route.h
index 5845896..09a3507 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -226,6 +226,9 @@ struct in_ifaddr;
 void fib_add_ifaddr(struct in_ifaddr *);
 void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *);
 
+void rt_add_uncached_list(struct rtable *rt);
+void rt_del_uncached_list(struct rtable *rt);
+
 static inline void ip_rt_put(struct rtable *rt)
 {
  /* dst_release() accepts a NULL parameter.
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 83a2c494..33db041 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1382,7 +1382,7 @@ struct uncached_list {
 
 static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list);
 
-static void rt_add_uncached_list(struct rtable *rt)
+void rt_add_uncached_list(struct rtable *rt)
 {
  struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list);
 
@@ -1393,14 +1393,8 @@ static void rt_add_uncached_list(struct rtable *rt)
  spin_unlock_bh(&ul->lock);
 }
 
-static void ipv4_dst_destroy(struct dst_entry *dst)
+void rt_del_uncached_list(struct rtable *rt)
 {
- struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
- struct rtable *rt = (struct rtable *) dst;
-
- if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
- kfree(p);
-
  if (!list_empty(&rt->rt_uncached)) {
  struct uncached_list *ul = rt->rt_uncached_list;
 
@@ -1410,6 +1404,17 @@ static void ipv4_dst_destroy(struct dst_entry *dst)
  }
 }
 
+static void ipv4_dst_destroy(struct dst_entry *dst)
+{
+ struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
+ struct rtable *rt = (struct rtable *)dst;
+
+ if (p != &dst_default_metrics && refcount_dec_and_test(&p->refcnt))
+ kfree(p);
+
+ rt_del_uncached_list(rt);
+}
+
 void rt_flush_dev(struct net_device *dev)
 {
  struct net *net = dev_net(dev);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 71b4ecc1..cb9890a 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -97,6 +97,7 @@ static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
  xdst->u.rt.rt_pmtu = rt->rt_pmtu;
  xdst->u.rt.rt_table_id = rt->rt_table_id;
  INIT_LIST_HEAD(&xdst->u.rt.rt_uncached);
+ rt_add_uncached_list(&xdst->u.rt);
 
  return 0;
 }
@@ -244,7 +245,8 @@ static void xfrm4_dst_destroy(struct dst_entry *dst)
  struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
 
  dst_destroy_metrics_generic(dst);
-
+ if (xdst->u.rt.rt_uncached_list)
+ rt_del_uncached_list(&xdst->u.rt);
  xfrm_dst_destroy(xdst);
 }
 
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d00e41c..6062c65 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -124,7 +124,7 @@ struct uncached_list {
 
 static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list);
 
-static void rt6_uncached_list_add(struct rt6_info *rt)
+void rt6_uncached_list_add(struct rt6_info *rt)
 {
  struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list);
 
@@ -135,7 +135,7 @@ static void rt6_uncached_list_add(struct rt6_info *rt)
  spin_unlock_bh(&ul->lock);
 }
 
-static void rt6_uncached_list_del(struct rt6_info *rt)
+void rt6_uncached_list_del(struct rt6_info *rt)
 {
  if (!list_empty(&rt->rt6i_uncached)) {
  struct uncached_list *ul = rt->rt6i_uncached_list;
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 79651bc..dec840c 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -109,6 +109,8 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev,
  xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway;
  xdst->u.rt6.rt6i_dst = rt->rt6i_dst;
  xdst->u.rt6.rt6i_src = rt->rt6i_src;
+ INIT_LIST_HEAD(&xdst->u.rt6.rt6i_uncached);
+ rt6_uncached_list_add(&xdst->u.rt6);
 
  return 0;
 }
@@ -247,6 +249,8 @@ static void xfrm6_dst_destroy(struct dst_entry *dst)
  if (likely(xdst->u.rt6.rt6i_idev))
  in6_dev_put(xdst->u.rt6.rt6i_idev);
  dst_destroy_metrics_generic(dst);
+ if (xdst->u.rt6.rt6i_uncached_list)
+ rt6_uncached_list_del(&xdst->u.rt6);
  xfrm_dst_destroy(xdst);
 }
 
--
2.7.4


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

ACK/cmnt: [SRU][Artful][PATCH 0/2][v3] Fixes for LP:1746474

Khaled Elmously
In reply to this post by Joseph Salisbury-3
On 2018-05-07 17:23:12 , Joseph Salisbury wrote:

> BugLink: http://bugs.launchpad.net/bugs/1746474
>
> == SRU Justification ==
> Commit 52df157f17e5 introduced a regression in v4.13-rc1.  This regression
> causes a stack trace to occur when tearing down an LXD container.  The process
> hangs with the following message:
>
> "unregister_netdevice: waiting for eth0 to become free. Usage count = 5"
>
> This regression is fixed by commit 510c321b5571, which is in mainline as of
> v4.16-rc7.  The fix is needed in Artful and Bionic.  However, Artful needs
> commit 9620fef27ed2 as a prereq commit, so it's SRU request es beinsss sent separately.
>
>
> == Fixes ==
> 9620fef27ed2 ("ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t")
> 510c321b5571 ("xfrm: reuse uncached_list to track xdsts")
>
> == Regression Potential ==
> Low.  This commit is to fix a current regression.
>
> == Test Case ==
> A test kernel was built with these patches and tested by the original bug reporter.
> The bug reporter states the test kernel resolved the bug.
>
>
>
> Eric Dumazet (1):
>   ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t
>
> Xin Long (1):
>   xfrm: reuse uncached_list to track xdsts
>
>  include/net/dst.h        |  3 ++-
>  include/net/ip6_route.h  |  2 ++
>  include/net/route.h      |  3 +++
>  net/core/dst.c           |  6 +++---
>  net/ipv4/fib_semantics.c |  4 ++--
>  net/ipv4/route.c         | 23 ++++++++++++++---------
>  net/ipv4/xfrm4_policy.c  |  4 +++-
>  net/ipv6/route.c         |  4 ++--
>  net/ipv6/xfrm6_policy.c  |  4 ++++
>  9 files changed, 35 insertions(+), 18 deletions(-)
>

I guess since it's intentional:  
Acked-by: Khalid Elmously <[hidden email]>


But I'm still not sure why drop the statistic-keeping. Do we not care about stats for some reason?

-Khalid


--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

ACK: [SRU][Artful][PATCH 0/2][v3] Fixes for LP:1746474

AceLan Kao
In reply to this post by Joseph Salisbury-3
Acked-By: AceLan Kao <[hidden email]>

--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team
Reply | Threaded
Open this post in threaded view
|

APPLIED: [SRU][Artful][PATCH 0/2][v3] Fixes for LP:1746474

Kleber Souza
In reply to this post by Joseph Salisbury-3
On 05/07/18 23:23, Joseph Salisbury wrote:

> BugLink: http://bugs.launchpad.net/bugs/1746474
>
> == SRU Justification ==
> Commit 52df157f17e5 introduced a regression in v4.13-rc1.  This regression
> causes a stack trace to occur when tearing down an LXD container.  The process
> hangs with the following message:
>
> "unregister_netdevice: waiting for eth0 to become free. Usage count = 5"
>
> This regression is fixed by commit 510c321b5571, which is in mainline as of
> v4.16-rc7.  The fix is needed in Artful and Bionic.  However, Artful needs
> commit 9620fef27ed2 as a prereq commit, so it's SRU request es beinsss sent separately.
>
>
> == Fixes ==
> 9620fef27ed2 ("ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t")
> 510c321b5571 ("xfrm: reuse uncached_list to track xdsts")
>
> == Regression Potential ==
> Low.  This commit is to fix a current regression.
>
> == Test Case ==
> A test kernel was built with these patches and tested by the original bug reporter.
> The bug reporter states the test kernel resolved the bug.
>
>
>
> Eric Dumazet (1):
>   ipv4: convert dst_metrics.refcnt from atomic_t to refcount_t
>
> Xin Long (1):
>   xfrm: reuse uncached_list to track xdsts
>
>  include/net/dst.h        |  3 ++-
>  include/net/ip6_route.h  |  2 ++
>  include/net/route.h      |  3 +++
>  net/core/dst.c           |  6 +++---
>  net/ipv4/fib_semantics.c |  4 ++--
>  net/ipv4/route.c         | 23 ++++++++++++++---------
>  net/ipv4/xfrm4_policy.c  |  4 +++-
>  net/ipv6/route.c         |  4 ++--
>  net/ipv6/xfrm6_policy.c  |  4 ++++
>  9 files changed, 35 insertions(+), 18 deletions(-)
>

Applied to artful/master-next branch.

Thanks,
Kleber

--
kernel-team mailing list
[hidden email]
https://lists.ubuntu.com/mailman/listinfo/kernel-team