rtnetlink: do not depend on RTNL in rtnl_fill_proto_down()

Change dev_change_proto_down() and dev_change_proto_down_reason()
to write once on dev->proto_down and dev->proto_down_reason.

Then rtnl_fill_proto_down() can use READ_ONCE() annotations
and run locklessly.

rtnl_proto_down_size() should assume worst case,
because readng dev->proto_down_reason multiple
times would be racy without RTNL in the future.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Eric Dumazet 2024-05-03 19:20:57 +00:00 committed by Paolo Abeni
parent 6747a5d499
commit 6890ab31d1
2 changed files with 11 additions and 8 deletions

View File

@ -9223,7 +9223,7 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
netif_carrier_off(dev);
else
netif_carrier_on(dev);
dev->proto_down = proto_down;
WRITE_ONCE(dev->proto_down, proto_down);
return 0;
}
@ -9237,18 +9237,21 @@ int dev_change_proto_down(struct net_device *dev, bool proto_down)
void dev_change_proto_down_reason(struct net_device *dev, unsigned long mask,
u32 value)
{
u32 proto_down_reason;
int b;
if (!mask) {
dev->proto_down_reason = value;
proto_down_reason = value;
} else {
proto_down_reason = dev->proto_down_reason;
for_each_set_bit(b, &mask, 32) {
if (value & (1 << b))
dev->proto_down_reason |= BIT(b);
proto_down_reason |= BIT(b);
else
dev->proto_down_reason &= ~BIT(b);
proto_down_reason &= ~BIT(b);
}
}
WRITE_ONCE(dev->proto_down_reason, proto_down_reason);
}
struct bpf_xdp_link {

View File

@ -1036,8 +1036,8 @@ static size_t rtnl_proto_down_size(const struct net_device *dev)
{
size_t size = nla_total_size(1);
if (dev->proto_down_reason)
size += nla_total_size(0) + nla_total_size(4);
/* Assume dev->proto_down_reason is not zero. */
size += nla_total_size(0) + nla_total_size(4);
return size;
}
@ -1737,10 +1737,10 @@ static int rtnl_fill_proto_down(struct sk_buff *skb,
struct nlattr *pr;
u32 preason;
if (nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down))
if (nla_put_u8(skb, IFLA_PROTO_DOWN, READ_ONCE(dev->proto_down)))
goto nla_put_failure;
preason = dev->proto_down_reason;
preason = READ_ONCE(dev->proto_down_reason);
if (!preason)
return 0;