Netdev List
 help / color / mirror / Atom feed
* Re: [RFC v2 03/10] snet: introduce security/snet, Makefile and Kconfig changes
From: Greg KH @ 2010-03-03  0:03 UTC (permalink / raw)
  To: Samir Bellabes
  Cc: linux-security-module, linux-kernel, netdev, netfilter-devel,
	jamal, Patrick McHardy, Evgeniy Polyakov, Neil Horman,
	Grzegorz Nosek
In-Reply-To: <1267561394-13626-4-git-send-email-sam@synack.fr>

On Tue, Mar 02, 2010 at 09:23:07PM +0100, Samir Bellabes wrote:
> this patch creates folder security/snet and adds changes for Kconfig and Makefile

But it breaks the build, as you are referring to files here that are not
present yet.  Please put this at the end of your patch series to make
the tree always build for every individual patch.

thanks,

greg k-h

^ permalink raw reply

* [PATCH 12/12] IPv6: addrconf cleanup addrconf_verify
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 11/12] ipv6: addrconf timer changes
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 10/12] IPv6: addrconf checkpatch fixes
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 09/12] IPv6: addrconf cleanups
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 08/12] ipv6: convert idev_list to list macros
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 07/12] ipv6: user better hash for addrconf
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 06/12] IPv6: convert addrconf hash list to RCU
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 05/12] ipv6: convert addrconf list to hlist
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 04/12] ipv6: convert temporary address list to list macros
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 03/12] IPv6: addrconf notify when address is unavailable
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 02/12] IPv6: addrconf timer race
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 01/12] IPv6: addrconf dad timer unnecessary bh_disable
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev
In-Reply-To: <20100302233243.259794027@vyatta.com>

[-- 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

* [PATCH 00/12] IPv6 addrconf changes
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David S. Miller, Hideaki YOSHIFUJI; +Cc: netdev

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).

-- 


^ permalink raw reply

* [Bridge] [PATCH]  bridge: per-cpu packet statistics (v3)
From: Stephen Hemminger @ 2010-03-02 23:32 UTC (permalink / raw)
  To: David Miller; +Cc: Eric Dumazet, netdev, bridge
In-Reply-To: <1267553173.2839.9.camel@edumazet-laptop>

The shared packet statistics are a potential source of slow down
on bridged traffic. Convert to per-cpu array, but only keep those
statistics which change per-packet.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

---
Move tx and rx to be next to each other per Eric's suggestion

 net/bridge/br_device.c  |   43 ++++++++++++++++++++++++++++++++++++++-----
 net/bridge/br_if.c      |    6 ++++++
 net/bridge/br_input.c   |    5 +++--
 net/bridge/br_private.h |    8 ++++++++
 4 files changed, 55 insertions(+), 7 deletions(-)

--- a/net/bridge/br_device.c	2010-03-02 10:48:44.527817663 -0800
+++ b/net/bridge/br_device.c	2010-03-02 10:48:48.287817348 -0800
@@ -26,11 +26,12 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
 	const unsigned char *dest = skb->data;
 	struct net_bridge_fdb_entry *dst;
 	struct net_bridge_mdb_entry *mdst;
+	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-	BR_INPUT_SKB_CB(skb)->brdev = dev;
+	brstats->tx_packets++;
+	brstats->tx_bytes += skb->len;
 
-	dev->stats.tx_packets++;
-	dev->stats.tx_bytes += skb->len;
+	BR_INPUT_SKB_CB(skb)->brdev = dev;
 
 	skb_reset_mac_header(skb);
 	skb_pull(skb, ETH_HLEN);
@@ -81,6 +82,31 @@ static int br_dev_stop(struct net_device
 	return 0;
 }
 
+static struct net_device_stats *br_get_stats(struct net_device *dev)
+{
+	struct net_bridge *br = netdev_priv(dev);
+	struct net_device_stats *stats = &dev->stats;
+	struct br_cpu_netstats sum = { 0 };
+	unsigned int cpu;
+
+	for_each_possible_cpu(cpu) {
+		const struct br_cpu_netstats *bstats
+			= per_cpu_ptr(br->stats, cpu);
+
+		sum.tx_bytes   += bstats->tx_bytes;
+		sum.tx_packets += bstats->tx_packets;
+		sum.rx_bytes   += bstats->rx_bytes;
+		sum.rx_packets += bstats->rx_packets;
+	}
+
+	stats->tx_bytes   = sum.tx_bytes;
+	stats->tx_packets = sum.tx_packets;
+	stats->rx_bytes   = sum.rx_bytes;
+	stats->rx_packets = sum.rx_packets;
+
+	return stats;
+}
+
 static int br_change_mtu(struct net_device *dev, int new_mtu)
 {
 	struct net_bridge *br = netdev_priv(dev);
@@ -180,19 +206,28 @@ static const struct net_device_ops br_ne
 	.ndo_open		 = br_dev_open,
 	.ndo_stop		 = br_dev_stop,
 	.ndo_start_xmit		 = br_dev_xmit,
+	.ndo_get_stats		 = br_get_stats,
 	.ndo_set_mac_address	 = br_set_mac_address,
 	.ndo_set_multicast_list	 = br_dev_set_multicast_list,
 	.ndo_change_mtu		 = br_change_mtu,
 	.ndo_do_ioctl		 = br_dev_ioctl,
 };
 
+static void br_dev_free(struct net_device *dev)
+{
+	struct net_bridge *br = netdev_priv(dev);
+
+	free_percpu(br->stats);
+	free_netdev(dev);
+}
+
 void br_dev_setup(struct net_device *dev)
 {
 	random_ether_addr(dev->dev_addr);
 	ether_setup(dev);
 
 	dev->netdev_ops = &br_netdev_ops;
-	dev->destructor = free_netdev;
+	dev->destructor = br_dev_free;
 	SET_ETHTOOL_OPS(dev, &br_ethtool_ops);
 	dev->tx_queue_len = 0;
 	dev->priv_flags = IFF_EBRIDGE;
--- a/net/bridge/br_if.c	2010-03-02 10:48:44.507817575 -0800
+++ b/net/bridge/br_if.c	2010-03-02 10:48:48.287817348 -0800
@@ -185,6 +185,12 @@ static struct net_device *new_bridge_dev
 	br = netdev_priv(dev);
 	br->dev = dev;
 
+	br->stats = alloc_percpu(struct br_cpu_netstats);
+	if (!br->stats) {
+		free_netdev(dev);
+		return NULL;
+	}
+
 	spin_lock_init(&br->lock);
 	INIT_LIST_HEAD(&br->port_list);
 	spin_lock_init(&br->hash_lock);
--- a/net/bridge/br_input.c	2010-03-02 10:48:44.515818544 -0800
+++ b/net/bridge/br_input.c	2010-03-02 10:48:48.287817348 -0800
@@ -23,9 +23,11 @@ const u8 br_group_address[ETH_ALEN] = { 
 static int br_pass_frame_up(struct sk_buff *skb)
 {
 	struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
+	struct net_bridge *br = netdev_priv(brdev);
+	struct br_cpu_netstats *brstats = this_cpu_ptr(br->stats);
 
-	brdev->stats.rx_packets++;
-	brdev->stats.rx_bytes += skb->len;
+	brstats->rx_packets++;
+	brstats->rx_bytes += skb->len;
 
 	indev = skb->dev;
 	skb->dev = brdev;
--- a/net/bridge/br_private.h	2010-03-02 10:48:44.503817627 -0800
+++ b/net/bridge/br_private.h	2010-03-02 10:49:10.632566819 -0800
@@ -135,6 +135,14 @@ struct net_bridge
 	spinlock_t			lock;
 	struct list_head		port_list;
 	struct net_device		*dev;
+
+	struct br_cpu_netstats __percpu {
+		unsigned long	rx_packets;
+		unsigned long	rx_bytes;
+		unsigned long	tx_packets;
+		unsigned long	tx_bytes;
+	} *stats;
+
 	spinlock_t			hash_lock;
 	struct hlist_head		hash[BR_HASH_SIZE];
 	unsigned long			feature_mask;

^ permalink raw reply

* Re: 2.6.33 problems
From: Eric Dumazet @ 2010-03-02 23:30 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: Andrew Morton, werner, linux-kernel, Tejun Heo, netdev
In-Reply-To: <20100302144219.3cd28ae9@nehalam>

Le mardi 02 mars 2010 à 14:42 -0800, Stephen Hemminger a écrit :


> The SNMP MIB stuff does allocate a disproportionately large amount of percpu
> data. Looks like 2 tables per MIB.

But did this percpu usage grew with 2.6.33 ?

In my understanding, ipv6 always wanted a lot of percpu data for its
MIBS (including per device MIBS), the big increase occurred with commit
96793b482540f3a26e2188eaf75cb56b7829d3e3
from David L Stevens, when RFC 4293 was implemented.
On IPV6, each net device needed 4096/8192 additional bytes of memory per
possible cpu.

An attempt to reduce SNMP mibs by 50% was attempted one ago, but not
completed. I'll try to find some time to resurrect the patch.

[RFC] percpu: convert SNMP mibs to new infra

(use one single table, for both user/bh contexts on x86)

http://lkml.org/lkml/2009/4/1/401



^ permalink raw reply

* [PATCH 37/62] net: move am79c961's probe function to .devinit.text
From: Greg Kroah-Hartman @ 2010-03-02 23:28 UTC (permalink / raw)
  To: linux-kernel
  Cc: Uwe Kleine-König, Roel Kluin, Russell King, netdev,
	Andrew Morton, Greg Kroah-Hartman
In-Reply-To: <20100302230933.GA32287@kroah.com>

From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

A pointer to am79c961_probe is passed to the core via
platform_driver_register and so the function must not disappear when the
.init sections are discarded.  Otherwise (if also having HOTPLUG=y)
unbinding and binding a device to the driver via sysfs will result in an
oops as does a device being registered late.

An alternative to this patch is using platform_driver_probe instead of
platform_driver_register plus removing the pointer to the probe function
from the struct platform_driver.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Cc: Roel Kluin <12o3l@tiscali.nl>
Cc: Russell King <rmk+kernel@arm.linux.org.uk>
Cc: <netdev@vger.kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/net/arm/am79c961a.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 164b37e..1c3c1f9 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -680,7 +680,7 @@ static const struct net_device_ops am79c961_netdev_ops = {
 #endif
 };
 
-static int __init am79c961_probe(struct platform_device *pdev)
+static int __devinit am79c961_probe(struct platform_device *pdev)
 {
 	struct resource *res;
 	struct net_device *dev;
-- 
1.7.0.1

^ permalink raw reply related

* Re: 2.6.33 problems
From: Stephen Hemminger @ 2010-03-02 22:42 UTC (permalink / raw)
  To: Andrew Morton; +Cc: werner, linux-kernel, Tejun Heo, netdev
In-Reply-To: <20100302135032.e3d11bbf.akpm@linux-foundation.org>

On Tue, 2 Mar 2010 13:50:32 -0800
Andrew Morton <akpm@linux-foundation.org> wrote:

> On Sat, 27 Feb 2010 14:09:11 -0300 (GFT)
> werner@guyane.dyn-o-saur.com wrote:
> 
> > For better error searching / correction, I add below the whole syslog.
> > 
> > This is refered to 2.6.33  published (without patchs)
> > 
> > This are different errors.
> > 
> > The most of them exists since 2.6.33-rc1 or appr. -rc5.
> > 
> > I posted here already the whole syslog.bz2 but nobody toke care.
> > 
> > the boot_vga error occurs only after I start the grafics mode.  It's the mainboard's embedded nvidia grafics. I use the vesa framebuffer driver of X 1.8
> > 
> > the int6_init error occurs also in text mode. I think it have something to do with internet.
> > 
> > Also the printk errors occur only when start the computer in the grafics mode, but not when starting it in the text mode.
> > 
> > Below is also the kernel config. Its the same like since -rc7 (but the errors are also the same)
> > 
> > 
> 
> Thanks.
> 
> >
> > ...
> >
> > Feb 27 13:43:07 werner kernel: PERCPU: allocation failed, size=2048 align=8, failed to allocate new chunk
> > Feb 27 13:43:07 werner kernel: Pid: 5314, comm: modprobe Tainted: G         C 2.6.33 #1
> > Feb 27 13:43:07 werner kernel: Call Trace:
> > Feb 27 13:43:07 werner kernel:  [<c1c682ca>] ? printk+0x14/0x16
> > Feb 27 13:43:07 werner kernel:  [<c10bdfa3>] pcpu_alloc+0x6ba/0x73b
> > Feb 27 13:43:07 werner kernel:  [<c10bb0be>] ? get_slab+0x8/0x50
> > Feb 27 13:43:07 werner kernel:  [<c1b7283d>] ? neigh_parms_alloc+0x55/0xd1
> > Feb 27 13:43:07 werner kernel:  [<c10be047>] __alloc_percpu+0xf/0x14
> > Feb 27 13:43:07 werner kernel:  [<c1bb26cb>] snmp_mib_init+0x22/0x5a
> > Feb 27 13:43:07 werner kernel:  [<fed105af>] ipv6_add_dev+0x191/0x30b [ipv6]
> > Feb 27 13:43:07 werner kernel:  [<fd269000>] ? inet6_init+0x0/0x2a2 [ipv6]
> > Feb 27 13:43:07 werner kernel:  [<fd2692ec>] addrconf_init+0x3b/0x11b [ipv6]
> > Feb 27 13:43:07 werner kernel:  [<fd269195>] inet6_init+0x195/0x2a2 [ipv6]
> > Feb 27 13:43:07 werner kernel:  [<c1001143>] do_one_initcall+0x51/0x13f
> > Feb 27 13:43:07 werner kernel:  [<c1066570>] sys_init_module+0xac/0x1e0
> > Feb 27 13:43:07 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb
> > Feb 27 13:43:19 werner kdm_greet[5382]: Can't open default user face
> > Feb 27 13:44:24 werner kernel: PERCPU: allocation failed, size=2048 align=8, failed to allocate new chunk
> > Feb 27 13:44:24 werner kernel: Pid: 5737, comm: modprobe Tainted: G         C 2.6.33 #1
> > Feb 27 13:44:24 werner kernel: Call Trace:
> > Feb 27 13:44:24 werner kernel:  [<c1c682ca>] ? printk+0x14/0x16
> > Feb 27 13:44:24 werner kernel:  [<c10bdfa3>] pcpu_alloc+0x6ba/0x73b
> > Feb 27 13:44:24 werner kernel:  [<c10bb0be>] ? get_slab+0x8/0x50
> > Feb 27 13:44:24 werner kernel:  [<c1b7283d>] ? neigh_parms_alloc+0x55/0xd1
> > Feb 27 13:44:24 werner kernel:  [<c10be047>] __alloc_percpu+0xf/0x14
> > Feb 27 13:44:24 werner kernel:  [<c1bb26cb>] snmp_mib_init+0x22/0x5a
> > Feb 27 13:44:24 werner kernel:  [<fed105af>] ipv6_add_dev+0x191/0x30b [ipv6]
> > Feb 27 13:44:24 werner kernel:  [<f91bf000>] ? inet6_init+0x0/0x2a2 [ipv6]
> > Feb 27 13:44:24 werner kernel:  [<f91bf2ec>] addrconf_init+0x3b/0x11b [ipv6]
> > Feb 27 13:44:24 werner kernel:  [<f91bf195>] inet6_init+0x195/0x2a2 [ipv6]
> > Feb 27 13:44:24 werner kernel:  [<c1001143>] do_one_initcall+0x51/0x13f
> > Feb 27 13:44:24 werner kernel:  [<c1066570>] sys_init_module+0xac/0x1e0
> > Feb 27 13:44:24 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb
> > Feb 27 13:44:27 werner kernel: PERCPU: allocation failed, size=2048 align=8, failed to allocate new chunk
> > Feb 27 13:44:27 werner kernel: Pid: 5772, comm: modprobe Tainted: G         C 2.6.33 #1
> > Feb 27 13:44:27 werner kernel: Call Trace:
> > Feb 27 13:44:27 werner kernel:  [<c1c682ca>] ? printk+0x14/0x16
> > Feb 27 13:44:27 werner kernel:  [<c10bdfa3>] pcpu_alloc+0x6ba/0x73b
> > Feb 27 13:44:27 werner kernel:  [<c10bb0be>] ? get_slab+0x8/0x50
> > Feb 27 13:44:27 werner kernel:  [<c1b7283d>] ? neigh_parms_alloc+0x55/0xd1
> > Feb 27 13:44:27 werner kernel:  [<c10be047>] __alloc_percpu+0xf/0x14
> > Feb 27 13:44:27 werner kernel:  [<c1bb26cb>] snmp_mib_init+0x22/0x5a
> > Feb 27 13:44:27 werner kernel:  [<fee155af>] ipv6_add_dev+0x191/0x30b [ipv6]
> > Feb 27 13:44:27 werner kernel:  [<f9185000>] ? inet6_init+0x0/0x2a2 [ipv6]
> > Feb 27 13:44:27 werner kernel:  [<f91852ec>] addrconf_init+0x3b/0x11b [ipv6]
> > Feb 27 13:44:27 werner kernel:  [<f9185195>] inet6_init+0x195/0x2a2 [ipv6]
> > Feb 27 13:44:27 werner kernel:  [<c1001143>] do_one_initcall+0x51/0x13f
> > Feb 27 13:44:27 werner kernel:  [<c1066570>] sys_init_module+0xac/0x1e0
> > Feb 27 13:44:27 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb
> 
> Methinks Tejun's stuff broke, and then triggered a bug in a
> hitherto-untested networking error recovery codepath.
> 
> 
> > Feb 27 13:44:27 werner kernel: BUG: unable to handle kernel paging request at fed348d4
> > Feb 27 13:44:27 werner kernel: IP: [<c1b68700>] unregister_pernet_operations+0x21/0x93
> > Feb 27 13:44:27 werner kernel: *pde = 360fc067 *pte = 00000000 
> > Feb 27 13:44:27 werner kernel: Oops: 0002 [#1] PREEMPT SMP 
> > Feb 27 13:44:27 werner kernel: last sysfs file: /sys/devices/pci0000:00/0000:00:0d.0/boot_vga
> > Feb 27 13:44:27 werner kernel: Modules linked in: ipv6(+) bnep rfcomm hidp l2cap bluetooth snd_usb_audio snd_usb_lib snd_rawmidi snd_seq_device rt2860sta(C) uvcvideo usbvideo lp snd_hda_codec_analog rtc_cmos rtc_core rtc_lib rtl8187 tpm_tis tpm tpm_bios mac80211 led_class snd_hda_intel snd_hda_codec k8temp hwmon 8139too cfg80211 snd_hwdep snd_pcm rfkill snd_timer snd soundcore snd_page_alloc forcedeth i2c_nforce2
> > Feb 27 13:44:27 werner kernel: 
> > Feb 27 13:44:27 werner kernel: Pid: 5772, comm: modprobe Tainted: G         C 2.6.33 #1 M2N-VM DH/System Product Name
> > Feb 27 13:44:27 werner kernel: EIP: 0060:[<c1b68700>] EFLAGS: 00010246 CPU: 0
> > Feb 27 13:44:27 werner kernel: EIP is at unregister_pernet_operations+0x21/0x93
> > Feb 27 13:44:27 werner kernel: EAX: fed348d4 EBX: fee39850 ECX: f0d7bf58 EDX: fee398d4
> > Feb 27 13:44:27 werner kernel: ESI: fee39850 EDI: f9185000 EBP: f0d7bf6c ESP: f0d7bf58
> > Feb 27 13:44:27 werner kernel:  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> > Feb 27 13:44:27 werner kernel: Process modprobe (pid: 5772, ti=f0d7a000 task=f0ccb660 task.ti=f0d7a000)
> > Feb 27 13:44:27 werner kernel: Stack:
> > Feb 27 13:44:27 werner kernel:  f0d7bf58 f0d7bf58 fee39850 00000000 f9185000 f0d7bf78 c1b687c6 fffffff4
> > Feb 27 13:44:27 werner kernel: <0> f0d7bf84 f9185257 fee3b834 f0d7bf9c c1001143 00000000 fee3b834 00000000
> > Feb 27 13:44:27 werner kernel: <0> 0805e188 f0d7bfac c1066570 b7516008 0805e138 f0d7a000 c1c6acec b7516008
> > Feb 27 13:44:27 werner kernel: Call Trace:
> > Feb 27 13:44:27 werner kernel:  [<f9185000>] ? inet6_init+0x0/0x2a2 [ipv6]
> > Feb 27 13:44:27 werner kernel:  [<c1b687c6>] ? unregister_pernet_subsys+0x1c/0x29
> > Feb 27 13:44:27 werner kernel:  [<f9185257>] ? inet6_init+0x257/0x2a2 [ipv6]
> > Feb 27 13:44:27 werner kernel:  [<c1001143>] ? do_one_initcall+0x51/0x13f
> > Feb 27 13:44:27 werner kernel:  [<c1066570>] ? sys_init_module+0xac/0x1e0
> > Feb 27 13:44:27 werner kernel:  [<c1c6acec>] ? syscall_call+0x7/0xb
> > Feb 27 13:44:27 werner kernel: Code: c2 75 e5 e8 78 0a 51 ff eb 97 55 89 e5 57 56 53 83 ec 08 e8 03 b2 49 ff 89 c6 8d 4d ec 89 4d ec 89 4d f0 8b 10 8b 40 04 89 42 04 <89> 10 c7 06 00 01 10 00 c7 46 04 00 02 20 00 a1 b8 b7 10 c2 8d 
> > Feb 27 13:44:27 werner kernel: EIP: [<c1b68700>] unregister_pernet_operations+0x21/0x93 SS:ESP 0068:f0d7bf58
> > Feb 27 13:44:27 werner kernel: CR2: 00000000fed348d4
> > Feb 27 13:44:27 werner kernel: ---[ end trace 120df121853896c9 ]---
> > Feb 27 13:45:39 werner kernel: BUG: Bad page map in process kio_http  pte:fee39850 pmd:ace05067
> > Feb 27 13:45:39 werner kernel: addr:b6635000 vm_flags:08000075 anon_vma:(null) mapping:f20f434c index:5d
> > Feb 27 13:45:39 werner kernel: vma->vm_ops->fault: filemap_fault+0x0/0x2eb
> > Feb 27 13:45:39 werner kernel: vma->vm_file->f_op->mmap: generic_file_mmap+0x0/0x44
> > Feb 27 13:45:39 werner kernel: Pid: 5764, comm: kio_http Tainted: G      D  C 2.6.33 #1
> > Feb 27 13:45:39 werner kernel: Call Trace:
> > Feb 27 13:45:39 werner kernel:  [<c10a47c7>] print_bad_pte+0x17e/0x190
> > Feb 27 13:45:39 werner kernel:  [<c10a5782>] unmap_vmas+0x444/0x676
> > Feb 27 13:45:39 werner kernel:  [<c10a461d>] ? __do_fault+0x3bd/0x3e9
> > Feb 27 13:45:39 werner kernel:  [<c10988b9>] ? ____pagevec_lru_add+0x101/0x10f
> > Feb 27 13:45:39 werner kernel:  [<c10a9344>] exit_mmap+0xab/0x13a
> > Feb 27 13:45:39 werner kernel:  [<c1038cc1>] mmput+0x3a/0xb0
> > Feb 27 13:45:39 werner kernel:  [<c103c669>] exit_mm+0xec/0xf4
> > Feb 27 13:45:39 werner kernel:  [<c1c6a525>] ? _raw_spin_lock_irq+0xb/0x34
> > Feb 27 13:45:39 werner kernel:  [<c1c6a855>] ? _raw_spin_unlock_irq+0x8/0x27
> > Feb 27 13:45:39 werner kernel:  [<c103dbc1>] do_exit+0x1ad/0x605
> > Feb 27 13:45:39 werner kernel:  [<c105554c>] ? up_read+0x8/0x18
> > Feb 27 13:45:39 werner kernel:  [<c103e080>] do_group_exit+0x67/0x8a
> > Feb 27 13:45:39 werner kernel:  [<c103e0bb>] sys_exit_group+0x18/0x1c
> > Feb 27 13:45:39 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb


The SNMP MIB stuff does allocate a disproportionately large amount of percpu
data. Looks like 2 tables per MIB.

^ permalink raw reply

* Re: [RFC][PATCH] ns: Syscalls for better namespace sharing control.
From: Eric W. Biederman @ 2010-03-02 22:13 UTC (permalink / raw)
  To: Sukadev Bhattiprolu
  Cc: Pavel Emelyanov, Daniel Lezcano, Linux Netdev List, containers,
	Netfilter Development Mailinglist, Ben Greear
In-Reply-To: <20100302211942.GA17816@us.ibm.com>

Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> writes:

> Pavel Emelyanov [xemul@parallels.com] wrote:
> | > I agree with all the points you and Pavel you talked about but I don't 
> | > feel comfortable to have the current process to switch the pid namespace 
> | > because of the process tree hierarchy (what will be the parent of the 
> | > process when you enter the pid namespace for example).
> | 
> | The answer is - the one, that used to be. I see no problems with it.
> | Do you?
>
> Just to be clear, when a process unshares its pid namespace, it takes
> on additional pid nr (== 1) in the new namespace but retains its original
> pid nr(s) in the parent (ancestor) namespaces right ?
>
> i.e the process becomes the container-init of the new namespace. When it
> exits, all its children belonging to the new namespace are killed too,
> but any children in the parent namespace (i.e children created before
> unshare()) are not killed.
>
> After the unshare() the process will not be able to signal any children
> it created before the unshare() (bc their active pid namespaces are
> different)

The only case that I see as being simple and unsurprising worked a bit
differently:

We currently have:

ns_of_pid(task_pid(tsk))
tsk->nsproxy->pid_ns


I would reduce the usage of tsk->nsproxy->pid_ns as much as possible,
and use ns_of_pid(task_pid(tsk)) for all of the routine things that
need to know the pid namespace of a process.  Possibly even to the point
or reversing the order of the upid array so using it is more efficient.

I would leave tsk->nsproxy->pid_ns for use by fork/clone when allocating
a childs pid number.

The unsharing process would have to become the child reaper.  I think the first
child would become pid 1 in that pid namespace.


>From an implementation point of view who gets pid 1 when the child_reaper is
not visible inside the pid namespace doesn't make much difference but we would
want to carefully look at the details so we minimize userspace confusion.


I don't think a process tree rooted at pid 0 is a show stopper.  It is
somewhat confusing but we already have a forked process tree today,
and user space certainly hasn't fallen over.  In the case of a join if you want
to live in properly in the process tree you can daemonize and become a child
of init.




I think replacing a struct pid for another struct pid allocated in
descendant pid_namespace (but has all of the same struct upid values
as the first struct pid) is a disastrous idea.  It destroys the
uniqueness of struct pid and we have a lot of places where we check
that for equality of pid pointers, and that now would be broken.
Otherthings like proc directories also used a cached struct pid and
would start thinking the process was gone when it was not.

Eric

^ permalink raw reply

* Re: BNX2: Kernel crashes with 2.6.31 and 2.6.31.9
From: Michael Chan @ 2010-03-02 22:12 UTC (permalink / raw)
  To: Bruno Prémont; +Cc: Benjamin Li, NetDEV, Linux-Kernel
In-Reply-To: <20100302092020.52cfcd0e@pluto.restena.lu>


On Tue, 2010-03-02 at 00:20 -0800, Bruno Prémont wrote:
> [ 3405.422963] ------------[ cut here ]------------
> [ 3405.428958] WARNING: at /usr/src/linux-2.6.33-rc8-git7/kernel/softirq.c:143 local_bh_enable_ip+0x72/0xa0()

In normal NAPI mode, we are in softirq context and we correctly use
spin_lock_bh() and spin_unlock_bh() here.  In netpoll mode, IRQs are
disabled and so we get a warning from spin_unlock_bh().

> [ 3405.431858] Hardware name: ProLiant DL360 G5
> [ 3405.431858] Modules linked in: netbomb bnx2 ipmi_devintf loop dm_mod sg sr_mod cdrom ata_piix ahci ipmi_si ipmi_msghandler uhci_hcd qla2xxx libata hpwdt ehci_hcd [last unloaded: bnx2]
> [ 3405.431858] Pid: 25763, comm: cat Not tainted 2.6.33-rc8-git7-x86_64 #1
> [ 3405.431858] Call Trace:
> [ 3405.431858]  [<ffffffff8103f002>] ? local_bh_enable_ip+0x72/0xa0
> [ 3405.431858]  [<ffffffff81039368>] warn_slowpath_common+0x78/0xd0
> [ 3405.431858]  [<ffffffff810393cf>] warn_slowpath_null+0xf/0x20
> [ 3405.431858]  [<ffffffff8103f002>] local_bh_enable_ip+0x72/0xa0
> [ 3405.431858]  [<ffffffff814002af>] _raw_spin_unlock_bh+0xf/0x20
> [ 3405.431858]  [<ffffffffa0108ed4>] bnx2_reg_rd_ind+0x44/0x60 [bnx2]
> [ 3405.431858]  [<ffffffffa0108eff>] bnx2_shmem_rd+0xf/0x20 [bnx2]
> [ 3405.431858]  [<ffffffffa0113464>] bnx2_poll+0x194/0x228 [bnx2]
> [ 3405.431858]  [<ffffffff8135c081>] netpoll_poll+0xe1/0x3c0
> [ 3405.431858]  [<ffffffff8135c518>] netpoll_send_skb+0x118/0x210
> [ 3405.431858]  [<ffffffff8135c80b>] netpoll_send_udp+0x1fb/0x210
> [ 3405.431858]  [<ffffffffa00131c5>] write_msg+0x95/0xd0 [netbomb]
> [ 3405.431858]  [<ffffffffa0013255>] netbomb_write+0x55/0xa4 [netbomb]
> [ 3405.431858]  [<ffffffff810f6571>] proc_reg_write+0x71/0xb0
> [ 3405.431858]  [<ffffffff810ab6db>] vfs_write+0xcb/0x180
> [ 3405.431858]  [<ffffffff810ab880>] sys_write+0x50/0x90
> [ 3405.431858]  [<ffffffff8102a1a4>] sysenter_dispatch+0x7/0x2b
> [ 3405.431858] ---[ end trace b4ac1510884bf2bc ]---
> [ 3411.050005] ------------[ cut here ]------------
> [ 3411.054851] WARNING: at /usr/src/linux-2.6.33-rc8-git7/net/sched/sch_generic.c:255 dev_watchdog+0x25e/0x270()
> [ 3411.059546] Hardware name: ProLiant DL360 G5
> [ 3411.061569] NETDEV WATCHDOG: eth0 (bnx2): transmit queue 0 timed out
> [ 3411.064582] Modules linked in: netbomb bnx2 ipmi_devintf loop dm_mod sg sr_mod cdrom ata_piix ahci ipmi_si ipmi_msghandler uhci_hcd qla2xxx libata hpwdt ehci_hcd [last unloaded: bnx2]
> [ 3411.064597] Pid: 0, comm: swapper Tainted: G        W  2.6.33-rc8-git7-x86_64 #1
> [ 3411.064599] Call Trace:

Do we have timers running in this environment?  The timer in the bnx2
driver, bnx2_timer(), needs to run to provide a heart beat to the
firmware.  In netpoll mode without timer interrupts, if we are regularly
calling the NAPI poll function, it should also be able to provide the
heartbeat.  Without the heartbeat, the firmware will reset the chip and
result in the NETDEV WATCHDOG.

> [ 3411.064601]  <IRQ>  [<ffffffff8135f84e>] ? dev_watchdog+0x25e/0x270
> [ 3411.064609]  [<ffffffff81039368>] warn_slowpath_common+0x78/0xd0
> [ 3411.064612]  [<ffffffff81039444>] warn_slowpath_fmt+0x64/0x70
> [ 3411.064616]  [<ffffffff8103486d>] ? default_wake_function+0xd/0x10
> [ 3411.064620]  [<ffffffff8119f339>] ? strlcpy+0x49/0x60
> [ 3411.064623]  [<ffffffff81349b33>] ? netdev_drivername+0x43/0x50
> [ 3411.064626]  [<ffffffff8135f84e>] dev_watchdog+0x25e/0x270
> [ 3411.064630]  [<ffffffff8104c000>] ? delayed_work_timer_fn+0x0/0x40
> [ 3411.064633]  [<ffffffff8104bf87>] ? __queue_work+0x77/0x90
> [ 3411.064636]  [<ffffffff8103558b>] ? scheduler_tick+0x1bb/0x290
> [ 3411.064639]  [<ffffffff8135f5f0>] ? dev_watchdog+0x0/0x270
> [ 3411.064642]  [<ffffffff810440fc>] run_timer_softirq+0x13c/0x210
> [ 3411.064645]  [<ffffffff8105b4b7>] ? clockevents_program_event+0x57/0xa0
> [ 3411.064649]  [<ffffffff8103edb6>] __do_softirq+0xa6/0x130
> [ 3411.064652]  [<ffffffff81003bcc>] call_softirq+0x1c/0x30
> [ 3411.064655]  [<ffffffff81005be5>] do_softirq+0x55/0x90
> [ 3411.064658]  [<ffffffff8103eb35>] irq_exit+0x75/0x90
> [ 3411.064661]  [<ffffffff8101aeed>] smp_apic_timer_interrupt+0x6d/0xa0
> [ 3411.064664]  [<ffffffff81003693>] apic_timer_interrupt+0x13/0x20
> [ 3411.064666]  <EOI>  [<ffffffff8100b186>] ? mwait_idle+0x66/0x80
> [ 3411.064670]  [<ffffffff81001f90>] ? enter_idle+0x20/0x30
> [ 3411.064673]  [<ffffffff81002003>] cpu_idle+0x63/0xb0
> [ 3411.064676]  [<ffffffff813f2f14>] rest_init+0x74/0x80
> [ 3411.064680]  [<ffffffff81880c15>] start_kernel+0x2f8/0x336
> [ 3411.064683]  [<ffffffff8188026d>] x86_64_start_reservations+0x7d/0x84
> [ 3411.064686]  [<ffffffff81880354>] x86_64_start_kernel+0xe0/0xf2
> [ 3411.064688] ---[ end trace b4ac1510884bf2bd ]---

^ permalink raw reply

* Re: 2.6.33 problems
From: Andrew Morton @ 2010-03-02 21:50 UTC (permalink / raw)
  To: werner; +Cc: linux-kernel, Tejun Heo, netdev
In-Reply-To: <1267290551.13148@guyane.dyn-o-saur.com>

On Sat, 27 Feb 2010 14:09:11 -0300 (GFT)
werner@guyane.dyn-o-saur.com wrote:

> For better error searching / correction, I add below the whole syslog.
> 
> This is refered to 2.6.33  published (without patchs)
> 
> This are different errors.
> 
> The most of them exists since 2.6.33-rc1 or appr. -rc5.
> 
> I posted here already the whole syslog.bz2 but nobody toke care.
> 
> the boot_vga error occurs only after I start the grafics mode.  It's the mainboard's embedded nvidia grafics. I use the vesa framebuffer driver of X 1.8
> 
> the int6_init error occurs also in text mode. I think it have something to do with internet.
> 
> Also the printk errors occur only when start the computer in the grafics mode, but not when starting it in the text mode.
> 
> Below is also the kernel config. Its the same like since -rc7 (but the errors are also the same)
> 
> 

Thanks.

>
> ...
>
> Feb 27 13:43:07 werner kernel: PERCPU: allocation failed, size=2048 align=8, failed to allocate new chunk
> Feb 27 13:43:07 werner kernel: Pid: 5314, comm: modprobe Tainted: G         C 2.6.33 #1
> Feb 27 13:43:07 werner kernel: Call Trace:
> Feb 27 13:43:07 werner kernel:  [<c1c682ca>] ? printk+0x14/0x16
> Feb 27 13:43:07 werner kernel:  [<c10bdfa3>] pcpu_alloc+0x6ba/0x73b
> Feb 27 13:43:07 werner kernel:  [<c10bb0be>] ? get_slab+0x8/0x50
> Feb 27 13:43:07 werner kernel:  [<c1b7283d>] ? neigh_parms_alloc+0x55/0xd1
> Feb 27 13:43:07 werner kernel:  [<c10be047>] __alloc_percpu+0xf/0x14
> Feb 27 13:43:07 werner kernel:  [<c1bb26cb>] snmp_mib_init+0x22/0x5a
> Feb 27 13:43:07 werner kernel:  [<fed105af>] ipv6_add_dev+0x191/0x30b [ipv6]
> Feb 27 13:43:07 werner kernel:  [<fd269000>] ? inet6_init+0x0/0x2a2 [ipv6]
> Feb 27 13:43:07 werner kernel:  [<fd2692ec>] addrconf_init+0x3b/0x11b [ipv6]
> Feb 27 13:43:07 werner kernel:  [<fd269195>] inet6_init+0x195/0x2a2 [ipv6]
> Feb 27 13:43:07 werner kernel:  [<c1001143>] do_one_initcall+0x51/0x13f
> Feb 27 13:43:07 werner kernel:  [<c1066570>] sys_init_module+0xac/0x1e0
> Feb 27 13:43:07 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb
> Feb 27 13:43:19 werner kdm_greet[5382]: Can't open default user face
> Feb 27 13:44:24 werner kernel: PERCPU: allocation failed, size=2048 align=8, failed to allocate new chunk
> Feb 27 13:44:24 werner kernel: Pid: 5737, comm: modprobe Tainted: G         C 2.6.33 #1
> Feb 27 13:44:24 werner kernel: Call Trace:
> Feb 27 13:44:24 werner kernel:  [<c1c682ca>] ? printk+0x14/0x16
> Feb 27 13:44:24 werner kernel:  [<c10bdfa3>] pcpu_alloc+0x6ba/0x73b
> Feb 27 13:44:24 werner kernel:  [<c10bb0be>] ? get_slab+0x8/0x50
> Feb 27 13:44:24 werner kernel:  [<c1b7283d>] ? neigh_parms_alloc+0x55/0xd1
> Feb 27 13:44:24 werner kernel:  [<c10be047>] __alloc_percpu+0xf/0x14
> Feb 27 13:44:24 werner kernel:  [<c1bb26cb>] snmp_mib_init+0x22/0x5a
> Feb 27 13:44:24 werner kernel:  [<fed105af>] ipv6_add_dev+0x191/0x30b [ipv6]
> Feb 27 13:44:24 werner kernel:  [<f91bf000>] ? inet6_init+0x0/0x2a2 [ipv6]
> Feb 27 13:44:24 werner kernel:  [<f91bf2ec>] addrconf_init+0x3b/0x11b [ipv6]
> Feb 27 13:44:24 werner kernel:  [<f91bf195>] inet6_init+0x195/0x2a2 [ipv6]
> Feb 27 13:44:24 werner kernel:  [<c1001143>] do_one_initcall+0x51/0x13f
> Feb 27 13:44:24 werner kernel:  [<c1066570>] sys_init_module+0xac/0x1e0
> Feb 27 13:44:24 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb
> Feb 27 13:44:27 werner kernel: PERCPU: allocation failed, size=2048 align=8, failed to allocate new chunk
> Feb 27 13:44:27 werner kernel: Pid: 5772, comm: modprobe Tainted: G         C 2.6.33 #1
> Feb 27 13:44:27 werner kernel: Call Trace:
> Feb 27 13:44:27 werner kernel:  [<c1c682ca>] ? printk+0x14/0x16
> Feb 27 13:44:27 werner kernel:  [<c10bdfa3>] pcpu_alloc+0x6ba/0x73b
> Feb 27 13:44:27 werner kernel:  [<c10bb0be>] ? get_slab+0x8/0x50
> Feb 27 13:44:27 werner kernel:  [<c1b7283d>] ? neigh_parms_alloc+0x55/0xd1
> Feb 27 13:44:27 werner kernel:  [<c10be047>] __alloc_percpu+0xf/0x14
> Feb 27 13:44:27 werner kernel:  [<c1bb26cb>] snmp_mib_init+0x22/0x5a
> Feb 27 13:44:27 werner kernel:  [<fee155af>] ipv6_add_dev+0x191/0x30b [ipv6]
> Feb 27 13:44:27 werner kernel:  [<f9185000>] ? inet6_init+0x0/0x2a2 [ipv6]
> Feb 27 13:44:27 werner kernel:  [<f91852ec>] addrconf_init+0x3b/0x11b [ipv6]
> Feb 27 13:44:27 werner kernel:  [<f9185195>] inet6_init+0x195/0x2a2 [ipv6]
> Feb 27 13:44:27 werner kernel:  [<c1001143>] do_one_initcall+0x51/0x13f
> Feb 27 13:44:27 werner kernel:  [<c1066570>] sys_init_module+0xac/0x1e0
> Feb 27 13:44:27 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb

Methinks Tejun's stuff broke, and then triggered a bug in a
hitherto-untested networking error recovery codepath.


> Feb 27 13:44:27 werner kernel: BUG: unable to handle kernel paging request at fed348d4
> Feb 27 13:44:27 werner kernel: IP: [<c1b68700>] unregister_pernet_operations+0x21/0x93
> Feb 27 13:44:27 werner kernel: *pde = 360fc067 *pte = 00000000 
> Feb 27 13:44:27 werner kernel: Oops: 0002 [#1] PREEMPT SMP 
> Feb 27 13:44:27 werner kernel: last sysfs file: /sys/devices/pci0000:00/0000:00:0d.0/boot_vga
> Feb 27 13:44:27 werner kernel: Modules linked in: ipv6(+) bnep rfcomm hidp l2cap bluetooth snd_usb_audio snd_usb_lib snd_rawmidi snd_seq_device rt2860sta(C) uvcvideo usbvideo lp snd_hda_codec_analog rtc_cmos rtc_core rtc_lib rtl8187 tpm_tis tpm tpm_bios mac80211 led_class snd_hda_intel snd_hda_codec k8temp hwmon 8139too cfg80211 snd_hwdep snd_pcm rfkill snd_timer snd soundcore snd_page_alloc forcedeth i2c_nforce2
> Feb 27 13:44:27 werner kernel: 
> Feb 27 13:44:27 werner kernel: Pid: 5772, comm: modprobe Tainted: G         C 2.6.33 #1 M2N-VM DH/System Product Name
> Feb 27 13:44:27 werner kernel: EIP: 0060:[<c1b68700>] EFLAGS: 00010246 CPU: 0
> Feb 27 13:44:27 werner kernel: EIP is at unregister_pernet_operations+0x21/0x93
> Feb 27 13:44:27 werner kernel: EAX: fed348d4 EBX: fee39850 ECX: f0d7bf58 EDX: fee398d4
> Feb 27 13:44:27 werner kernel: ESI: fee39850 EDI: f9185000 EBP: f0d7bf6c ESP: f0d7bf58
> Feb 27 13:44:27 werner kernel:  DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
> Feb 27 13:44:27 werner kernel: Process modprobe (pid: 5772, ti=f0d7a000 task=f0ccb660 task.ti=f0d7a000)
> Feb 27 13:44:27 werner kernel: Stack:
> Feb 27 13:44:27 werner kernel:  f0d7bf58 f0d7bf58 fee39850 00000000 f9185000 f0d7bf78 c1b687c6 fffffff4
> Feb 27 13:44:27 werner kernel: <0> f0d7bf84 f9185257 fee3b834 f0d7bf9c c1001143 00000000 fee3b834 00000000
> Feb 27 13:44:27 werner kernel: <0> 0805e188 f0d7bfac c1066570 b7516008 0805e138 f0d7a000 c1c6acec b7516008
> Feb 27 13:44:27 werner kernel: Call Trace:
> Feb 27 13:44:27 werner kernel:  [<f9185000>] ? inet6_init+0x0/0x2a2 [ipv6]
> Feb 27 13:44:27 werner kernel:  [<c1b687c6>] ? unregister_pernet_subsys+0x1c/0x29
> Feb 27 13:44:27 werner kernel:  [<f9185257>] ? inet6_init+0x257/0x2a2 [ipv6]
> Feb 27 13:44:27 werner kernel:  [<c1001143>] ? do_one_initcall+0x51/0x13f
> Feb 27 13:44:27 werner kernel:  [<c1066570>] ? sys_init_module+0xac/0x1e0
> Feb 27 13:44:27 werner kernel:  [<c1c6acec>] ? syscall_call+0x7/0xb
> Feb 27 13:44:27 werner kernel: Code: c2 75 e5 e8 78 0a 51 ff eb 97 55 89 e5 57 56 53 83 ec 08 e8 03 b2 49 ff 89 c6 8d 4d ec 89 4d ec 89 4d f0 8b 10 8b 40 04 89 42 04 <89> 10 c7 06 00 01 10 00 c7 46 04 00 02 20 00 a1 b8 b7 10 c2 8d 
> Feb 27 13:44:27 werner kernel: EIP: [<c1b68700>] unregister_pernet_operations+0x21/0x93 SS:ESP 0068:f0d7bf58
> Feb 27 13:44:27 werner kernel: CR2: 00000000fed348d4
> Feb 27 13:44:27 werner kernel: ---[ end trace 120df121853896c9 ]---
> Feb 27 13:45:39 werner kernel: BUG: Bad page map in process kio_http  pte:fee39850 pmd:ace05067
> Feb 27 13:45:39 werner kernel: addr:b6635000 vm_flags:08000075 anon_vma:(null) mapping:f20f434c index:5d
> Feb 27 13:45:39 werner kernel: vma->vm_ops->fault: filemap_fault+0x0/0x2eb
> Feb 27 13:45:39 werner kernel: vma->vm_file->f_op->mmap: generic_file_mmap+0x0/0x44
> Feb 27 13:45:39 werner kernel: Pid: 5764, comm: kio_http Tainted: G      D  C 2.6.33 #1
> Feb 27 13:45:39 werner kernel: Call Trace:
> Feb 27 13:45:39 werner kernel:  [<c10a47c7>] print_bad_pte+0x17e/0x190
> Feb 27 13:45:39 werner kernel:  [<c10a5782>] unmap_vmas+0x444/0x676
> Feb 27 13:45:39 werner kernel:  [<c10a461d>] ? __do_fault+0x3bd/0x3e9
> Feb 27 13:45:39 werner kernel:  [<c10988b9>] ? ____pagevec_lru_add+0x101/0x10f
> Feb 27 13:45:39 werner kernel:  [<c10a9344>] exit_mmap+0xab/0x13a
> Feb 27 13:45:39 werner kernel:  [<c1038cc1>] mmput+0x3a/0xb0
> Feb 27 13:45:39 werner kernel:  [<c103c669>] exit_mm+0xec/0xf4
> Feb 27 13:45:39 werner kernel:  [<c1c6a525>] ? _raw_spin_lock_irq+0xb/0x34
> Feb 27 13:45:39 werner kernel:  [<c1c6a855>] ? _raw_spin_unlock_irq+0x8/0x27
> Feb 27 13:45:39 werner kernel:  [<c103dbc1>] do_exit+0x1ad/0x605
> Feb 27 13:45:39 werner kernel:  [<c105554c>] ? up_read+0x8/0x18
> Feb 27 13:45:39 werner kernel:  [<c103e080>] do_group_exit+0x67/0x8a
> Feb 27 13:45:39 werner kernel:  [<c103e0bb>] sys_exit_group+0x18/0x1c
> Feb 27 13:45:39 werner kernel:  [<c1c6acec>] syscall_call+0x7/0xb
> 


^ permalink raw reply

* Re: [RFC][PATCH] ns: Syscalls for better namespace sharing control.
From: Eric W. Biederman @ 2010-03-02 21:45 UTC (permalink / raw)
  To: Jan Engelhardt
  Cc: Pavel Emelyanov, Daniel Lezcano, hadi, Patrick McHardy,
	Linux Netdev List, containers, Netfilter Development Mailinglist,
	Ben Greear, Serge Hallyn, Matt Helsley
In-Reply-To: <alpine.LSU.2.01.1003021613570.17303@obet.zrqbmnf.qr>

Jan Engelhardt <jengelh@medozas.de> writes:

> On Tuesday 2010-03-02 16:03, Pavel Emelyanov wrote:
>
>>> I agree with all the points you and Pavel you talked about but I don't 
>>> feel comfortable to have the current process to switch the pid namespace 
>>> because of the process tree hierarchy (what will be the parent of the 
>>> process when you enter the pid namespace for example).
>>
>>The answer is - the one, that used to be. I see no problems with it.
>>Do you?
>
> But perhaps it could be named "namespacefd" instead of nsfd, to reduce 
> potential clashes (because glibc will usually just use the same name 
> when making the syscall available as a C function).

Maybe.  namespacefd seems like a real mouthful.  I agree nsfd might be
a bit non-obvious for a rarish syscall.

Eric


^ permalink raw reply

* Re: [RFC][PATCH] ns: Syscalls for better namespace sharing control.
From: Sukadev Bhattiprolu @ 2010-03-02 21:19 UTC (permalink / raw)
  To: Pavel Emelyanov
  Cc: Daniel Lezcano, Linux Netdev List, containers,
	Netfilter Development Mailinglist, Eric W. Biederman, Ben Greear
In-Reply-To: <4B8D28CF.8060304@parallels.com>

Pavel Emelyanov [xemul@parallels.com] wrote:
| > I agree with all the points you and Pavel you talked about but I don't 
| > feel comfortable to have the current process to switch the pid namespace 
| > because of the process tree hierarchy (what will be the parent of the 
| > process when you enter the pid namespace for example).
| 
| The answer is - the one, that used to be. I see no problems with it.
| Do you?

Just to be clear, when a process unshares its pid namespace, it takes
on additional pid nr (== 1) in the new namespace but retains its original
pid nr(s) in the parent (ancestor) namespaces right ?

i.e the process becomes the container-init of the new namespace. When it
exits, all its children belonging to the new namespace are killed too,
but any children in the parent namespace (i.e children created before
unshare()) are not killed.

After the unshare() the process will not be able to signal any children
it created before the unshare() (bc their active pid namespaces are
different)

Sukadev

^ permalink raw reply

* [RFC v2 05/10] snet: introduce snet_event
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

This patch adds the snet's subsystem responsive of managing events

snet is using the word 'event' for a couple of values [syscall, protocol].
For example, [listen, tcp] or [sendmsg, dccp] are events.

This patch introduces a hastable 'event_hash' and operations (add/remove/search..)
in order to manage which events have to be protected.
With the help of the communication's subsystem, managing orders are coming from
userspace.

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_event.c |  189 ++++++++++++++++++++++++++++++++++++++++++++
 security/snet/snet_event.h |   21 +++++
 2 files changed, 210 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_event.c
 create mode 100644 security/snet/snet_event.h

diff --git a/security/snet/snet_event.c b/security/snet/snet_event.c
new file mode 100644
index 0000000..9e3f7d2
--- /dev/null
+++ b/security/snet/snet_event.c
@@ -0,0 +1,189 @@
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/slab.h>
+#include <linux/netlink.h>
+#include <linux/snet.h>
+#include "snet_event.h"
+#include "snet_netlink.h"
+#include "snet_utils.h"
+
+static struct list_head *snet_evh;
+static rwlock_t snet_evh_lock = __RW_LOCK_UNLOCKED();
+
+struct snet_event_entry {
+	struct list_head list;
+	struct snet_event se;
+};
+
+/* lookup for a snet_evh - before using this function, lock snet_evh_lock */
+static struct snet_event_entry *__snet_event_lookup(const enum snet_syscall syscall,
+						    const u8 protocol)
+{
+	unsigned int h = 0;
+	struct list_head *l;
+	struct snet_event_entry *s;
+
+	/* computing its hash value */
+	h = jhash_2words(syscall, protocol, 0) % snet_evh_size;
+	l = &snet_evh[h];
+
+	list_for_each_entry(s, l, list) {
+		if ((s->se.protocol == protocol) &&
+		    (s->se.syscall == syscall)) {
+			return s;
+		}
+	}
+	return NULL;
+}
+
+int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb)
+{
+	unsigned int i = 0, n = 0;
+	int ret = -1;
+	unsigned hashs_to_skip = cb->args[0];
+	unsigned events_to_skip = cb->args[1];
+	struct list_head *l;
+	struct snet_event_entry *s;
+
+	read_lock_bh(&snet_evh_lock);
+
+	for (i = 0; i < snet_evh_size; i++) {
+		if (i < hashs_to_skip)
+			continue;
+		l = &snet_evh[i];
+		n = 0;
+		list_for_each_entry(s, l, list) {
+			if (++n < events_to_skip)
+				continue;
+			ret = snet_nl_list_fill_info(skb,
+						     NETLINK_CB(cb->skb).pid,
+						     cb->nlh->nlmsg_seq,
+						     NLM_F_MULTI,
+						     s->se.protocol,
+						     s->se.syscall);
+			if (ret < 0)
+				goto errout;
+		}
+	}
+
+errout:
+	read_unlock_bh(&snet_evh_lock);
+
+	cb->args[0] = i;
+	cb->args[1] = n;
+	return skb->len;
+}
+
+/*
+ * check if a event is registered or not
+ * return 1 if event is registered, 0 if not
+ */
+int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol)
+{
+	int ret = 0;
+
+	read_lock_bh(&snet_evh_lock);
+	if (__snet_event_lookup(syscall, protocol) != NULL)
+		ret = 1;
+	read_unlock_bh(&snet_evh_lock);
+	return ret;
+}
+
+/* adding a event */
+int snet_event_insert(const enum snet_syscall syscall, const u8 protocol)
+{
+	struct snet_event_entry *data = NULL;
+	unsigned int h = 0;
+	int err = 0;
+
+	data = kzalloc(sizeof(struct snet_event_entry), GFP_KERNEL);
+	if (!data) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	write_lock_bh(&snet_evh_lock);
+	/* check if event is already registered */
+	if (__snet_event_lookup(syscall, protocol) != NULL) {
+		write_unlock_bh(&snet_evh_lock);
+		kfree(data);
+		err = -EINVAL;
+		goto out;
+	}
+
+	data->se.syscall = syscall;
+	data->se.protocol = protocol;
+	INIT_LIST_HEAD(&(data->list));
+	h = jhash_2words(data->se.syscall, data->se.protocol, 0) % snet_evh_size;
+	list_add_tail(&data->list, &snet_evh[h]);
+	write_unlock_bh(&snet_evh_lock);
+	pr_debug("[%u]=(syscall=%s, protocol=%u)\n",
+		 h, snet_syscall_name(syscall), protocol);
+out:
+	return err;
+}
+
+/* removing a event */
+int snet_event_remove(const enum snet_syscall syscall, const u8 protocol)
+{
+	struct snet_event_entry *data = NULL;
+
+	write_lock_bh(&snet_evh_lock);
+	data = __snet_event_lookup(syscall, protocol);
+	if (data == NULL) {
+		write_unlock_bh(&snet_evh_lock);
+		return -EINVAL;
+	}
+	pr_debug("(syscall=%s, protocol=%u)\n",
+		 snet_syscall_name(syscall), protocol);
+	list_del(&data->list);
+	write_unlock_bh(&snet_evh_lock);
+	kfree(data);
+	return 0;
+}
+
+/* flushing all events */
+void snet_event_flush(void)
+{
+	unsigned int i = 0;
+
+	write_lock_bh(&snet_evh_lock);
+	for (i = 0; i < snet_evh_size; i++) {
+		struct snet_event_entry *data, *tmp;
+		list_for_each_entry_safe(data, tmp, &snet_evh[i], list) {
+			list_del(&data->list);
+			kfree(data);
+		}
+	}
+	write_unlock_bh(&snet_evh_lock);
+	return;
+}
+
+/* init function */
+int snet_event_init(void)
+{
+	int err = 0, i = 0;
+
+	snet_evh = kzalloc(sizeof(struct list_head) * snet_evh_size,
+			     GFP_KERNEL);
+	if (!snet_evh) {
+		printk(KERN_WARNING
+		       "snet: can't alloc memory for snet_evh\n");
+		err = -ENOMEM;
+		goto out;
+	}
+
+	for (i = 0; i < snet_evh_size; i++)
+		INIT_LIST_HEAD(&snet_evh[i]);
+
+out:
+	return err;
+}
+
+/* exit function */
+void snet_event_exit(void)
+{
+	kfree(snet_evh);
+	snet_evh = NULL;
+}
diff --git a/security/snet/snet_event.h b/security/snet/snet_event.h
new file mode 100644
index 0000000..fa991c7
--- /dev/null
+++ b/security/snet/snet_event.h
@@ -0,0 +1,21 @@
+#ifndef _SNET_EVENT_H
+#define _SNET_EVENT_H
+
+#include <linux/skbuff.h>
+
+extern unsigned int snet_evh_size;
+
+/* manipulate the events hash table */
+int snet_event_fill_info(struct sk_buff *skb, struct netlink_callback *cb);
+int snet_event_is_registered(const enum snet_syscall syscall, const u8 protocol);
+int snet_event_insert(const enum snet_syscall syscall, const u8 protocol);
+int snet_event_remove(const enum snet_syscall syscall, const u8 protocol);
+void snet_event_flush(void);
+void snet_event_dumpall(void);
+
+/* init function */
+int snet_event_init(void);
+/* exit funtion */
+void snet_event_exit(void);
+
+#endif /* _SNET_EVENT_H */
-- 
1.6.3.3


^ permalink raw reply related

* [RFC v2 10/10] snet: introduce snet_utils
From: Samir Bellabes @ 2010-03-02 20:23 UTC (permalink / raw)
  To: linux-security-module
  Cc: linux-kernel, netdev, netfilter-devel, jamal, Patrick McHardy,
	Evgeniy Polyakov, Neil Horman, Grzegorz Nosek, Samir Bellabes
In-Reply-To: <1267561394-13626-1-git-send-email-sam@synack.fr>

This patch provides helper functions for other subsystems

Signed-off-by: Samir Bellabes <sam@synack.fr>
---
 security/snet/snet_utils.c |   38 ++++++++++++++++++++++++++++++++++++++
 security/snet/snet_utils.h |   10 ++++++++++
 2 files changed, 48 insertions(+), 0 deletions(-)
 create mode 100644 security/snet/snet_utils.c
 create mode 100644 security/snet/snet_utils.h

diff --git a/security/snet/snet_utils.c b/security/snet/snet_utils.c
new file mode 100644
index 0000000..e9178d7
--- /dev/null
+++ b/security/snet/snet_utils.c
@@ -0,0 +1,38 @@
+#include <linux/types.h>
+#include <linux/snet.h>
+
+const char *snet_verdict_name(const enum snet_verdict cmd)
+{
+	static const char *const verdict_name[] = {
+		[SNET_VERDICT_GRANT]	= "Grant",
+		[SNET_VERDICT_DENY]	= "Deny",
+		[SNET_VERDICT_PENDING]	= "Pending",
+		[SNET_VERDICT_NONE]	= "None",
+	};
+
+	if (cmd >= SNET_NR_VERDICT_TYPES)
+		return "INVALID";
+	else
+		return verdict_name[cmd];
+}
+
+const char *snet_syscall_name(const enum snet_syscall sys)
+{
+	static const char *const syscall_name[] = {
+		[SNET_SOCKET_CREATE]		= "Create",
+		[SNET_SOCKET_BIND]		= "Bind",
+		[SNET_SOCKET_CONNECT]		= "Connect",
+		[SNET_SOCKET_LISTEN]		= "Listen",
+		[SNET_SOCKET_ACCEPT]		= "Accept",
+		[SNET_SOCKET_POST_ACCEPT]	= "Post Accept",
+		[SNET_SOCKET_SENDMSG]		= "Sendmsg",
+		[SNET_SOCKET_RECVMSG]		= "Recvmsg",
+		[SNET_SOCKET_SOCK_RCV_SKB]	= "Sock Rcv Skb",
+		[SNET_SOCKET_CLOSE]		= "Close",
+	};
+
+	if (sys >= SNET_NR_SOCKET_TYPES)
+		return "INVALID";
+	else
+		return syscall_name[sys];
+}
diff --git a/security/snet/snet_utils.h b/security/snet/snet_utils.h
new file mode 100644
index 0000000..4dad18b
--- /dev/null
+++ b/security/snet/snet_utils.h
@@ -0,0 +1,10 @@
+#ifndef _SNET_UTILS_H
+#define _SNET_UTILS_H
+
+#include <linux/skbuff.h>
+
+int snet_data_fill(struct sk_buff *skb_rsp, struct snet_info *info);
+const char *snet_verdict_name(const enum snet_verdict cmd);
+const char *snet_syscall_name(const enum snet_syscall sys);
+
+#endif	/* _SNET_UTILS_H */
-- 
1.6.3.3


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox