* [RFC] ipv6: rt6_update_expires() seems racy @ 2013-02-18 23:55 Eric Dumazet 2013-02-19 20:28 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] Neil Horman 0 siblings, 1 reply; 18+ messages in thread From: Eric Dumazet @ 2013-02-18 23:55 UTC (permalink / raw) To: David Miller; +Cc: netdev, Gao feng, Neil Horman, Jiri Bohac Some strange crashes happen in rt6_check_expired(), with access to random addresses. At first glance, it looks like the RTF_EXPIRES and stuff added in commit 1716a96101c49186b (ipv6: fix problem with expired dst cache) are racy : same dst could be manipulated at the same time on different cpus. At some point, our stack believes rt->dst.from contains a dst pointer, while its really a jiffie value (as rt->dst.expires shares the same area of memory) rt6_update_expires() should be fixed, or am I missing something ? CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060 ^ permalink raw reply [flat|nested] 18+ messages in thread
* [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-18 23:55 [RFC] ipv6: rt6_update_expires() seems racy Eric Dumazet @ 2013-02-19 20:28 ` Neil Horman 2013-02-19 21:17 ` Eric Dumazet 2013-02-20 10:55 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] David Laight 0 siblings, 2 replies; 18+ messages in thread From: Neil Horman @ 2013-02-19 20:28 UTC (permalink / raw) To: netdev; +Cc: Neil Horman, eric.dumazet, David Miller, Gao feng, Jiri Bohac I've been looking into some random ipv6 crashes lately that occur around ip6_link_failure. This and simmilar partial stack traces: ip6_link_failure+0xbe/0xd0 ipip6_tunnel_xmit+0x7e7/0x860 [sit] dev_hard_start_xmit+0x3e3/0x690 dev_queue_xmit+0x38f/0x610 neigh_direct_output+0x11/0x20 ip6_finish_output2+0x90/0x340 ? ac6_proc_exit+0x20/0x20 ip6_finish_output+0x98/0xc0 ip6_output ? __ip6_local_out ip6_local_out ip6_push_pending ? ip6_append_data udp_v6_push_pending_frames udpv6_sendmsg were all I had. Eric D. Made this click with me this morning however, noting a possible/likely race condition in the ipv6 code. It appears that, if a dst entry is accessed by multiple cpus (and it appears that certainly can happen, as routes created via ip6_rt_copy are hashed back into the fib, for future lookups), then the use of the rt6i_flags field can race, leading to multiple conflicting uses of the aforementioned union (jiffies being interpreted as the from pointer and vice versa). Eric suggested that this be fixed in rt6_update_expires, but looking at the other uses of this union I don't think thats a complete fix. All the accessors for the expired|from union in the dst entry seem to rely on the RTF_EXPIRES flag being accessed and updated atomically, and thats just not the case. I think the only fix here, that doesn't involve additional locking, is to separate the expires and from fields into their own storage, so as not to trample one another. This is currently untested, but I've given it to several people who can reproduce this problem and are testing it now. I'll post again when I have results from them. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> CC: eric.dumazet@gmail.com CC: David Miller <davem@davemloft.net> CC: Gao feng <gaofeng@cn.fujitsu.com> CC: Jiri Bohac <jbohac@suse.cz> --- include/net/dst.h | 9 +++------ include/net/ip6_fib.h | 13 ++++++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 3da47e0..6b7ebcf 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -36,13 +36,10 @@ struct dst_entry { struct net_device *dev; struct dst_ops *ops; unsigned long _metrics; - union { - unsigned long expires; - /* point to where the dst_entry copied from */ - struct dst_entry *from; - }; + unsigned long expires; + /* point to where the dst_entry copied from */ + struct dst_entry *from; struct dst_entry *path; - void *__pad0; #ifdef CONFIG_XFRM struct xfrm_state *xfrm; #else diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 6919a50..a285e37 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -164,31 +164,33 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) static inline void rt6_clean_expires(struct rt6_info *rt) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) + if (!rt->rt6i_flags & RTF_EXPIRES) dst_release(rt->dst.from); rt->rt6i_flags &= ~RTF_EXPIRES; rt->dst.from = NULL; + rt->dst.expires = 0; } static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) + if (!rt->rt6i_flags & RTF_EXPIRES) dst_release(rt->dst.from); rt->rt6i_flags |= RTF_EXPIRES; + rt->dst.from = NULL; rt->dst.expires = expires; } static inline void rt6_update_expires(struct rt6_info *rt, int timeout) { if (!(rt->rt6i_flags & RTF_EXPIRES)) { - if (rt->dst.from) - dst_release(rt->dst.from); + dst_release(rt->dst.from); /* dst_set_expires relies on expires == 0 * if it has not been set previously. */ rt->dst.expires = 0; + rt6->dst.from = NULL; } dst_set_expires(&rt->dst, timeout); @@ -199,7 +201,7 @@ static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) { struct dst_entry *new = (struct dst_entry *) from; - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) { + if (!rt->rt6i_flags & RTF_EXPIRES) { if (new == rt->dst.from) return; dst_release(rt->dst.from); @@ -207,6 +209,7 @@ static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) rt->rt6i_flags &= ~RTF_EXPIRES; rt->dst.from = new; + rt->dst.expires = 0; dst_hold(new); } -- 1.7.11.7 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-19 20:28 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] Neil Horman @ 2013-02-19 21:17 ` Eric Dumazet 2013-02-19 21:49 ` Neil Horman 2013-02-20 10:55 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] David Laight 1 sibling, 1 reply; 18+ messages in thread From: Eric Dumazet @ 2013-02-19 21:17 UTC (permalink / raw) To: Neil Horman; +Cc: netdev, David Miller, Gao feng, Jiri Bohac On Tue, 2013-02-19 at 15:28 -0500, Neil Horman wrote: > static inline void rt6_update_expires(struct rt6_info *rt, int timeout) > { > if (!(rt->rt6i_flags & RTF_EXPIRES)) { > - if (rt->dst.from) > - dst_release(rt->dst.from); > + dst_release(rt->dst.from); > /* dst_set_expires relies on expires == 0 > * if it has not been set previously. > */ > rt->dst.expires = 0; > + rt6->dst.from = NULL; > } > Sorry you didnt really address the problem, only reduce the race window. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-19 21:17 ` Eric Dumazet @ 2013-02-19 21:49 ` Neil Horman 2013-02-19 21:55 ` Eric Dumazet 0 siblings, 1 reply; 18+ messages in thread From: Neil Horman @ 2013-02-19 21:49 UTC (permalink / raw) To: Eric Dumazet; +Cc: netdev, David Miller, Gao feng, Jiri Bohac On Tue, Feb 19, 2013 at 01:17:45PM -0800, Eric Dumazet wrote: > On Tue, 2013-02-19 at 15:28 -0500, Neil Horman wrote: > > > static inline void rt6_update_expires(struct rt6_info *rt, int timeout) > > { > > if (!(rt->rt6i_flags & RTF_EXPIRES)) { > > - if (rt->dst.from) > > - dst_release(rt->dst.from); > > + dst_release(rt->dst.from); > > /* dst_set_expires relies on expires == 0 > > * if it has not been set previously. > > */ > > rt->dst.expires = 0; > > + rt6->dst.from = NULL; > > } > > > > Sorry you didnt really address the problem, only reduce the race window. > I kinda had a feeling you would say that, but the only other solution I see here is to either introduce some locking to protect the from pointer, or two revert the patch that introduced the from pointer alltogether, neither of which sounds appealing to me. I suppose we could use an xchng to atomically update the from pointer, so there was only ever one context that was able to free it in rt6_update_path. Does that seem reasonable to you? Neil ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-19 21:49 ` Neil Horman @ 2013-02-19 21:55 ` Eric Dumazet 2013-02-20 6:33 ` Gao feng 0 siblings, 1 reply; 18+ messages in thread From: Eric Dumazet @ 2013-02-19 21:55 UTC (permalink / raw) To: Neil Horman; +Cc: netdev, David Miller, Gao feng, Jiri Bohac On Tue, 2013-02-19 at 16:49 -0500, Neil Horman wrote: > On Tue, Feb 19, 2013 at 01:17:45PM -0800, Eric Dumazet wrote: > > On Tue, 2013-02-19 at 15:28 -0500, Neil Horman wrote: > > > > > static inline void rt6_update_expires(struct rt6_info *rt, int timeout) > > > { > > > if (!(rt->rt6i_flags & RTF_EXPIRES)) { > > > - if (rt->dst.from) > > > - dst_release(rt->dst.from); > > > + dst_release(rt->dst.from); > > > /* dst_set_expires relies on expires == 0 > > > * if it has not been set previously. > > > */ > > > rt->dst.expires = 0; > > > + rt6->dst.from = NULL; > > > } > > > > > > > Sorry you didnt really address the problem, only reduce the race window. > > > I kinda had a feeling you would say that, but the only other solution I see here > is to either introduce some locking to protect the from pointer, or two revert > the patch that introduced the from pointer alltogether, neither of which sounds > appealing to me. I suppose we could use an xchng to atomically update the from > pointer, so there was only ever one context that was able to free it in > rt6_update_path. Does that seem reasonable to you? I believe the setting of rt6->dst.from is safe : It should be done at : - dst creation time, when we are the only user. - dst destry time, when we are the only user. We only have to do the dst_release() at the right place, when we are the last user of the dst. So rt6_update_expires() should not mess with rt6->dst.from at all. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-19 21:55 ` Eric Dumazet @ 2013-02-20 6:33 ` Gao feng 2013-02-20 7:00 ` Eric Dumazet 0 siblings, 1 reply; 18+ messages in thread From: Gao feng @ 2013-02-20 6:33 UTC (permalink / raw) To: Eric Dumazet; +Cc: Neil Horman, netdev, David Miller, Jiri Bohac Hi Eric & Neil, On 2013/02/20 05:55, Eric Dumazet wrote: > On Tue, 2013-02-19 at 16:49 -0500, Neil Horman wrote: >> On Tue, Feb 19, 2013 at 01:17:45PM -0800, Eric Dumazet wrote: >>> On Tue, 2013-02-19 at 15:28 -0500, Neil Horman wrote: >>> >>>> static inline void rt6_update_expires(struct rt6_info *rt, int timeout) >>>> { >>>> if (!(rt->rt6i_flags & RTF_EXPIRES)) { >>>> - if (rt->dst.from) >>>> - dst_release(rt->dst.from); >>>> + dst_release(rt->dst.from); >>>> /* dst_set_expires relies on expires == 0 >>>> * if it has not been set previously. >>>> */ >>>> rt->dst.expires = 0; >>>> + rt6->dst.from = NULL; >>>> } >>>> >>> >>> Sorry you didnt really address the problem, only reduce the race window. >>> >> I kinda had a feeling you would say that, but the only other solution I see here >> is to either introduce some locking to protect the from pointer, or two revert >> the patch that introduced the from pointer alltogether, neither of which sounds >> appealing to me. I suppose we could use an xchng to atomically update the from >> pointer, so there was only ever one context that was able to free it in >> rt6_update_path. Does that seem reasonable to you? > Thanks for your research on this problem. > I believe the setting of rt6->dst.from is safe : > It should be done at : > - dst creation time, when we are the only user. > - dst destry time, when we are the only user. > > We only have to do the dst_release() at the right place, when we are the > last user of the dst. > > So rt6_update_expires() should not mess with rt6->dst.from at all. > How can we? one usage of rt6_update_expires and rt6_set_expires is changing rt6->dst.from to rt6->dst.expires, we should release the already holded reference of rt6->dst.from. I think maybe we should rework the commit 1716a96101c49186b (ipv6: fix problem with expired dst cache). just force setting flag RTF_EXPIRES and expires for the rt6 which copied from the rt6(which is generated from RA). The only problem of this situation is this copied rt6's expire time may be imprecise, we may receive a new RA with a new expire time. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-20 6:33 ` Gao feng @ 2013-02-20 7:00 ` Eric Dumazet 2013-02-20 9:31 ` Gao feng 2013-02-20 10:02 ` YOSHIFUJI Hideaki 0 siblings, 2 replies; 18+ messages in thread From: Eric Dumazet @ 2013-02-20 7:00 UTC (permalink / raw) To: Gao feng; +Cc: Neil Horman, netdev, David Miller, Jiri Bohac On Wed, 2013-02-20 at 14:33 +0800, Gao feng wrote: > How can we? > one usage of rt6_update_expires and rt6_set_expires > is changing rt6->dst.from to rt6->dst.expires, we should release the > already holded reference of rt6->dst.from. > Just don't union the two fields, as Neil did. Setting the dst.expires value should not change dst.from at all. Something like the (untested, because its too late here) patch ? include/net/dst.h | 11 +++++------ include/net/ip6_fib.h | 21 +++------------------ net/ipv6/route.c | 3 +-- 3 files changed, 9 insertions(+), 26 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 3da47e0..3f31a48 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -36,13 +36,12 @@ struct dst_entry { struct net_device *dev; struct dst_ops *ops; unsigned long _metrics; - union { - unsigned long expires; - /* point to where the dst_entry copied from */ - struct dst_entry *from; - }; + unsigned long expires; + + /* point to where the dst_entry copied from */ + struct dst_entry *from; + struct dst_entry *path; - void *__pad0; #ifdef CONFIG_XFRM struct xfrm_state *xfrm; #else diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 6919a50..731b35c 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -164,33 +164,19 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) static inline void rt6_clean_expires(struct rt6_info *rt) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) - dst_release(rt->dst.from); - rt->rt6i_flags &= ~RTF_EXPIRES; - rt->dst.from = NULL; + rt->dst.expires = 0; } static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) - dst_release(rt->dst.from); - rt->rt6i_flags |= RTF_EXPIRES; rt->dst.expires = expires; } static inline void rt6_update_expires(struct rt6_info *rt, int timeout) { - if (!(rt->rt6i_flags & RTF_EXPIRES)) { - if (rt->dst.from) - dst_release(rt->dst.from); - /* dst_set_expires relies on expires == 0 - * if it has not been set previously. - */ - rt->dst.expires = 0; - } - + rt->dst.expires = 0; dst_set_expires(&rt->dst, timeout); rt->rt6i_flags |= RTF_EXPIRES; } @@ -199,13 +185,12 @@ static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) { struct dst_entry *new = (struct dst_entry *) from; - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) { + if (rt->dst.from) { if (new == rt->dst.from) return; dst_release(rt->dst.from); } - rt->rt6i_flags &= ~RTF_EXPIRES; rt->dst.from = new; dst_hold(new); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 515bb51..6874b6e 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -296,8 +296,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) in6_dev_put(idev); } - if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from) - dst_release(dst->from); + dst_release(dst->from); if (rt6_has_peer(rt)) { struct inet_peer *peer = rt6_peer_ptr(rt); ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-20 7:00 ` Eric Dumazet @ 2013-02-20 9:31 ` Gao feng 2013-02-20 10:02 ` YOSHIFUJI Hideaki 1 sibling, 0 replies; 18+ messages in thread From: Gao feng @ 2013-02-20 9:31 UTC (permalink / raw) To: Eric Dumazet; +Cc: Neil Horman, netdev, David Miller, Jiri Bohac On 2013/02/20 15:00, Eric Dumazet wrote: > On Wed, 2013-02-20 at 14:33 +0800, Gao feng wrote: > >> How can we? >> one usage of rt6_update_expires and rt6_set_expires >> is changing rt6->dst.from to rt6->dst.expires, we should release the >> already holded reference of rt6->dst.from. >> > > Just don't union the two fields, as Neil did. > > Setting the dst.expires value should not change dst.from at all. > Get it,it looks good to me.we can make sure dst->from doesn't being operated at same time. Thanks! ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-20 7:00 ` Eric Dumazet 2013-02-20 9:31 ` Gao feng @ 2013-02-20 10:02 ` YOSHIFUJI Hideaki 2013-02-20 10:17 ` [PATCH] ipv6: fix race condition regarding dst->expires and dst->from YOSHIFUJI Hideaki 1 sibling, 1 reply; 18+ messages in thread From: YOSHIFUJI Hideaki @ 2013-02-20 10:02 UTC (permalink / raw) To: Eric Dumazet; +Cc: Gao feng, Neil Horman, netdev, David Miller, Jiri Bohac Eric Dumazet wrote: > On Wed, 2013-02-20 at 14:33 +0800, Gao feng wrote: > >> How can we? >> one usage of rt6_update_expires and rt6_set_expires >> is changing rt6->dst.from to rt6->dst.expires, we should release the >> already holded reference of rt6->dst.from. >> > > Just don't union the two fields, as Neil did. > > Setting the dst.expires value should not change dst.from at all. > > Something like the (untested, because its too late here) patch ? > > include/net/dst.h | 11 +++++------ > include/net/ip6_fib.h | 21 +++------------------ > net/ipv6/route.c | 3 +-- > 3 files changed, 9 insertions(+), 26 deletions(-) > > diff --git a/include/net/dst.h b/include/net/dst.h > index 3da47e0..3f31a48 100644 > --- a/include/net/dst.h > +++ b/include/net/dst.h > @@ -36,13 +36,12 @@ struct dst_entry { > struct net_device *dev; > struct dst_ops *ops; > unsigned long _metrics; > - union { > - unsigned long expires; > - /* point to where the dst_entry copied from */ > - struct dst_entry *from; > - }; > + unsigned long expires; > + > + /* point to where the dst_entry copied from */ > + struct dst_entry *from; > + > struct dst_entry *path; > - void *__pad0; > #ifdef CONFIG_XFRM > struct xfrm_state *xfrm; > #else Initialize "from" in dst_alloc(). > @@ -199,13 +185,12 @@ static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) > { > struct dst_entry *new = (struct dst_entry *) from; > > - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) { > + if (rt->dst.from) { > if (new == rt->dst.from) > return; > dst_release(rt->dst.from); > } > > - rt->rt6i_flags &= ~RTF_EXPIRES; > rt->dst.from = new; > dst_hold(new); > } rt6_set_from can work only for fresh entries. In fact, I have very similar patch. --yoshfuji ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH] ipv6: fix race condition regarding dst->expires and dst->from. 2013-02-20 10:02 ` YOSHIFUJI Hideaki @ 2013-02-20 10:17 ` YOSHIFUJI Hideaki 2013-02-20 10:25 ` YOSHIFUJI Hideaki 0 siblings, 1 reply; 18+ messages in thread From: YOSHIFUJI Hideaki @ 2013-02-20 10:17 UTC (permalink / raw) To: David Miller, Eric Dumazet, Neil Horman, Gao feng, netdev Cc: YOSHIFUJI Hideaki Eric Dumazet wrote: | Some strange crashes happen in rt6_check_expired(), with access | to random addresses. | | At first glance, it looks like the RTF_EXPIRES and | stuff added in commit 1716a96101c49186b | (ipv6: fix problem with expired dst cache) | are racy : same dst could be manipulated at the same time | on different cpus. | | At some point, our stack believes rt->dst.from contains a dst pointer, | while its really a jiffie value (as rt->dst.expires shares the same area | of memory) | | rt6_update_expires() should be fixed, or am I missing something ? | | CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060 Because we do not have any locks for dst_entry, we cannot change essential structure in the entry; e.g., we cannot change reference to other entities. To fix this issue, split 'from' and 'expires' field in dst_entry out of union. Once it is 'from' is assigned in the constructor, keep the reference until the very last stage of the life time of the object. Of course, it is unsafe to change 'from', so make rt6_set_from simple just for fresh entries. Reported-by: Eric Dumazet <eric.dumazet@gmail.com> Reported-by: Neil Horman <nhorman@tuxdriver.com> CC: Gao Feng <gaofeng@cn.fujitsu.com> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> --- include/net/dst.h | 8 ++------ include/net/ip6_fib.h | 38 +++++++++++--------------------------- net/core/dst.c | 1 + net/ipv6/route.c | 8 +++----- 4 files changed, 17 insertions(+), 38 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 3da47e0..853cda1 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -36,13 +36,9 @@ struct dst_entry { struct net_device *dev; struct dst_ops *ops; unsigned long _metrics; - union { - unsigned long expires; - /* point to where the dst_entry copied from */ - struct dst_entry *from; - }; + unsigned long expires; struct dst_entry *path; - void *__pad0; + struct dst_entry *from; #ifdef CONFIG_XFRM struct xfrm_state *xfrm; #else diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 6919a50..6a3c8ab 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -164,50 +164,34 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) static inline void rt6_clean_expires(struct rt6_info *rt) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) - dst_release(rt->dst.from); - rt->rt6i_flags &= ~RTF_EXPIRES; - rt->dst.from = NULL; } static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) - dst_release(rt->dst.from); - - rt->rt6i_flags |= RTF_EXPIRES; rt->dst.expires = expires; + rt->rt6i_flags |= RTF_EXPIRES; } -static inline void rt6_update_expires(struct rt6_info *rt, int timeout) +static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) { - if (!(rt->rt6i_flags & RTF_EXPIRES)) { - if (rt->dst.from) - dst_release(rt->dst.from); - /* dst_set_expires relies on expires == 0 - * if it has not been set previously. - */ - rt->dst.expires = 0; - } - - dst_set_expires(&rt->dst, timeout); - rt->rt6i_flags |= RTF_EXPIRES; + struct rt6_info *rt; + + for (rt = rt0; rt && !(rt->rt6i_flags & RTF_EXPIRES); rt = rt->dst.from); + if (rt && rt != rt0) + rt0->dst.expires = rt->dst.expires; + + dst_set_expires(&rt0->dst, timeout); + rt0->rt6i_flags |= RTF_EXPIRES; } static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) { struct dst_entry *new = (struct dst_entry *) from; - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) { - if (new == rt->dst.from) - return; - dst_release(rt->dst.from); - } - rt->rt6i_flags &= ~RTF_EXPIRES; - rt->dst.from = new; dst_hold(new); + rt->dst.from = new; } static inline void ip6_rt_put(struct rt6_info *rt) diff --git a/net/core/dst.c b/net/core/dst.c index ee6153e..35fd12f 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -179,6 +179,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst_init_metrics(dst, dst_default_metrics, true); dst->expires = 0UL; dst->path = dst; + dst->from = NULL; #ifdef CONFIG_XFRM dst->xfrm = NULL; #endif diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 515bb51..9db8622 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -287,6 +287,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; + struct dst_entry *from = dst->from; if (!(rt->dst.flags & DST_HOST)) dst_destroy_metrics_generic(dst); @@ -296,8 +297,8 @@ static void ip6_dst_destroy(struct dst_entry *dst) in6_dev_put(idev); } - if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from) - dst_release(dst->from); + dst->from = NULL; + dst_release(dst->from); if (rt6_has_peer(rt)) { struct inet_peer *peer = rt6_peer_ptr(rt); @@ -1010,7 +1011,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori rt->rt6i_gateway = ort->rt6i_gateway; rt->rt6i_flags = ort->rt6i_flags; - rt6_clean_expires(rt); rt->rt6i_metric = 0; memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); @@ -1784,8 +1784,6 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == (RTF_DEFAULT | RTF_ADDRCONF)) rt6_set_from(rt, ort); - else - rt6_clean_expires(rt); rt->rt6i_metric = 0; #ifdef CONFIG_IPV6_SUBTREES -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH] ipv6: fix race condition regarding dst->expires and dst->from. 2013-02-20 10:17 ` [PATCH] ipv6: fix race condition regarding dst->expires and dst->from YOSHIFUJI Hideaki @ 2013-02-20 10:25 ` YOSHIFUJI Hideaki 2013-02-20 10:29 ` [PATCH V2] " YOSHIFUJI Hideaki 0 siblings, 1 reply; 18+ messages in thread From: YOSHIFUJI Hideaki @ 2013-02-20 10:25 UTC (permalink / raw) To: YOSHIFUJI Hideaki Cc: David Miller, Eric Dumazet, Neil Horman, Gao feng, netdev YOSHIFUJI Hideaki wrote: > -static inline void rt6_update_expires(struct rt6_info *rt, int timeout) > +static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) > { > - if (!(rt->rt6i_flags & RTF_EXPIRES)) { > - if (rt->dst.from) > - dst_release(rt->dst.from); > - /* dst_set_expires relies on expires == 0 > - * if it has not been set previously. > - */ > - rt->dst.expires = 0; > - } > - > - dst_set_expires(&rt->dst, timeout); > - rt->rt6i_flags |= RTF_EXPIRES; > + struct rt6_info *rt; > + > + for (rt = rt0; rt && !(rt->rt6i_flags & RTF_EXPIRES); rt = rt->dst.from); > + if (rt && rt != rt0) > + rt0->dst.expires = rt->dst.expires; > + > + dst_set_expires(&rt0->dst, timeout); > + rt0->rt6i_flags |= RTF_EXPIRES; > } > Oops, I sent wrong version, will resend. --yoshfuji ^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH V2] ipv6: fix race condition regarding dst->expires and dst->from. 2013-02-20 10:25 ` YOSHIFUJI Hideaki @ 2013-02-20 10:29 ` YOSHIFUJI Hideaki 2013-02-20 16:12 ` Eric Dumazet 2013-02-20 20:12 ` David Miller 0 siblings, 2 replies; 18+ messages in thread From: YOSHIFUJI Hideaki @ 2013-02-20 10:29 UTC (permalink / raw) To: Eric Dumazet, Neil Horman, Gao Feng, netdev, davem; +Cc: yoshfuji Eric Dumazet wrote: | Some strange crashes happen in rt6_check_expired(), with access | to random addresses. | | At first glance, it looks like the RTF_EXPIRES and | stuff added in commit 1716a96101c49186b | (ipv6: fix problem with expired dst cache) | are racy : same dst could be manipulated at the same time | on different cpus. | | At some point, our stack believes rt->dst.from contains a dst pointer, | while its really a jiffie value (as rt->dst.expires shares the same area | of memory) | | rt6_update_expires() should be fixed, or am I missing something ? | | CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060 Because we do not have any locks for dst_entry, we cannot change essential structure in the entry; e.g., we cannot change reference to other entity. To fix this issue, split 'from' and 'expires' field in dst_entry out of union. Once it is 'from' is assigned in the constructor, keep the reference until the very last stage of the life time of the object. Of course, it is unsafe to change 'from', so make rt6_set_from simple just for fresh entries. Reported-by: Eric Dumazet <eric.dumazet@gmail.com> Reported-by: Neil Horman <nhorman@tuxdriver.com> CC: Gao Feng <gaofeng@cn.fujitsu.com> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> --- include/net/dst.h | 8 ++------ include/net/ip6_fib.h | 39 ++++++++++++--------------------------- net/core/dst.c | 1 + net/ipv6/route.c | 8 +++----- 4 files changed, 18 insertions(+), 38 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 3da47e0..853cda1 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -36,13 +36,9 @@ struct dst_entry { struct net_device *dev; struct dst_ops *ops; unsigned long _metrics; - union { - unsigned long expires; - /* point to where the dst_entry copied from */ - struct dst_entry *from; - }; + unsigned long expires; struct dst_entry *path; - void *__pad0; + struct dst_entry *from; #ifdef CONFIG_XFRM struct xfrm_state *xfrm; #else diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 6919a50..2a601e7 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -164,50 +164,35 @@ static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) static inline void rt6_clean_expires(struct rt6_info *rt) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) - dst_release(rt->dst.from); - rt->rt6i_flags &= ~RTF_EXPIRES; - rt->dst.from = NULL; } static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) { - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) - dst_release(rt->dst.from); - - rt->rt6i_flags |= RTF_EXPIRES; rt->dst.expires = expires; + rt->rt6i_flags |= RTF_EXPIRES; } -static inline void rt6_update_expires(struct rt6_info *rt, int timeout) +static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) { - if (!(rt->rt6i_flags & RTF_EXPIRES)) { - if (rt->dst.from) - dst_release(rt->dst.from); - /* dst_set_expires relies on expires == 0 - * if it has not been set previously. - */ - rt->dst.expires = 0; - } - - dst_set_expires(&rt->dst, timeout); - rt->rt6i_flags |= RTF_EXPIRES; + struct rt6_info *rt; + + for (rt = rt0; rt && !(rt->rt6i_flags & RTF_EXPIRES); + rt = (struct rt6_info *)rt->dst.from); + if (rt && rt != rt0) + rt0->dst.expires = rt->dst.expires; + + dst_set_expires(&rt0->dst, timeout); + rt0->rt6i_flags |= RTF_EXPIRES; } static inline void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) { struct dst_entry *new = (struct dst_entry *) from; - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) { - if (new == rt->dst.from) - return; - dst_release(rt->dst.from); - } - rt->rt6i_flags &= ~RTF_EXPIRES; - rt->dst.from = new; dst_hold(new); + rt->dst.from = new; } static inline void ip6_rt_put(struct rt6_info *rt) diff --git a/net/core/dst.c b/net/core/dst.c index ee6153e..35fd12f 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -179,6 +179,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst_init_metrics(dst, dst_default_metrics, true); dst->expires = 0UL; dst->path = dst; + dst->from = NULL; #ifdef CONFIG_XFRM dst->xfrm = NULL; #endif diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 515bb51..9282665 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -287,6 +287,7 @@ static void ip6_dst_destroy(struct dst_entry *dst) { struct rt6_info *rt = (struct rt6_info *)dst; struct inet6_dev *idev = rt->rt6i_idev; + struct dst_entry *from = dst->from; if (!(rt->dst.flags & DST_HOST)) dst_destroy_metrics_generic(dst); @@ -296,8 +297,8 @@ static void ip6_dst_destroy(struct dst_entry *dst) in6_dev_put(idev); } - if (!(rt->rt6i_flags & RTF_EXPIRES) && dst->from) - dst_release(dst->from); + dst->from = NULL; + dst_release(from); if (rt6_has_peer(rt)) { struct inet_peer *peer = rt6_peer_ptr(rt); @@ -1010,7 +1011,6 @@ struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_ori rt->rt6i_gateway = ort->rt6i_gateway; rt->rt6i_flags = ort->rt6i_flags; - rt6_clean_expires(rt); rt->rt6i_metric = 0; memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); @@ -1784,8 +1784,6 @@ static struct rt6_info *ip6_rt_copy(struct rt6_info *ort, if ((ort->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) == (RTF_DEFAULT | RTF_ADDRCONF)) rt6_set_from(rt, ort); - else - rt6_clean_expires(rt); rt->rt6i_metric = 0; #ifdef CONFIG_IPV6_SUBTREES -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 18+ messages in thread
* Re: [PATCH V2] ipv6: fix race condition regarding dst->expires and dst->from. 2013-02-20 10:29 ` [PATCH V2] " YOSHIFUJI Hideaki @ 2013-02-20 16:12 ` Eric Dumazet 2013-02-20 16:34 ` Neil Horman 2013-02-20 20:12 ` David Miller 1 sibling, 1 reply; 18+ messages in thread From: Eric Dumazet @ 2013-02-20 16:12 UTC (permalink / raw) To: YOSHIFUJI Hideaki Cc: Neil Horman, Gao Feng, netdev, davem, Steinar H. Gunderson On Wed, 2013-02-20 at 19:29 +0900, YOSHIFUJI Hideaki wrote: > Eric Dumazet wrote: > | Some strange crashes happen in rt6_check_expired(), with access > | to random addresses. > | > | At first glance, it looks like the RTF_EXPIRES and > | stuff added in commit 1716a96101c49186b > | (ipv6: fix problem with expired dst cache) > | are racy : same dst could be manipulated at the same time > | on different cpus. > | > | At some point, our stack believes rt->dst.from contains a dst pointer, > | while its really a jiffie value (as rt->dst.expires shares the same area > | of memory) > | > | rt6_update_expires() should be fixed, or am I missing something ? > | > | CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060 > > Because we do not have any locks for dst_entry, we cannot change > essential structure in the entry; e.g., we cannot change reference > to other entity. > > To fix this issue, split 'from' and 'expires' field in dst_entry > out of union. Once it is 'from' is assigned in the constructor, > keep the reference until the very last stage of the life time of > the object. > > Of course, it is unsafe to change 'from', so make rt6_set_from simple > just for fresh entries. > > Reported-by: Eric Dumazet <eric.dumazet@gmail.com> > Reported-by: Neil Horman <nhorman@tuxdriver.com> > CC: Gao Feng <gaofeng@cn.fujitsu.com> > Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> > --- This seems good to me, but I cant test it at this moment. I CC Steinar as he reported one crash to me. Thanks Yoshifuji ! Reviewed-by: Eric Dumazet <edumazet@google.com> Reported-by: Steinar H. Gunderson <sesse@google.com> ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2] ipv6: fix race condition regarding dst->expires and dst->from. 2013-02-20 16:12 ` Eric Dumazet @ 2013-02-20 16:34 ` Neil Horman 0 siblings, 0 replies; 18+ messages in thread From: Neil Horman @ 2013-02-20 16:34 UTC (permalink / raw) To: Eric Dumazet Cc: YOSHIFUJI Hideaki, Gao Feng, netdev, davem, Steinar H. Gunderson On Wed, Feb 20, 2013 at 08:12:40AM -0800, Eric Dumazet wrote: > On Wed, 2013-02-20 at 19:29 +0900, YOSHIFUJI Hideaki wrote: > > Eric Dumazet wrote: > > | Some strange crashes happen in rt6_check_expired(), with access > > | to random addresses. > > | > > | At first glance, it looks like the RTF_EXPIRES and > > | stuff added in commit 1716a96101c49186b > > | (ipv6: fix problem with expired dst cache) > > | are racy : same dst could be manipulated at the same time > > | on different cpus. > > | > > | At some point, our stack believes rt->dst.from contains a dst pointer, > > | while its really a jiffie value (as rt->dst.expires shares the same area > > | of memory) > > | > > | rt6_update_expires() should be fixed, or am I missing something ? > > | > > | CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060 > > > > Because we do not have any locks for dst_entry, we cannot change > > essential structure in the entry; e.g., we cannot change reference > > to other entity. > > > > To fix this issue, split 'from' and 'expires' field in dst_entry > > out of union. Once it is 'from' is assigned in the constructor, > > keep the reference until the very last stage of the life time of > > the object. > > > > Of course, it is unsafe to change 'from', so make rt6_set_from simple > > just for fresh entries. > > > > Reported-by: Eric Dumazet <eric.dumazet@gmail.com> > > Reported-by: Neil Horman <nhorman@tuxdriver.com> > > CC: Gao Feng <gaofeng@cn.fujitsu.com> > > Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> > > --- > > This seems good to me, but I cant test it at this moment. > > I CC Steinar as he reported one crash to me. > > Thanks Yoshifuji ! > > Reviewed-by: Eric Dumazet <edumazet@google.com> > > Reported-by: Steinar H. Gunderson <sesse@google.com> > I've also got requests in to test, and a recent fedora build running here: http://koji.fedoraproject.org/koji/taskinfo?taskID=5036210 If anyone else wants to test it. Although, looking at it, I think this is a good fix: Reviewed-by: Neil Horman <nhorman@tuxdriver.com> > > > ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [PATCH V2] ipv6: fix race condition regarding dst->expires and dst->from. 2013-02-20 10:29 ` [PATCH V2] " YOSHIFUJI Hideaki 2013-02-20 16:12 ` Eric Dumazet @ 2013-02-20 20:12 ` David Miller 1 sibling, 0 replies; 18+ messages in thread From: David Miller @ 2013-02-20 20:12 UTC (permalink / raw) To: yoshfuji; +Cc: eric.dumazet, nhorman, gaofeng, netdev From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Date: Wed, 20 Feb 2013 19:29:08 +0900 > Eric Dumazet wrote: > | Some strange crashes happen in rt6_check_expired(), with access > | to random addresses. > | > | At first glance, it looks like the RTF_EXPIRES and > | stuff added in commit 1716a96101c49186b > | (ipv6: fix problem with expired dst cache) > | are racy : same dst could be manipulated at the same time > | on different cpus. > | > | At some point, our stack believes rt->dst.from contains a dst pointer, > | while its really a jiffie value (as rt->dst.expires shares the same area > | of memory) > | > | rt6_update_expires() should be fixed, or am I missing something ? > | > | CC Neil because of https://bugzilla.redhat.com/show_bug.cgi?id=892060 > > Because we do not have any locks for dst_entry, we cannot change > essential structure in the entry; e.g., we cannot change reference > to other entity. > > To fix this issue, split 'from' and 'expires' field in dst_entry > out of union. Once it is 'from' is assigned in the constructor, > keep the reference until the very last stage of the life time of > the object. > > Of course, it is unsafe to change 'from', so make rt6_set_from simple > just for fresh entries. > > Reported-by: Eric Dumazet <eric.dumazet@gmail.com> > Reported-by: Neil Horman <nhorman@tuxdriver.com> > CC: Gao Feng <gaofeng@cn.fujitsu.com> > Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Applied and queued up for -stable, thanks. ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-19 20:28 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] Neil Horman 2013-02-19 21:17 ` Eric Dumazet @ 2013-02-20 10:55 ` David Laight 2013-02-20 12:02 ` Neil Horman 1 sibling, 1 reply; 18+ messages in thread From: David Laight @ 2013-02-20 10:55 UTC (permalink / raw) To: Neil Horman, netdev; +Cc: eric.dumazet, David Miller, Gao feng, Jiri Bohac > static inline void rt6_clean_expires(struct rt6_info *rt) > { > - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) > + if (!rt->rt6i_flags & RTF_EXPIRES) > dst_release(rt->dst.from); > > rt->rt6i_flags &= ~RTF_EXPIRES; > rt->dst.from = NULL; > + rt->dst.expires = 0; > } > > static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) > { > - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) > + if (!rt->rt6i_flags & RTF_EXPIRES) > dst_release(rt->dst.from); > > rt->rt6i_flags |= RTF_EXPIRES; > + rt->dst.from = NULL; > rt->dst.expires = expires; > } > > static inline void rt6_update_expires(struct rt6_info *rt, int timeout) > { > if (!(rt->rt6i_flags & RTF_EXPIRES)) { > - if (rt->dst.from) > - dst_release(rt->dst.from); > + dst_release(rt->dst.from); > /* dst_set_expires relies on expires == 0 > * if it has not been set previously. > */ > rt->dst.expires = 0; > + rt6->dst.from = NULL; > } Aren't there also problems with setting and clearing RTF_EXPIRES? Since that flag looks as though it was the descriminant for the union it probably isn't needed - provided dst.expires is never 0 when valid. David ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-20 10:55 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] David Laight @ 2013-02-20 12:02 ` Neil Horman 2013-02-20 12:08 ` David Laight 0 siblings, 1 reply; 18+ messages in thread From: Neil Horman @ 2013-02-20 12:02 UTC (permalink / raw) To: David Laight; +Cc: netdev, eric.dumazet, David Miller, Gao feng, Jiri Bohac On Wed, Feb 20, 2013 at 10:55:35AM -0000, David Laight wrote: > > static inline void rt6_clean_expires(struct rt6_info *rt) > > { > > - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) > > + if (!rt->rt6i_flags & RTF_EXPIRES) > > dst_release(rt->dst.from); > > > > rt->rt6i_flags &= ~RTF_EXPIRES; > > rt->dst.from = NULL; > > + rt->dst.expires = 0; > > } > > > > static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) > > { > > - if (!(rt->rt6i_flags & RTF_EXPIRES) && rt->dst.from) > > + if (!rt->rt6i_flags & RTF_EXPIRES) > > dst_release(rt->dst.from); > > > > rt->rt6i_flags |= RTF_EXPIRES; > > + rt->dst.from = NULL; > > rt->dst.expires = expires; > > } > > > > static inline void rt6_update_expires(struct rt6_info *rt, int timeout) > > { > > if (!(rt->rt6i_flags & RTF_EXPIRES)) { > > - if (rt->dst.from) > > - dst_release(rt->dst.from); > > + dst_release(rt->dst.from); > > /* dst_set_expires relies on expires == 0 > > * if it has not been set previously. > > */ > > rt->dst.expires = 0; > > + rt6->dst.from = NULL; > > } > > Aren't there also problems with setting and clearing RTF_EXPIRES? > Since that flag looks as though it was the descriminant for the union > it probably isn't needed - provided dst.expires is never 0 when valid. > > David The use of RTF_EXPIRES is weak at this point, if there are multiple accessors, but I think the point is moot, in that the only thing we ever do when we change the flag is release dst.from, which is safe. Neil ^ permalink raw reply [flat|nested] 18+ messages in thread
* RE: [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] 2013-02-20 12:02 ` Neil Horman @ 2013-02-20 12:08 ` David Laight 0 siblings, 0 replies; 18+ messages in thread From: David Laight @ 2013-02-20 12:08 UTC (permalink / raw) To: Neil Horman; +Cc: netdev, eric.dumazet, David Miller, Gao feng, Jiri Bohac > > Aren't there also problems with setting and clearing RTF_EXPIRES? > > Since that flag looks as though it was the descriminant for the union > > it probably isn't needed - provided dst.expires is never 0 when valid. > > > > David > > The use of RTF_EXPIRES is weak at this point, if there are multiple accessors, > but I think the point is moot, in that the only thing we ever do when we change > the flag is release dst.from, which is safe. > > Neil I was also worried about the RMW cycles of rt6i_flags itself. David ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2013-02-20 20:12 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2013-02-18 23:55 [RFC] ipv6: rt6_update_expires() seems racy Eric Dumazet 2013-02-19 20:28 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] Neil Horman 2013-02-19 21:17 ` Eric Dumazet 2013-02-19 21:49 ` Neil Horman 2013-02-19 21:55 ` Eric Dumazet 2013-02-20 6:33 ` Gao feng 2013-02-20 7:00 ` Eric Dumazet 2013-02-20 9:31 ` Gao feng 2013-02-20 10:02 ` YOSHIFUJI Hideaki 2013-02-20 10:17 ` [PATCH] ipv6: fix race condition regarding dst->expires and dst->from YOSHIFUJI Hideaki 2013-02-20 10:25 ` YOSHIFUJI Hideaki 2013-02-20 10:29 ` [PATCH V2] " YOSHIFUJI Hideaki 2013-02-20 16:12 ` Eric Dumazet 2013-02-20 16:34 ` Neil Horman 2013-02-20 20:12 ` David Miller 2013-02-20 10:55 ` [RFC PATCH] ipv6: Split from and expires field in dst_entry out of union [net-next] David Laight 2013-02-20 12:02 ` Neil Horman 2013-02-20 12:08 ` David Laight
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).