diff options
Diffstat (limited to 'net/ipv4/fib_semantics.c')
| -rw-r--r-- | net/ipv4/fib_semantics.c | 16 | 
1 files changed, 10 insertions, 6 deletions
| diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 57a5d48acee8..01ed22139ac2 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -1365,8 +1365,6 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,  	    nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc))  		goto nla_put_failure;  	if (fi->fib_nhs == 1) { -		struct in_device *in_dev; -  		if (fi->fib_nh->nh_gw &&  		    nla_put_in_addr(skb, RTA_GATEWAY, fi->fib_nh->nh_gw))  			goto nla_put_failure; @@ -1374,10 +1372,14 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,  		    nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif))  			goto nla_put_failure;  		if (fi->fib_nh->nh_flags & RTNH_F_LINKDOWN) { -			in_dev = __in_dev_get_rtnl(fi->fib_nh->nh_dev); +			struct in_device *in_dev; + +			rcu_read_lock(); +			in_dev = __in_dev_get_rcu(fi->fib_nh->nh_dev);  			if (in_dev &&  			    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))  				rtm->rtm_flags |= RTNH_F_DEAD; +			rcu_read_unlock();  		}  		if (fi->fib_nh->nh_flags & RTNH_F_OFFLOAD)  			rtm->rtm_flags |= RTNH_F_OFFLOAD; @@ -1400,18 +1402,20 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,  			goto nla_put_failure;  		for_nexthops(fi) { -			struct in_device *in_dev; -  			rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh));  			if (!rtnh)  				goto nla_put_failure;  			rtnh->rtnh_flags = nh->nh_flags & 0xFF;  			if (nh->nh_flags & RTNH_F_LINKDOWN) { -				in_dev = __in_dev_get_rtnl(nh->nh_dev); +				struct in_device *in_dev; + +				rcu_read_lock(); +				in_dev = __in_dev_get_rcu(nh->nh_dev);  				if (in_dev &&  				    IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev))  					rtnh->rtnh_flags |= RTNH_F_DEAD; +				rcu_read_unlock();  			}  			rtnh->rtnh_hops = nh->nh_weight - 1;  			rtnh->rtnh_ifindex = nh->nh_oif; |