From 372e6c8f1f7b2bb68f9992d2e664925c73552a1d Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 17 Mar 2010 20:31:09 +0000 Subject: ipv6: convert temporary address list to list macros Use list macros instead of open coded linked list. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/net/if_inet6.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/net/if_inet6.h') diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 545d8b059be..09d906460a4 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -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; -- cgit v1.2.3-70-g09d2 From c2e21293c054817c42eb5fa9c613d2ad51954136 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 17 Mar 2010 20:31:10 +0000 Subject: ipv6: convert addrconf list to hlist 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 Signed-off-by: David S. Miller --- include/net/if_inet6.h | 2 +- net/ipv6/addrconf.c | 128 ++++++++++++++++++++----------------------------- 2 files changed, 54 insertions(+), 76 deletions(-) (limited to 'include/net/if_inet6.h') diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 09d906460a4..49840154151 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -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 diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index f372f895cd4..0488b9f8071 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -126,7 +126,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev); /* * 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(struct ctl_table *table, int *p, int old) 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, const struct in6_addr *addr, int pfxlen, 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, const struct in6_addr *addr, int pfxlen, /* 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_ifaddr *ifp) 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 inet6_dev *idev) 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)) { @@ -2612,7 +2608,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) struct inet6_dev *idev; struct inet6_ifaddr *ifa, *keep_list, **bifa; struct net *net = dev_net(dev); - int i; ASSERT_RTNL(); @@ -2637,25 +2632,6 @@ static int addrconf_ifdown(struct net_device *dev, int how) } - /* Step 2: clear hash table */ - for (i=0; iidev == 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 */ @@ -2721,6 +2697,12 @@ static int addrconf_ifdown(struct net_device *dev, int how) } 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); @@ -2963,36 +2945,37 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) 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) @@ -3094,10 +3077,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) && @@ -3118,6 +3103,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) static void addrconf_verify(unsigned long foo) { struct inet6_ifaddr *ifp; + struct hlist_node *node; unsigned long now, next; int i; @@ -3131,7 +3117,7 @@ static void addrconf_verify(unsigned long foo) 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; @@ -4550,7 +4536,7 @@ EXPORT_SYMBOL(unregister_inet6addr_notifier); 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", @@ -4585,6 +4571,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); @@ -4613,7 +4602,6 @@ errlo: void addrconf_cleanup(void) { - struct inet6_ifaddr *ifa; struct net_device *dev; int i; @@ -4634,18 +4622,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); -- cgit v1.2.3-70-g09d2 From 5c578aedcb21d79eeb4e9cf04ca5b276ac82614c Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 17 Mar 2010 20:31:11 +0000 Subject: IPv6: convert addrconf hash list to RCU 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 Signed-off-by: David S. Miller --- include/linux/rculist.h | 13 ++++++++ include/net/if_inet6.h | 1 + net/ipv6/addrconf.c | 85 +++++++++++++++++++++++++------------------------ 3 files changed, 58 insertions(+), 41 deletions(-) (limited to 'include/net/if_inet6.h') diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 2c9b46cff3d..004908b104d 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -428,5 +428,18 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, ({ 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 diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 49840154151..22a00b1d2c3 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -64,6 +64,7 @@ struct inet6_ifaddr { #endif int dead; + struct rcu_head rcu; }; struct ip6_sf_socklist { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0488b9f8071..7ffd5eeab96 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -127,7 +127,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev); * 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(struct ctl_table *table, int *p, int old) } #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 inet6_ifaddr *ifp) } 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, const struct in6_addr *addr, int pfxlen, 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, const struct in6_addr *addr, int pfxlen, /* 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_ifaddr *ifp) 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, struct in6_addr *addr, 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, struct in6_addr *addr, 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(struct net *net, const struct in6_addr *add 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(struct net *net, const struct in6_addr *add } } } - read_unlock_bh(&addrconf_hash_lock); + rcu_read_unlock_bh(); return ifp; } @@ -2698,10 +2704,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) 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); @@ -2946,11 +2952,10 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq) 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; } @@ -2962,10 +2967,9 @@ static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, 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, @@ -2989,9 +2993,9 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) } 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); } @@ -3005,9 +3009,9 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos) } 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) @@ -3081,8 +3085,8 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) 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) && @@ -3091,7 +3095,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) break; } } - read_unlock_bh(&addrconf_hash_lock); + rcu_read_unlock_bh(); return ret; } #endif @@ -3107,7 +3111,8 @@ static void addrconf_verify(unsigned long foo) 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; @@ -3116,8 +3121,8 @@ static void addrconf_verify(unsigned long foo) 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; @@ -3139,7 +3144,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) { @@ -3161,7 +3165,6 @@ restart: if (deprecate) { in6_ifa_hold(ifp); - read_unlock(&addrconf_hash_lock); ipv6_ifa_notify(0, ifp); in6_ifa_put(ifp); @@ -3179,7 +3182,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); @@ -3199,12 +3202,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) @@ -4621,10 +4624,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(); -- cgit v1.2.3-70-g09d2 From 502a2ffd7376ae27cfde6172257db0ff9d8cfec2 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Wed, 17 Mar 2010 20:31:13 +0000 Subject: ipv6: convert idev_list to list macros Convert to list macro's for the list of addresses per interface in IPv6. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/bonding/bond_ipv6.c | 9 ++--- include/net/if_inet6.h | 6 ++-- net/ipv6/addrconf.c | 78 ++++++++++++++++++++--------------------- net/sctp/ipv6.c | 2 +- 4 files changed, 48 insertions(+), 47 deletions(-) (limited to 'include/net/if_inet6.h') diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c index 6dd64cf3cb7..969ffed86b9 100644 --- a/drivers/net/bonding/bond_ipv6.c +++ b/drivers/net/bonding/bond_ipv6.c @@ -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 net_device *dev, struct in6_addr *addr) 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); diff --git a/include/net/if_inet6.h b/include/net/if_inet6.h index 22a00b1d2c3..13f9fc086d5 100644 --- a/include/net/if_inet6.h +++ b/include/net/if_inet6.h @@ -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; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 1e5e41fe92b..6dbf0f79b76 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -317,7 +317,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev) { 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(struct net_device *dev) 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 inet6_dev *idev) 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(struct rcu_head *head) /* 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 inet6_ifaddr *ifp) 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_ifaddr *ifp) } #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_ifaddr *ifp) } } } - ifap = &ifa->if_next; } write_unlock_bh(&idev->lock); @@ -1146,7 +1147,7 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, 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 *dev, struct in6_addr *addr, 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 inet6_dev *idev) 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 *addr, struct net_device *dev) 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) @@ -1555,7 +1557,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) 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; @@ -2159,7 +2161,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, 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); @@ -2170,7 +2172,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, /* 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; } @@ -2602,9 +2604,10 @@ static void addrconf_type_change(struct net_device *dev, unsigned long event) static int addrconf_ifdown(struct net_device *dev, int how) { - struct inet6_dev *idev; - struct inet6_ifaddr *ifa, *keep_list, **bifa; struct net *net = dev_net(dev); + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + LIST_HEAD(keep_list); ASSERT_RTNL(); @@ -2658,12 +2661,10 @@ static int addrconf_ifdown(struct net_device *dev, int how) write_lock_bh(&idev->lock); } #endif - keep_list = NULL; - bifa = &keep_list; - while ((ifa = idev->addr_list) != NULL) { - idev->addr_list = ifa->if_next; - ifa->if_next = 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 @@ -2671,10 +2672,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) 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; + 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)) || @@ -2690,6 +2688,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) ifa->flags |= IFA_F_TENTATIVE; in6_ifa_hold(ifa); } else { + list_del(&ifa->if_list); ifa->dead = 1; } write_unlock_bh(&idev->lock); @@ -2707,7 +2706,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) write_lock_bh(&idev->lock); } - idev->addr_list = keep_list; + list_splice(&keep_list, &idev->addr_list); write_unlock_bh(&idev->lock); @@ -2917,7 +2916,7 @@ static void addrconf_dad_run(struct inet6_dev *idev) { 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); @@ -3500,7 +3499,6 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, 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; @@ -3508,11 +3506,12 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, 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, @@ -3523,6 +3522,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, break; } break; + } case MULTICAST_ADDR: /* multicast address */ for (ifmca = idev->mc_list; ifmca; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 1d7ac70ba39..240dceba06e 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -371,7 +371,7 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist, } 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) { -- cgit v1.2.3-70-g09d2