ip6mr: do not acquire mrt_lock in ioctl(SIOCGETMIFCNT_IN6)
authorEric Dumazet <edumazet@google.com>
Thu, 23 Jun 2022 04:34:42 +0000 (04:34 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 24 Jun 2022 10:34:37 +0000 (11:34 +0100)
rcu_read_lock() protection is good enough.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/ip6mr.c

index fa67203..b4ad606 100644 (file)
@@ -1896,20 +1896,20 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg)
                if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
                vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
-               read_lock(&mrt_lock);
+               rcu_read_lock();
                vif = &mrt->vif_table[vr.mifi];
                if (VIF_EXISTS(mrt, vr.mifi)) {
-                       vr.icount = vif->pkt_in;
-                       vr.ocount = vif->pkt_out;
-                       vr.ibytes = vif->bytes_in;
-                       vr.obytes = vif->bytes_out;
-                       read_unlock(&mrt_lock);
+                       vr.icount = READ_ONCE(vif->pkt_in);
+                       vr.ocount = READ_ONCE(vif->pkt_out);
+                       vr.ibytes = READ_ONCE(vif->bytes_in);
+                       vr.obytes = READ_ONCE(vif->bytes_out);
+                       rcu_read_unlock();
 
                        if (copy_to_user(arg, &vr, sizeof(vr)))
                                return -EFAULT;
                        return 0;
                }
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
                return -EADDRNOTAVAIL;
        case SIOCGETSGCNT_IN6:
                if (copy_from_user(&sr, arg, sizeof(sr)))
@@ -1971,20 +1971,20 @@ int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg)
                if (vr.mifi >= mrt->maxvif)
                        return -EINVAL;
                vr.mifi = array_index_nospec(vr.mifi, mrt->maxvif);
-               read_lock(&mrt_lock);
+               rcu_read_lock();
                vif = &mrt->vif_table[vr.mifi];
                if (VIF_EXISTS(mrt, vr.mifi)) {
-                       vr.icount = vif->pkt_in;
-                       vr.ocount = vif->pkt_out;
-                       vr.ibytes = vif->bytes_in;
-                       vr.obytes = vif->bytes_out;
-                       read_unlock(&mrt_lock);
+                       vr.icount = READ_ONCE(vif->pkt_in);
+                       vr.ocount = READ_ONCE(vif->pkt_out);
+                       vr.ibytes = READ_ONCE(vif->bytes_in);
+                       vr.obytes = READ_ONCE(vif->bytes_out);
+                       rcu_read_unlock();
 
                        if (copy_to_user(arg, &vr, sizeof(vr)))
                                return -EFAULT;
                        return 0;
                }
-               read_unlock(&mrt_lock);
+               rcu_read_unlock();
                return -EADDRNOTAVAIL;
        case SIOCGETSGCNT_IN6:
                if (copy_from_user(&sr, arg, sizeof(sr)))
@@ -2038,8 +2038,8 @@ static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
 
 #ifdef CONFIG_IPV6_PIMSM_V2
        if (vif->flags & MIFF_REGISTER) {
-               vif->pkt_out++;
-               vif->bytes_out += skb->len;
+               WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
+               WRITE_ONCE(vif->bytes_out, vif->bytes_out + skb->len);
                vif_dev->stats.tx_bytes += skb->len;
                vif_dev->stats.tx_packets++;
                rcu_read_lock();
@@ -2077,8 +2077,8 @@ static int ip6mr_forward2(struct net *net, struct mr_table *mrt,
         * result in receiving multiple packets.
         */
        skb->dev = vif_dev;
-       vif->pkt_out++;
-       vif->bytes_out += skb->len;
+       WRITE_ONCE(vif->pkt_out, vif->pkt_out + 1);
+       WRITE_ONCE(vif->bytes_out, vif->bytes_out + skb->len);
 
        /* We are about to write */
        /* XXX: extension headers? */
@@ -2168,8 +2168,10 @@ static void ip6_mr_forward(struct net *net, struct mr_table *mrt,
        }
 
 forward:
-       mrt->vif_table[vif].pkt_in++;
-       mrt->vif_table[vif].bytes_in += skb->len;
+       WRITE_ONCE(mrt->vif_table[vif].pkt_in,
+                  mrt->vif_table[vif].pkt_in + 1);
+       WRITE_ONCE(mrt->vif_table[vif].bytes_in,
+                  mrt->vif_table[vif].bytes_in + skb->len);
 
        /*
         *      Forward the frame