Commit d46b1a35 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents e5f39047 8ed421dc
...@@ -1350,7 +1350,7 @@ void skb_add_mtu(int mtu) ...@@ -1350,7 +1350,7 @@ void skb_add_mtu(int mtu)
} }
#endif #endif
static void inline skb_split_inside_header(struct sk_buff *skb, static inline void skb_split_inside_header(struct sk_buff *skb,
struct sk_buff* skb1, struct sk_buff* skb1,
const u32 len, const int pos) const u32 len, const int pos)
{ {
...@@ -1371,7 +1371,7 @@ static void inline skb_split_inside_header(struct sk_buff *skb, ...@@ -1371,7 +1371,7 @@ static void inline skb_split_inside_header(struct sk_buff *skb,
skb->tail = skb->data + len; skb->tail = skb->data + len;
} }
static void inline skb_split_no_header(struct sk_buff *skb, static inline void skb_split_no_header(struct sk_buff *skb,
struct sk_buff* skb1, struct sk_buff* skb1,
const u32 len, int pos) const u32 len, int pos)
{ {
......
...@@ -1075,7 +1075,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -1075,7 +1075,7 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
skb = dn_wait_for_connect(sk, &timeo); skb = dn_wait_for_connect(sk, &timeo);
if (IS_ERR(skb)) { if (IS_ERR(skb)) {
release_sock(sk); release_sock(sk);
return PTR_ERR(sk); return PTR_ERR(skb);
} }
} }
......
...@@ -1102,8 +1102,8 @@ static int __init ic_dynamic(void) ...@@ -1102,8 +1102,8 @@ static int __init ic_dynamic(void)
jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout); jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout);
while (time_before(jiffies, jiff) && !ic_got_reply) { while (time_before(jiffies, jiff) && !ic_got_reply) {
barrier(); set_current_state(TASK_UNINTERRUPTIBLE);
cpu_relax(); schedule_timeout(1);
} }
#ifdef IPCONFIG_DHCP #ifdef IPCONFIG_DHCP
/* DHCP isn't done until we get a DHCPACK. */ /* DHCP isn't done until we get a DHCPACK. */
...@@ -1245,7 +1245,6 @@ u32 __init root_nfs_parse_addr(char *name) ...@@ -1245,7 +1245,6 @@ u32 __init root_nfs_parse_addr(char *name)
static int __init ip_auto_config(void) static int __init ip_auto_config(void)
{ {
unsigned long jiff;
u32 addr; u32 addr;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -1260,18 +1259,16 @@ static int __init ip_auto_config(void) ...@@ -1260,18 +1259,16 @@ static int __init ip_auto_config(void)
try_try_again: try_try_again:
#endif #endif
/* Give hardware a chance to settle */ /* Give hardware a chance to settle */
jiff = jiffies + CONF_PRE_OPEN; set_current_state(TASK_UNINTERRUPTIBLE);
while (time_before(jiffies, jiff)) schedule_timeout(CONF_PRE_OPEN);
cpu_relax();
/* Setup all network devices */ /* Setup all network devices */
if (ic_open_devs() < 0) if (ic_open_devs() < 0)
return -1; return -1;
/* Give drivers a chance to settle */ /* Give drivers a chance to settle */
jiff = jiffies + CONF_POST_OPEN; set_current_state(TASK_UNINTERRUPTIBLE);
while (time_before(jiffies, jiff)) schedule_timeout(CONF_POST_OPEN);
cpu_relax();
/* /*
* If the config information is insufficient (e.g., our IP address or * If the config information is insufficient (e.g., our IP address or
......
...@@ -137,6 +137,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags); ...@@ -137,6 +137,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
static void addrconf_dad_timer(unsigned long data); static void addrconf_dad_timer(unsigned long data);
static void addrconf_dad_completed(struct inet6_ifaddr *ifp); static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_rs_timer(unsigned long data); static void addrconf_rs_timer(unsigned long data);
static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);
static void inet6_prefix_notify(int event, struct inet6_dev *idev, static void inet6_prefix_notify(int event, struct inet6_dev *idev,
...@@ -486,10 +487,15 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -486,10 +487,15 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
struct inet6_ifaddr *ifa = NULL; struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt; struct rt6_info *rt;
int hash; int hash;
static spinlock_t lock = SPIN_LOCK_UNLOCKED;
int err = 0; int err = 0;
spin_lock_bh(&lock); read_lock_bh(&addrconf_lock);
if (idev->dead) {
err = -ENODEV; /*XXX*/
goto out2;
}
write_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */ /* Ignore adding duplicate addresses on an interface */
if (ipv6_chk_same_addr(addr, idev->dev)) { if (ipv6_chk_same_addr(addr, idev->dev)) {
...@@ -523,13 +529,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -523,13 +529,6 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
ifa->flags = flags | IFA_F_TENTATIVE; ifa->flags = flags | IFA_F_TENTATIVE;
ifa->cstamp = ifa->tstamp = jiffies; ifa->cstamp = ifa->tstamp = jiffies;
read_lock(&addrconf_lock);
if (idev->dead) {
read_unlock(&addrconf_lock);
err = -ENODEV; /*XXX*/
goto out;
}
inet6_ifa_count++; inet6_ifa_count++;
ifa->idev = idev; ifa->idev = idev;
in6_dev_hold(idev); in6_dev_hold(idev);
...@@ -539,35 +538,30 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -539,35 +538,30 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
/* Add to big hash table */ /* Add to big hash table */
hash = ipv6_addr_hash(addr); hash = ipv6_addr_hash(addr);
write_lock_bh(&addrconf_hash_lock);
ifa->lst_next = inet6_addr_lst[hash]; ifa->lst_next = inet6_addr_lst[hash];
inet6_addr_lst[hash] = ifa; inet6_addr_lst[hash] = ifa;
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
write_unlock_bh(&addrconf_hash_lock); write_unlock(&addrconf_hash_lock);
write_lock_bh(&idev->lock); write_lock(&idev->lock);
/* Add to inet6_dev unicast addr list. */ /* Add to inet6_dev unicast addr list. */
ifa->if_next = idev->addr_list; ifa->if_next = idev->addr_list;
idev->addr_list = ifa; idev->addr_list = ifa;
#ifdef CONFIG_IPV6_PRIVACY #ifdef CONFIG_IPV6_PRIVACY
ifa->regen_count = 0;
if (ifa->flags&IFA_F_TEMPORARY) { if (ifa->flags&IFA_F_TEMPORARY) {
ifa->tmp_next = idev->tempaddr_list; ifa->tmp_next = idev->tempaddr_list;
idev->tempaddr_list = ifa; idev->tempaddr_list = ifa;
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
} else {
ifa->tmp_next = NULL;
} }
#endif #endif
ifa->rt = rt; ifa->rt = rt;
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
write_unlock_bh(&idev->lock); write_unlock(&idev->lock);
read_unlock(&addrconf_lock); out2:
out: read_unlock_bh(&addrconf_lock);
spin_unlock_bh(&lock);
if (unlikely(err == 0)) if (unlikely(err == 0))
notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa); notifier_call_chain(&inet6addr_chain, NETDEV_UP, ifa);
...@@ -577,6 +571,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen, ...@@ -577,6 +571,9 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
} }
return ifa; return ifa;
out:
write_unlock(&addrconf_hash_lock);
goto out2;
} }
/* This function wants to get referenced ifp and releases it before return */ /* This function wants to get referenced ifp and releases it before return */
...@@ -645,13 +642,14 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -645,13 +642,14 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
#ifdef CONFIG_IPV6_PRIVACY #ifdef CONFIG_IPV6_PRIVACY
static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift) static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift)
{ {
struct inet6_dev *idev; struct inet6_dev *idev = ifp->idev;
struct in6_addr addr, *tmpaddr; struct in6_addr addr, *tmpaddr;
unsigned long tmp_prefered_lft, tmp_valid_lft; unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp;
int tmp_plen; int tmp_plen;
int ret = 0; int ret = 0;
int max_addresses; int max_addresses;
write_lock(&idev->lock);
if (ift) { if (ift) {
spin_lock_bh(&ift->lock); spin_lock_bh(&ift->lock);
memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);
...@@ -661,40 +659,35 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i ...@@ -661,40 +659,35 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
tmpaddr = NULL; tmpaddr = NULL;
} }
retry: retry:
spin_lock_bh(&ifp->lock);
in6_ifa_hold(ifp);
idev = ifp->idev;
in6_dev_hold(idev); in6_dev_hold(idev);
memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
write_lock(&idev->lock);
if (idev->cnf.use_tempaddr <= 0) { if (idev->cnf.use_tempaddr <= 0) {
write_unlock(&idev->lock); write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock);
printk(KERN_INFO printk(KERN_INFO
"ipv6_create_tempaddr(): use_tempaddr is disabled.\n"); "ipv6_create_tempaddr(): use_tempaddr is disabled.\n");
in6_dev_put(idev); in6_dev_put(idev);
in6_ifa_put(ifp);
ret = -1; ret = -1;
goto out; goto out;
} }
spin_lock_bh(&ifp->lock);
if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
idev->cnf.use_tempaddr = -1; /*XXX*/ idev->cnf.use_tempaddr = -1; /*XXX*/
write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
write_unlock(&idev->lock);
printk(KERN_WARNING printk(KERN_WARNING
"ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n"); "ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n");
in6_dev_put(idev); in6_dev_put(idev);
in6_ifa_put(ifp);
ret = -1; ret = -1;
goto out; goto out;
} }
in6_ifa_hold(ifp);
memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) { if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) {
write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
write_unlock(&idev->lock);
printk(KERN_WARNING printk(KERN_WARNING
"ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n"); "ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n");
in6_dev_put(idev);
in6_ifa_put(ifp); in6_ifa_put(ifp);
in6_dev_put(idev);
ret = -1; ret = -1;
goto out; goto out;
} }
...@@ -707,27 +700,33 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i ...@@ -707,27 +700,33 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
idev->cnf.temp_prefered_lft - desync_factor / HZ); idev->cnf.temp_prefered_lft - desync_factor / HZ);
tmp_plen = ifp->prefix_len; tmp_plen = ifp->prefix_len;
max_addresses = idev->cnf.max_addresses; max_addresses = idev->cnf.max_addresses;
write_unlock(&idev->lock); tmp_cstamp = ifp->cstamp;
tmp_tstamp = ifp->tstamp;
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
write_unlock(&idev->lock);
ift = !max_addresses || ift = !max_addresses ||
ipv6_count_addresses(idev) < max_addresses ? ipv6_count_addresses(idev) < max_addresses ?
ipv6_add_addr(idev, &addr, tmp_plen, ipv6_add_addr(idev, &addr, tmp_plen,
ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL; ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : NULL;
if (!ift || IS_ERR(ift)) { if (!ift || IS_ERR(ift)) {
in6_dev_put(idev);
in6_ifa_put(ifp); in6_ifa_put(ifp);
in6_dev_put(idev);
printk(KERN_INFO printk(KERN_INFO
"ipv6_create_tempaddr(): retry temporary address regeneration.\n"); "ipv6_create_tempaddr(): retry temporary address regeneration.\n");
tmpaddr = &addr; tmpaddr = &addr;
write_lock(&idev->lock);
goto retry; goto retry;
} }
spin_lock_bh(&ift->lock); spin_lock_bh(&ift->lock);
ift->ifpub = ifp; ift->ifpub = ifp;
ift->valid_lft = tmp_valid_lft; ift->valid_lft = tmp_valid_lft;
ift->prefered_lft = tmp_prefered_lft; ift->prefered_lft = tmp_prefered_lft;
ift->cstamp = ifp->cstamp; ift->cstamp = tmp_cstamp;
ift->tstamp = ifp->tstamp; ift->tstamp = tmp_tstamp;
spin_unlock_bh(&ift->lock); spin_unlock_bh(&ift->lock);
addrconf_dad_start(ift, 0); addrconf_dad_start(ift, 0);
in6_ifa_put(ift); in6_ifa_put(ift);
in6_dev_put(idev); in6_dev_put(idev);
...@@ -938,14 +937,12 @@ int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev) ...@@ -938,14 +937,12 @@ int ipv6_chk_same_addr(const struct in6_addr *addr, struct net_device *dev)
struct inet6_ifaddr * ifp; struct inet6_ifaddr * ifp;
u8 hash = ipv6_addr_hash(addr); u8 hash = ipv6_addr_hash(addr);
read_lock_bh(&addrconf_hash_lock);
for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
if (ipv6_addr_equal(&ifp->addr, addr)) { if (ipv6_addr_equal(&ifp->addr, addr)) {
if (dev == NULL || ifp->idev->dev == dev) if (dev == NULL || ifp->idev->dev == dev)
break; break;
} }
} }
read_unlock_bh(&addrconf_hash_lock);
return ifp != NULL; return ifp != NULL;
} }
...@@ -2049,7 +2046,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) ...@@ -2049,7 +2046,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
addrconf_del_timer(ifa); addrconf_del_timer(ifa);
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
ipv6_ifa_notify(RTM_DELADDR, ifa); __ipv6_ifa_notify(RTM_DELADDR, ifa);
in6_ifa_put(ifa); in6_ifa_put(ifa);
write_lock_bh(&idev->lock); write_lock_bh(&idev->lock);
...@@ -2129,11 +2126,10 @@ static void addrconf_rs_timer(unsigned long data) ...@@ -2129,11 +2126,10 @@ static void addrconf_rs_timer(unsigned long data)
*/ */
static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags) static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
{ {
struct net_device *dev; struct inet6_dev *idev = ifp->idev;
struct net_device *dev = idev->dev;
unsigned long rand_num; unsigned long rand_num;
dev = ifp->idev->dev;
addrconf_join_solict(dev, &ifp->addr); addrconf_join_solict(dev, &ifp->addr);
if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT)) if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))
...@@ -2141,31 +2137,43 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags) ...@@ -2141,31 +2137,43 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
flags); flags);
net_srandom(ifp->addr.s6_addr32[3]); net_srandom(ifp->addr.s6_addr32[3]);
rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1); rand_num = net_random() % (idev->cnf.rtr_solicit_delay ? : 1);
read_lock_bh(&idev->lock);
if (ifp->dead)
goto out;
spin_lock_bh(&ifp->lock); spin_lock_bh(&ifp->lock);
if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||
!(ifp->flags&IFA_F_TENTATIVE)) { !(ifp->flags&IFA_F_TENTATIVE)) {
ifp->flags &= ~IFA_F_TENTATIVE; ifp->flags &= ~IFA_F_TENTATIVE;
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
read_unlock_bh(&idev->lock);
addrconf_dad_completed(ifp); addrconf_dad_completed(ifp);
return; return;
} }
ifp->probes = ifp->idev->cnf.dad_transmits; ifp->probes = idev->cnf.dad_transmits;
addrconf_mod_timer(ifp, AC_DAD, rand_num); addrconf_mod_timer(ifp, AC_DAD, rand_num);
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
out:
read_unlock_bh(&idev->lock);
} }
static void addrconf_dad_timer(unsigned long data) static void addrconf_dad_timer(unsigned long data)
{ {
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data; struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
struct inet6_dev *idev = ifp->idev;
struct in6_addr unspec; struct in6_addr unspec;
struct in6_addr mcaddr; struct in6_addr mcaddr;
read_lock_bh(&idev->lock);
if (idev->dead) {
read_unlock_bh(&idev->lock);
goto out;
}
spin_lock_bh(&ifp->lock); spin_lock_bh(&ifp->lock);
if (ifp->probes == 0) { if (ifp->probes == 0) {
/* /*
...@@ -2174,22 +2182,23 @@ static void addrconf_dad_timer(unsigned long data) ...@@ -2174,22 +2182,23 @@ static void addrconf_dad_timer(unsigned long data)
ifp->flags &= ~IFA_F_TENTATIVE; ifp->flags &= ~IFA_F_TENTATIVE;
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
read_unlock_bh(&idev->lock);
addrconf_dad_completed(ifp); addrconf_dad_completed(ifp);
in6_ifa_put(ifp); goto out;
return;
} }
ifp->probes--; ifp->probes--;
addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time); addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
read_unlock_bh(&idev->lock);
/* send a neighbour solicitation for our addr */ /* send a neighbour solicitation for our addr */
memset(&unspec, 0, sizeof(unspec)); memset(&unspec, 0, sizeof(unspec));
addrconf_addr_solict_mult(&ifp->addr, &mcaddr); addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec); ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &unspec);
out:
in6_ifa_put(ifp); in6_ifa_put(ifp);
} }
...@@ -2980,7 +2989,7 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = { ...@@ -2980,7 +2989,7 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
.dumpit = inet6_dump_fib, }, .dumpit = inet6_dump_fib, },
}; };
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{ {
inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); inet6_ifa_notify(event ? : RTM_NEWADDR, ifp);
...@@ -3005,6 +3014,14 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) ...@@ -3005,6 +3014,14 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
} }
} }
static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
{
read_lock_bh(&addrconf_lock);
if (likely(ifp->idev->dead == 0))
__ipv6_ifa_notify(event, ifp);
read_unlock_bh(&addrconf_lock);
}
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
static static
......
...@@ -476,13 +476,19 @@ void ip6_route_input(struct sk_buff *skb) ...@@ -476,13 +476,19 @@ void ip6_route_input(struct sk_buff *skb)
BACKTRACK(); BACKTRACK();
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
struct rt6_info *nrt;
dst_hold(&rt->u.dst);
read_unlock_bh(&rt6_lock); read_unlock_bh(&rt6_lock);
rt = rt6_cow(rt, &skb->nh.ipv6h->daddr, nrt = rt6_cow(rt, &skb->nh.ipv6h->daddr,
&skb->nh.ipv6h->saddr); &skb->nh.ipv6h->saddr);
dst_release(&rt->u.dst);
rt = nrt;
if (rt->u.dst.error != -EEXIST || --attempts <= 0) if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2; goto out2;
/* Race condition! In the gap, when rt6_lock was /* Race condition! In the gap, when rt6_lock was
released someone could insert this route. Relookup. released someone could insert this route. Relookup.
*/ */
...@@ -531,9 +537,14 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) ...@@ -531,9 +537,14 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
} }
if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {
struct rt6_info *nrt;
dst_hold(&rt->u.dst);
read_unlock_bh(&rt6_lock); read_unlock_bh(&rt6_lock);
rt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src); nrt = rt6_cow(rt, &fl->fl6_dst, &fl->fl6_src);
dst_release(&rt->u.dst);
rt = nrt;
if (rt->u.dst.error != -EEXIST || --attempts <= 0) if (rt->u.dst.error != -EEXIST || --attempts <= 0)
goto out2; goto out2;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment