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);
|
hlist_add_head_rcu(&newp->list, &net->ipv6.ip6addrlbl_table.head);
|
||||||
out:
|
out:
|
||||||
if (!ret)
|
if (!ret)
|
||||||
net->ipv6.ip6addrlbl_table.seq++;
|
WRITE_ONCE(net->ipv6.ip6addrlbl_table.seq,
|
||||||
|
net->ipv6.ip6addrlbl_table.seq + 1);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,7 +446,7 @@ static void ip6addrlbl_putmsg(struct nlmsghdr *nlh,
|
|||||||
};
|
};
|
||||||
|
|
||||||
static int ip6addrlbl_fill(struct sk_buff *skb,
|
static int ip6addrlbl_fill(struct sk_buff *skb,
|
||||||
struct ip6addrlbl_entry *p,
|
const struct ip6addrlbl_entry *p,
|
||||||
u32 lseq,
|
u32 lseq,
|
||||||
u32 portid, u32 seq, int event,
|
u32 portid, u32 seq, int event,
|
||||||
unsigned int flags)
|
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 net *net = sock_net(skb->sk);
|
||||||
struct ip6addrlbl_entry *p;
|
struct ip6addrlbl_entry *p;
|
||||||
int idx = 0, s_idx = cb->args[0];
|
int idx = 0, s_idx = cb->args[0];
|
||||||
int err;
|
int err = 0;
|
||||||
|
u32 lseq;
|
||||||
|
|
||||||
if (cb->strict_check) {
|
if (cb->strict_check) {
|
||||||
err = ip6addrlbl_valid_dump_req(nlh, cb->extack);
|
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();
|
rcu_read_lock();
|
||||||
|
lseq = READ_ONCE(net->ipv6.ip6addrlbl_table.seq);
|
||||||
hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
|
hlist_for_each_entry_rcu(p, &net->ipv6.ip6addrlbl_table.head, list) {
|
||||||
if (idx >= s_idx) {
|
if (idx >= s_idx) {
|
||||||
err = ip6addrlbl_fill(skb, p,
|
err = ip6addrlbl_fill(skb, p,
|
||||||
net->ipv6.ip6addrlbl_table.seq,
|
lseq,
|
||||||
NETLINK_CB(cb->skb).portid,
|
NETLINK_CB(cb->skb).portid,
|
||||||
nlh->nlmsg_seq,
|
nlh->nlmsg_seq,
|
||||||
RTM_NEWADDRLABEL,
|
RTM_NEWADDRLABEL,
|
||||||
@ -522,7 +525,7 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
|||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
cb->args[0] = idx;
|
cb->args[0] = idx;
|
||||||
return skb->len;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ip6addrlbl_msgsize(void)
|
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();
|
rcu_read_lock();
|
||||||
p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
|
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)
|
if (p)
|
||||||
err = ip6addrlbl_fill(skb, p, lseq,
|
err = ip6addrlbl_fill(skb, p, lseq,
|
||||||
NETLINK_CB(in_skb).portid,
|
NETLINK_CB(in_skb).portid,
|
||||||
@ -647,6 +650,7 @@ int __init ipv6_addr_label_rtnl_register(void)
|
|||||||
return ret;
|
return ret;
|
||||||
ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
|
ret = rtnl_register_module(THIS_MODULE, PF_INET6, RTM_GETADDRLABEL,
|
||||||
ip6addrlbl_get,
|
ip6addrlbl_get,
|
||||||
ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED);
|
ip6addrlbl_dump, RTNL_FLAG_DOIT_UNLOCKED |
|
||||||
|
RTNL_FLAG_DUMP_UNLOCKED);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user