Commit 3493a5b7 authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

ip6mr: ip6mr_cache_report() changes

ip6mr_cache_report() first argument can be marked const, and we change
the caller convention about which lock needs to be held.

Instead of read_lock(&mrt_lock), we can use rcu_read_lock().
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e4cd9868
...@@ -91,11 +91,11 @@ static void ip6mr_free_table(struct mr_table *mrt); ...@@ -91,11 +91,11 @@ static void ip6mr_free_table(struct mr_table *mrt);
static void ip6_mr_forward(struct net *net, struct mr_table *mrt, static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
struct net_device *dev, struct sk_buff *skb, struct net_device *dev, struct sk_buff *skb,
struct mfc6_cache *cache); struct mfc6_cache *cache);
static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt,
mifi_t mifi, int assert); mifi_t mifi, int assert);
static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc, static void mr6_netlink_event(struct mr_table *mrt, struct mfc6_cache *mfc,
int cmd); int cmd);
static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt); static void mrt6msg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt);
static int ip6mr_rtm_dumproute(struct sk_buff *skb, static int ip6mr_rtm_dumproute(struct sk_buff *skb,
struct netlink_callback *cb); struct netlink_callback *cb);
static void mroute_clean_tables(struct mr_table *mrt, int flags); static void mroute_clean_tables(struct mr_table *mrt, int flags);
...@@ -608,11 +608,12 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb, ...@@ -608,11 +608,12 @@ static netdev_tx_t reg_vif_xmit(struct sk_buff *skb,
if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0) if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
goto tx_err; goto tx_err;
read_lock(&mrt_lock);
dev->stats.tx_bytes += skb->len; dev->stats.tx_bytes += skb->len;
dev->stats.tx_packets++; dev->stats.tx_packets++;
ip6mr_cache_report(mrt, skb, mrt->mroute_reg_vif_num, MRT6MSG_WHOLEPKT); rcu_read_lock();
read_unlock(&mrt_lock); ip6mr_cache_report(mrt, skb, READ_ONCE(mrt->mroute_reg_vif_num),
MRT6MSG_WHOLEPKT);
rcu_read_unlock();
kfree_skb(skb); kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
...@@ -718,8 +719,10 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify, ...@@ -718,8 +719,10 @@ static int mif6_delete(struct mr_table *mrt, int vifi, int notify,
RCU_INIT_POINTER(v->dev, NULL); RCU_INIT_POINTER(v->dev, NULL);
#ifdef CONFIG_IPV6_PIMSM_V2 #ifdef CONFIG_IPV6_PIMSM_V2
if (vifi == mrt->mroute_reg_vif_num) if (vifi == mrt->mroute_reg_vif_num) {
mrt->mroute_reg_vif_num = -1; /* Pairs with READ_ONCE() in ip6mr_cache_report() and reg_vif_xmit() */
WRITE_ONCE(mrt->mroute_reg_vif_num, -1);
}
#endif #endif
if (vifi + 1 == mrt->maxvif) { if (vifi + 1 == mrt->maxvif) {
...@@ -922,7 +925,7 @@ static int mif6_add(struct net *net, struct mr_table *mrt, ...@@ -922,7 +925,7 @@ static int mif6_add(struct net *net, struct mr_table *mrt,
netdev_tracker_alloc(dev, &v->dev_tracker, GFP_ATOMIC); netdev_tracker_alloc(dev, &v->dev_tracker, GFP_ATOMIC);
#ifdef CONFIG_IPV6_PIMSM_V2 #ifdef CONFIG_IPV6_PIMSM_V2
if (v->flags & MIFF_REGISTER) if (v->flags & MIFF_REGISTER)
mrt->mroute_reg_vif_num = vifi; WRITE_ONCE(mrt->mroute_reg_vif_num, vifi);
#endif #endif
if (vifi + 1 > mrt->maxvif) if (vifi + 1 > mrt->maxvif)
mrt->maxvif = vifi + 1; mrt->maxvif = vifi + 1;
...@@ -1033,10 +1036,10 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt, ...@@ -1033,10 +1036,10 @@ static void ip6mr_cache_resolve(struct net *net, struct mr_table *mrt,
/* /*
* Bounce a cache query up to pim6sd and netlink. * Bounce a cache query up to pim6sd and netlink.
* *
* Called under mrt_lock. * Called under rcu_read_lock()
*/ */
static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, static int ip6mr_cache_report(const struct mr_table *mrt, struct sk_buff *pkt,
mifi_t mifi, int assert) mifi_t mifi, int assert)
{ {
struct sock *mroute6_sk; struct sock *mroute6_sk;
...@@ -1077,7 +1080,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1077,7 +1080,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
if (assert == MRT6MSG_WRMIFWHOLE) if (assert == MRT6MSG_WRMIFWHOLE)
msg->im6_mif = mifi; msg->im6_mif = mifi;
else else
msg->im6_mif = mrt->mroute_reg_vif_num; msg->im6_mif = READ_ONCE(mrt->mroute_reg_vif_num);
msg->im6_pad = 0; msg->im6_pad = 0;
msg->im6_src = ipv6_hdr(pkt)->saddr; msg->im6_src = ipv6_hdr(pkt)->saddr;
msg->im6_dst = ipv6_hdr(pkt)->daddr; msg->im6_dst = ipv6_hdr(pkt)->daddr;
...@@ -1112,10 +1115,8 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1112,10 +1115,8 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
skb->ip_summed = CHECKSUM_UNNECESSARY; skb->ip_summed = CHECKSUM_UNNECESSARY;
} }
rcu_read_lock();
mroute6_sk = rcu_dereference(mrt->mroute_sk); mroute6_sk = rcu_dereference(mrt->mroute_sk);
if (!mroute6_sk) { if (!mroute6_sk) {
rcu_read_unlock();
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
} }
...@@ -1124,7 +1125,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt, ...@@ -1124,7 +1125,7 @@ static int ip6mr_cache_report(struct mr_table *mrt, struct sk_buff *pkt,
/* Deliver to user space multicast routing algorithms */ /* Deliver to user space multicast routing algorithms */
ret = sock_queue_rcv_skb(mroute6_sk, skb); ret = sock_queue_rcv_skb(mroute6_sk, skb);
rcu_read_unlock();
if (ret < 0) { if (ret < 0) {
net_warn_ratelimited("mroute6: pending queue full, dropping entries\n"); net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
kfree_skb(skb); kfree_skb(skb);
...@@ -2042,7 +2043,9 @@ static int ip6mr_forward2(struct net *net, struct mr_table *mrt, ...@@ -2042,7 +2043,9 @@ static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
vif->bytes_out += skb->len; vif->bytes_out += skb->len;
vif_dev->stats.tx_bytes += skb->len; vif_dev->stats.tx_bytes += skb->len;
vif_dev->stats.tx_packets++; vif_dev->stats.tx_packets++;
rcu_read_lock();
ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT); ip6mr_cache_report(mrt, skb, vifi, MRT6MSG_WHOLEPKT);
rcu_read_unlock();
goto out_free; goto out_free;
} }
#endif #endif
...@@ -2155,10 +2158,12 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt, ...@@ -2155,10 +2158,12 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
c->_c.mfc_un.res.last_assert + c->_c.mfc_un.res.last_assert +
MFC_ASSERT_THRESH)) { MFC_ASSERT_THRESH)) {
c->_c.mfc_un.res.last_assert = jiffies; c->_c.mfc_un.res.last_assert = jiffies;
rcu_read_lock();
ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF); ip6mr_cache_report(mrt, skb, true_vifi, MRT6MSG_WRONGMIF);
if (mrt->mroute_do_wrvifwhole) if (mrt->mroute_do_wrvifwhole)
ip6mr_cache_report(mrt, skb, true_vifi, ip6mr_cache_report(mrt, skb, true_vifi,
MRT6MSG_WRMIFWHOLE); MRT6MSG_WRMIFWHOLE);
rcu_read_unlock();
} }
goto dont_forward; goto dont_forward;
} }
...@@ -2465,7 +2470,7 @@ static size_t mrt6msg_netlink_msgsize(size_t payloadlen) ...@@ -2465,7 +2470,7 @@ static size_t mrt6msg_netlink_msgsize(size_t payloadlen)
return len; return len;
} }
static void mrt6msg_netlink_event(struct mr_table *mrt, struct sk_buff *pkt) static void mrt6msg_netlink_event(const struct mr_table *mrt, struct sk_buff *pkt)
{ {
struct net *net = read_pnet(&mrt->net); struct net *net = read_pnet(&mrt->net);
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment