* [PATCH 01/12] IPv6: addrconf dad timer unnecessary bh_disable
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-04 8:39 ` David Miller
2010-03-02 23:32 ` [PATCH 02/12] IPv6: addrconf timer race Stephen Hemminger
` (11 subsequent siblings)
12 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-dad-bh.patch --]
[-- Type: text/plain, Size: 1296 bytes --]
Timer code runs in bottom half, so there is no need for
using _bh form of locking. Also check if device is not ready
to avoid race with address that is no longer active.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv6/addrconf.c 2010-02-26 20:00:39.967484383 -0800
+++ b/net/ipv6/addrconf.c 2010-02-27 08:29:44.544108734 -0800
@@ -2850,9 +2850,9 @@ static void addrconf_dad_timer(unsigned
struct inet6_dev *idev = ifp->idev;
struct in6_addr mcaddr;
- read_lock_bh(&idev->lock);
- if (idev->dead) {
- read_unlock_bh(&idev->lock);
+ read_lock(&idev->lock);
+ if (idev->dead || !(idev->if_flags & IF_READY)) {
+ read_unlock(&idev->lock);
goto out;
}
@@ -2864,7 +2864,7 @@ static void addrconf_dad_timer(unsigned
ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);
spin_unlock(&ifp->lock);
- read_unlock_bh(&idev->lock);
+ read_unlock(&idev->lock);
addrconf_dad_completed(ifp);
@@ -2874,7 +2874,7 @@ static void addrconf_dad_timer(unsigned
ifp->probes--;
addrconf_mod_timer(ifp, AC_DAD, ifp->idev->nd_parms->retrans_time);
spin_unlock(&ifp->lock);
- read_unlock_bh(&idev->lock);
+ read_unlock(&idev->lock);
/* send a neighbour solicitation for our addr */
addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 02/12] IPv6: addrconf timer race
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
2010-03-02 23:32 ` [PATCH 01/12] IPv6: addrconf dad timer unnecessary bh_disable Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-04 8:40 ` David Miller
2010-03-02 23:32 ` [PATCH 03/12] IPv6: addrconf notify when address is unavailable Stephen Hemminger
` (10 subsequent siblings)
12 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-rstimer.patch --]
[-- Type: text/plain, Size: 1949 bytes --]
The Router Solicitation timer races with device state changes
because it doesn't lock the device. Use local variable to avoid
one repeated dereference.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv6/addrconf.c 2010-02-26 20:00:43.703982448 -0800
+++ b/net/ipv6/addrconf.c 2010-02-27 08:29:41.727984521 -0800
@@ -2739,28 +2739,29 @@ static int addrconf_ifdown(struct net_de
static void addrconf_rs_timer(unsigned long data)
{
struct inet6_ifaddr *ifp = (struct inet6_ifaddr *) data;
+ struct inet6_dev *idev = ifp->idev;
- if (ifp->idev->cnf.forwarding)
+ read_lock(&idev->lock);
+ if (idev->dead || !(idev->if_flags & IF_READY))
goto out;
- if (ifp->idev->if_flags & IF_RA_RCVD) {
- /*
- * Announcement received after solicitation
- * was sent
- */
+ if (idev->cnf.forwarding)
+ goto out;
+
+ /* Announcement received after solicitation was sent */
+ if (idev->if_flags & IF_RA_RCVD)
goto out;
- }
spin_lock(&ifp->lock);
- if (ifp->probes++ < ifp->idev->cnf.rtr_solicits) {
+ if (ifp->probes++ < idev->cnf.rtr_solicits) {
/* The wait after the last probe can be shorter */
addrconf_mod_timer(ifp, AC_RS,
- (ifp->probes == ifp->idev->cnf.rtr_solicits) ?
- ifp->idev->cnf.rtr_solicit_delay :
- ifp->idev->cnf.rtr_solicit_interval);
+ (ifp->probes == idev->cnf.rtr_solicits) ?
+ idev->cnf.rtr_solicit_delay :
+ idev->cnf.rtr_solicit_interval);
spin_unlock(&ifp->lock);
- ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
+ ndisc_send_rs(idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);
} else {
spin_unlock(&ifp->lock);
/*
@@ -2768,10 +2769,11 @@ static void addrconf_rs_timer(unsigned l
* assumption any longer.
*/
printk(KERN_DEBUG "%s: no IPv6 routers present\n",
- ifp->idev->dev->name);
+ idev->dev->name);
}
out:
+ read_unlock(&idev->lock);
in6_ifa_put(ifp);
}
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 03/12] IPv6: addrconf notify when address is unavailable
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
2010-03-02 23:32 ` [PATCH 01/12] IPv6: addrconf dad timer unnecessary bh_disable Stephen Hemminger
2010-03-02 23:32 ` [PATCH 02/12] IPv6: addrconf timer race Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-04 8:40 ` David Miller
2010-03-02 23:32 ` [PATCH 04/12] ipv6: convert temporary address list to list macros Stephen Hemminger
` (9 subsequent siblings)
12 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-anycast-notify.patch --]
[-- Type: text/plain, Size: 3038 bytes --]
My recent change in net-next to retain permanent addresses caused regression.
Device refcount would not go to zero when device was unregistered because
left over anycast reference would hold ipv6 dev reference which would hold
device references...
The correct procedure is to call notify chain when address is no longer
available for use. When interface comes back DAD timer will notify
back that address is available.
Also, link local addresses should be purged when interface is brought
down. The address might be changed.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 37 ++++++++++++++++++++++---------------
1 file changed, 22 insertions(+), 15 deletions(-)
--- a/net/ipv6/addrconf.c 2010-02-27 08:56:23.955450341 -0800
+++ b/net/ipv6/addrconf.c 2010-02-27 08:57:02.271199959 -0800
@@ -2649,11 +2649,11 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&addrconf_hash_lock);
while ((ifa = *bifa) != NULL) {
if (ifa->idev == idev &&
- (how || !(ifa->flags&IFA_F_PERMANENT))) {
+ (how || !(ifa->flags&IFA_F_PERMANENT) ||
+ ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
*bifa = ifa->lst_next;
ifa->lst_next = NULL;
- addrconf_del_timer(ifa);
- in6_ifa_put(ifa);
+ __in6_ifa_put(ifa);
continue;
}
bifa = &ifa->lst_next;
@@ -2691,28 +2691,40 @@ static int addrconf_ifdown(struct net_de
#endif
bifa = &idev->addr_list;
while ((ifa = *bifa) != NULL) {
- if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) {
- /* Retain permanent address on admin down */
+ addrconf_del_timer(ifa);
+
+ /* If just doing link down, and address is permanent
+ and not link-local, then retain it. */
+ if (how == 0 &&
+ (ifa->flags&IFA_F_PERMANENT) &&
+ !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
bifa = &ifa->if_next;
- /* Restart DAD if needed when link comes back up */
- if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
- idev->cnf.accept_dad <= 0 ||
- (ifa->flags & IFA_F_NODAD)))
- ifa->flags |= IFA_F_TENTATIVE;
+ /* If not doing DAD on this address, just keep it. */
+ if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
+ idev->cnf.accept_dad <= 0 ||
+ (ifa->flags & IFA_F_NODAD))
+ continue;
+
+ /* If it was tentative already, no need to notify */
+ if (ifa->flags & IFA_F_TENTATIVE)
+ continue;
+
+ /* Flag it for later restoration when link comes up */
+ ifa->flags |= IFA_F_TENTATIVE;
+ in6_ifa_hold(ifa);
} else {
*bifa = ifa->if_next;
ifa->if_next = NULL;
-
ifa->dead = 1;
- write_unlock_bh(&idev->lock);
+ }
+ write_unlock_bh(&idev->lock);
- __ipv6_ifa_notify(RTM_DELADDR, ifa);
- atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
- in6_ifa_put(ifa);
+ __ipv6_ifa_notify(RTM_DELADDR, ifa);
+ atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
+ in6_ifa_put(ifa);
- write_lock_bh(&idev->lock);
- }
+ write_lock_bh(&idev->lock);
}
write_unlock_bh(&idev->lock);
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 03/12] IPv6: addrconf notify when address is unavailable
2010-03-02 23:32 ` [PATCH 03/12] IPv6: addrconf notify when address is unavailable Stephen Hemminger
@ 2010-03-04 8:40 ` David Miller
0 siblings, 0 replies; 20+ messages in thread
From: David Miller @ 2010-03-04 8:40 UTC (permalink / raw)
To: shemminger; +Cc: yoshfuji, netdev
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Tue, 02 Mar 2010 15:32:46 -0800
> My recent change in net-next to retain permanent addresses caused regression.
> Device refcount would not go to zero when device was unregistered because
> left over anycast reference would hold ipv6 dev reference which would hold
> device references...
>
> The correct procedure is to call notify chain when address is no longer
> available for use. When interface comes back DAD timer will notify
> back that address is available.
>
>
> Also, link local addresses should be purged when interface is brought
> down. The address might be changed.
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Applied.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 04/12] ipv6: convert temporary address list to list macros
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (2 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 03/12] IPv6: addrconf notify when address is unavailable Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 05/12] ipv6: convert addrconf list to hlist Stephen Hemminger
` (8 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: ipv6-tmp-addrlist.patch --]
[-- Type: text/plain, Size: 3069 bytes --]
Use list macros instead of open coded linked list.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
include/net/if_inet6.h | 4 ++--
net/ipv6/addrconf.c | 30 ++++++++++++------------------
2 files changed, 14 insertions(+), 20 deletions(-)
--- a/include/net/if_inet6.h 2010-02-26 17:50:50.719484571 -0800
+++ b/include/net/if_inet6.h 2010-02-27 08:29:38.872232789 -0800
@@ -58,7 +58,7 @@ struct inet6_ifaddr {
struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
#ifdef CONFIG_IPV6_PRIVACY
- struct inet6_ifaddr *tmp_next; /* next addr in tempaddr_lst */
+ struct list_head tmp_list;
struct inet6_ifaddr *ifpub;
int regen_count;
#endif
@@ -175,7 +175,7 @@ struct inet6_dev {
#ifdef CONFIG_IPV6_PRIVACY
u8 rndid[8];
struct timer_list regen_timer;
- struct inet6_ifaddr *tempaddr_list;
+ struct list_head tempaddr_list;
#endif
struct neigh_parms *nd_parms;
--- a/net/ipv6/addrconf.c 2010-02-26 20:00:45.207484349 -0800
+++ b/net/ipv6/addrconf.c 2010-02-27 08:29:38.856233475 -0800
@@ -401,6 +401,7 @@ static struct inet6_dev * ipv6_add_dev(s
#endif
#ifdef CONFIG_IPV6_PRIVACY
+ INIT_LIST_HEAD(&ndev->tempaddr_list);
setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
if ((dev->flags&IFF_LOOPBACK) ||
dev->type == ARPHRD_TUNNEL ||
@@ -679,8 +680,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
#ifdef CONFIG_IPV6_PRIVACY
if (ifa->flags&IFA_F_TEMPORARY) {
- ifa->tmp_next = idev->tempaddr_list;
- idev->tempaddr_list = ifa;
+ list_add(&ifa->tmp_list, &idev->tempaddr_list);
in6_ifa_hold(ifa);
}
#endif
@@ -732,19 +732,12 @@ static void ipv6_del_addr(struct inet6_i
write_lock_bh(&idev->lock);
#ifdef CONFIG_IPV6_PRIVACY
if (ifp->flags&IFA_F_TEMPORARY) {
- for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL;
- ifap = &ifa->tmp_next) {
- if (ifa == ifp) {
- *ifap = ifa->tmp_next;
- if (ifp->ifpub) {
- in6_ifa_put(ifp->ifpub);
- ifp->ifpub = NULL;
- }
- __in6_ifa_put(ifp);
- ifa->tmp_next = NULL;
- break;
- }
+ list_del(&ifp->tmp_list);
+ if (ifp->ifpub) {
+ in6_ifa_put(ifp->ifpub);
+ ifp->ifpub = NULL;
}
+ __in6_ifa_put(ifp);
}
#endif
@@ -1968,7 +1961,7 @@ ok:
#ifdef CONFIG_IPV6_PRIVACY
read_lock_bh(&in6_dev->lock);
/* update all temporary addresses in the list */
- for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) {
+ list_for_each_entry(ift, &in6_dev->tempaddr_list, tmp_list) {
/*
* When adjusting the lifetimes of an existing
* temporary address, only lower the lifetimes.
@@ -2673,9 +2666,10 @@ static int addrconf_ifdown(struct net_de
in6_dev_put(idev);
/* clear tempaddr list */
- while ((ifa = idev->tempaddr_list) != NULL) {
- idev->tempaddr_list = ifa->tmp_next;
- ifa->tmp_next = NULL;
+ while (!list_empty(&idev->tempaddr_list)) {
+ ifa = list_first_entry(&idev->tempaddr_list,
+ struct inet6_ifaddr, tmp_list);
+ list_del(&ifa->tmp_list);
ifa->dead = 1;
write_unlock_bh(&idev->lock);
spin_lock_bh(&ifa->lock);
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 05/12] ipv6: convert addrconf list to hlist
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (3 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 04/12] ipv6: convert temporary address list to list macros Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 06/12] IPv6: convert addrconf hash list to RCU Stephen Hemminger
` (7 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: ipv6-addrconf-hlist.patch --]
[-- Type: text/plain, Size: 9363 bytes --]
Using hash list macros, simplifies code and helps later RCU.
This patch includes some initialization that is not strictly necessary,
since an empty hlist node/list is all zero; and list is in BSS
and node is allocated with kzalloc.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
include/net/if_inet6.h | 2
net/ipv6/addrconf.c | 128 ++++++++++++++++++++-----------------------------
2 files changed, 54 insertions(+), 76 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:20:10.473202008 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:25:23.173252540 -0800
@@ -126,7 +126,7 @@ static int ipv6_count_addresses(struct i
/*
* Configured unicast address hash table
*/
-static struct inet6_ifaddr *inet6_addr_lst[IN6_ADDR_HSIZE];
+static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
static DEFINE_RWLOCK(addrconf_hash_lock);
static void addrconf_verify(unsigned long);
@@ -528,7 +528,7 @@ static int addrconf_fixup_forwarding(str
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
{
WARN_ON(ifp->if_next != NULL);
- WARN_ON(ifp->lst_next != NULL);
+ WARN_ON(!hlist_unhashed(&ifp->addr_lst));
#ifdef NET_REFCNT_DEBUG
printk(KERN_DEBUG "inet6_ifa_finish_destroy\n");
@@ -643,6 +643,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
spin_lock_init(&ifa->lock);
init_timer(&ifa->timer);
+ INIT_HLIST_NODE(&ifa->addr_lst);
ifa->timer.data = (unsigned long) ifa;
ifa->scope = scope;
ifa->prefix_len = pfxlen;
@@ -669,8 +670,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
/* Add to big hash table */
hash = ipv6_addr_hash(addr);
- ifa->lst_next = inet6_addr_lst[hash];
- inet6_addr_lst[hash] = ifa;
+ hlist_add_head(&ifa->addr_lst, &inet6_addr_lst[hash]);
in6_ifa_hold(ifa);
write_unlock(&addrconf_hash_lock);
@@ -718,15 +718,8 @@ static void ipv6_del_addr(struct inet6_i
ifp->dead = 1;
write_lock_bh(&addrconf_hash_lock);
- for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL;
- ifap = &ifa->lst_next) {
- if (ifa == ifp) {
- *ifap = ifa->lst_next;
- __in6_ifa_put(ifp);
- ifa->lst_next = NULL;
- break;
- }
- }
+ hlist_del_init(&ifp->addr_lst);
+ __in6_ifa_put(ifp);
write_unlock_bh(&addrconf_hash_lock);
write_lock_bh(&idev->lock);
@@ -1277,11 +1270,12 @@ static int ipv6_count_addresses(struct i
int ipv6_chk_addr(struct net *net, struct in6_addr *addr,
struct net_device *dev, int strict)
{
- struct inet6_ifaddr * ifp;
+ struct inet6_ifaddr *ifp = NULL;
+ struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
read_lock_bh(&addrconf_hash_lock);
- for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -1300,10 +1294,11 @@ static
int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
struct net_device *dev)
{
- struct inet6_ifaddr * ifp;
+ struct inet6_ifaddr *ifp;
+ struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
- for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr)) {
@@ -1342,11 +1337,12 @@ EXPORT_SYMBOL(ipv6_chk_prefix);
struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr,
struct net_device *dev, int strict)
{
- struct inet6_ifaddr * ifp;
+ struct inet6_ifaddr *ifp = NULL;
+ struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
read_lock_bh(&addrconf_hash_lock);
- for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) {
+ hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr)) {
@@ -2610,7 +2606,6 @@ static int addrconf_ifdown(struct net_de
struct inet6_dev *idev;
struct inet6_ifaddr *ifa, **bifa;
struct net *net = dev_net(dev);
- int i;
ASSERT_RTNL();
@@ -2635,25 +2630,6 @@ static int addrconf_ifdown(struct net_de
}
- /* Step 2: clear hash table */
- for (i=0; i<IN6_ADDR_HSIZE; i++) {
- bifa = &inet6_addr_lst[i];
-
- write_lock_bh(&addrconf_hash_lock);
- while ((ifa = *bifa) != NULL) {
- if (ifa->idev == idev &&
- (how || !(ifa->flags&IFA_F_PERMANENT) ||
- ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
- *bifa = ifa->lst_next;
- ifa->lst_next = NULL;
- __in6_ifa_put(ifa);
- continue;
- }
- bifa = &ifa->lst_next;
- }
- write_unlock_bh(&addrconf_hash_lock);
- }
-
write_lock_bh(&idev->lock);
/* Step 3: clear flags for stateless addrconf */
@@ -2714,6 +2690,12 @@ static int addrconf_ifdown(struct net_de
}
write_unlock_bh(&idev->lock);
+ /* clear hash table */
+ write_lock_bh(&addrconf_hash_lock);
+ hlist_del_init(&ifa->addr_lst);
+ __in6_ifa_put(ifa);
+ write_unlock_bh(&addrconf_hash_lock);
+
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
in6_ifa_put(ifa);
@@ -2953,36 +2935,37 @@ static struct inet6_ifaddr *if6_get_firs
struct net *net = seq_file_net(seq);
for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
- ifa = inet6_addr_lst[state->bucket];
-
- while (ifa && !net_eq(dev_net(ifa->idev->dev), net))
- ifa = ifa->lst_next;
- if (ifa)
- break;
+ struct hlist_node *n;
+ hlist_for_each_entry(ifa, n,
+ &inet6_addr_lst[state->bucket], addr_lst) {
+ if (net_eq(dev_net(ifa->idev->dev), net))
+ return ifa;
+ }
}
- return ifa;
+ return NULL;
}
-static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa)
+static struct inet6_ifaddr *if6_get_next(struct seq_file *seq,
+ struct inet6_ifaddr *ifa)
{
struct if6_iter_state *state = seq->private;
struct net *net = seq_file_net(seq);
+ struct hlist_node *n = &ifa->addr_lst;
- ifa = ifa->lst_next;
-try_again:
- if (ifa) {
- if (!net_eq(dev_net(ifa->idev->dev), net)) {
- ifa = ifa->lst_next;
- goto try_again;
- }
+ hlist_for_each_entry_continue(ifa, n, addr_lst) {
+ if (net_eq(dev_net(ifa->idev->dev), net))
+ return ifa;
}
- if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) {
- ifa = inet6_addr_lst[state->bucket];
- goto try_again;
+ while (++state->bucket < IN6_ADDR_HSIZE) {
+ hlist_for_each_entry(ifa, n,
+ &inet6_addr_lst[state->bucket], addr_lst) {
+ if (net_eq(dev_net(ifa->idev->dev), net))
+ return ifa;
+ }
}
- return ifa;
+ return NULL;
}
static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)
@@ -3084,10 +3067,12 @@ void if6_proc_exit(void)
int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
{
int ret = 0;
- struct inet6_ifaddr * ifp;
+ struct inet6_ifaddr *ifp = NULL;
+ struct hlist_node *n;
u8 hash = ipv6_addr_hash(addr);
+
read_lock_bh(&addrconf_hash_lock);
- for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) {
+ hlist_for_each_entry(ifp, n, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -3108,6 +3093,7 @@ int ipv6_chk_home_addr(struct net *net,
static void addrconf_verify(unsigned long foo)
{
struct inet6_ifaddr *ifp;
+ struct hlist_node *node;
unsigned long now, next;
int i;
@@ -3121,7 +3107,7 @@ static void addrconf_verify(unsigned lon
restart:
read_lock(&addrconf_hash_lock);
- for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
+ hlist_for_each_entry(ifp, node, &inet6_addr_lst[i], addr_lst) {
unsigned long age;
#ifdef CONFIG_IPV6_PRIVACY
unsigned long regen_advance;
@@ -4540,7 +4526,7 @@ EXPORT_SYMBOL(unregister_inet6addr_notif
int __init addrconf_init(void)
{
- int err;
+ int i, err;
if ((err = ipv6_addr_label_init()) < 0) {
printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n",
@@ -4575,6 +4561,9 @@ int __init addrconf_init(void)
if (err)
goto errlo;
+ for (i = 0; i < IN6_ADDR_HSIZE; i++)
+ INIT_HLIST_HEAD(&inet6_addr_lst[i]);
+
register_netdevice_notifier(&ipv6_dev_notf);
addrconf_verify(0);
@@ -4603,7 +4592,6 @@ errlo:
void addrconf_cleanup(void)
{
- struct inet6_ifaddr *ifa;
struct net_device *dev;
int i;
@@ -4624,18 +4612,8 @@ void addrconf_cleanup(void)
* Check hash table.
*/
write_lock_bh(&addrconf_hash_lock);
- for (i=0; i < IN6_ADDR_HSIZE; i++) {
- for (ifa=inet6_addr_lst[i]; ifa; ) {
- struct inet6_ifaddr *bifa;
-
- bifa = ifa;
- ifa = ifa->lst_next;
- printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa);
- /* Do not free it; something is wrong.
- Now we can investigate it with debugger.
- */
- }
- }
+ for (i = 0; i < IN6_ADDR_HSIZE; i++)
+ WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
write_unlock_bh(&addrconf_hash_lock);
del_timer(&addr_chk_timer);
--- a/include/net/if_inet6.h 2010-03-02 14:20:10.473202008 -0800
+++ b/include/net/if_inet6.h 2010-03-02 14:24:40.305201840 -0800
@@ -54,7 +54,7 @@ struct inet6_ifaddr {
struct inet6_dev *idev;
struct rt6_info *rt;
- struct inet6_ifaddr *lst_next; /* next addr in addr_lst */
+ struct hlist_node addr_lst;
struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
#ifdef CONFIG_IPV6_PRIVACY
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 06/12] IPv6: convert addrconf hash list to RCU
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (4 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 05/12] ipv6: convert addrconf list to hlist Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 07/12] ipv6: user better hash for addrconf Stephen Hemminger
` (6 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: ipv6-addrconf-rcu.patch --]
[-- Type: text/plain, Size: 9668 bytes --]
Convert from reader/writer lock to RCU and spinlock for addrconf
hash list.
Adds an additional helper macro for hlist_for_each_entry_continue_rcu
to handle the continue case.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
include/linux/rculist.h | 13 +++++++
include/net/if_inet6.h | 1
net/ipv6/addrconf.c | 80 +++++++++++++++++++++++++-----------------------
3 files changed, 57 insertions(+), 37 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:29:25.444951749 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:33:59.033450885 -0800
@@ -127,7 +127,7 @@ static int ipv6_count_addresses(struct i
* Configured unicast address hash table
*/
static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE];
-static DEFINE_RWLOCK(addrconf_hash_lock);
+static DEFINE_SPINLOCK(addrconf_hash_lock);
static void addrconf_verify(unsigned long);
@@ -523,8 +523,13 @@ static int addrconf_fixup_forwarding(str
}
#endif
-/* Nobody refers to this ifaddr, destroy it */
+static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head)
+{
+ struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu);
+ kfree(ifp);
+}
+/* Nobody refers to this ifaddr, destroy it */
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
{
WARN_ON(ifp->if_next != NULL);
@@ -545,7 +550,7 @@ void inet6_ifa_finish_destroy(struct ine
}
dst_release(&ifp->rt->u.dst);
- kfree(ifp);
+ call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);
}
static void
@@ -616,7 +621,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
goto out2;
}
- write_lock(&addrconf_hash_lock);
+ spin_lock(&addrconf_hash_lock);
/* Ignore adding duplicate addresses on an interface */
if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
@@ -670,9 +675,9 @@ ipv6_add_addr(struct inet6_dev *idev, co
/* Add to big hash table */
hash = ipv6_addr_hash(addr);
- hlist_add_head(&ifa->addr_lst, &inet6_addr_lst[hash]);
+ hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]);
in6_ifa_hold(ifa);
- write_unlock(&addrconf_hash_lock);
+ spin_unlock(&addrconf_hash_lock);
write_lock(&idev->lock);
/* Add to inet6_dev unicast addr list. */
@@ -699,7 +704,7 @@ out2:
return ifa;
out:
- write_unlock(&addrconf_hash_lock);
+ spin_unlock(&addrconf_hash_lock);
goto out2;
}
@@ -717,10 +722,10 @@ static void ipv6_del_addr(struct inet6_i
ifp->dead = 1;
- write_lock_bh(&addrconf_hash_lock);
- hlist_del_init(&ifp->addr_lst);
+ spin_lock_bh(&addrconf_hash_lock);
+ hlist_del_init_rcu(&ifp->addr_lst);
__in6_ifa_put(ifp);
- write_unlock_bh(&addrconf_hash_lock);
+ spin_unlock_bh(&addrconf_hash_lock);
write_lock_bh(&idev->lock);
#ifdef CONFIG_IPV6_PRIVACY
@@ -1274,8 +1279,8 @@ int ipv6_chk_addr(struct net *net, struc
struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
- read_lock_bh(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
+ rcu_read_lock_bh();
+ hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -1285,7 +1290,8 @@ int ipv6_chk_addr(struct net *net, struc
break;
}
}
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
+
return ifp != NULL;
}
EXPORT_SYMBOL(ipv6_chk_addr);
@@ -1341,8 +1347,8 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str
struct hlist_node *node;
u8 hash = ipv6_addr_hash(addr);
- read_lock_bh(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
+ rcu_read_lock_bh();
+ hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr)) {
@@ -1353,7 +1359,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str
}
}
}
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
return ifp;
}
@@ -2691,10 +2697,10 @@ static int addrconf_ifdown(struct net_de
write_unlock_bh(&idev->lock);
/* clear hash table */
- write_lock_bh(&addrconf_hash_lock);
- hlist_del_init(&ifa->addr_lst);
+ spin_lock_bh(&addrconf_hash_lock);
+ hlist_del_init_rcu(&ifa->addr_lst);
__in6_ifa_put(ifa);
- write_unlock_bh(&addrconf_hash_lock);
+ spin_unlock_bh(&addrconf_hash_lock);
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
@@ -2936,11 +2942,10 @@ static struct inet6_ifaddr *if6_get_firs
for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) {
struct hlist_node *n;
- hlist_for_each_entry(ifa, n,
- &inet6_addr_lst[state->bucket], addr_lst) {
+ hlist_for_each_entry_rcu(ifa, n, &inet6_addr_lst[state->bucket],
+ addr_lst)
if (net_eq(dev_net(ifa->idev->dev), net))
return ifa;
- }
}
return NULL;
}
@@ -2952,10 +2957,9 @@ static struct inet6_ifaddr *if6_get_next
struct net *net = seq_file_net(seq);
struct hlist_node *n = &ifa->addr_lst;
- hlist_for_each_entry_continue(ifa, n, addr_lst) {
+ hlist_for_each_entry_continue_rcu(ifa, n, addr_lst)
if (net_eq(dev_net(ifa->idev->dev), net))
return ifa;
- }
while (++state->bucket < IN6_ADDR_HSIZE) {
hlist_for_each_entry(ifa, n,
@@ -2979,9 +2983,9 @@ static struct inet6_ifaddr *if6_get_idx(
}
static void *if6_seq_start(struct seq_file *seq, loff_t *pos)
- __acquires(addrconf_hash_lock)
+ __acquires(rcu)
{
- read_lock_bh(&addrconf_hash_lock);
+ rcu_read_lock_bh();
return if6_get_idx(seq, *pos);
}
@@ -2995,9 +2999,9 @@ static void *if6_seq_next(struct seq_fil
}
static void if6_seq_stop(struct seq_file *seq, void *v)
- __releases(addrconf_hash_lock)
+ __releases(rcu)
{
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
}
static int if6_seq_show(struct seq_file *seq, void *v)
@@ -3071,8 +3075,8 @@ int ipv6_chk_home_addr(struct net *net,
struct hlist_node *n;
u8 hash = ipv6_addr_hash(addr);
- read_lock_bh(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, n, &inet6_addr_lst[hash], addr_lst) {
+ rcu_read_lock_bh();
+ hlist_for_each_entry_rcu(ifp, n, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
continue;
if (ipv6_addr_equal(&ifp->addr, addr) &&
@@ -3081,7 +3085,7 @@ int ipv6_chk_home_addr(struct net *net,
break;
}
}
- read_unlock_bh(&addrconf_hash_lock);
+ rcu_read_unlock_bh();
return ret;
}
#endif
@@ -3097,7 +3101,8 @@ static void addrconf_verify(unsigned lon
unsigned long now, next;
int i;
- spin_lock_bh(&addrconf_verify_lock);
+ rcu_read_lock_bh();
+ spin_lock(&addrconf_verify_lock);
now = jiffies;
next = now + ADDR_CHECK_FREQUENCY;
@@ -3106,8 +3111,8 @@ static void addrconf_verify(unsigned lon
for (i=0; i < IN6_ADDR_HSIZE; i++) {
restart:
- read_lock(&addrconf_hash_lock);
- hlist_for_each_entry(ifp, node, &inet6_addr_lst[i], addr_lst) {
+ hlist_for_each_entry_rcu(ifp, node,
+ &inet6_addr_lst[i], addr_lst) {
unsigned long age;
#ifdef CONFIG_IPV6_PRIVACY
unsigned long regen_advance;
@@ -3129,7 +3134,6 @@ restart:
age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
in6_ifa_hold(ifp);
- read_unlock(&addrconf_hash_lock);
ipv6_del_addr(ifp);
goto restart;
} else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
@@ -3151,7 +3155,6 @@ restart:
if (deprecate) {
in6_ifa_hold(ifp);
- read_unlock(&addrconf_hash_lock);
ipv6_ifa_notify(0, ifp);
in6_ifa_put(ifp);
@@ -3169,7 +3172,7 @@ restart:
in6_ifa_hold(ifp);
in6_ifa_hold(ifpub);
spin_unlock(&ifp->lock);
- read_unlock(&addrconf_hash_lock);
+
spin_lock(&ifpub->lock);
ifpub->regen_count = 0;
spin_unlock(&ifpub->lock);
@@ -3189,12 +3192,12 @@ restart:
spin_unlock(&ifp->lock);
}
}
- read_unlock(&addrconf_hash_lock);
}
addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
add_timer(&addr_chk_timer);
- spin_unlock_bh(&addrconf_verify_lock);
+ spin_unlock(&addrconf_verify_lock);
+ rcu_read_unlock_bh();
}
static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local)
@@ -4611,10 +4614,10 @@ void addrconf_cleanup(void)
/*
* Check hash table.
*/
- write_lock_bh(&addrconf_hash_lock);
+ spin_lock_bh(&addrconf_hash_lock);
for (i = 0; i < IN6_ADDR_HSIZE; i++)
WARN_ON(!hlist_empty(&inet6_addr_lst[i]));
- write_unlock_bh(&addrconf_hash_lock);
+ spin_unlock_bh(&addrconf_hash_lock);
del_timer(&addr_chk_timer);
rtnl_unlock();
--- a/include/linux/rculist.h 2010-03-01 08:22:23.456662311 -0800
+++ b/include/linux/rculist.h 2010-03-02 14:29:56.641076077 -0800
@@ -428,5 +428,18 @@ static inline void hlist_add_after_rcu(s
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
pos = rcu_dereference_raw(pos->next))
+/**
+ * hlist_for_each_entry_continue_rcu - iterate over a hlist continuing after current point
+ * @tpos: the type * to use as a loop cursor.
+ * @pos: the &struct hlist_node to use as a loop cursor.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue_rcu(tpos, pos, member) \
+ for (pos = rcu_dereference((pos)->next); \
+ pos && ({ prefetch(pos->next); 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); \
+ pos = rcu_dereference(pos->next))
+
+
#endif /* __KERNEL__ */
#endif
--- a/include/net/if_inet6.h 2010-03-02 14:29:25.465077512 -0800
+++ b/include/net/if_inet6.h 2010-03-02 14:31:13.137385294 -0800
@@ -64,6 +64,7 @@ struct inet6_ifaddr {
#endif
int dead;
+ struct rcu_head rcu;
};
struct ip6_sf_socklist {
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 07/12] ipv6: user better hash for addrconf
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (5 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 06/12] IPv6: convert addrconf hash list to RCU Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 08/12] ipv6: convert idev_list to list macros Stephen Hemminger
` (5 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: ipv6-hash-addrconf.patch --]
[-- Type: text/plain, Size: 2752 bytes --]
The existing hash function has a couple of issues:
* it is hardwired to 16 for IN6_ADDR_HSIZE
* limited to 256 and callers using int
* use jhash2 rather than some old BSD algorithm
No need for random seed since this is local only (based on assigned
addresses) table.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 26 +++++++++-----------------
1 file changed, 9 insertions(+), 17 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:33:59.033450885 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:34:41.516826671 -0800
@@ -573,23 +573,14 @@ ipv6_link_dev_addr(struct inet6_dev *ide
*ifap = ifp;
}
-/*
- * Hash function taken from net_alias.c
- */
-static u8 ipv6_addr_hash(const struct in6_addr *addr)
+static u32 ipv6_addr_hash(const struct in6_addr *addr)
{
- __u32 word;
-
/*
* We perform the hash function over the last 64 bits of the address
* This will include the IEEE address token on links that support it.
*/
-
- word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]);
- word ^= (word >> 16);
- word ^= (word >> 8);
-
- return ((word ^ (word >> 4)) & 0x0f);
+ return jhash_2words(addr->s6_addr32[2], addr->s6_addr32[3], 0)
+ & (IN6_ADDR_HSIZE - 1);
}
/* On success it returns ifp with increased reference count */
@@ -600,7 +591,7 @@ ipv6_add_addr(struct inet6_dev *idev, co
{
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt;
- int hash;
+ unsigned int hash;
int err = 0;
int addr_type = ipv6_addr_type(addr);
@@ -1277,7 +1268,7 @@ int ipv6_chk_addr(struct net *net, struc
{
struct inet6_ifaddr *ifp = NULL;
struct hlist_node *node;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
@@ -1302,7 +1293,7 @@ int ipv6_chk_same_addr(struct net *net,
{
struct inet6_ifaddr *ifp;
struct hlist_node *node;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net))
@@ -1345,7 +1336,7 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str
{
struct inet6_ifaddr *ifp = NULL;
struct hlist_node *node;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {
@@ -3073,7 +3064,7 @@ int ipv6_chk_home_addr(struct net *net,
int ret = 0;
struct inet6_ifaddr *ifp = NULL;
struct hlist_node *n;
- u8 hash = ipv6_addr_hash(addr);
+ unsigned int hash = ipv6_addr_hash(addr);
rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, n, &inet6_addr_lst[hash], addr_lst) {
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 08/12] ipv6: convert idev_list to list macros
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (6 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 07/12] ipv6: user better hash for addrconf Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 09/12] IPv6: addrconf cleanups Stephen Hemminger
` (4 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: ipv6-idev-list.patch --]
[-- Type: text/plain, Size: 10491 bytes --]
Convert to list macro's for the list of addresses per interface
in IPv6.
This also solves a potential race problem during the cleanup process.
The issue is that addrconf_ifdown() needs to traverse address list,
but then drop lock to call the notifier. The version in -next
could get confused if add/delete happened during this window.
Original code (2.6.32 and earlier) was okay because all addresses
were always deleted.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
drivers/net/bonding/bond_ipv6.c | 9 ++--
include/net/if_inet6.h | 6 +--
net/ipv6/addrconf.c | 74 ++++++++++++++++++++++------------------
net/sctp/ipv6.c | 2 -
4 files changed, 50 insertions(+), 41 deletions(-)
--- a/drivers/net/bonding/bond_ipv6.c 2010-03-02 14:29:25.436951570 -0800
+++ b/drivers/net/bonding/bond_ipv6.c 2010-03-02 14:46:33.864952850 -0800
@@ -37,7 +37,6 @@
static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr)
{
struct inet6_dev *idev;
- struct inet6_ifaddr *ifa;
if (!dev)
return;
@@ -47,10 +46,12 @@ static void bond_glean_dev_ipv6(struct n
return;
read_lock_bh(&idev->lock);
- ifa = idev->addr_list;
- if (ifa)
+ if (!list_empty(&idev->addr_list)) {
+ struct inet6_ifaddr *ifa
+ = list_first_entry(&idev->addr_list,
+ struct inet6_ifaddr, if_list);
ipv6_addr_copy(addr, &ifa->addr);
- else
+ } else
ipv6_addr_set(addr, 0, 0, 0, 0);
read_unlock_bh(&idev->lock);
--- a/include/net/if_inet6.h 2010-03-02 14:38:15.169701060 -0800
+++ b/include/net/if_inet6.h 2010-03-02 14:46:33.864952850 -0800
@@ -55,7 +55,7 @@ struct inet6_ifaddr {
struct rt6_info *rt;
struct hlist_node addr_lst;
- struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
+ struct list_head if_list;
#ifdef CONFIG_IPV6_PRIVACY
struct list_head tmp_list;
@@ -152,9 +152,9 @@ struct ipv6_devstat {
};
struct inet6_dev {
- struct net_device *dev;
+ struct net_device *dev;
- struct inet6_ifaddr *addr_list;
+ struct list_head addr_list;
struct ifmcaddr6 *mc_list;
struct ifmcaddr6 *mc_tomb;
--- a/net/ipv6/addrconf.c 2010-03-02 14:34:41.516826671 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:33.868952041 -0800
@@ -317,7 +317,7 @@ void in6_dev_finish_destroy(struct inet6
{
struct net_device *dev = idev->dev;
- WARN_ON(idev->addr_list != NULL);
+ WARN_ON(!list_empty(&idev->addr_list));
WARN_ON(idev->mc_list != NULL);
#ifdef NET_REFCNT_DEBUG
@@ -350,6 +350,8 @@ static struct inet6_dev * ipv6_add_dev(s
rwlock_init(&ndev->lock);
ndev->dev = dev;
+ INIT_LIST_HEAD(&ndev->addr_list);
+
memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
ndev->cnf.mtu6 = dev->mtu;
ndev->cnf.sysctl = NULL;
@@ -466,7 +468,8 @@ static void dev_forward_change(struct in
else
ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);
}
- for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) {
+
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
if (ifa->flags&IFA_F_TENTATIVE)
continue;
if (idev->cnf.forwarding)
@@ -532,7 +535,6 @@ static void inet6_ifa_finish_destroy_rcu
/* Nobody refers to this ifaddr, destroy it */
void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)
{
- WARN_ON(ifp->if_next != NULL);
WARN_ON(!hlist_unhashed(&ifp->addr_lst));
#ifdef NET_REFCNT_DEBUG
@@ -556,21 +558,21 @@ void inet6_ifa_finish_destroy(struct ine
static void
ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
{
- struct inet6_ifaddr *ifa, **ifap;
+ struct list_head *p;
int ifp_scope = ipv6_addr_src_scope(&ifp->addr);
/*
* Each device address list is sorted in order of scope -
* global before linklocal.
*/
- for (ifap = &idev->addr_list; (ifa = *ifap) != NULL;
- ifap = &ifa->if_next) {
+ list_for_each(p, &idev->addr_list) {
+ struct inet6_ifaddr *ifa
+ = list_entry(p, struct inet6_ifaddr, if_list);
if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))
break;
}
- ifp->if_next = *ifap;
- *ifap = ifp;
+ list_add(&ifp->if_list, p);
}
static u32 ipv6_addr_hash(const struct in6_addr *addr)
@@ -703,7 +705,7 @@ out:
static void ipv6_del_addr(struct inet6_ifaddr *ifp)
{
- struct inet6_ifaddr *ifa, **ifap;
+ struct inet6_ifaddr *ifa, *ifn;
struct inet6_dev *idev = ifp->idev;
int hash;
int deleted = 0, onlink = 0;
@@ -730,11 +732,11 @@ static void ipv6_del_addr(struct inet6_i
}
#endif
- for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) {
+ list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) {
if (ifa == ifp) {
- *ifap = ifa->if_next;
+ list_del_init(&ifp->if_list);
__in6_ifa_put(ifp);
- ifa->if_next = NULL;
+
if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)
break;
deleted = 1;
@@ -767,7 +769,6 @@ static void ipv6_del_addr(struct inet6_i
}
}
}
- ifap = &ifa->if_next;
}
write_unlock_bh(&idev->lock);
@@ -1146,7 +1147,7 @@ int ipv6_dev_get_saddr(struct net *net,
continue;
read_lock_bh(&idev->lock);
- for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) {
+ list_for_each_entry(score->ifa, &idev->addr_list, if_list) {
int i;
/*
@@ -1238,8 +1239,9 @@ int ipv6_get_lladdr(struct net_device *d
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
- if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
+ if (ifp->scope == IFA_LINK &&
+ !(ifp->flags & banned_flags)) {
ipv6_addr_copy(addr, &ifp->addr);
err = 0;
break;
@@ -1257,7 +1259,7 @@ static int ipv6_count_addresses(struct i
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next)
+ list_for_each_entry(ifp, &idev->addr_list, if_list)
cnt++;
read_unlock_bh(&idev->lock);
return cnt;
@@ -1317,7 +1319,7 @@ int ipv6_chk_prefix(struct in6_addr *add
idev = __in6_dev_get(dev);
if (idev) {
read_lock_bh(&idev->lock);
- for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
onlink = ipv6_prefix_equal(addr, &ifa->addr,
ifa->prefix_len);
if (onlink)
@@ -1553,7 +1555,7 @@ static int ipv6_inherit_eui64(u8 *eui, s
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
memcpy(eui, ifp->addr.s6_addr+8, 8);
err = 0;
@@ -2157,7 +2159,7 @@ static int inet6_addr_del(struct net *ne
return -ENXIO;
read_lock_bh(&idev->lock);
- for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
if (ifp->prefix_len == plen &&
ipv6_addr_equal(pfx, &ifp->addr)) {
in6_ifa_hold(ifp);
@@ -2168,7 +2170,7 @@ static int inet6_addr_del(struct net *ne
/* If the last address is deleted administratively,
disable IPv6 on this interface.
*/
- if (idev->addr_list == NULL)
+ if (list_empty(&idev->addr_list))
addrconf_ifdown(idev->dev, 1);
return 0;
}
@@ -2601,8 +2603,9 @@ static void addrconf_bonding_change(stru
static int addrconf_ifdown(struct net_device *dev, int how)
{
struct inet6_dev *idev;
- struct inet6_ifaddr *ifa, **bifa;
+ struct inet6_ifaddr *ifa;
struct net *net = dev_net(dev);
+ LIST_HEAD(keep_list);
ASSERT_RTNL();
@@ -2656,8 +2659,10 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
#endif
- bifa = &idev->addr_list;
- while ((ifa = *bifa) != NULL) {
+ while (!list_empty(&idev->addr_list)) {
+ ifa = list_first_entry(&idev->addr_list,
+ struct inet6_ifaddr, if_list);
+
addrconf_del_timer(ifa);
/* If just doing link down, and address is permanent
@@ -2665,7 +2670,7 @@ static int addrconf_ifdown(struct net_de
if (how == 0 &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
- bifa = &ifa->if_next;
+ list_move_tail(&ifa->if_list, &keep_list);
/* If not doing DAD on this address, just keep it. */
if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
@@ -2681,8 +2686,7 @@ static int addrconf_ifdown(struct net_de
ifa->flags |= IFA_F_TENTATIVE;
in6_ifa_hold(ifa);
} else {
- *bifa = ifa->if_next;
- ifa->if_next = NULL;
+ list_del(&ifa->if_list);
ifa->dead = 1;
}
write_unlock_bh(&idev->lock);
@@ -2699,6 +2703,9 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
+
+ list_splice(&keep_list, &idev->addr_list);
+
write_unlock_bh(&idev->lock);
/* Step 5: Discard multicast list */
@@ -2907,7 +2914,7 @@ static void addrconf_dad_run(struct inet
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
- for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) {
+ list_for_each_entry(ifp, &idev->addr_list, if_list) {
spin_lock(&ifp->lock);
if (!(ifp->flags & IFA_F_TENTATIVE)) {
spin_unlock(&ifp->lock);
@@ -3490,7 +3497,6 @@ static int in6_dump_addrs(struct inet6_d
struct netlink_callback *cb, enum addr_type_t type,
int s_ip_idx, int *p_ip_idx)
{
- struct inet6_ifaddr *ifa;
struct ifmcaddr6 *ifmca;
struct ifacaddr6 *ifaca;
int err = 1;
@@ -3498,11 +3504,12 @@ static int in6_dump_addrs(struct inet6_d
read_lock_bh(&idev->lock);
switch (type) {
- case UNICAST_ADDR:
+ case UNICAST_ADDR: {
+ struct inet6_ifaddr *ifa;
+
/* unicast address incl. temp addr */
- for (ifa = idev->addr_list; ifa;
- ifa = ifa->if_next, ip_idx++) {
- if (ip_idx < s_ip_idx)
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ if (++ip_idx < s_ip_idx)
continue;
err = inet6_fill_ifaddr(skb, ifa,
NETLINK_CB(cb->skb).pid,
@@ -3513,6 +3520,7 @@ static int in6_dump_addrs(struct inet6_d
break;
}
break;
+ }
case MULTICAST_ADDR:
/* multicast address */
for (ifmca = idev->mc_list; ifmca;
--- a/net/sctp/ipv6.c 2010-03-02 14:29:25.452951406 -0800
+++ b/net/sctp/ipv6.c 2010-03-02 14:46:33.868952041 -0800
@@ -371,7 +371,7 @@ static void sctp_v6_copy_addrlist(struct
}
read_lock_bh(&in6_dev->lock);
- for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
+ list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
/* Add the address to the local list. */
addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
if (addr) {
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 09/12] IPv6: addrconf cleanups
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (7 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 08/12] ipv6: convert idev_list to list macros Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 10/12] IPv6: addrconf checkpatch fixes Stephen Hemminger
` (3 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-ifdown-comment.patch --]
[-- Type: text/plain, Size: 6076 bytes --]
Some minor stuff:
* Use bool where appropriate
* Reformat comments and add whitespace for clarity
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 57 ++++++++++++++++++++++++++++------------------------
1 file changed, 31 insertions(+), 26 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:33.868952041 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:37.933576182 -0800
@@ -139,7 +139,7 @@ static void addrconf_leave_anycast(struc
static void addrconf_bonding_change(struct net_device *dev,
unsigned long event);
-static int addrconf_ifdown(struct net_device *dev, int how);
+static int addrconf_ifdown(struct net_device *dev, bool how);
static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags);
static void addrconf_dad_timer(unsigned long data);
@@ -2171,7 +2171,7 @@ static int inet6_addr_del(struct net *ne
disable IPv6 on this interface.
*/
if (list_empty(&idev->addr_list))
- addrconf_ifdown(idev->dev, 1);
+ addrconf_ifdown(idev->dev, true);
return 0;
}
}
@@ -2454,6 +2454,7 @@ static int addrconf_notify(struct notifi
return notifier_from_errno(-ENOMEM);
}
break;
+
case NETDEV_UP:
case NETDEV_CHANGE:
if (dev->flags & IFF_SLAVE)
@@ -2483,10 +2484,9 @@ static int addrconf_notify(struct notifi
}
if (idev) {
- if (idev->if_flags & IF_READY) {
+ if (idev->if_flags & IF_READY)
/* device is already configured. */
break;
- }
idev->if_flags |= IF_READY;
}
@@ -2515,25 +2515,30 @@ static int addrconf_notify(struct notifi
addrconf_dev_config(dev);
break;
}
+
if (idev) {
if (run_pending)
addrconf_dad_run(idev);
- /* If the MTU changed during the interface down, when the
- interface up, the changed MTU must be reflected in the
- idev as well as routers.
+ /*
+ * If the MTU changed during the interface down,
+ * when the interface up, the changed MTU must be
+ * reflected in the idev as well as routers.
*/
- if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) {
+ if (idev->cnf.mtu6 != dev->mtu &&
+ dev->mtu >= IPV6_MIN_MTU) {
rt6_mtu_change(dev, dev->mtu);
idev->cnf.mtu6 = dev->mtu;
}
idev->tstamp = jiffies;
inet6_ifinfo_notify(RTM_NEWLINK, idev);
- /* If the changed mtu during down is lower than IPV6_MIN_MTU
- stop IPv6 on this interface.
+
+ /*
+ * If the changed mtu during down is lower than
+ * IPV6_MIN_MTU stop IPv6 on this interface.
*/
if (dev->mtu < IPV6_MIN_MTU)
- addrconf_ifdown(dev, event != NETDEV_DOWN);
+ addrconf_ifdown(dev, true);
}
break;
@@ -2550,7 +2555,10 @@ static int addrconf_notify(struct notifi
break;
}
- /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */
+ /*
+ * MTU falled under IPV6_MIN_MTU.
+ * Stop IPv6 on this interface.
+ */
case NETDEV_DOWN:
case NETDEV_UNREGISTER:
@@ -2570,6 +2578,7 @@ static int addrconf_notify(struct notifi
return notifier_from_errno(err);
}
break;
+
case NETDEV_BONDING_OLDTYPE:
case NETDEV_BONDING_NEWTYPE:
addrconf_bonding_change(dev, event);
@@ -2584,7 +2593,6 @@ static int addrconf_notify(struct notifi
*/
static struct notifier_block ipv6_dev_notf = {
.notifier_call = addrconf_notify,
- .priority = 0
};
static void addrconf_bonding_change(struct net_device *dev, unsigned long event)
@@ -2600,7 +2608,7 @@ static void addrconf_bonding_change(stru
ipv6_mc_unmap(idev);
}
-static int addrconf_ifdown(struct net_device *dev, int how)
+static int addrconf_ifdown(struct net_device *dev, bool how)
{
struct inet6_dev *idev;
struct inet6_ifaddr *ifa;
@@ -2616,8 +2624,9 @@ static int addrconf_ifdown(struct net_de
if (idev == NULL)
return -ENODEV;
- /* Step 1: remove reference to ipv6 device from parent device.
- Do not dev_put!
+ /*
+ * Step 1: remove reference to ipv6 device from parent device.
+ * Do not dev_put!
*/
if (how) {
idev->dead = 1;
@@ -2632,16 +2641,15 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
- /* Step 3: clear flags for stateless addrconf */
+ /* Step 2: clear flags for stateless addrconf */
if (!how)
idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY);
- /* Step 4: clear address list */
#ifdef CONFIG_IPV6_PRIVACY
if (how && del_timer(&idev->regen_timer))
in6_dev_put(idev);
- /* clear tempaddr list */
+ /* Step 3: clear tempaddr list */
while (!list_empty(&idev->tempaddr_list)) {
ifa = list_first_entry(&idev->tempaddr_list,
struct inet6_ifaddr, tmp_list);
@@ -2667,7 +2675,7 @@ static int addrconf_ifdown(struct net_de
/* If just doing link down, and address is permanent
and not link-local, then retain it. */
- if (how == 0 &&
+ if (!how &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
list_move_tail(&ifa->if_list, &keep_list);
@@ -2709,7 +2717,6 @@ static int addrconf_ifdown(struct net_de
write_unlock_bh(&idev->lock);
/* Step 5: Discard multicast list */
-
if (how)
ipv6_mc_destroy_dev(idev);
else
@@ -2717,8 +2724,7 @@ static int addrconf_ifdown(struct net_de
idev->tstamp = jiffies;
- /* Shot the device (if unregistered) */
-
+ /* Last: Shot the device (if unregistered) */
if (how) {
addrconf_sysctl_unregister(idev);
neigh_parms_release(&nd_tbl, idev->nd_parms);
@@ -3106,8 +3112,7 @@ static void addrconf_verify(unsigned lon
del_timer(&addr_chk_timer);
- for (i=0; i < IN6_ADDR_HSIZE; i++) {
-
+ for (i = 0; i < IN6_ADDR_HSIZE; i++) {
restart:
hlist_for_each_entry_rcu(ifp, node,
&inet6_addr_lst[i], addr_lst) {
@@ -4374,7 +4379,7 @@ static int __addrconf_sysctl_register(st
if (t == NULL)
goto out;
- for (i=0; t->addrconf_vars[i].data; i++) {
+ for (i = 0; t->addrconf_vars[i].data; i++) {
t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
t->addrconf_vars[i].extra2 = net;
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 10/12] IPv6: addrconf checkpatch fixes
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (8 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 09/12] IPv6: addrconf cleanups Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 11/12] ipv6: addrconf timer changes Stephen Hemminger
` (2 subsequent siblings)
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-checkpatch.patch --]
[-- Type: text/plain, Size: 16752 bytes --]
This resolves a number of checkpatch complaints.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:37.933576182 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:40.529202001 -0800
@@ -81,7 +81,7 @@
#include <linux/random.h>
#endif
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/unaligned.h>
#include <linux/proc_fs.h>
@@ -97,7 +97,7 @@
#endif
#define INFINITY_LIFE_TIME 0xFFFFFFFF
-#define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b)))
+#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
#ifdef CONFIG_SYSCTL
static void addrconf_sysctl_register(struct inet6_dev *idev);
@@ -249,8 +249,7 @@ static void addrconf_del_timer(struct in
__in6_ifa_put(ifp);
}
-enum addrconf_timer_t
-{
+enum addrconf_timer_t {
AC_NONE,
AC_DAD,
AC_RS,
@@ -270,7 +269,8 @@ static void addrconf_mod_timer(struct in
case AC_RS:
ifp->timer.function = addrconf_rs_timer;
break;
- default:;
+ default:
+ break;
}
ifp->timer.expires = jiffies + when;
add_timer(&ifp->timer);
@@ -325,7 +325,7 @@ void in6_dev_finish_destroy(struct inet6
#endif
dev_put(dev);
if (!idev->dead) {
- printk("Freeing alive inet6 device %p\n", idev);
+ pr_warning("Freeing alive inet6 device %p\n", idev);
return;
}
snmp6_free_dev(idev);
@@ -441,8 +441,10 @@ static struct inet6_dev * ipv6_find_idev
ASSERT_RTNL();
- if ((idev = __in6_dev_get(dev)) == NULL) {
- if ((idev = ipv6_add_dev(dev)) == NULL)
+ idev = __in6_dev_get(dev);
+ if (!idev) {
+ idev = ipv6_add_dev(dev);
+ if (!idev)
return NULL;
}
@@ -544,10 +546,10 @@ void inet6_ifa_finish_destroy(struct ine
in6_dev_put(ifp->idev);
if (del_timer(&ifp->timer))
- printk("Timer is still running, when freeing ifa=%p\n", ifp);
+ pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);
if (!ifp->dead) {
- printk("Freeing alive inet6 address %p\n", ifp);
+ pr_warning("Freeing alive inet6 address %p\n", ifp);
return;
}
dst_release(&ifp->rt->u.dst);
@@ -1225,7 +1227,6 @@ try_nextdev:
in6_ifa_put(hiscore->ifa);
return 0;
}
-
EXPORT_SYMBOL(ipv6_dev_get_saddr);
int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,
@@ -1235,7 +1236,8 @@ int ipv6_get_lladdr(struct net_device *d
int err = -EADDRNOTAVAIL;
rcu_read_lock();
- if ((idev = __in6_dev_get(dev)) != NULL) {
+ idev = __in6_dev_get(dev);
+ if (idev) {
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
@@ -1723,7 +1725,8 @@ static struct inet6_dev *addrconf_add_de
ASSERT_RTNL();
- if ((idev = ipv6_find_idev(dev)) == NULL)
+ idev = ipv6_find_idev(dev);
+ if (!idev)
return NULL;
/* Add default multicast route */
@@ -2431,7 +2434,8 @@ static void addrconf_ip6_tnl_config(stru
ASSERT_RTNL();
- if ((idev = addrconf_add_dev(dev)) == NULL) {
+ idev = addrconf_add_dev(dev);
+ if (!idev) {
printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");
return;
}
@@ -2446,7 +2450,7 @@ static int addrconf_notify(struct notifi
int run_pending = 0;
int err;
- switch(event) {
+ switch (event) {
case NETDEV_REGISTER:
if (!idev && dev->mtu >= IPV6_MIN_MTU) {
idev = ipv6_add_dev(dev);
@@ -2498,7 +2502,7 @@ static int addrconf_notify(struct notifi
run_pending = 1;
}
- switch(dev->type) {
+ switch (dev->type) {
#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
case ARPHRD_SIT:
addrconf_sit_config(dev);
@@ -2835,7 +2839,7 @@ static void addrconf_dad_start(struct in
* Optimistic nodes can start receiving
* Frames right away
*/
- if(ifp->flags & IFA_F_OPTIMISTIC)
+ if (ifp->flags & IFA_F_OPTIMISTIC)
ip6_ins_rt(ifp->rt);
addrconf_dad_kick(ifp);
@@ -2885,7 +2889,7 @@ out:
static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
{
- struct net_device * dev = ifp->idev->dev;
+ struct net_device *dev = ifp->idev->dev;
/*
* Configure the address for reception. Now it is valid.
@@ -2916,7 +2920,8 @@ static void addrconf_dad_completed(struc
}
}
-static void addrconf_dad_run(struct inet6_dev *idev) {
+static void addrconf_dad_run(struct inet6_dev *idev)
+{
struct inet6_ifaddr *ifp;
read_lock_bh(&idev->lock);
@@ -2981,7 +2986,7 @@ static struct inet6_ifaddr *if6_get_idx(
struct inet6_ifaddr *ifa = if6_get_first(seq);
if (ifa)
- while(pos && (ifa = if6_get_next(seq, ifa)) != NULL)
+ while (pos && (ifa = if6_get_next(seq, ifa)) != NULL)
--pos;
return pos ? NULL : ifa;
}
@@ -3490,8 +3495,7 @@ static int inet6_fill_ifacaddr(struct sk
return nlmsg_end(skb, nlh);
}
-enum addr_type_t
-{
+enum addr_type_t {
UNICAST_ADDR,
MULTICAST_ADDR,
ANYCAST_ADDR,
@@ -3590,7 +3594,8 @@ static int inet6_dump_addr(struct sk_buf
if (idx > s_idx)
s_ip_idx = 0;
ip_idx = 0;
- if ((idev = __in6_dev_get(dev)) == NULL)
+ idev = __in6_dev_get(dev);
+ if (!idev)
goto cont;
if (in6_dump_addrs(idev, skb, cb, type,
@@ -3657,12 +3662,14 @@ static int inet6_rtm_getaddr(struct sk_b
if (ifm->ifa_index)
dev = __dev_get_by_index(net, ifm->ifa_index);
- if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) {
+ ifa = ipv6_get_ifaddr(net, addr, dev, 1);
+ if (!ifa) {
err = -EADDRNOTAVAIL;
goto errout;
}
- if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) {
+ skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL);
+ if (!skb) {
err = -ENOBUFS;
goto errout_ifa;
}
@@ -3787,7 +3794,7 @@ static inline void __snmp6_fill_stats(u6
static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
int bytes)
{
- switch(attrtype) {
+ switch (attrtype) {
case IFLA_INET6_STATS:
__snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
break;
@@ -4139,211 +4146,211 @@ static struct addrconf_sysctl_table
.sysctl_header = NULL,
.addrconf_vars = {
{
- .procname = "forwarding",
- .data = &ipv6_devconf.forwarding,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_forward,
+ .procname = "forwarding",
+ .data = &ipv6_devconf.forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_forward,
},
{
- .procname = "hop_limit",
- .data = &ipv6_devconf.hop_limit,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "hop_limit",
+ .data = &ipv6_devconf.hop_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "mtu",
- .data = &ipv6_devconf.mtu6,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "mtu",
+ .data = &ipv6_devconf.mtu6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_ra",
- .data = &ipv6_devconf.accept_ra,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra",
+ .data = &ipv6_devconf.accept_ra,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_redirects",
- .data = &ipv6_devconf.accept_redirects,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_redirects",
+ .data = &ipv6_devconf.accept_redirects,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "autoconf",
- .data = &ipv6_devconf.autoconf,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "autoconf",
+ .data = &ipv6_devconf.autoconf,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "dad_transmits",
- .data = &ipv6_devconf.dad_transmits,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "dad_transmits",
+ .data = &ipv6_devconf.dad_transmits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "router_solicitations",
- .data = &ipv6_devconf.rtr_solicits,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "router_solicitations",
+ .data = &ipv6_devconf.rtr_solicits,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "router_solicitation_interval",
- .data = &ipv6_devconf.rtr_solicit_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .procname = "router_solicitation_interval",
+ .data = &ipv6_devconf.rtr_solicit_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
},
{
- .procname = "router_solicitation_delay",
- .data = &ipv6_devconf.rtr_solicit_delay,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .procname = "router_solicitation_delay",
+ .data = &ipv6_devconf.rtr_solicit_delay,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
},
{
- .procname = "force_mld_version",
- .data = &ipv6_devconf.force_mld_version,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "force_mld_version",
+ .data = &ipv6_devconf.force_mld_version,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_PRIVACY
{
- .procname = "use_tempaddr",
- .data = &ipv6_devconf.use_tempaddr,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "use_tempaddr",
+ .data = &ipv6_devconf.use_tempaddr,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "temp_valid_lft",
- .data = &ipv6_devconf.temp_valid_lft,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "temp_valid_lft",
+ .data = &ipv6_devconf.temp_valid_lft,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "temp_prefered_lft",
- .data = &ipv6_devconf.temp_prefered_lft,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "temp_prefered_lft",
+ .data = &ipv6_devconf.temp_prefered_lft,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "regen_max_retry",
- .data = &ipv6_devconf.regen_max_retry,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "regen_max_retry",
+ .data = &ipv6_devconf.regen_max_retry,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "max_desync_factor",
- .data = &ipv6_devconf.max_desync_factor,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "max_desync_factor",
+ .data = &ipv6_devconf.max_desync_factor,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#endif
{
- .procname = "max_addresses",
- .data = &ipv6_devconf.max_addresses,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "max_addresses",
+ .data = &ipv6_devconf.max_addresses,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_ra_defrtr",
- .data = &ipv6_devconf.accept_ra_defrtr,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_defrtr",
+ .data = &ipv6_devconf.accept_ra_defrtr,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_ra_pinfo",
- .data = &ipv6_devconf.accept_ra_pinfo,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_pinfo",
+ .data = &ipv6_devconf.accept_ra_pinfo,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_ROUTER_PREF
{
- .procname = "accept_ra_rtr_pref",
- .data = &ipv6_devconf.accept_ra_rtr_pref,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_rtr_pref",
+ .data = &ipv6_devconf.accept_ra_rtr_pref,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "router_probe_interval",
- .data = &ipv6_devconf.rtr_probe_interval,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .procname = "router_probe_interval",
+ .data = &ipv6_devconf.rtr_probe_interval,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_jiffies,
},
#ifdef CONFIG_IPV6_ROUTE_INFO
{
- .procname = "accept_ra_rt_info_max_plen",
- .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_ra_rt_info_max_plen",
+ .data = &ipv6_devconf.accept_ra_rt_info_max_plen,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#endif
#endif
{
- .procname = "proxy_ndp",
- .data = &ipv6_devconf.proxy_ndp,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "proxy_ndp",
+ .data = &ipv6_devconf.proxy_ndp,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
- .procname = "accept_source_route",
- .data = &ipv6_devconf.accept_source_route,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_source_route",
+ .data = &ipv6_devconf.accept_source_route,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
{
- .procname = "optimistic_dad",
- .data = &ipv6_devconf.optimistic_dad,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "optimistic_dad",
+ .data = &ipv6_devconf.optimistic_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
#endif
#ifdef CONFIG_IPV6_MROUTE
{
- .procname = "mc_forwarding",
- .data = &ipv6_devconf.mc_forwarding,
- .maxlen = sizeof(int),
- .mode = 0444,
- .proc_handler = proc_dointvec,
+ .procname = "mc_forwarding",
+ .data = &ipv6_devconf.mc_forwarding,
+ .maxlen = sizeof(int),
+ .mode = 0444,
+ .proc_handler = proc_dointvec,
},
#endif
{
- .procname = "disable_ipv6",
- .data = &ipv6_devconf.disable_ipv6,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = addrconf_sysctl_disable,
+ .procname = "disable_ipv6",
+ .data = &ipv6_devconf.disable_ipv6,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = addrconf_sysctl_disable,
},
{
- .procname = "accept_dad",
- .data = &ipv6_devconf.accept_dad,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec,
+ .procname = "accept_dad",
+ .data = &ipv6_devconf.accept_dad,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
},
{
.procname = "force_tllao",
@@ -4380,7 +4387,7 @@ static int __addrconf_sysctl_register(st
goto out;
for (i = 0; t->addrconf_vars[i].data; i++) {
- t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
+ t->addrconf_vars[i].data += (char *)p - (char *)&ipv6_devconf;
t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */
t->addrconf_vars[i].extra2 = net;
}
@@ -4517,14 +4524,12 @@ int register_inet6addr_notifier(struct n
{
return atomic_notifier_chain_register(&inet6addr_chain, nb);
}
-
EXPORT_SYMBOL(register_inet6addr_notifier);
int unregister_inet6addr_notifier(struct notifier_block *nb)
{
- return atomic_notifier_chain_unregister(&inet6addr_chain,nb);
+ return atomic_notifier_chain_unregister(&inet6addr_chain, nb);
}
-
EXPORT_SYMBOL(unregister_inet6addr_notifier);
/*
@@ -4535,9 +4540,10 @@ int __init addrconf_init(void)
{
int i, err;
- if ((err = ipv6_addr_label_init()) < 0) {
- printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n",
- err);
+ err = ipv6_addr_label_init();
+ if (err < 0) {
+ printk(KERN_CRIT "IPv6 Addrconf:"
+ " cannot initialize default policy table: %d.\n", err);
return err;
}
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 11/12] ipv6: addrconf timer changes
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (9 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 10/12] IPv6: addrconf checkpatch fixes Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-02 23:32 ` [PATCH 12/12] IPv6: addrconf cleanup addrconf_verify Stephen Hemminger
2010-03-03 9:16 ` [PATCH 00/12] IPv6 addrconf changes David Miller
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-timer.patch --]
[-- Type: text/plain, Size: 677 bytes --]
For addrconf timer:
* use round_jiffies since this timer doesn't need to happen sub-second
* use mod_timer for safer timer modification
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
net/ipv6/addrconf.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:40.529202001 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:44.709576675 -0800
@@ -3202,7 +3202,7 @@ restart:
}
}
- addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
+ addr_chk_timer.expires = round_jiffies(next);
add_timer(&addr_chk_timer);
spin_unlock(&addrconf_verify_lock);
rcu_read_unlock_bh();
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 12/12] IPv6: addrconf cleanup addrconf_verify
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (10 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 11/12] ipv6: addrconf timer changes Stephen Hemminger
@ 2010-03-02 23:32 ` Stephen Hemminger
2010-03-03 9:16 ` [PATCH 00/12] IPv6 addrconf changes David Miller
12 siblings, 0 replies; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
[-- Attachment #1: addrconf-verify-clean.patch --]
[-- Type: text/plain, Size: 1403 bytes --]
The variable regen_advance is only used in the privacy case.
Move it to simplify code and eliminate ifdef's
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
--- a/net/ipv6/addrconf.c 2010-03-02 14:46:44.709576675 -0800
+++ b/net/ipv6/addrconf.c 2010-03-02 14:46:46.017202416 -0800
@@ -3122,9 +3122,6 @@ restart:
hlist_for_each_entry_rcu(ifp, node,
&inet6_addr_lst[i], addr_lst) {
unsigned long age;
-#ifdef CONFIG_IPV6_PRIVACY
- unsigned long regen_advance;
-#endif
if (ifp->flags & IFA_F_PERMANENT)
continue;
@@ -3132,12 +3129,6 @@ restart:
spin_lock(&ifp->lock);
age = (now - ifp->tstamp) / HZ;
-#ifdef CONFIG_IPV6_PRIVACY
- regen_advance = ifp->idev->cnf.regen_max_retry *
- ifp->idev->cnf.dad_transmits *
- ifp->idev->nd_parms->retrans_time / HZ;
-#endif
-
if (ifp->valid_lft != INFINITY_LIFE_TIME &&
age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
@@ -3171,6 +3162,10 @@ restart:
#ifdef CONFIG_IPV6_PRIVACY
} else if ((ifp->flags&IFA_F_TEMPORARY) &&
!(ifp->flags&IFA_F_TENTATIVE)) {
+ unsigned long regen_advance = ifp->idev->cnf.regen_max_retry *
+ ifp->idev->cnf.dad_transmits *
+ ifp->idev->nd_parms->retrans_time / HZ;
+
if (age >= ifp->prefered_lft - regen_advance) {
struct inet6_ifaddr *ifpub = ifp->ifpub;
if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next))
--
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 00/12] IPv6 addrconf changes
2010-03-02 23:32 [PATCH 00/12] IPv6 addrconf changes Stephen Hemminger
` (11 preceding siblings ...)
2010-03-02 23:32 ` [PATCH 12/12] IPv6: addrconf cleanup addrconf_verify Stephen Hemminger
@ 2010-03-03 9:16 ` David Miller
2010-03-03 18:14 ` Stephen Hemminger
12 siblings, 1 reply; 20+ messages in thread
From: David Miller @ 2010-03-03 9:16 UTC (permalink / raw)
To: shemminger; +Cc: yoshfuji, netdev
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Tue, 02 Mar 2010 15:32:43 -0800
> This set includes a mixed bag of changes all related to
> IPv6 address configuration: bugfixes (1-3,8), changes to use
> list interface (4-5,8), RCU (6), cosmetic cleanups (9-10,12) and
> minor improvments (7,11).
Unless you split out the change that are not bug fixes, this
will have to wait until the next merge window.
As I very clearly stated the other day I'm really not taking
anything other than bug fixes after Linus takes in my pull
request, which he did today.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 00/12] IPv6 addrconf changes
2010-03-03 9:16 ` [PATCH 00/12] IPv6 addrconf changes David Miller
@ 2010-03-03 18:14 ` Stephen Hemminger
2010-03-03 18:19 ` [PATCH] IPv6: fix race between cleanup and add/delete address Stephen Hemminger
0 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-03 18:14 UTC (permalink / raw)
To: David Miller; +Cc: yoshfuji, netdev
On Wed, 03 Mar 2010 01:16:05 -0800 (PST)
David Miller <davem@davemloft.net> wrote:
> From: Stephen Hemminger <shemminger@vyatta.com>
> Date: Tue, 02 Mar 2010 15:32:43 -0800
>
> > This set includes a mixed bag of changes all related to
> > IPv6 address configuration: bugfixes (1-3,8), changes to use
> > list interface (4-5,8), RCU (6), cosmetic cleanups (9-10,12) and
> > minor improvments (7,11).
>
> Unless you split out the change that are not bug fixes, this
> will have to wait until the next merge window.
Go ahead and apply 1-3 which are bug fixes, I will split out later
patch (8) into a bug fix and resend the rest as a new bundle for next
merge window.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH] IPv6: fix race between cleanup and add/delete address
2010-03-03 18:14 ` Stephen Hemminger
@ 2010-03-03 18:19 ` Stephen Hemminger
2010-03-04 8:40 ` David Miller
0 siblings, 1 reply; 20+ messages in thread
From: Stephen Hemminger @ 2010-03-03 18:19 UTC (permalink / raw)
To: Stephen Hemminger, David Miller; +Cc: yoshfuji, netdev
This solves a potential race problem during the cleanup process.
The issue is that addrconf_ifdown() needs to traverse address list,
but then drop lock to call the notifier. The version in -next
could get confused if add/delete happened during this window.
Original code (2.6.32 and earlier) was okay because all addresses
were always deleted.
Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
---
Apply after earlier bug fixes.
1 IPv6: addrconf dad timer unnecessary bh_disable
2 IPv6: addrconf timer race
3 IPv6: addrconf notify when address is unavailable
net/ipv6/addrconf.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
--- a/net/ipv6/addrconf.c 2010-03-03 08:47:07.157300818 -0800
+++ b/net/ipv6/addrconf.c 2010-03-03 09:31:20.213022628 -0800
@@ -2615,7 +2615,7 @@ static void addrconf_bonding_change(stru
static int addrconf_ifdown(struct net_device *dev, int how)
{
struct inet6_dev *idev;
- struct inet6_ifaddr *ifa, **bifa;
+ struct inet6_ifaddr *ifa, *keep_list, **bifa;
struct net *net = dev_net(dev);
int i;
@@ -2689,8 +2689,12 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
#endif
- bifa = &idev->addr_list;
- while ((ifa = *bifa) != NULL) {
+ keep_list = NULL;
+ bifa = &keep_list;
+ while ((ifa = idev->addr_list) != NULL) {
+ idev->addr_list = ifa->if_next;
+ ifa->if_next = NULL;
+
addrconf_del_timer(ifa);
/* If just doing link down, and address is permanent
@@ -2698,6 +2702,9 @@ static int addrconf_ifdown(struct net_de
if (how == 0 &&
(ifa->flags&IFA_F_PERMANENT) &&
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
+
+ /* Move to holding list */
+ *bifa = ifa;
bifa = &ifa->if_next;
/* If not doing DAD on this address, just keep it. */
@@ -2714,8 +2721,6 @@ static int addrconf_ifdown(struct net_de
ifa->flags |= IFA_F_TENTATIVE;
in6_ifa_hold(ifa);
} else {
- *bifa = ifa->if_next;
- ifa->if_next = NULL;
ifa->dead = 1;
}
write_unlock_bh(&idev->lock);
@@ -2726,6 +2731,9 @@ static int addrconf_ifdown(struct net_de
write_lock_bh(&idev->lock);
}
+
+ idev->addr_list = keep_list;
+
write_unlock_bh(&idev->lock);
/* Step 5: Discard multicast list */
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] IPv6: fix race between cleanup and add/delete address
2010-03-03 18:19 ` [PATCH] IPv6: fix race between cleanup and add/delete address Stephen Hemminger
@ 2010-03-04 8:40 ` David Miller
0 siblings, 0 replies; 20+ messages in thread
From: David Miller @ 2010-03-04 8:40 UTC (permalink / raw)
To: shemminger; +Cc: yoshfuji, netdev
From: Stephen Hemminger <shemminger@vyatta.com>
Date: Wed, 3 Mar 2010 10:19:59 -0800
> This solves a potential race problem during the cleanup process.
> The issue is that addrconf_ifdown() needs to traverse address list,
> but then drop lock to call the notifier. The version in -next
> could get confused if add/delete happened during this window.
> Original code (2.6.32 and earlier) was okay because all addresses
> were always deleted.
>
> Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Applied.
^ permalink raw reply [flat|nested] 20+ messages in thread