ip_frag: dont touch device refcount
authorEric Dumazet <eric.dumazet@gmail.com>
Fri, 6 Nov 2009 04:59:47 +0000 (20:59 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 6 Nov 2009 06:34:22 +0000 (22:34 -0800)
When sending fragmentation expiration ICMP V4/V6 messages,
we can avoid touching device refcount, thanks to RCU

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_fragment.c
net/ipv6/reassembly.c

index 575f9bd..b007f8a 100644 (file)
@@ -206,10 +206,11 @@ static void ip_expire(unsigned long arg)
                struct sk_buff *head = qp->q.fragments;
 
                /* Send an ICMP "Fragment Reassembly Timeout" message. */
-               if ((head->dev = dev_get_by_index(net, qp->iif)) != NULL) {
+               rcu_read_lock();
+               head->dev = dev_get_by_index_rcu(net, qp->iif);
+               if (head->dev)
                        icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0);
-                       dev_put(head->dev);
-               }
+               rcu_read_unlock();
        }
 out:
        spin_unlock(&qp->q.lock);
index da5bd0e..dce699f 100644 (file)
@@ -208,18 +208,17 @@ static void ip6_frag_expire(unsigned long data)
        fq_kill(fq);
 
        net = container_of(fq->q.net, struct net, ipv6.frags);
-       dev = dev_get_by_index(net, fq->iif);
+       rcu_read_lock();
+       dev = dev_get_by_index_rcu(net, fq->iif);
        if (!dev)
-               goto out;
+               goto out_rcu_unlock;
 
-       rcu_read_lock();
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT);
        IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
-       rcu_read_unlock();
 
        /* Don't send error if the first segment did not arrive. */
        if (!(fq->q.last_in & INET_FRAG_FIRST_IN) || !fq->q.fragments)
-               goto out;
+               goto out_rcu_unlock;
 
        /*
           But use as source device on which LAST ARRIVED
@@ -228,9 +227,9 @@ static void ip6_frag_expire(unsigned long data)
         */
        fq->q.fragments->dev = dev;
        icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0, dev);
+out_rcu_unlock:
+       rcu_read_unlock();
 out:
-       if (dev)
-               dev_put(dev);
        spin_unlock(&fq->q.lock);
        fq_put(fq);
 }