X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fdecnet%2Fdn_route.c;h=9881933167bd8e9ae497a60b8615a2118b0674da;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=90d0583f56f4213de789ab3311fbcff3dd279a12;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 90d0583f5..988193316 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -1,4 +1,3 @@ - /* * DECnet An implementation of the DECnet protocol suite for the LINUX * operating system. DECnet is implemented using the BSD Socket @@ -56,7 +55,6 @@ GNU General Public License for more details. *******************************************************************************/ -#include #include #include #include @@ -82,6 +80,7 @@ #include #include #include +#include #include #include #include @@ -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; } @@ -271,9 +267,12 @@ static void dn_dst_link_failure(struct sk_buff *skb) static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { - return memcmp(&fl1->nl_u.dn_u, &fl2->nl_u.dn_u, sizeof(fl1->nl_u.dn_u)) == 0 && - fl1->oif == fl2->oif && - fl1->iif == fl2->iif; + return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) | + (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) | + (fl1->mark ^ fl2->mark) | + (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) | + (fl1->oif ^ fl2->oif) | + (fl1->iif ^ fl2->iif)) == 0; } static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp) @@ -288,10 +287,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 +303,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 +336,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 +381,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 +396,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 +477,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 +508,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 +516,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 +544,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 +574,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; @@ -635,8 +632,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type padlen); if (flags & DN_RT_PKT_CNTL) { - if (unlikely(skb_is_nonlinear(skb)) && - skb_linearize(skb, GFP_ATOMIC) != 0) + if (unlikely(skb_linearize(skb))) goto dump_it; switch(flags & DN_RT_CNTL_MSK) { @@ -684,9 +680,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 +784,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 +792,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 +818,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 +836,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 +863,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; } @@ -890,10 +880,8 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old { .daddr = oldflp->fld_dst, .saddr = oldflp->fld_src, .scope = RT_SCOPE_UNIVERSE, -#ifdef CONFIG_DECNET_ROUTE_FWMARK - .fwmark = oldflp->fld_fwmark -#endif } }, + .mark = oldflp->mark, .iif = loopback_dev.ifindex, .oif = oldflp->oif }; struct dn_route *rt = NULL; @@ -904,13 +892,14 @@ 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, - oldflp->fld_fwmark, loopback_dev.ifindex, oldflp->oif); + " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), + dn_ntohs(oldflp->fld_src), + oldflp->mark, loopback_dev.ifindex, oldflp->oif); /* If we have an output interface, verify its a DECnet device */ if (oldflp->oif) { @@ -938,8 +927,13 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old for(dev_out = dev_base; dev_out; dev_out = dev_out->next) { if (!dev_out->dn_ptr) continue; - if (dn_dev_islocal(dev_out, oldflp->fld_src)) - break; + if (!dn_dev_islocal(dev_out, oldflp->fld_src)) + continue; + if ((dev_out->flags & IFF_LOOPBACK) && + oldflp->fld_dst && + !dn_dev_islocal(dev_out, oldflp->fld_dst)) + continue; + break; } read_unlock(&dev_base_lock); if (dev_out == NULL) @@ -973,8 +967,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 +992,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)) || @@ -1109,9 +1104,7 @@ make_route: rt->fl.fld_dst = oldflp->fld_dst; rt->fl.oif = oldflp->oif; rt->fl.iif = 0; -#ifdef CONFIG_DECNET_ROUTE_FWMARK - rt->fl.fld_fwmark = oldflp->fld_fwmark; -#endif + rt->fl.mark = oldflp->mark; rt->rt_saddr = fl.fld_src; rt->rt_daddr = fl.fld_dst; @@ -1174,25 +1167,23 @@ 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 - (flp->fld_fwmark == rt->fl.fld_fwmark) && -#endif + (flp->mark == rt->fl.mark) && (rt->fl.iif == 0) && (rt->fl.oif == flp->oif)) { 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,16 +1221,14 @@ 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, .scope = RT_SCOPE_UNIVERSE, -#ifdef CONFIG_DECNET_ROUTE_FWMARK - .fwmark = skb->nfmark -#endif } }, + .mark = skb->mark, .iif = skb->dev->ifindex }; struct dn_fib_res res = { .fi = NULL, .type = RTN_UNREACHABLE }; int err = -EINVAL; @@ -1276,9 +1265,8 @@ static int dn_route_input_slow(struct sk_buff *skb) goto e_inval; 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); @@ -1291,7 +1279,7 @@ static int dn_route_input_slow(struct sk_buff *skb) dev_hold(out_dev); if (res.r) - src_map = dn_fib_rules_policy(fl.fld_src, &res, &flags); + src_map = fl.fld_src; /* no NAT support for now */ gateway = DN_FIB_RES_GW(res); if (res.type == RTN_NAT) { @@ -1347,7 +1335,7 @@ static int dn_route_input_slow(struct sk_buff *skb) goto make_route; /* Packet was intra-ethernet, so we know its on-link */ - if (cb->rt_flags | DN_RT_F_IE) { + if (cb->rt_flags & DN_RT_F_IE) { gateway = cb->src; flags |= RTCF_DIRECTSRC; goto make_route; @@ -1387,13 +1375,13 @@ make_route: rt->fl.fld_dst = cb->dst; rt->fl.oif = 0; rt->fl.iif = in_dev->ifindex; - rt->fl.fld_fwmark = fl.fld_fwmark; + rt->fl.mark = fl.mark; rt->u.dst.flags = DST_HOST; 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,14 +1442,12 @@ 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) && -#ifdef CONFIG_DECNET_ROUTE_FWMARK - (rt->fl.fld_fwmark == skb->nfmark) && -#endif + (rt->fl.mark == skb->mark) && (rt->fl.iif == cb->iif)) { rt->u.dst.lastuse = jiffies; dst_hold(&rt->u.dst); @@ -1476,22 +1462,23 @@ 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; struct nlmsghdr *nlh; unsigned char *b = skb->tail; - struct rta_cacheinfo ci; + long expires; - 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; r->rtm_tos = 0; r->rtm_table = RT_TABLE_MAIN; + RTA_PUT_U32(skb, RTA_TABLE, RT_TABLE_MAIN); r->rtm_type = rt->rt_type; r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; r->rtm_scope = RT_SCOPE_UNIVERSE; @@ -1515,16 +1502,10 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event, int RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway); if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0) goto rtattr_failure; - ci.rta_lastuse = jiffies_to_clock_t(jiffies - rt->u.dst.lastuse); - ci.rta_used = rt->u.dst.__use; - ci.rta_clntref = atomic_read(&rt->u.dst.__refcnt); - if (rt->u.dst.expires) - ci.rta_expires = jiffies_to_clock_t(rt->u.dst.expires - jiffies); - else - ci.rta_expires = 0; - ci.rta_error = rt->u.dst.error; - ci.rta_id = ci.rta_ts = ci.rta_tsage = 0; - RTA_PUT(skb, RTA_CACHEINFO, sizeof(ci), &ci); + expires = rt->u.dst.expires ? rt->u.dst.expires - jiffies : 0; + if (rtnl_put_cacheinfo(skb, &rt->u.dst, 0, 0, 0, expires, + rt->u.dst.error) < 0) + goto rtattr_failure; if (rt->fl.iif) RTA_PUT(skb, RTA_IIF, sizeof(int), &rt->fl.iif); @@ -1605,9 +1586,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) if (rtm->rtm_flags & RTM_F_NOTIFY) rt->rt_flags |= RTCF_NOTIFY; - 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; @@ -1616,9 +1595,7 @@ int dn_cache_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, void *arg) goto out_free; } - err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); - - return err; + return rtnl_unicast(skb, NETLINK_CB(in_skb).pid); out_free: kfree_skb(skb); @@ -1647,21 +1624,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 +1660,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 +1705,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) @@ -1787,14 +1765,9 @@ void __init dn_route_init(void) { int i, goal, order; - dn_dst_ops.kmem_cachep = kmem_cache_create("dn_dst_cache", - sizeof(struct dn_route), - 0, SLAB_HWCACHE_ALIGN, - NULL, NULL); - - if (!dn_dst_ops.kmem_cachep) - panic("DECnet: Failed to allocate dn_dst_cache\n"); - + dn_dst_ops.kmem_cachep = + kmem_cache_create("dn_dst_cache", sizeof(struct dn_route), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); init_timer(&dn_route_timer); dn_route_timer.function = dn_dst_check_expire; dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ; @@ -1832,7 +1805,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; }