ipv6: remove RTNL protection from ip6addrlbl_dump()
No longer hold RTNL while calling ip6addrlbl_dump() ("ip addrlabel show") ip6addrlbl_dump() was already mostly relying on RCU anyway. Add READ_ONCE()/WRITE_ONCE() annotations around net->ipv6.ip6addrlbl_table.seq Note that ifal_seq value is currently ignored in iproute2, and a bit weak. We might user later cb->seq / nl_dump_check_consistent() protocol if needed. Also change return value for a completed dump, so that NLMSG_DONE can be appended to current skb, saving one recvmsg() system call. v2: read net->ipv6.ip6addrlbl_table.seq once, (David Ahern) Signed-off-by: Eric Dumazet <edumazet@google.com> Link:https://lore.kernel.org/netdev/67f5cb70-14a4-4455-8372-f039da2f15c2@kernel.org/ Reviewed-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
802e12ff9c
commit
eec53cc38c
|
@ -234,7 +234,8 @@ static int __ip6addrlbl_add(struct net *net, struct ip6addrlbl_entry *newp,
|
|||
hlist_add_head_rcu(&newp->list, &net->ipv6.ip6addrlbl_table.head);
|
||||
out:
|
||||
if (!ret)
|
||||
net->ipv6.ip6addrlbl_table.seq++;
|
||||
WRITE_ONCE(net->ipv6.ip6addrlbl_table.seq,
|
||||
net->ipv6.ip6addrlbl_table.seq + 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -445,7 +446,7 @@ static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
|
|||
};
|
||||
|
||||
static int ip6addrlbl_fill(struct sk_buff *skb,
|
||||
struct ip6addrlbl_entry *p,
|
||||
const struct ip6addrlbl_entry *p,
|
||||
u32 lseq,
|
||||
u32 portid, u32 seq, int event,
|
||||
unsigned int flags)
|
||||
|
@ -498,7 +499,8 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
struct net *net = sock_net(skb->sk);
|
||||
struct ip6addrlbl_entry *p;
|
||||
int idx = 0, s_idx = cb->args[0];
|
||||
int err;
|
||||
int err = 0;
|
||||
u32 lseq;
|
||||
|
||||
if (cb->strict_check) {
|
||||
err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
|
||||
|
@ -507,10 +509,11 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
}
|
||||
|
||||
rcu_read_lock();
|
||||
lseq = READ_ONCE(net->ipv6.ip6addrlbl_table.seq);
|
||||
hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
|
||||
if (idx >= s_idx) {
|
||||
err = ip6addrlbl_fill(skb, p,
|
||||
net->ipv6.ip6addrlbl_table.seq,
|
||||
lseq,
|
||||
NETLINK_CB(cb->skb).portid,
|
||||
nlh->nlmsg_seq,
|
||||
RTM_NEWADDRLABEL,
|
||||
|
@ -522,7 +525,7 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||
}
|
||||
rcu_read_unlock();
|
||||
cb->args[0] = idx;
|
||||
return skb->len;
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline int ip6addrlbl_msgsize(void)
|
||||
|
@ -614,7 +617,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh,
|
|||
|
||||
rcu_read_lock();
|
||||
p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
|
||||
lseq = net->ipv6.ip6addrlbl_table.seq;
|
||||
lseq = READ_ONCE(net->ipv6.ip6addrlbl_table.seq);
|
||||
if (p)
|
||||
err = ip6addrlbl_fill(skb, p, lseq,
|
||||
NETLINK_CB(in_skb).portid,
|
||||
|
@ -647,6 +650,7 @@ int __init ipv6_addr_label_rtnl_register(void)
|
|||
return ret;
|
||||
ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
|
||||
ip6addrlbl_get,
|
||||
ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED);
|
||||
ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED |
|
||||
RTNL_FLAG_DUMP_UNLOCKED);
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue