Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / decnet / dn_route.c
index 90d0583..e172cf9 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * DECnet       An implementation of the DECnet protocol suite for the LINUX
  *              operating system.  DECnet is implemented using the  BSD Socket
@@ -100,9 +99,9 @@ extern struct neigh_table dn_neigh_table;
 
 static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00};
 
-int dn_rt_min_delay = 2 * HZ;
-int dn_rt_max_delay = 10 * HZ;
-int dn_rt_mtu_expires = 10 * 60 * HZ;
+static const int dn_rt_min_delay = 2 * HZ;
+static const int dn_rt_max_delay = 10 * HZ;
+static const int dn_rt_mtu_expires = 10 * 60 * HZ;
 
 static unsigned long dn_rt_deadline;
 
@@ -118,8 +117,7 @@ static struct dn_rt_hash_bucket *dn_rt_hash_table;
 static unsigned dn_rt_hash_mask;
 
 static struct timer_list dn_route_timer;
-static struct timer_list dn_rt_flush_timer =
-               TIMER_INITIALIZER(dn_run_flush, 0, 0);
+static DEFINE_TIMER(dn_rt_flush_timer, dn_run_flush, 0, 0);
 int decnet_dst_gc_interval = 2;
 
 static struct dst_ops dn_dst_ops = {
@@ -135,9 +133,9 @@ static struct dst_ops dn_dst_ops = {
        .entries =              ATOMIC_INIT(0),
 };
 
-static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst)
+static __inline__ unsigned dn_hash(__le16 src, __le16 dst)
 {
-       unsigned short tmp = src ^ dst;
+       __u16 tmp = (__u16 __force)(src ^ dst);
        tmp ^= (tmp >> 3);
        tmp ^= (tmp >> 5);
        tmp ^= (tmp >> 10);
@@ -146,14 +144,13 @@ static __inline__ unsigned dn_hash(unsigned short src, unsigned short dst)
 
 static inline void dnrt_free(struct dn_route *rt)
 {
-       call_rcu(&rt->u.dst.rcu_head, (void (*)(void *))dst_free, &rt->u.dst);
+       call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
 }
 
 static inline void dnrt_drop(struct dn_route *rt)
 {
-       if (rt)
-               dst_release(&rt->u.dst);
-       call_rcu(&rt->u.dst.rcu_head, (void (*)(void *))dst_free, &rt->u.dst);
+       dst_release(&rt->u.dst);
+       call_rcu_bh(&rt->u.dst.rcu_head, dst_rcu_free);
 }
 
 static void dn_dst_check_expire(unsigned long dummy)
@@ -254,7 +251,6 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
  */
 static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
 {
-       dst_release(dst);
        return NULL;
 }
 
@@ -288,10 +284,9 @@ static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route *
                if (compare_keys(&rth->fl, &rt->fl)) {
                        /* Put it first */
                        *rthp = rth->u.rt_next;
-                       smp_wmb();
-                       rth->u.rt_next = dn_rt_hash_table[hash].chain;
-                       smp_wmb();
-                       dn_rt_hash_table[hash].chain = rth;
+                       rcu_assign_pointer(rth->u.rt_next,
+                                          dn_rt_hash_table[hash].chain);
+                       rcu_assign_pointer(dn_rt_hash_table[hash].chain, rth);
 
                        rth->u.dst.__use++;
                        dst_hold(&rth->u.dst);
@@ -305,10 +300,8 @@ static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route *
                rthp = &rth->u.rt_next;
        }
 
-       smp_wmb();
-       rt->u.rt_next = dn_rt_hash_table[hash].chain;
-       smp_wmb();
-       dn_rt_hash_table[hash].chain = rt;
+       rcu_assign_pointer(rt->u.rt_next, dn_rt_hash_table[hash].chain);
+       rcu_assign_pointer(dn_rt_hash_table[hash].chain, rt);
        
        dst_hold(&rt->u.dst);
        rt->u.dst.__use++;
@@ -340,7 +333,7 @@ nothing_to_declare:
        }
 }
 
-static spinlock_t dn_rt_flush_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(dn_rt_flush_lock);
 
 void dn_rt_cache_flush(int delay)
 {
@@ -385,9 +378,9 @@ static int dn_return_short(struct sk_buff *skb)
 {
        struct dn_skb_cb *cb;
        unsigned char *ptr;
-       dn_address *src;
-       dn_address *dst;
-       dn_address tmp;
+       __le16 *src;
+       __le16 *dst;
+       __le16 tmp;
 
        /* Add back headers */
        skb_push(skb, skb->data - skb->nh.raw);
@@ -400,9 +393,9 @@ static int dn_return_short(struct sk_buff *skb)
        ptr = skb->data + 2;
        *ptr++ = (cb->rt_flags & ~DN_RT_F_RQR) | DN_RT_F_RTS;
 
-       dst = (dn_address *)ptr;
+       dst = (__le16 *)ptr;
        ptr += 2;
-       src = (dn_address *)ptr;
+       src = (__le16 *)ptr;
        ptr += 2;
        *ptr = 0; /* Zero hop count */
 
@@ -481,7 +474,8 @@ static int dn_route_rx_packet(struct sk_buff *skb)
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
                printk(KERN_DEBUG
                        "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n",
-                       (int)cb->rt_flags, devname, skb->len, cb->src, cb->dst, 
+                       (int)cb->rt_flags, devname, skb->len,
+                       dn_ntohs(cb->src), dn_ntohs(cb->dst),
                        err, skb->pkt_type);
        }
 
@@ -511,7 +505,7 @@ static int dn_route_rx_long(struct sk_buff *skb)
 
         /* Destination info */
         ptr += 2;
-       cb->dst = dn_htons(dn_eth2dn(ptr));
+       cb->dst = dn_eth2dn(ptr);
         if (memcmp(ptr, dn_hiord_addr, 4) != 0)
                 goto drop_it;
         ptr += 6;
@@ -519,7 +513,7 @@ static int dn_route_rx_long(struct sk_buff *skb)
 
         /* Source info */
         ptr += 2;
-       cb->src = dn_htons(dn_eth2dn(ptr));
+       cb->src = dn_eth2dn(ptr);
         if (memcmp(ptr, dn_hiord_addr, 4) != 0)
                 goto drop_it;
         ptr += 6;
@@ -547,9 +541,9 @@ static int dn_route_rx_short(struct sk_buff *skb)
        skb_pull(skb, 5);
        skb->h.raw = skb->data;
 
-       cb->dst = *(dn_address *)ptr;
+       cb->dst = *(__le16 *)ptr;
         ptr += 2;
-        cb->src = *(dn_address *)ptr;
+        cb->src = *(__le16 *)ptr;
         ptr += 2;
         cb->hops = *ptr & 0x3f;
 
@@ -577,11 +571,11 @@ static int dn_route_ptp_hello(struct sk_buff *skb)
        return NET_RX_SUCCESS;
 }
 
-int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
+int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
 {
        struct dn_skb_cb *cb;
        unsigned char flags = 0;
-       __u16 len = dn_ntohs(*(__u16 *)skb->data);
+       __u16 len = dn_ntohs(*(__le16 *)skb->data);
        struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr;
        unsigned char padlen = 0;
 
@@ -684,9 +678,8 @@ out:
        return NET_RX_DROP;
 }
 
-static int dn_output(struct sk_buff **pskb)
+static int dn_output(struct sk_buff *skb)
 {
-       struct sk_buff *skb = *pskb;
        struct dst_entry *dst = skb->dst;
        struct dn_route *rt = (struct dn_route *)dst;
        struct net_device *dev = dst->dev;
@@ -789,7 +782,7 @@ static int dn_rt_bug(struct sk_buff *skb)
                struct dn_skb_cb *cb = DN_SKB_CB(skb);
 
                printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n",
-                               cb->src, cb->dst);
+                               dn_ntohs(cb->src), dn_ntohs(cb->dst));
        }
 
        kfree_skb(skb);
@@ -797,11 +790,6 @@ static int dn_rt_bug(struct sk_buff *skb)
        return NET_RX_BAD;
 }
 
-static int dn_rt_bug_out(struct sk_buff **pskb)
-{
-       return dn_rt_bug(*pskb);
-}
-
 static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
 {
        struct dn_fib_info *fi = res->fi;
@@ -828,14 +816,14 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
        if (rt->u.dst.metrics[RTAX_MTU-1] == 0 || 
             rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu)
                rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
-       mss = dn_mss_from_pmtu(dev, dst_pmtu(&rt->u.dst));
+       mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst));
        if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 ||
            rt->u.dst.metrics[RTAX_ADVMSS-1] > mss)
                rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
        return 0;
 }
 
-static inline int dn_match_addr(__u16 addr1, __u16 addr2)
+static inline int dn_match_addr(__le16 addr1, __le16 addr2)
 {
        __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
        int match = 16;
@@ -846,9 +834,9 @@ static inline int dn_match_addr(__u16 addr1, __u16 addr2)
        return match;
 }
 
-static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int scope)
+static __le16 dnet_select_source(const struct net_device *dev, __le16 daddr, int scope)
 {
-       __u16 saddr = 0;
+       __le16 saddr = 0;
        struct dn_dev *dn_db = dev->dn_ptr;
        struct dn_ifaddr *ifa;
        int best_match = 0;
@@ -873,14 +861,14 @@ static __u16 dnet_select_source(const struct net_device *dev, __u16 daddr, int s
        return saddr;
 }
 
-static inline __u16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
+static inline __le16 __dn_fib_res_prefsrc(struct dn_fib_res *res)
 {
        return dnet_select_source(DN_FIB_RES_DEV(*res), DN_FIB_RES_GW(*res), res->scope);
 }
 
-static inline __u16 dn_fib_rules_map_destination(__u16 daddr, struct dn_fib_res *res)
+static inline __le16 dn_fib_rules_map_destination(__le16 daddr, struct dn_fib_res *res)
 {
-       __u16 mask = dnet_make_mask(res->prefixlen);
+       __le16 mask = dnet_make_mask(res->prefixlen);
        return (daddr&~mask)|res->fi->fib_nh->nh_gw;
 }
 
@@ -904,12 +892,13 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old
        struct dn_fib_res res = { .fi = NULL, .type = RTN_UNICAST };
        int err;
        int free_res = 0;
-       __u16 gateway = 0;
+       __le16 gateway = 0;
 
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: dst=%04x src=%04x mark=%d"
-                      " iif=%d oif=%d\n", oldflp->fld_dst, oldflp->fld_src,
+                      " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst),
+                      dn_ntohs(oldflp->fld_src),
                        oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif);
 
        /* If we have an output interface, verify its a DECnet device */
@@ -973,8 +962,9 @@ source_ok:
        if (decnet_debug_level & 16)
                printk(KERN_DEBUG
                       "dn_route_output_slow: initial checks complete."
-                      " dst=%o4x src=%04x oif=%d try_hard=%d\n", fl.fld_dst,
-                      fl.fld_src, fl.oif, try_hard);
+                      " dst=%o4x src=%04x oif=%d try_hard=%d\n",
+                      dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src),
+                      fl.oif, try_hard);
 
        /*
         * N.B. If the kernel is compiled without router support then
@@ -997,7 +987,7 @@ source_ok:
                 * here
                 */
                if (!try_hard) {
-                       neigh = dn_neigh_lookup(&dn_neigh_table, &fl.fld_dst);
+                       neigh = neigh_lookup_nodev(&dn_neigh_table, &fl.fld_dst);
                        if (neigh) {
                                if ((oldflp->oif && 
                                    (neigh->dev->ifindex != oldflp->oif)) ||
@@ -1174,9 +1164,9 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl
        struct dn_route *rt = NULL;
 
        if (!(flags & MSG_TRYHARD)) {
-               rcu_read_lock();
-               for(rt = dn_rt_hash_table[hash].chain; rt; rt = rt->u.rt_next) {
-                       read_barrier_depends();
+               rcu_read_lock_bh();
+               for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt;
+                       rt = rcu_dereference(rt->u.rt_next)) {
                        if ((flp->fld_dst == rt->fl.fld_dst) &&
                            (flp->fld_src == rt->fl.fld_src) &&
 #ifdef CONFIG_DECNET_ROUTE_FWMARK
@@ -1187,12 +1177,12 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl
                                rt->u.dst.lastuse = jiffies;
                                dst_hold(&rt->u.dst);
                                rt->u.dst.__use++;
-                               rcu_read_unlock();
+                               rcu_read_unlock_bh();
                                *pprt = &rt->u.dst;
                                return 0;
                        }
                }
-               rcu_read_unlock();
+               rcu_read_unlock_bh();
        }
 
        return dn_route_output_slow(pprt, flp, flags);
@@ -1230,8 +1220,8 @@ static int dn_route_input_slow(struct sk_buff *skb)
        struct neighbour *neigh = NULL;
        unsigned hash;
        int flags = 0;
-       __u16 gateway = 0;
-       __u16 local_src = 0;
+       __le16 gateway = 0;
+       __le16 local_src = 0;
        struct flowi fl = { .nl_u = { .dn_u = 
                                     { .daddr = cb->dst,
                                       .saddr = cb->src,
@@ -1278,7 +1268,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
                res.type = RTN_LOCAL;
                flags |= RTCF_DIRECTSRC;
        } else {
-               __u16 src_map = fl.fld_src;
+               __le16 src_map = fl.fld_src;
                free_res = 1;
 
                out_dev = DN_FIB_RES_DEV(res);
@@ -1393,7 +1383,7 @@ make_route:
        rt->u.dst.neighbour = neigh;
        rt->u.dst.dev = out_dev;
        rt->u.dst.lastuse = jiffies;
-       rt->u.dst.output = dn_rt_bug_out;
+       rt->u.dst.output = dn_rt_bug;
        switch(res.type) {
                case RTN_UNICAST:
                        rt->u.dst.input = dn_forward;
@@ -1454,8 +1444,8 @@ int dn_route_input(struct sk_buff *skb)
                return 0;
 
        rcu_read_lock();
-       for(rt = dn_rt_hash_table[hash].chain; rt != NULL; rt = rt->u.rt_next) {
-               read_barrier_depends();
+       for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt != NULL;
+           rt = rcu_dereference(rt->u.rt_next)) {
                if ((rt->fl.fld_src == cb->src) &&
                    (rt->fl.fld_dst == cb->dst) &&
                    (rt->fl.oif == 0) &&
@@ -1476,7 +1466,8 @@ int dn_route_input(struct sk_buff *skb)
        return dn_route_input_slow(skb);
 }
 
-static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int nowait)
+static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
+                          int event, int nowait, unsigned int flags)
 {
        struct dn_route *rt = (struct dn_route *)skb->dst;
        struct rtmsg *r;
@@ -1484,9 +1475,8 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int
        unsigned char *b = skb->tail;
        struct rta_cacheinfo ci;
 
-       nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*r));
+       nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
        r = NLMSG_DATA(nlh);
-       nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0;
        r->rtm_family = AF_DECnet;
        r->rtm_dst_len = 16;
        r->rtm_src_len = 0;
@@ -1607,7 +1597,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg)
 
        NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
 
-       err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0);
+       err = dn_rt_fill_info(skb, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq, RTM_NEWROUTE, 0, 0);
 
        if (err == 0)
                goto out_free;
@@ -1647,21 +1637,23 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
                        continue;
                if (h > s_h)
                        s_idx = 0;
-               rcu_read_lock();
-               for(rt = dn_rt_hash_table[h].chain, idx = 0; rt; rt = rt->u.rt_next, idx++) {
-                       read_barrier_depends();
+               rcu_read_lock_bh();
+               for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0;
+                       rt;
+                       rt = rcu_dereference(rt->u.rt_next), idx++) {
                        if (idx < s_idx)
                                continue;
                        skb->dst = dst_clone(&rt->u.dst);
                        if (dn_rt_fill_info(skb, NETLINK_CB(cb->skb).pid,
-                                       cb->nlh->nlmsg_seq, RTM_NEWROUTE, 1) <= 0) {
+                                       cb->nlh->nlmsg_seq, RTM_NEWROUTE, 
+                                       1, NLM_F_MULTI) <= 0) {
                                dst_release(xchg(&skb->dst, NULL));
-                               rcu_read_unlock();
+                               rcu_read_unlock_bh();
                                goto done;
                        }
                        dst_release(xchg(&skb->dst, NULL));
                }
-               rcu_read_unlock();
+               rcu_read_unlock_bh();
        }
 
 done:
@@ -1681,26 +1673,25 @@ static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
        struct dn_rt_cache_iter_state *s = seq->private;
 
        for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
-               rcu_read_lock();
+               rcu_read_lock_bh();
                rt = dn_rt_hash_table[s->bucket].chain;
                if (rt)
                        break;
-               rcu_read_unlock();
+               rcu_read_unlock_bh();
        }
        return rt;
 }
 
 static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
 {
-       struct dn_rt_cache_iter_state *s = seq->private;
+       struct dn_rt_cache_iter_state *s = rcu_dereference(seq->private);
 
-       smp_read_barrier_depends();
        rt = rt->u.rt_next;
        while(!rt) {
-               rcu_read_unlock();
+               rcu_read_unlock_bh();
                if (--s->bucket < 0)
                        break;
-               rcu_read_lock();
+               rcu_read_lock_bh();
                rt = dn_rt_hash_table[s->bucket].chain;
        }
        return rt;
@@ -1727,7 +1718,7 @@ static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v)
 {
        if (v)
-               rcu_read_unlock();
+               rcu_read_unlock_bh();
 }
 
 static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
@@ -1832,7 +1823,7 @@ void __init dn_route_init(void)
 
        dn_rt_hash_mask--;
         for(i = 0; i <= dn_rt_hash_mask; i++) {
-                dn_rt_hash_table[i].lock = SPIN_LOCK_UNLOCKED;
+                spin_lock_init(&dn_rt_hash_table[i].lock);
                 dn_rt_hash_table[i].chain = NULL;
         }