Please consider this request for suggestions on an attempt at a partial patch 
based on the assumptions below to identify rcu read-side critical sections 
for in_dev_get() defined in inetdevice.h.  Thank you.

drivers/s390/net/lcs.c          |        2 ++
drivers/s390/net/qeth_main.c    |        4 ++++
include/linux/inetdevice.h      |        2 +-
net/ipv4/arp.c                  |       17 +++++++++++------
net/ipv4/devinet.c              |        6 +++++-
net/ipv4/icmp.c                 |        4 ++--
net/ipv4/igmp.c                 |       22 ++++++++++++++++++----
net/ipv4/ip_gre.c               |        1 +
net/ipv4/ip_input.c             |        6 ++++--
net/ipv4/route.c                |       41 
++++++++++++++++++++++++++++-------------
10 files changed, 76 insertions(+), 29 deletions(-)

---------------------------------------------------

Assumptions made in this patch development:

1. Programmer who inserts rcu_lock/unlock around an in_dev_get or
   __in_dev_get expects the protection of deferred destruction.

2. The marking of an rcu read-side critical section done by
   the calling function has the vision of the extent of use of the
   protected dereference.

3. Pairings of in_dev_get/in_dev_put and __in_dev_get/__in_dev_put
   indicate the need to balance increment/decrement of refcnt, 
   so __in_dev_get which does not increment is likely paired in 
   error with __in_dev_put which decrements (unless in_dev_hold 
   or similar is in the path).  

4. If programmer chooses __in_dev_get rather than in_dev_get, 
   the refcnt is not desired.

5. If a function returns an rcu protected pointer, the rcu_read_lock
   is in place, so the rcu_read_unlock occurs in the caller.

Questions/Suggestions:

   A pairing of in_dev_get with in_dev_put may indicate the addition
   in the in_dev_put conditional of something like 
   call_rcu(&idev->rcu_head, in_dev->rcu_put)
   after in_dev_finish_destroy or replace the latter with a call like
   inetdev_destroy().

   Differences between inetdevice.h in kernel 2.5.60 and linux-2.6.13-rc6
   include the replacement in in_dev_get() of read_lock(&inetdev_lock)/unlock 
   with rcu_read_lock/unlock and the addition of the rcu_head to the 
   in_ifaddr struct.

   In net/ipv4/route.c, consider __mkroute_output and follow the
   three refcnt increments done to out_dev by dev_hold and in_dev_get, 
   then one decrement to in_dev.  Correct refcnt may also be an issue in
   xfrm4_policy.c to allow the atomic_dec_and_test in in_dev_put
   to appropriately recognize the condition to free the in_device.

   In net/ipv4/arp.c, arp_req_set() includes the following where,
   with possible update, might this be risky to test the deref and
   deref again: 
                if (__in_dev_get(dev)) {
                        __in_dev_get(dev)->cnf.proxy_arp = 1;
                        return 0;
                }
   and similarly in arp_req_delete?  While the vast majority of uses
   of __in_dev_get indicate rcu protection, the above may be the exception
   that breaks the rule.  It seems reasonable to have both in_dev_get
   and __in_dev_get use rcu_dereference and have the difference between
   them be the refcnt.  For now, I'll submit a patch addressing only
   in_dev_get and hope for feedback on patching __in_dev_get.  Because
   one way or another, there are __in_dev_get uses that probably need 
   to be addressed.

While this is a subjective attempt to understand programmer intent,
with your help and suggestions, the plan is to build an automated
checker.  Thank you.

------------------------------------------------------------------

diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/drivers/s390/net/lcs.c 
linux-2.6.13-rc6/drivers/s390/net/lcs.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/drivers/s390/net/lcs.c  
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/drivers/s390/net/lcs.c     2005-09-07 21:37:41.000000000 
-0700
@@ -1270,6 +1270,7 @@ lcs_register_mc_addresses(void *data)
                return 0;
        LCS_DBF_TEXT(4, trace, "regmulti");
 
+       rcu_read_lock();
        in4_dev = in_dev_get(card->dev);
        if (in4_dev == NULL)
                goto out;
@@ -1278,6 +1279,7 @@ lcs_register_mc_addresses(void *data)
        lcs_set_mc_addresses(card, in4_dev);
        read_unlock(&in4_dev->mc_list_lock);
        in_dev_put(in4_dev);
+       rcu_read_unlock();
 
        lcs_fix_multicast_list(card);
 out:
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/drivers/s390/net/qeth_main.c 
linux-2.6.13-rc6/drivers/s390/net/qeth_main.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/drivers/s390/net/qeth_main.c    
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/drivers/s390/net/qeth_main.c       2005-09-07 
22:22:10.000000000 -0700
@@ -5441,6 +5441,7 @@ qeth_add_vlan_mc(struct qeth_card *card)
                if (vg->vlan_devices[i] == NULL ||
                    !(vg->vlan_devices[i]->flags & IFF_UP))
                        continue;
+               rcu_read_lock();
                in_dev = in_dev_get(vg->vlan_devices[i]);
                if (!in_dev)
                        continue;
@@ -5448,6 +5449,7 @@ qeth_add_vlan_mc(struct qeth_card *card)
                qeth_add_mc(card,in_dev);
                read_unlock(&in_dev->mc_list_lock);
                in_dev_put(in_dev);
+               rcu_read_unlock();
        }
 #endif
 }
@@ -5458,6 +5460,7 @@ qeth_add_multicast_ipv4(struct qeth_card
        struct in_device *in4_dev;
 
        QETH_DBF_TEXT(trace,4,"chkmcv4");
+       rcu_read_lock();
        in4_dev = in_dev_get(card->dev);
        if (in4_dev == NULL)
                return;
@@ -5466,6 +5469,7 @@ qeth_add_multicast_ipv4(struct qeth_card
        qeth_add_vlan_mc(card);
        read_unlock(&in4_dev->mc_list_lock);
        in_dev_put(in4_dev);
+       rcu_read_unlock();
 }
 
 #ifdef CONFIG_QETH_IPV6
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/include/linux/inetdevice.h 
linux-2.6.13-rc6/include/linux/inetdevice.h
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/include/linux/inetdevice.h      
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/include/linux/inetdevice.h 2005-08-19 14:27:02.000000000 
-0700
@@ -148,7 +148,7 @@ in_dev_get(const struct net_device *dev)
        struct in_device *in_dev;
 
        rcu_read_lock();
-       in_dev = dev->ip_ptr;
+       in_dev = rcu_dereference(dev->ip_ptr);
        if (in_dev)
                atomic_inc(&in_dev->refcnt);
        rcu_read_unlock();
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/arp.c 
linux-2.6.13-rc6/net/ipv4/arp.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/arp.c  2005-08-07 
11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/arp.c     2005-09-07 22:49:09.000000000 -0700
@@ -334,9 +334,10 @@ static void arp_solicit(struct neighbour
        struct net_device *dev = neigh->dev;
        u32 target = *(u32*)neigh->primary_key;
        int probes = atomic_read(&neigh->probes);
-       struct in_device *in_dev = in_dev_get(dev);
+       struct in_device *in_dev;
 
-       if (!in_dev)
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(dev)) == NULL)
                return;
 
        switch (IN_DEV_ARP_ANNOUNCE(in_dev)) {
@@ -362,6 +363,8 @@ static void arp_solicit(struct neighbour
 
        if (in_dev)
                in_dev_put(in_dev);
+       rcu_read_unlock();
+
        if (!saddr)
                saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
 
@@ -543,11 +546,12 @@ static inline int arp_fwd_proxy(struct i
                return 0;
 
        /* place to check for proxy_arp for routes */
-
+       rcu_read_lock();
        if ((out_dev = in_dev_get(rt->u.dst.dev)) != NULL) {
                omi = IN_DEV_MEDIUM_ID(out_dev);
                in_dev_put(out_dev);
        }
+       rcu_read_unlock();
        return (omi != imi && omi != -1);
 }
 
@@ -710,7 +714,7 @@ static void parp_redo(struct sk_buff *sk
 static int arp_process(struct sk_buff *skb)
 {
        struct net_device *dev = skb->dev;
-       struct in_device *in_dev = in_dev_get(dev);
+       struct in_device *in_dev;
        struct arphdr *arp;
        unsigned char *arp_ptr;
        struct rtable *rt;
@@ -723,8 +727,8 @@ static int arp_process(struct sk_buff *s
        /* arp_rcv below verifies the ARP header and verifies the device
         * is ARP'able.
         */
-
-       if (in_dev == NULL)
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(dev)) == NULL)
                goto out;
 
        arp = skb->nh.arph;
@@ -918,6 +922,7 @@ static int arp_process(struct sk_buff *s
 out:
        if (in_dev)
                in_dev_put(in_dev);
+       rcu_read_unlock();
        kfree_skb(skb);
        return 0;
 }
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/devinet.c 
linux-2.6.13-rc6/net/ipv4/devinet.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/devinet.c      
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/devinet.c 2005-09-08 00:38:01.000000000 -0700
@@ -372,12 +372,15 @@ static int inet_set_ifa(struct net_devic
        return inet_insert_ifa(ifa);
 }
 
+/* returns with rcu read-critical section open, so rcu_read_unlock() in caller 
*/
+
 struct in_device *inetdev_by_index(int ifindex)
 {
        struct net_device *dev;
        struct in_device *in_dev = NULL;
        read_lock(&dev_base_lock);
        dev = __dev_get_by_index(ifindex);
+       rcu_read_lock();
        if (dev)
                in_dev = in_dev_get(dev);
        read_unlock(&dev_base_lock);
@@ -409,7 +412,8 @@ static int inet_rtm_deladdr(struct sk_bu
 
        if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
                goto out;
-       __in_dev_put(in_dev);
+       in_dev_put(in_dev);
+       rcu_read_unlock();
 
        for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
             ifap = &ifa->ifa_next) {
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/icmp.c 
linux-2.6.13-rc6/net/ipv4/icmp.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/icmp.c 2005-08-07 
11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/icmp.c    2005-09-07 23:37:08.000000000 -0700
@@ -890,10 +890,10 @@ static void icmp_address_reply(struct sk
        if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
                goto out;
 
+       rcu_read_lock();
        in_dev = in_dev_get(dev);
        if (!in_dev)
                goto out;
-       rcu_read_lock();
        if (in_dev->ifa_list &&
            IN_DEV_LOG_MARTIANS(in_dev) &&
            IN_DEV_FORWARD(in_dev)) {
@@ -913,8 +913,8 @@ static void icmp_address_reply(struct sk
                               NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src));
                }
        }
-       rcu_read_unlock();
        in_dev_put(in_dev);
+       rcu_read_unlock();
 out:;
 }
 
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/igmp.c 
linux-2.6.13-rc6/net/ipv4/igmp.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/igmp.c 2005-08-07 
11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/igmp.c    2005-09-08 00:35:52.000000000 -0700
@@ -864,10 +864,12 @@ int igmp_rcv(struct sk_buff *skb)
 {
        /* This basically follows the spec line by line -- see RFC1112 */
        struct igmphdr *ih;
-       struct in_device *in_dev = in_dev_get(skb->dev);
+       struct in_device *in_dev;
        int len = skb->len;
 
-       if (in_dev==NULL) {
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(skb->dev) == NULL) {
+               rcu_read_unlock();
                kfree_skb(skb);
                return 0;
        }
@@ -875,6 +877,7 @@ int igmp_rcv(struct sk_buff *skb)
        if (!pskb_may_pull(skb, sizeof(struct igmphdr)) || 
            (u16)csum_fold(skb_checksum(skb, 0, len, 0))) {
                in_dev_put(in_dev);
+               rcu_read_unlock();
                kfree_skb(skb);
                return 0;
        }
@@ -907,6 +910,7 @@ int igmp_rcv(struct sk_buff *skb)
                NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not 
know about it?\n", ih->type));
        }
        in_dev_put(in_dev);
+       rcu_read_unlock();
        kfree_skb(skb);
        return 0;
 }
@@ -1307,8 +1311,8 @@ static struct in_device * ip_mc_find_dev
        if (imr->imr_ifindex) {
                idev = inetdev_by_index(imr->imr_ifindex);
                if (idev)
-                       __in_dev_put(idev);
-               return idev;
+                       __in_dev_put(idev); /* decrement before return? */
+               return idev; /* caller should rcu_read_unlock */
        }
        if (imr->imr_address.s_addr) {
                dev = ip_dev_find(imr->imr_address.s_addr);
@@ -2098,6 +2102,7 @@ void ip_mc_drop_socket(struct sock *sk)
                        (void) ip_mc_leave_src(sk, iml, in_dev);
                        ip_mc_dec_group(in_dev, 
iml->multi.imr_multiaddr.s_addr);
                        in_dev_put(in_dev);
+                       rcu_read_unlock();
                }
                sock_kfree_s(sk, iml, sizeof(*iml));
 
@@ -2154,6 +2159,7 @@ static inline struct ip_mc_list *igmp_mc
             state->dev; 
             state->dev = state->dev->next) {
                struct in_device *in_dev;
+               rcu_read_lock();
                in_dev = in_dev_get(state->dev);
                if (!in_dev)
                        continue;
@@ -2165,6 +2171,7 @@ static inline struct ip_mc_list *igmp_mc
                }
                read_unlock(&in_dev->mc_list_lock);
                in_dev_put(in_dev);
+               rcu_read_unlock();
        }
        return im;
 }
@@ -2183,11 +2190,13 @@ static struct ip_mc_list *igmp_mc_get_ne
                        state->in_dev = NULL;
                        break;
                }
+               rcu_read_lock();
                state->in_dev = in_dev_get(state->dev);
                if (!state->in_dev)
                        continue;
                read_lock(&state->in_dev->mc_list_lock);
                im = state->in_dev->mc_list;
+               rcu_read_unlock();
        }
        return im;
 }
@@ -2317,6 +2326,7 @@ static inline struct ip_sf_list *igmp_mc
             state->dev; 
             state->dev = state->dev->next) {
                struct in_device *idev;
+               rcu_read_lock();
                idev = in_dev_get(state->dev);
                if (unlikely(idev == NULL))
                        continue;
@@ -2334,6 +2344,7 @@ static inline struct ip_sf_list *igmp_mc
                }
                read_unlock(&idev->mc_list_lock);
                in_dev_put(idev);
+               rcu_read_unlock();
        }
        return psf;
 }
@@ -2356,11 +2367,14 @@ static struct ip_sf_list *igmp_mcf_get_n
                                state->idev = NULL;
                                goto out;
                        }
+                       rcu_read_lock();
                        state->idev = in_dev_get(state->dev);
                        if (!state->idev)
+                               rcu_read_unlock();
                                continue;
                        read_lock(&state->idev->mc_list_lock);
                        state->im = state->idev->mc_list;
+                       rcu_read_unlock();
                }
                if (!state->im)
                        break;
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/ip_gre.c 
linux-2.6.13-rc6/net/ipv4/ip_gre.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/ip_gre.c       
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/ip_gre.c  2005-09-08 00:42:38.000000000 -0700
@@ -1121,6 +1121,7 @@ static int ipgre_close(struct net_device
                        ip_mc_dec_group(in_dev, t->parms.iph.daddr);
                        in_dev_put(in_dev);
                }
+               rcu_read_unlock();
        }
        return 0;
 }
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/ip_input.c 
linux-2.6.13-rc6/net/ipv4/ip_input.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/ip_input.c     
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/ip_input.c        2005-09-08 00:45:42.000000000 
-0700
@@ -330,8 +330,9 @@ static inline int ip_rcv_finish(struct s
 
                opt = &(IPCB(skb)->opt);
                if (opt->srr) {
-                       struct in_device *in_dev = in_dev_get(dev);
-                       if (in_dev) {
+                       struct in_device *in_dev;
+                       rcu_read_lock();
+                       if ((in_dev = in_dev_get(dev)) != NULL) {
                                if (!IN_DEV_SOURCE_ROUTE(in_dev)) {
                                        if (IN_DEV_LOG_MARTIANS(in_dev) && 
net_ratelimit())
                                                printk(KERN_INFO "source route 
option %u.%u.%u.%u -> %u.%u.%u.%u\n",
@@ -341,6 +342,7 @@ static inline int ip_rcv_finish(struct s
                                }
                                in_dev_put(in_dev);
                        }
+                       rcu_read_unlock();
                        if (ip_options_rcv_srr(skb))
                                goto drop;
                }
diff -urpNa -X dontdiff 
/mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/route.c 
linux-2.6.13-rc6/net/ipv4/route.c
--- /mnt/shared/linuxKernel2_6/linux-2.6.13-rc6/net/ipv4/route.c        
2005-08-07 11:18:56.000000000 -0700
+++ linux-2.6.13-rc6/net/ipv4/route.c   2005-09-08 08:39:01.000000000 -0700
@@ -1112,14 +1112,15 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
                    u32 saddr, u8 tos, struct net_device *dev)
 {
        int i, k;
-       struct in_device *in_dev = in_dev_get(dev);
+       struct in_device *in_dev;
        struct rtable *rth, **rthp;
        u32  skeys[2] = { saddr, 0 };
        int  ikeys[2] = { dev->ifindex, 0 };
 
        tos &= IPTOS_RT_MASK;
 
-       if (!in_dev)
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(dev)) == NULL)
                return;
 
        if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev)
@@ -1171,6 +1172,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
                                if (rt == NULL) {
                                        ip_rt_put(rth);
                                        in_dev_put(in_dev);
+                                       rcu_read_unlock();
                                        return;
                                }
 
@@ -1223,6 +1225,7 @@ void ip_rt_redirect(u32 old_gw, u32 dadd
                }
        }
        in_dev_put(in_dev);
+       rcu_read_unlock();
        return;
 
 reject_redirect:
@@ -1236,6 +1239,7 @@ reject_redirect:
                       NIPQUAD(saddr), NIPQUAD(daddr), tos);
 #endif
        in_dev_put(in_dev);
+       rcu_read_unlock();
 }
 
 static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
@@ -1284,9 +1288,9 @@ static struct dst_entry *ipv4_negative_a
 void ip_rt_send_redirect(struct sk_buff *skb)
 {
        struct rtable *rt = (struct rtable*)skb->dst;
-       struct in_device *in_dev = in_dev_get(rt->u.dst.dev);
-
-       if (!in_dev)
+       struct in_device *in_dev;
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(rt->u.dst.dev)) == NULL)
                return;
 
        if (!IN_DEV_TX_REDIRECTS(in_dev))
@@ -1327,6 +1331,7 @@ void ip_rt_send_redirect(struct sk_buff 
        }
 out:
         in_dev_put(in_dev);
+       rcu_read_unlock();
 }
 
 static int ip_error(struct sk_buff *skb)
@@ -1482,10 +1487,12 @@ static void ipv4_dst_ifdown(struct dst_e
        struct rtable *rt = (struct rtable *) dst;
        struct in_device *idev = rt->idev;
        if (dev != &loopback_dev && idev && idev->dev == dev) {
-               struct in_device *loopback_idev = in_dev_get(&loopback_dev);
-               if (loopback_idev) {
+               struct in_device *loopback_idev;
+               rcu_read_lock();
+               if (loopback_idev = in_dev_get(&loopback_dev) != NULL) {
                        rt->idev = loopback_idev;
                        in_dev_put(idev);
+                       rcu_read_unlock();
                }
        }
 }
@@ -1593,12 +1600,12 @@ static int ip_route_input_mc(struct sk_b
        unsigned hash;
        struct rtable *rth;
        u32 spec_dst;
-       struct in_device *in_dev = in_dev_get(dev);
+       struct in_device *in_dev;
        u32 itag = 0;
 
        /* Primary sanity checks. */
-
-       if (in_dev == NULL)
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(dev)) == NULL)
                return -EINVAL;
 
        if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr) ||
@@ -1656,15 +1663,18 @@ static int ip_route_input_mc(struct sk_b
        RT_CACHE_STAT_INC(in_slow_mc);
 
        in_dev_put(in_dev);
+       rcu_read_unlock();
        hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5), tos);
        return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
 
 e_nobufs:
        in_dev_put(in_dev);
+       rcu_read_unlock();
        return -ENOBUFS;
 
 e_inval:
        in_dev_put(in_dev);
+       rcu_read_unlock();
        return -EINVAL;
 }
 
@@ -1714,6 +1724,7 @@ static inline int __mkroute_input(struct
        u32 spec_dst, itag;
 
        /* get a working reference to the output device */
+       rcu_read_lock()
        out_dev = in_dev_get(FIB_RES_DEV(*res));
        if (out_dev == NULL) {
                if (net_ratelimit())
@@ -1796,6 +1807,7 @@ static inline int __mkroute_input(struct
  cleanup:
        /* release the working reference to the output device */
        in_dev_put(out_dev);
+       rcu_read_unlock();
        return err;
 }                                              
 
@@ -1899,7 +1911,7 @@ static int ip_route_input_slow(struct sk
                               u8 tos, struct net_device *dev)
 {
        struct fib_result res;
-       struct in_device *in_dev = in_dev_get(dev);
+       struct in_device *in_dev;
        struct flowi fl = { .nl_u = { .ip4_u =
                                      { .daddr = daddr,
                                        .saddr = saddr,
@@ -1919,8 +1931,8 @@ static int ip_route_input_slow(struct sk
        int             free_res = 0;
 
        /* IP on this device is disabled. */
-
-       if (!in_dev)
+       rcu_read_lock();
+       if ((in_dev = in_dev_get(dev)) == NULL)
                goto out;
 
        /* Check for the most weird martians, which can be not detected
@@ -1983,6 +1995,7 @@ static int ip_route_input_slow(struct sk
        
 done:
        in_dev_put(in_dev);
+       rcu_read_unlock();
        if (free_res)
                fib_res_put(&res);
 out:   return err;
@@ -2174,6 +2187,7 @@ static inline int __mkroute_output(struc
                flags |= RTCF_LOCAL;
 
        /* get work reference to inet device */
+       rcu_read_lock();
        in_dev = in_dev_get(dev_out);
        if (!in_dev)
                return -EINVAL;
@@ -2270,6 +2284,7 @@ static inline int __mkroute_output(struc
        *result = rth;
  cleanup:
        /* release work reference to inet device */
+       rcu_read_unlock();
        in_dev_put(in_dev);
 
        return err;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to