Netdev List
 help / color / mirror / Atom feed
* Re: strict isolation of net interfaces
From: Andrey Savochkin @ 2006-07-03 14:53 UTC (permalink / raw)
  To: Sam Vilain, Serge E. Hallyn, Cedric Le Goater
  Cc: hadi, Herbert Poetzl, Alexey Kuznetsov, viro, devel, dev,
	Andrew Morton, netdev, linux-kernel, Daniel Lezcano, Ben Greear,
	Dave Hansen, Alexey Kuznetsov, Eric W. Biederman
In-Reply-To: <44A49121.4050004@vilain.net>

Sam, Serge, Cedric,

On Fri, Jun 30, 2006 at 02:49:05PM +1200, Sam Vilain wrote:
> Serge E. Hallyn wrote:
> > The last one in your diagram confuses me - why foo0:1?  I would
> > have thought it'd be
> >
> > host                  |  guest 0  |  guest 1  |  guest2
> > ----------------------+-----------+-----------+--------------
> >   |                   |           |           |
> >   |-> l0      <-------+-> lo0 ... | lo0       | lo0
> >   |                   |           |           |
> >   |-> eth0            |           |           |
> >   |                   |           |           |
> >   |-> veth0  <--------+-> eth0    |           |
> >   |                   |           |           |
> >   |-> veth1  <--------+-----------+-----------+-> eth0
> >   |                   |           |           |
> >   |-> veth2   <-------+-----------+-> eth0    |
> >
> > [...]
> >
> > So conceptually using a full virtual net device per container
> > certainly seems cleaner to me, and it seems like it should be
> > simpler by way of statistics gathering etc, but are there actually
> > any real gains?  Or is the support for multiple IPs per device
> > actually enough?
> >   
> 
> Why special case loopback?
> 
> Why not:
> 
> host                  |  guest 0  |  guest 1  |  guest2
> ----------------------+-----------+-----------+--------------
>   |                   |           |           |
>   |-> lo              |           |           |
>   |                   |           |           |
>   |-> vlo0  <---------+-> lo      |           |
>   |                   |           |           |
>   |-> vlo1  <---------+-----------+-----------+-> lo
>   |                   |           |           |
>   |-> vlo2   <--------+-----------+-> lo      |
>   |                   |           |           |
>   |-> eth0            |           |           |
>   |                   |           |           |
>   |-> veth0  <--------+-> eth0    |           |
>   |                   |           |           |
>   |-> veth1  <--------+-----------+-----------+-> eth0
>   |                   |           |           |
>   |-> veth2   <-------+-----------+-> eth0    |

I still can't completely understand your direction of thoughts.
Could you elaborate on IP address assignment in your diagram, please?  For
example, guest0 wants 127.0.0.1 and 192.168.0.1 addresses on its lo
interface, and 10.1.1.1 on its eth0 interface.
Does this diagram assume any local IP addresses on v* interfaces in the
"host"?

And the second question.
Are vlo0, veth0, etc. devices supposed to have hard_xmit routines?

Best regards

Andrey

^ permalink raw reply

* Re: [Patch][RFC] Disabling per-tgid stats on task exit in taskstats
From: Shailabh Nagar @ 2006-07-03 15:02 UTC (permalink / raw)
  To: Paul Jackson
  Cc: akpm, Valdis.Kletnieks, jlan, balbir, csturtiv, linux-kernel,
	hadi, netdev
In-Reply-To: <20060702215350.2c1de596.pj@sgi.com>

Paul Jackson wrote:

>Shailabh wrote:
>  
>
>>Sends a separate "registration" message with cpumask to listen to. 
>>Kernel stores (real) pid and cpumask.
>>    
>>
>
>Question:
>=========
>
>Ah - good.
>
>So this means that I could configure a system with a fork/exit
>intensive, performance critical job on some dedicated CPUs, and be able
>to collect taskstat data from tasks exiting on the -other- CPUS, while
>avoiding collecting data from this special job, thus avoiding any
>taskstat collection performance impact on said job.
>
>If I'm understanding this correctly, excellent.
>  
>
Yes. If no one registers to listen on a particular CPU, data from tasks 
exiting on that cpu is
not sent out at all.

>Caveat:
>=======
>
>Passing cpumasks across the kernel-user boundary can be tricky.
>
>Historically, Unix has a long tradition of boloxing up the passing
>of variable length data types across the kernel-user boundary.
>
>We've got perhaps a half dozen ways of getting these masks out of the
>kernel, and three ways of getting them (or the similar nodemasks) back
>into the kernel.  The three ways being used in the sched_setaffinity
>system call, the mbind and set_mempolicy system calls, and the cpuset
>file system.
>
>All three of these ways have their controversial details:
> * The kernel cpumask mask size needed for sched_setaffinity calls is
>   not trivially available to userland.
> * The nodemask bit size is off by one in the mbind and set_mempolicy
>   calls.
> * The CPU and Node masks are ascii, not binary, in the cpuset calls.
>
>One option that might make sense for these task stat registrations
>would be to:
> 1) make the kernel/sched.c get_user_cpu_mask() routine generic,
>    moving it to non-static lib/*.c code, and
> 2) provide a sensible way for user space to query the size of
>    the kernel cpumask (and perhaps nodemask while you're at it.)
>
>Currently, the best way I know for user space to query the kernels
>cpumask and nodemask size is to examine the length of the ascii
>string values labeled "Cpus_allowed:" and "Mems_allowed:" in the file
>/proc/self/status.  These ascii strings always require exactly nine
>ascii chars to express each 32 bits of kernel mask code, if you include
>in the count the trailing ',' comma or '\n' newline after each eight
>ascii character word.
>
>Probing /proc/self/status fields for these mask sizes is rather
>unobvious and indirect, and requires caching the result if you care at
>all about performance.  Userland code in support of your taskstat
>facility might be better served by a more obvious way to size cpumasks.
>
>... unless of course you're inclined to pass cpumasks formatted as
>    ascii strings, in which case speak up, as I'd be delighted to
>    throw in my 2 cents on how to do that ;).
>  
>
Thanks for the size info. I did hit it while coding this up.

So I chose to use the "cpulist" ascii format that has been helpfully 
provided in include/linux/cpumask.h (by whom I wonder :-)

User specified the cpumask as an ascii string containing comma separated 
cpu ranges.
Kernel parses the same and stores it as a cpumask_t after which we can 
iterate over the
mask using standard helpers.

Since registration/deregistration is not a common operation, the 
overhead of parsing
ascii strings should be acceptable and avoids the hassles of trying to 
determine kernel cpumask size. I don't know if there are buffer overflow 
issues in passing a string (though I'm using the
standard netlink way of passing it up using NLA_STRING).

Will post the patch shortly.

--Shailabh

^ permalink raw reply

* Re: [Patch][RFC] Disabling per-tgid stats on task exit in taskstats
From: Paul Jackson @ 2006-07-03 15:55 UTC (permalink / raw)
  To: Shailabh Nagar
  Cc: akpm, Valdis.Kletnieks, jlan, balbir, csturtiv, linux-kernel,
	hadi, netdev
In-Reply-To: <44A93179.2080303@watson.ibm.com>

Shailabh wrote:
> Yes. If no one registers to listen on a particular CPU, data from tasks 
> exiting on that cpu is not sent out at all.

Excellent.


> So I chose to use the "cpulist" ascii format that has been helpfully 
> provided in include/linux/cpumask.h (by whom I wonder :-)

Excellent.

-- 
                  I won't rest till it's the best ...
                  Programmer, Linux Scalability
                  Paul Jackson <pj@sgi.com> 1.925.600.0401

^ permalink raw reply

* [patch 1/7] net_device list cleanup: core
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev; +Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov

Cleanup of net_device list use in net_dev core and IP.
The cleanup consists of
 - converting the to list_head, to make the list double-linked (thus making
   remove operation O(1)), and list walks more readable;
 - introducing of for_each_netdev wrapper over list_for_each.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
Signed-off-by: Kirill Korotaev <dev@openvz.org>
---
 include/linux/netdevice.h |   29 ++++++++++++++++++++++++++-
 net/core/dev.c            |   48 +++++++++++++++++++++++++---------------------
 net/ipv4/devinet.c        |    6 ++---
 net/ipv6/addrconf.c       |    8 +++----
 net/ipv6/anycast.c        |   10 +++++----
 5 files changed, 68 insertions(+), 33 deletions(-)

--- ./include/linux/netdevice.h.vedevbase-core	Mon Jul  3 15:14:15 2006
+++ ./include/linux/netdevice.h	Mon Jul  3 16:09:11 2006
@@ -290,7 +290,8 @@ struct net_device
 	unsigned long		state;
 
 	struct net_device	*next;
-	
+	struct list_head	dev_list;
+
 	/* The device initialization function. Called only once. */
 	int			(*init)(struct net_device *dev);
 
@@ -558,8 +559,34 @@ struct packet_type {
 
 extern struct net_device		loopback_dev;		/* The loopback */
 extern struct net_device		*dev_base;		/* All devices */
+extern struct list_head			dev_base_head;		/* All devices */
 extern rwlock_t				dev_base_lock;		/* Device list lock */
 
+#define for_each_netdev(p)	list_for_each_entry(p, &dev_base_head, dev_list)
+
+/*
+ * When possible, it is preferrable to use for_each_netdev() loop
+ * defined above, rather than first_netdev()/next_netdev() macros.
+ * for_each_netdev() loop makes the intentions clearer, and gives more
+ * flexibility in device list implementation.
+ * While next_netdev() is unavoidable in seq_proc functions,
+ * first_netdev() should be needed quite rarely.
+ */
+#define first_netdev()		({ \
+					list_empty(&dev_base_head) ? NULL : \
+						list_entry(dev_base_head.next, \
+							struct net_device, \
+							dev_list); \
+				 })
+#define next_netdev(dev)	({ \
+					struct list_head *__next; \
+					__next = (dev)->dev_list.next; \
+					__next == &dev_base_head ? NULL : \
+						list_entry(__next, \
+							struct net_device, \
+							dev_list); \
+				 })
+
 extern int 			netdev_boot_setup_check(struct net_device *dev);
 extern unsigned long		netdev_boot_base(const char *prefix, int unit);
 extern struct net_device    *dev_getbyhwaddr(unsigned short type, char *hwaddr);
--- ./net/core/dev.c.vedevbase-core	Mon Jul  3 15:14:19 2006
+++ ./net/core/dev.c	Mon Jul  3 16:09:11 2006
@@ -181,6 +181,9 @@ DEFINE_RWLOCK(dev_base_lock);
 EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_base_lock);
 
+LIST_HEAD(dev_base_head);
+EXPORT_SYMBOL(dev_base_head);
+
 #define NETDEV_HASHBITS	8
 static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];
 static struct hlist_head dev_index_head[1<<NETDEV_HASHBITS];
@@ -575,11 +578,11 @@ struct net_device *dev_getbyhwaddr(unsig
 
 	ASSERT_RTNL();
 
-	for (dev = dev_base; dev; dev = dev->next)
+	for_each_netdev(dev)
 		if (dev->type == type &&
 		    !memcmp(dev->dev_addr, ha, dev->addr_len))
-			break;
-	return dev;
+			return dev;
+	return NULL;
 }
 
 EXPORT_SYMBOL(dev_getbyhwaddr);
@@ -589,14 +592,15 @@ struct net_device *dev_getfirstbyhwtype(
 	struct net_device *dev;
 
 	rtnl_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (dev->type == type) {
 			dev_hold(dev);
-			break;
+			rtnl_unlock();
+			return dev;
 		}
 	}
 	rtnl_unlock();
-	return dev;
+	return NULL;
 }
 
 EXPORT_SYMBOL(dev_getfirstbyhwtype);
@@ -617,14 +621,15 @@ struct net_device * dev_get_by_flags(uns
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (((dev->flags ^ if_flags) & mask) == 0) {
 			dev_hold(dev);
-			break;
+			read_unlock(&dev_base_lock);
+			return dev;
 		}
 	}
 	read_unlock(&dev_base_lock);
-	return dev;
+	return NULL;
 }
 
 /**
@@ -680,7 +685,7 @@ int dev_alloc_name(struct net_device *de
 		if (!inuse)
 			return -ENOMEM;
 
-		for (d = dev_base; d; d = d->next) {
+		for_each_netdev(d) {
 			if (!sscanf(d->name, name, &i))
 				continue;
 			if (i < 0 || i >= max_netdevices)
@@ -966,7 +971,7 @@ int register_netdevice_notifier(struct n
 	rtnl_lock();
 	err = raw_notifier_chain_register(&netdev_chain, nb);
 	if (!err) {
-		for (dev = dev_base; dev; dev = dev->next) {
+		for_each_netdev(dev) {
 			nb->notifier_call(nb, NETDEV_REGISTER, dev);
 
 			if (dev->flags & IFF_UP) 
@@ -2035,7 +2040,7 @@ static int dev_ifconf(char __user *arg)
 	 */
 
 	total = 0;
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		for (i = 0; i < NPROTO; i++) {
 			if (gifconf_list[i]) {
 				int done;
@@ -2974,6 +2979,7 @@ int register_netdevice(struct net_device
 	write_lock_bh(&dev_base_lock);
 	*dev_tail = dev;
 	dev_tail = &dev->next;
+	list_add_tail(&dev->dev_list, &dev_base_head);
 	hlist_add_head(&dev->name_hlist, head);
 	hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
 	dev_hold(dev);
@@ -3271,22 +3277,22 @@ int unregister_netdevice(struct net_devi
 
 	/* And unlink it from device chain. */
 	for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
-		if (d == dev) {
-			write_lock_bh(&dev_base_lock);
-			hlist_del(&dev->name_hlist);
-			hlist_del(&dev->index_hlist);
-			if (dev_tail == &dev->next)
-				dev_tail = dp;
-			*dp = d->next;
-			write_unlock_bh(&dev_base_lock);
+		if (d == dev)
 			break;
-		}
 	}
 	if (!d) {
 		printk(KERN_ERR "unregister net_device: '%s' not found\n",
 		       dev->name);
 		return -ENODEV;
 	}
+	write_lock_bh(&dev_base_lock);
+	list_del(&dev->dev_list);
+	hlist_del(&dev->name_hlist);
+	hlist_del(&dev->index_hlist);
+	if (dev_tail == &dev->next)
+		dev_tail = dp;
+	*dp = d->next;
+	write_unlock_bh(&dev_base_lock);
 
 	dev->reg_state = NETREG_UNREGISTERING;
 
--- ./net/ipv4/devinet.c.vedevbase-core	Mon Jul  3 15:14:20 2006
+++ ./net/ipv4/devinet.c	Mon Jul  3 16:09:11 2006
@@ -841,7 +841,7 @@ no_in_dev:
 	 */
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
 			continue;
 
@@ -920,7 +920,7 @@ u32 inet_confirm_addr(const struct net_d
 
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((in_dev = __in_dev_get_rcu(dev))) {
 			addr = confirm_addr_indev(in_dev, dst, local, scope);
 			if (addr)
@@ -1170,7 +1170,7 @@ void inet_forward_change(void)
 	ipv4_devconf_dflt.forwarding = on;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		struct in_device *in_dev;
 		rcu_read_lock();
 		in_dev = __in_dev_get_rcu(dev);
--- ./net/ipv6/addrconf.c.vedevbase-core	Mon Jul  3 15:14:22 2006
+++ ./net/ipv6/addrconf.c	Mon Jul  3 16:09:11 2006
@@ -469,7 +469,7 @@ static void addrconf_forward_change(void
 	struct inet6_dev *idev;
 
 	read_lock(&dev_base_lock);
-	for (dev=dev_base; dev; dev=dev->next) {
+	for_each_netdev(dev) {
 		read_lock(&addrconf_lock);
 		idev = __in6_dev_get(dev);
 		if (idev) {
@@ -894,7 +894,7 @@ int ipv6_dev_get_saddr(struct net_device
 	read_lock(&dev_base_lock);
 	read_lock(&addrconf_lock);
 
-	for (dev = dev_base; dev; dev=dev->next) {
+	for_each_netdev(dev) {
 		struct inet6_dev *idev;
 		struct inet6_ifaddr *ifa;
 
@@ -1979,7 +1979,7 @@ static void sit_add_v4_addrs(struct inet
 		return;
 	}
 
-        for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		struct in_device * in_dev = __in_dev_get_rtnl(dev);
 		if (in_dev && (dev->flags & IFF_UP)) {
 			struct in_ifaddr * ifa;
@@ -2128,7 +2128,7 @@ static void ip6_tnl_add_linklocal(struct
 			return;
 	}
 	/* then try to inherit it from any device */
-	for (link_dev = dev_base; link_dev; link_dev = link_dev->next) {
+	for_each_netdev(link_dev) {
 		if (!ipv6_inherit_linklocal(idev, link_dev))
 			return;
 	}
--- ./net/ipv6/anycast.c.vedevbase-core	Mon Jul  3 15:14:22 2006
+++ ./net/ipv6/anycast.c	Mon Jul  3 16:09:11 2006
@@ -427,11 +427,13 @@ int ipv6_chk_acast_addr(struct net_devic
 	if (dev)
 		return ipv6_chk_acast_dev(dev, addr);
 	read_lock(&dev_base_lock);
-	for (dev=dev_base; dev; dev=dev->next)
-		if (ipv6_chk_acast_dev(dev, addr))
-			break;
+	for_each_netdev(dev)
+		if (ipv6_chk_acast_dev(dev, addr)) {
+			read_unlock(&dev_base_lock);
+			return 1;
+		}
 	read_unlock(&dev_base_lock);
-	return dev != 0;
+	return 0;
 }
 
 

^ permalink raw reply

* [patch 4/7] net_device list cleanup: drivers and non-IP protocols
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev
  Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov,
	Stuart Cheshire, Ben Greear, Stephen Hemminger, patrick, acme,
	ralf, sri, per.liden
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

Cleanup of net_device list use in network device drivers and protocols
other than IP.

The cleanup consists of
 - converting the to list_head, to make the list double-linked (thus making
   remove operation O(1)), and list walks more readable;
 - introducing of for_each_netdev wrapper over list_for_each.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
Requires "bridge: br_dump_ifinfo index fix"

 drivers/net/wireless/strip.c |    4 +---
 net/8021q/vlan.c             |    4 ++--
 net/8021q/vlanproc.c         |   10 +++++-----
 net/bridge/br_if.c           |    4 ++--
 net/bridge/br_ioctl.c        |    4 +++-
 net/bridge/br_netlink.c      |    3 ++-
 net/decnet/af_decnet.c       |   11 +++++++----
 net/decnet/dn_dev.c          |   17 ++++++++++-------
 net/decnet/dn_fib.c          |    2 +-
 net/decnet/dn_route.c        |   13 +++++++------
 net/llc/llc_core.c           |    7 +++++--
 net/netrom/nr_route.c        |    5 +++--
 net/rose/rose_route.c        |    8 +++++---
 net/sctp/protocol.c          |    2 +-
 net/tipc/eth_media.c         |   11 +++++++----
 15 files changed, 61 insertions(+), 44 deletions(-)

--- ./drivers/net/wireless/strip.c.vedevbase-onet	Mon Jul  3 15:13:46 2006
+++ ./drivers/net/wireless/strip.c	Mon Jul  3 16:12:11 2006
@@ -1969,8 +1969,7 @@ static struct net_device *get_strip_dev(
 		      sizeof(zero_address))) {
 		struct net_device *dev;
 		read_lock_bh(&dev_base_lock);
-		dev = dev_base;
-		while (dev) {
+		for_each_netdev(dev) {
 			if (dev->type == strip_info->dev->type &&
 			    !memcmp(dev->dev_addr,
 				    &strip_info->true_dev_addr,
@@ -1981,7 +1980,6 @@ static struct net_device *get_strip_dev(
 				read_unlock_bh(&dev_base_lock);
 				return (dev);
 			}
-			dev = dev->next;
 		}
 		read_unlock_bh(&dev_base_lock);
 	}
--- ./net/8021q/vlan.c.vedevbase-onet	Mon Jul  3 15:14:17 2006
+++ ./net/8021q/vlan.c	Mon Jul  3 16:12:11 2006
@@ -121,8 +121,8 @@ static void __exit vlan_cleanup_devices(
 	struct net_device *dev, *nxt;
 
 	rtnl_lock();
-	for (dev = dev_base; dev; dev = nxt) {
-		nxt = dev->next;
+	for (dev = first_netdev(); dev; dev = nxt) {
+		nxt = next_netdev(dev);
 		if (dev->priv_flags & IFF_802_1Q_VLAN) {
 			unregister_vlan_dev(VLAN_DEV_INFO(dev)->real_dev,
 					    VLAN_DEV_INFO(dev)->vlan_id);
--- ./net/8021q/vlanproc.c.vedevbase-onet	Mon Jul  3 15:14:17 2006
+++ ./net/8021q/vlanproc.c	Mon Jul  3 16:12:11 2006
@@ -241,7 +241,7 @@ int vlan_proc_rem_dev(struct net_device 
 static struct net_device *vlan_skip(struct net_device *dev) 
 {
 	while (dev && !(dev->priv_flags & IFF_802_1Q_VLAN)) 
-		dev = dev->next;
+		dev = next_netdev(dev);
 
 	return dev;
 }
@@ -257,8 +257,8 @@ static void *vlan_seq_start(struct seq_f
 	if (*pos == 0)
 		return SEQ_START_TOKEN;
 	
-	for (dev = vlan_skip(dev_base); dev && i < *pos; 
-	     dev = vlan_skip(dev->next), ++i);
+	for (dev = vlan_skip(first_netdev()); dev && i < *pos; 
+	     dev = vlan_skip(next_netdev(dev)), ++i);
 		
 	return  (i == *pos) ? dev : NULL;
 } 
@@ -268,8 +268,8 @@ static void *vlan_seq_next(struct seq_fi
 	++*pos;
 
 	return vlan_skip((v == SEQ_START_TOKEN)  
-			    ? dev_base 
-			    : ((struct net_device *)v)->next);
+			    ? first_netdev()
+			    : next_netdev((struct net_device *)v));
 }
 
 static void vlan_seq_stop(struct seq_file *seq, void *v)
--- ./net/bridge/br_if.c.vedevbase-onet	Mon Jul  3 15:14:19 2006
+++ ./net/bridge/br_if.c	Mon Jul  3 16:12:11 2006
@@ -474,8 +474,8 @@ void __exit br_cleanup_bridges(void)
 	struct net_device *dev, *nxt;
 
 	rtnl_lock();
-	for (dev = dev_base; dev; dev = nxt) {
-		nxt = dev->next;
+	for (dev = first_netdev(); dev; dev = nxt) {
+		nxt = next_netdev(dev);
 		if (dev->priv_flags & IFF_EBRIDGE)
 			del_br(dev->priv);
 	}
--- ./net/bridge/br_ioctl.c.vedevbase-onet	Mon Mar 20 08:53:29 2006
+++ ./net/bridge/br_ioctl.c	Mon Jul  3 16:12:11 2006
@@ -27,7 +27,9 @@ static int get_bridge_ifindices(int *ind
 	struct net_device *dev;
 	int i = 0;
 
-	for (dev = dev_base; dev && i < num; dev = dev->next) {
+	for_each_netdev(dev) {
+		if (i >= num)
+			break;
 		if (dev->priv_flags & IFF_EBRIDGE) 
 			indices[i++] = dev->ifindex;
 	}
--- ./net/bridge/br_netlink.c.vedevbase-onet	Mon Jul  3 16:12:11 2006
+++ ./net/bridge/br_netlink.c	Mon Jul  3 16:12:11 2006
@@ -109,7 +109,8 @@ static int br_dump_ifinfo(struct sk_buff
 	int err = 0;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base, idx = 0; dev; dev = dev->next) {
+	idx = 0;
+	for_each_netdev(dev) {
 		struct net_bridge_port *p = dev->br_port;
 
 		/* not a bridge port */
--- ./net/decnet/af_decnet.c.vedevbase-onet	Mon Jul  3 15:14:19 2006
+++ ./net/decnet/af_decnet.c	Mon Jul  3 16:12:11 2006
@@ -720,7 +720,7 @@ static int dn_bind(struct socket *sock, 
 	struct sock *sk = sock->sk;
 	struct dn_scp *scp = DN_SK(sk);
 	struct sockaddr_dn *saddr = (struct sockaddr_dn *)uaddr;
-	struct net_device *dev;
+	struct net_device *pdev, *dev;
 	int rv;
 
 	if (addr_len != sizeof(struct sockaddr_dn))
@@ -744,12 +744,15 @@ static int dn_bind(struct socket *sock, 
 
 	if (!(saddr->sdn_flags & SDF_WILD)) {
 		if (dn_ntohs(saddr->sdn_nodeaddrl)) {
+			dev = NULL;
 			read_lock(&dev_base_lock);
-			for(dev = dev_base; dev; dev = dev->next) {
-				if (!dev->dn_ptr)
+			for_each_netdev(pdev) {
+				if (!pdev->dn_ptr)
 					continue;
-				if (dn_dev_islocal(dev, dn_saddr2dn(saddr)))
+				if (dn_dev_islocal(pdev, dn_saddr2dn(saddr))) {
+					dev = pdev;
 					break;
+				}
 			}
 			read_unlock(&dev_base_lock);
 			if (dev == NULL)
--- ./net/decnet/dn_dev.c.vedevbase-onet	Mon Jul  3 15:14:19 2006
+++ ./net/decnet/dn_dev.c	Mon Jul  3 16:12:11 2006
@@ -775,13 +775,14 @@ static int dn_dev_dump_ifaddr(struct sk_
 	s_idx = cb->args[0];
 	s_dn_idx = dn_idx = cb->args[1];
 	read_lock(&dev_base_lock);
-	for(dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+	idx = 0;
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if (idx > s_idx)
 			s_dn_idx = 0;
 		if ((dn_db = dev->dn_ptr) == NULL)
-			continue;
+			goto cont;
 
 		for(ifa = dn_db->ifa_list, dn_idx = 0; ifa; ifa = ifa->ifa_next, dn_idx++) {
 			if (dn_idx < s_dn_idx)
@@ -794,6 +795,8 @@ static int dn_dev_dump_ifaddr(struct sk_
 					       NLM_F_MULTI) <= 0)
 				goto done;
 		}
+cont:
+		idx++;
 	}
 done:
 	read_unlock(&dev_base_lock);
@@ -1264,7 +1267,7 @@ void dn_dev_devices_off(void)
 	struct net_device *dev;
 
 	rtnl_lock();
-	for(dev = dev_base; dev; dev = dev->next)
+	for_each_netdev(dev)
 		dn_dev_down(dev);
 	rtnl_unlock();
 
@@ -1275,7 +1278,7 @@ void dn_dev_devices_on(void)
 	struct net_device *dev;
 
 	rtnl_lock();
-	for(dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (dev->flags & IFF_UP)
 			dn_dev_up(dev);
 	}
@@ -1296,7 +1299,7 @@ int unregister_dnaddr_notifier(struct no
 static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
 {
 	do {
-		dev = dev->next;
+		dev = next_netdev(dev);
 	} while(dev && !dev->dn_ptr);
 
 	return dev;
@@ -1306,7 +1309,7 @@ static struct net_device *dn_dev_get_idx
 {
 	struct net_device *dev;
 
-	dev = dev_base;
+	dev = first_netdev();
 	if (dev && !dev->dn_ptr)
 		dev = dn_dev_get_next(seq, dev);
 	if (pos) {
--- ./net/decnet/dn_fib.c.vedevbase-onet	Mon Jul  3 15:14:19 2006
+++ ./net/decnet/dn_fib.c	Mon Jul  3 16:12:11 2006
@@ -630,7 +630,7 @@ static void dn_fib_del_ifaddr(struct dn_
 
 	/* Scan device list */
 	read_lock(&dev_base_lock);
-	for(dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		dn_db = dev->dn_ptr;
 		if (dn_db == NULL)
 			continue;
--- ./net/decnet/dn_route.c.vedevbase-onet	Mon Jul  3 15:14:19 2006
+++ ./net/decnet/dn_route.c	Mon Jul  3 16:12:47 2006
@@ -922,16 +922,17 @@ static int dn_route_output_slow(struct d
 			goto out;
 		}
 		read_lock(&dev_base_lock);
-		for(dev_out = dev_base; dev_out; dev_out = dev_out->next) {
+		for_each_netdev(dev_out) {
 			if (!dev_out->dn_ptr)
 				continue;
-			if (dn_dev_islocal(dev_out, oldflp->fld_src))
-				break;
+			if (dn_dev_islocal(dev_out, oldflp->fld_src)) {
+				dev_hold(dev_out);
+				read_unlock(&dev_base_lock);
+				goto source_ok;
+			}
 		}
 		read_unlock(&dev_base_lock);
-		if (dev_out == NULL)
-			goto out;
-		dev_hold(dev_out);
+		goto out;
 source_ok:
 		;
 	}
--- ./net/llc/llc_core.c.vedevbase-onet	Mon Jul  3 15:10:43 2006
+++ ./net/llc/llc_core.c	Mon Jul  3 16:12:11 2006
@@ -161,8 +161,11 @@ static struct packet_type llc_tr_packet_
 
 static int __init llc_init(void)
 {
-	if (dev_base->next)
-		memcpy(llc_station_mac_sa, dev_base->next->dev_addr, ETH_ALEN);
+	struct net_device *dev;
+
+	dev = next_netdev(first_netdev());
+	if (dev)
+		memcpy(llc_station_mac_sa, dev->dev_addr, ETH_ALEN);
 	else
 		memset(llc_station_mac_sa, 0, ETH_ALEN);
 	dev_add_pack(&llc_packet_type);
--- ./net/netrom/nr_route.c.vedevbase-onet	Mon Jul  3 15:14:22 2006
+++ ./net/netrom/nr_route.c	Mon Jul  3 16:12:11 2006
@@ -595,7 +595,7 @@ struct net_device *nr_dev_first(void)
 	struct net_device *dev, *first = NULL;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM)
 			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 				first = dev;
@@ -615,12 +615,13 @@ struct net_device *nr_dev_get(ax25_addre
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_NETROM && ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) {
 			dev_hold(dev);
 			goto out;
 		}
 	}
+	dev = NULL;
 out:
 	read_unlock(&dev_base_lock);
 	return dev;
--- ./net/rose/rose_route.c.vedevbase-onet	Mon Jul  3 15:10:43 2006
+++ ./net/rose/rose_route.c	Mon Jul  3 16:12:11 2006
@@ -600,7 +600,7 @@ struct net_device *rose_dev_first(void)
 	struct net_device *dev, *first = NULL;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE)
 			if (first == NULL || strncmp(dev->name, first->name, 3) < 0)
 				first = dev;
@@ -618,12 +618,13 @@ struct net_device *rose_dev_get(rose_add
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0) {
 			dev_hold(dev);
 			goto out;
 		}
 	}
+	dev = NULL;
 out:
 	read_unlock(&dev_base_lock);
 	return dev;
@@ -634,10 +635,11 @@ static int rose_dev_exists(rose_address 
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ROSE && rosecmp(addr, (rose_address *)dev->dev_addr) == 0)
 			goto out;
 	}
+	dev = NULL;
 out:
 	read_unlock(&dev_base_lock);
 	return dev != NULL;
--- ./net/sctp/protocol.c.vedevbase-onet	Mon Jul  3 15:14:22 2006
+++ ./net/sctp/protocol.c	Mon Jul  3 16:12:11 2006
@@ -177,7 +177,7 @@ static void __sctp_get_local_addr_list(v
 	struct sctp_af *af;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		__list_for_each(pos, &sctp_address_families) {
 			af = list_entry(pos, struct sctp_af, list);
 			af->copy_addrlist(&sctp_local_addr_list, dev);
--- ./net/tipc/eth_media.c.vedevbase-onet	Mon Jul  3 15:14:23 2006
+++ ./net/tipc/eth_media.c	Mon Jul  3 16:14:31 2006
@@ -120,16 +120,19 @@ static int recv_msg(struct sk_buff *buf,
 
 static int enable_bearer(struct tipc_bearer *tb_ptr)
 {
-	struct net_device *dev = dev_base;
+	struct net_device *pdev, *dev;
 	struct eth_bearer *eb_ptr = &eth_bearers[0];
 	struct eth_bearer *stop = &eth_bearers[MAX_ETH_BEARERS];
 	char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
 
 	/* Find device with specified name */
 
-	while (dev && dev->name && strncmp(dev->name, driver_name, IFNAMSIZ)) {	
-		dev = dev->next;
-	}
+	dev = NULL;
+	for_each_netdev(pdev)
+		if (pdev->name && !strncmp(pdev->name, driver_name, IFNAMSIZ)) {
+			dev = pdev;
+			break;
+		}
 	if (!dev)
 		return -ENODEV;
 

^ permalink raw reply

* [patch 6/7] net_device list cleanup: dev_base removal
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev; +Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

Removal of dev_base and dev_tail variables as a part of net_device list
cleanup.
The cleanup consists of
 - converting the to list_head, to make the list double-linked (thus making
   remove operation O(1)), and list walks more readable;
 - introducing of for_each_netdev wrapper over list_for_each.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
 include/linux/netdevice.h |    2 --
 net/core/dev.c            |   21 ---------------------
 2 files changed, 23 deletions(-)

--- ./include/linux/netdevice.h.vedevbase-fin	Mon Jul  3 16:16:28 2006
+++ ./include/linux/netdevice.h	Mon Jul  3 16:16:28 2006
@@ -289,7 +289,6 @@ struct net_device
 
 	unsigned long		state;
 
-	struct net_device	*next;
 	struct list_head	dev_list;
 
 	/* The device initialization function. Called only once. */
@@ -558,7 +557,6 @@ struct packet_type {
 #include <linux/notifier.h>
 
 extern struct net_device		loopback_dev;		/* The loopback */
-extern struct net_device		*dev_base;		/* All devices */
 extern struct list_head			dev_base_head;		/* All devices */
 extern rwlock_t				dev_base_lock;		/* Device list lock */
 
--- ./net/core/dev.c.vedevbase-fin	Mon Jul  3 16:16:28 2006
+++ ./net/core/dev.c	Mon Jul  3 16:16:28 2006
@@ -174,11 +174,7 @@ static spinlock_t net_dma_event_lock;
  * unregister_netdevice(), which must be called with the rtnl
  * semaphore held.
  */
-struct net_device *dev_base;
-static struct net_device **dev_tail = &dev_base;
 DEFINE_RWLOCK(dev_base_lock);
-
-EXPORT_SYMBOL(dev_base);
 EXPORT_SYMBOL(dev_base_lock);
 
 LIST_HEAD(dev_base_head);
@@ -2973,11 +2969,8 @@ int register_netdevice(struct net_device
 
 	set_bit(__LINK_STATE_PRESENT, &dev->state);
 
-	dev->next = NULL;
 	dev_init_scheduler(dev);
 	write_lock_bh(&dev_base_lock);
-	*dev_tail = dev;
-	dev_tail = &dev->next;
 	list_add_tail(&dev->dev_list, &dev_base_head);
 	hlist_add_head(&dev->name_hlist, head);
 	hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
@@ -3256,8 +3249,6 @@ void synchronize_net(void) 
 
 int unregister_netdevice(struct net_device *dev)
 {
-	struct net_device *d, **dp;
-
 	BUG_ON(dev_boot_phase);
 	ASSERT_RTNL();
 
@@ -3275,22 +3266,10 @@ int unregister_netdevice(struct net_devi
 		dev_close(dev);
 
 	/* And unlink it from device chain. */
-	for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
-		if (d == dev)
-			break;
-	}
-	if (!d) {
-		printk(KERN_ERR "unregister net_device: '%s' not found\n",
-		       dev->name);
-		return -ENODEV;
-	}
 	write_lock_bh(&dev_base_lock);
 	list_del(&dev->dev_list);
 	hlist_del(&dev->name_hlist);
 	hlist_del(&dev->index_hlist);
-	if (dev_tail == &dev->next)
-		dev_tail = dp;
-	*dp = d->next;
 	write_unlock_bh(&dev_base_lock);
 
 	dev->reg_state = NETREG_UNREGISTERING;

^ permalink raw reply

* [patch 2/7] net_device list cleanup: proc seq_file output
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev; +Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

Cleanup of net_device list use in seq_file output routines in core networking
files.  Implementation of /proc/net/dev was copied from dev_mcast, since the
latter did the same in a more compact and cleaner way.

The cleanup consists of
 - converting the to list_head, to make the list double-linked (thus making
   remove operation O(1)), and list walks more readable;
 - introducing of for_each_netdev wrapper over list_for_each.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
Note: functions covered by this patch are good candidates for further
restructuring by introduction of "library" routines for seq_file's showing some
information for each device.

 core/dev.c       |   23 +++++++++++------------
 core/dev_mcast.c |    4 ++--
 ipv4/igmp.c      |   25 +++++++++++++++----------
 ipv6/anycast.c   |   12 +++++++-----
 ipv6/mcast.c     |   25 +++++++++++++++----------
 5 files changed, 50 insertions(+), 39 deletions(-)

--- ./net/core/dev.c.vedevbase-proc	Mon Jul  3 16:09:54 2006
+++ ./net/core/dev.c	Mon Jul  3 16:09:54 2006
@@ -2072,26 +2072,25 @@ static int dev_ifconf(char __user *arg)
  *	This is invoked by the /proc filesystem handler to display a device
  *	in detail.
  */
-static __inline__ struct net_device *dev_get_idx(loff_t pos)
-{
-	struct net_device *dev;
-	loff_t i;
-
-	for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next);
-
-	return i == pos ? dev : NULL;
-}
-
 void *dev_seq_start(struct seq_file *seq, loff_t *pos)
 {
+	struct net_device *dev;
+	loff_t off = 1;
 	read_lock(&dev_base_lock);
-	return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
+	if (!*pos)
+		return SEQ_START_TOKEN;
+	for_each_netdev(dev) {
+		if (off++ == *pos)
+			return dev;
+	}
+	return NULL;
 }
 
 void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 {
+	struct net_device *dev = v;
 	++*pos;
-	return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next;
+	return v == SEQ_START_TOKEN ? first_netdev() : next_netdev(dev);
 }
 
 void dev_seq_stop(struct seq_file *seq, void *v)
--- ./net/core/dev_mcast.c.vedevbase-proc	Mon Jul  3 15:14:19 2006
+++ ./net/core/dev_mcast.c	Mon Jul  3 16:09:54 2006
@@ -225,7 +225,7 @@ static void *dev_mc_seq_start(struct seq
 	loff_t off = 0;
 
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (off++ == *pos) 
 			return dev;
 	}
@@ -236,7 +236,7 @@ static void *dev_mc_seq_next(struct seq_
 {
 	struct net_device *dev = v;
 	++*pos;
-	return dev->next;
+	return next_netdev(dev);
 }
 
 static void dev_mc_seq_stop(struct seq_file *seq, void *v)
--- ./net/ipv4/igmp.c.vedevbase-proc	Mon Jul  3 15:14:20 2006
+++ ./net/ipv4/igmp.c	Mon Jul  3 16:09:54 2006
@@ -2254,19 +2254,21 @@ struct igmp_mc_iter_state {
 
 static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq)
 {
+	struct net_device *dev;
 	struct ip_mc_list *im = NULL;
 	struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq);
 
-	for (state->dev = dev_base, state->in_dev = NULL;
-	     state->dev; 
-	     state->dev = state->dev->next) {
+	state->dev = NULL;
+	state->in_dev = NULL;
+	for_each_netdev(dev) {
 		struct in_device *in_dev;
-		in_dev = in_dev_get(state->dev);
+		in_dev = in_dev_get(dev);
 		if (!in_dev)
 			continue;
 		read_lock(&in_dev->mc_list_lock);
 		im = in_dev->mc_list;
 		if (im) {
+			state->dev = dev;
 			state->in_dev = in_dev;
 			break;
 		}
@@ -2285,7 +2287,7 @@ static struct ip_mc_list *igmp_mc_get_ne
 			read_unlock(&state->in_dev->mc_list_lock);
 			in_dev_put(state->in_dev);
 		}
-		state->dev = state->dev->next;
+		state->dev = next_netdev(state->dev);
 		if (!state->dev) {
 			state->in_dev = NULL;
 			break;
@@ -2416,15 +2418,17 @@ struct igmp_mcf_iter_state {
 
 static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq)
 {
+	struct net_device *dev;
 	struct ip_sf_list *psf = NULL;
 	struct ip_mc_list *im = NULL;
 	struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
-	     state->dev; 
-	     state->dev = state->dev->next) {
+	state->dev = NULL;
+	state->im = NULL;
+	state->idev = NULL;
+	for_each_netdev(dev) {
 		struct in_device *idev;
-		idev = in_dev_get(state->dev);
+		idev = in_dev_get(dev);
 		if (unlikely(idev == NULL))
 			continue;
 		read_lock(&idev->mc_list_lock);
@@ -2433,6 +2437,7 @@ static inline struct ip_sf_list *igmp_mc
 			spin_lock_bh(&im->lock);
 			psf = im->sources;
 			if (likely(psf != NULL)) {
+				state->dev = dev;
 				state->im = im;
 				state->idev = idev;
 				break;
@@ -2458,7 +2463,7 @@ static struct ip_sf_list *igmp_mcf_get_n
 				read_unlock(&state->idev->mc_list_lock);
 				in_dev_put(state->idev);
 			}
-			state->dev = state->dev->next;
+			state->dev = next_netdev(state->dev);
 			if (!state->dev) {
 				state->idev = NULL;
 				goto out;
--- ./net/ipv6/anycast.c.vedevbase-proc	Mon Jul  3 16:09:54 2006
+++ ./net/ipv6/anycast.c	Mon Jul  3 16:09:54 2006
@@ -447,19 +447,21 @@ struct ac6_iter_state {
 
 static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq)
 {
+	struct net_device *dev;
 	struct ifacaddr6 *im = NULL;
 	struct ac6_iter_state *state = ac6_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL;
-	     state->dev;
-	     state->dev = state->dev->next) {
+	state->dev = NULL;
+	state->idev = NULL;
+	for_each_netdev(dev) {
 		struct inet6_dev *idev;
-		idev = in6_dev_get(state->dev);
+		idev = in6_dev_get(dev);
 		if (!idev)
 			continue;
 		read_lock_bh(&idev->lock);
 		im = idev->ac_list;
 		if (im) {
+			state->dev = dev;
 			state->idev = idev;
 			break;
 		}
@@ -478,7 +480,7 @@ static struct ifacaddr6 *ac6_get_next(st
 			read_unlock_bh(&state->idev->lock);
 			in6_dev_put(state->idev);
 		}
-		state->dev = state->dev->next;
+		state->dev = next_netdev(state->dev);
 		if (!state->dev) {
 			state->idev = NULL;
 			break;
--- ./net/ipv6/mcast.c.vedevbase-proc	Mon Jul  3 15:14:22 2006
+++ ./net/ipv6/mcast.c	Mon Jul  3 16:09:54 2006
@@ -2322,19 +2322,21 @@ struct igmp6_mc_iter_state {
 
 static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq)
 {
+	struct net_device *dev;
 	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL;
-	     state->dev; 
-	     state->dev = state->dev->next) {
+	state->dev = NULL;
+	state->idev = NULL;
+	for_each_netdev(dev) {
 		struct inet6_dev *idev;
-		idev = in6_dev_get(state->dev);
+		idev = in6_dev_get(dev);
 		if (!idev)
 			continue;
 		read_lock_bh(&idev->lock);
 		im = idev->mc_list;
 		if (im) {
+			state->dev = dev;
 			state->idev = idev;
 			break;
 		}
@@ -2354,7 +2356,7 @@ static struct ifmcaddr6 *igmp6_mc_get_ne
 			read_unlock_bh(&state->idev->lock);
 			in6_dev_put(state->idev);
 		}
-		state->dev = state->dev->next;
+		state->dev = next_netdev(state->dev);
 		if (!state->dev) {
 			state->idev = NULL;
 			break;
@@ -2465,15 +2467,17 @@ struct igmp6_mcf_iter_state {
 
 static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq)
 {
+	struct net_device *dev;
 	struct ip6_sf_list *psf = NULL;
 	struct ifmcaddr6 *im = NULL;
 	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);
 
-	for (state->dev = dev_base, state->idev = NULL, state->im = NULL;
-	     state->dev; 
-	     state->dev = state->dev->next) {
+	state->dev = NULL;
+	state->im = NULL;
+	state->idev = NULL;
+	for_each_netdev(dev) {
 		struct inet6_dev *idev;
-		idev = in6_dev_get(state->dev);
+		idev = in6_dev_get(dev);
 		if (unlikely(idev == NULL))
 			continue;
 		read_lock_bh(&idev->lock);
@@ -2482,6 +2486,7 @@ static inline struct ip6_sf_list *igmp6_
 			spin_lock_bh(&im->mca_lock);
 			psf = im->mca_sources;
 			if (likely(psf != NULL)) {
+				state->dev = dev;
 				state->im = im;
 				state->idev = idev;
 				break;
@@ -2507,7 +2512,7 @@ static struct ip6_sf_list *igmp6_mcf_get
 				read_unlock_bh(&state->idev->lock);
 				in6_dev_put(state->idev);
 			}
-			state->dev = state->dev->next;
+			state->dev = next_netdev(state->dev);
 			if (!state->dev) {
 				state->idev = NULL;
 				goto out;

^ permalink raw reply

* [patch 3/7] net_device list cleanup: netlink_dump
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev; +Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

Cleanup of net_device list use in netlink_dump routines in core networking
files.

The cleanup consists of
 - converting the to list_head, to make the list double-linked (thus making
   remove operation O(1)), and list walks more readable;
 - introducing of for_each_netdev wrapper over list_for_each.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
 core/rtnetlink.c |   18 ++++++++++--------
 ipv4/devinet.c   |   14 ++++++++------
 ipv6/addrconf.c  |   20 +++++++++++++-------
 sched/sch_api.c  |    8 ++++++--
 4 files changed, 37 insertions(+), 23 deletions(-)

--- ./net/core/rtnetlink.c.vedevbase-dump	Mon Jul  3 15:14:19 2006
+++ ./net/core/rtnetlink.c	Mon Jul  3 16:10:12 2006
@@ -319,14 +319,16 @@ static int rtnetlink_dump_ifinfo(struct 
 	struct net_device *dev;
 
 	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
-		if (idx < s_idx)
-			continue;
-		if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK,
-					  NETLINK_CB(cb->skb).pid,
-					  cb->nlh->nlmsg_seq, 0,
-					  NLM_F_MULTI) <= 0)
-			break;
+	idx = 0;
+	for_each_netdev(dev) {
+		if (idx >= s_idx) {
+			if (rtnetlink_fill_ifinfo(skb, dev, RTM_NEWLINK,
+						  NETLINK_CB(cb->skb).pid,
+						  cb->nlh->nlmsg_seq, 0,
+						  NLM_F_MULTI) <= 0)
+				break;
+		}
+		idx++;
 	}
 	read_unlock(&dev_base_lock);
 	cb->args[0] = idx;
--- ./net/ipv4/devinet.c.vedevbase-dump	Mon Jul  3 16:10:12 2006
+++ ./net/ipv4/devinet.c	Mon Jul  3 16:10:12 2006
@@ -1094,18 +1094,17 @@ static int inet_dump_ifaddr(struct sk_bu
 	struct in_ifaddr *ifa;
 	int s_ip_idx, s_idx = cb->args[0];
 
+	idx = 0;
 	s_ip_idx = ip_idx = cb->args[1];
 	read_lock(&dev_base_lock);
-	for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if (idx > s_idx)
 			s_ip_idx = 0;
 		rcu_read_lock();
-		if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
-			rcu_read_unlock();
-			continue;
-		}
+		if ((in_dev = __in_dev_get_rcu(dev)) == NULL)
+			goto cont_unlock;
 
 		for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
 		     ifa = ifa->ifa_next, ip_idx++) {
@@ -1118,7 +1117,10 @@ static int inet_dump_ifaddr(struct sk_bu
 				goto done;
 			}
 		}
+cont_unlock:
 		rcu_read_unlock();
+cont:
+		idx++;
 	}
 
 done:
--- ./net/ipv6/addrconf.c.vedevbase-dump	Mon Jul  3 16:10:12 2006
+++ ./net/ipv6/addrconf.c	Mon Jul  3 16:10:12 2006
@@ -3013,18 +3013,19 @@ static int inet6_dump_addr(struct sk_buf
 	struct ifmcaddr6 *ifmca;
 	struct ifacaddr6 *ifaca;
 
+	idx = 0;
 	s_idx = cb->args[0];
 	s_ip_idx = ip_idx = cb->args[1];
 	read_lock(&dev_base_lock);
 	
-	for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if (idx > s_idx)
 			s_ip_idx = 0;
 		ip_idx = 0;
 		if ((idev = in6_dev_get(dev)) == NULL)
-			continue;
+			goto cont;
 		read_lock_bh(&idev->lock);
 		switch (type) {
 		case UNICAST_ADDR:
@@ -3071,6 +3072,8 @@ static int inet6_dump_addr(struct sk_buf
 		}
 		read_unlock_bh(&idev->lock);
 		in6_dev_put(idev);
+cont:
+		idx++;
 	}
 done:
 	if (err <= 0) {
@@ -3238,17 +3241,20 @@ static int inet6_dump_ifinfo(struct sk_b
 	struct net_device *dev;
 	struct inet6_dev *idev;
 
+	idx = 0;
 	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+	for_each_netdev(dev) {
 		if (idx < s_idx)
-			continue;
+			goto cont;
 		if ((idev = in6_dev_get(dev)) == NULL)
-			continue;
+			goto cont;
 		err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, 
 				cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
 		in6_dev_put(idev);
 		if (err <= 0)
 			break;
+cont:
+		idx++;
 	}
 	read_unlock(&dev_base_lock);
 	cb->args[0] = idx;
@@ -3872,7 +3878,7 @@ void __exit addrconf_cleanup(void)
 	 *	clean dev list.
 	 */
 
-	for (dev=dev_base; dev; dev=dev->next) {
+	for_each_netdev(dev) {
 		if ((idev = __in6_dev_get(dev)) == NULL)
 			continue;
 		addrconf_ifdown(dev, 1);
--- ./net/sched/sch_api.c.vedevbase-dump	Mon Jul  3 15:14:22 2006
+++ ./net/sched/sch_api.c	Mon Jul  3 16:10:12 2006
@@ -829,12 +829,15 @@ static int tc_dump_qdisc(struct sk_buff 
 	struct net_device *dev;
 	struct Qdisc *q;
 
+	idx = 0;
 	s_idx = cb->args[0];
 	s_q_idx = q_idx = cb->args[1];
 	read_lock(&dev_base_lock);
-	for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
-		if (idx < s_idx)
+	for_each_netdev(dev) {
+		if (idx < s_idx) {
+			idx++;
 			continue;
+		}
 		if (idx > s_idx)
 			s_q_idx = 0;
 		read_lock_bh(&qdisc_tree_lock);
@@ -852,6 +855,7 @@ static int tc_dump_qdisc(struct sk_buff 
 			q_idx++;
 		}
 		read_unlock_bh(&qdisc_tree_lock);
+		idx++;
 	}
 
 done:

^ permalink raw reply

* [patch 5/7] net_device list cleanup: arch-dependent code and block devices
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev
  Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov,
	Gerald Schaefer, schwidefsky, davem, ecashin, matthew
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

Cleanup of net_device list use in arch-dependent code and block devices.

The cleanup consists of
 - converting the to list_head, to make the list double-linked (thus making
   remove operation O(1)), and list walks more readable;
 - introducing of for_each_netdev wrapper over list_for_each.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
 arch/s390/appldata/appldata_net_sum.c |    2 +-
 arch/sparc64/solaris/ioctl.c          |    2 +-
 drivers/block/aoe/aoecmd.c            |    8 ++++++--
 drivers/parisc/led.c                  |    2 +-
 4 files changed, 9 insertions(+), 5 deletions(-)

--- ./arch/s390/appldata/appldata_net_sum.c.vedevbase-misc	Mon Jul  3 15:13:15 2006
+++ ./arch/s390/appldata/appldata_net_sum.c	Mon Jul  3 16:16:05 2006
@@ -107,7 +107,7 @@ static void appldata_get_net_sum_data(vo
 	tx_dropped = 0;
 	collisions = 0;
 	read_lock(&dev_base_lock);
-	for (dev = dev_base; dev != NULL; dev = dev->next) {
+	for_each_netdev(dev) {
 		if (dev->get_stats == NULL) {
 			continue;
 		}
--- ./arch/sparc64/solaris/ioctl.c.vedevbase-misc	Mon Mar 20 08:53:29 2006
+++ ./arch/sparc64/solaris/ioctl.c	Mon Jul  3 16:16:05 2006
@@ -686,7 +686,7 @@ static inline int solaris_i(unsigned int
 			int i = 0;
 			
 			read_lock_bh(&dev_base_lock);
-			for (d = dev_base; d; d = d->next) i++;
+			for_each_netdev(d) i++;
 			read_unlock_bh(&dev_base_lock);
 
 			if (put_user (i, (int __user *)A(arg)))
--- ./drivers/block/aoe/aoecmd.c.vedevbase-misc	Mon Jul  3 15:09:57 2006
+++ ./drivers/block/aoe/aoecmd.c	Mon Jul  3 16:16:05 2006
@@ -204,14 +204,17 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
 	sl = sl_tail = NULL;
 
 	read_lock(&dev_base_lock);
-	for (ifp = dev_base; ifp; dev_put(ifp), ifp = ifp->next) {
+	for_each_netdev(ifp) {
 		dev_hold(ifp);
-		if (!is_aoe_netif(ifp))
+		if (!is_aoe_netif(ifp)) {
+			dev_put(ifp);
 			continue;
+		}
 
 		skb = new_skb(ifp, sizeof *h + sizeof *ch);
 		if (skb == NULL) {
 			printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
+			dev_put(ifp);
 			continue;
 		}
 		if (sl_tail == NULL)
@@ -229,6 +232,7 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigne
 
 		skb->next = sl;
 		sl = skb;
+		dev_put(ifp);
 	}
 	read_unlock(&dev_base_lock);
 
--- ./drivers/parisc/led.c.vedevbase-misc	Mon Jul  3 15:13:46 2006
+++ ./drivers/parisc/led.c	Mon Jul  3 16:16:05 2006
@@ -367,7 +367,7 @@ static __inline__ int led_get_net_activi
 	 * for reading should be OK */
 	read_lock(&dev_base_lock);
 	rcu_read_lock();
-	for (dev = dev_base; dev; dev = dev->next) {
+	for_each_netdev(dev) {
 	    struct net_device_stats *stats;
 	    struct in_device *in_dev = __in_dev_get_rcu(dev);
 	    if (!in_dev || !in_dev->ifa_list)

^ permalink raw reply

* [patch 7/7] net_device list cleanup: debugging
From: Andrey Savochkin @ 2006-07-03  8:18 UTC (permalink / raw)
  To: netdev; +Cc: Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

Optional code to catch cases when loop cursor is used after for_each_netdev
loop: often it's a sign of a bug, since it isn't guaranteed to point to a
device.

Signed-off-by: Andrey Savochkin <saw@swsoft.com>
---
If anyone wants to keep this under some debug config option,
let me know which one.

 netdevice.h |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletion(-)

--- ./include/linux/netdevice.h.vedevbase-dbg	Mon Jul  3 16:16:51 2006
+++ ./include/linux/netdevice.h	Mon Jul  3 16:16:51 2006
@@ -560,7 +560,13 @@ extern struct net_device		loopback_dev;	
 extern struct list_head			dev_base_head;		/* All devices */
 extern rwlock_t				dev_base_lock;		/* Device list lock */
 
-#define for_each_netdev(p)	list_for_each_entry(p, &dev_base_head, dev_list)
+#define for_each_netdev(pos)	\
+for (pos = list_entry(dev_base_head.next, typeof(*pos), dev_list); \
+     prefetch(pos->dev_list.next), \
+	&pos->dev_list != &dev_base_head ? : \
+		({ void *__check_dev_use_after_for_each_netdev; \
+		   pos = __check_dev_use_after_for_each_netdev; 0; }); \
+     pos = list_entry(pos->dev_list.next, typeof(*pos), dev_list))
 
 /*
  * When possible, it is preferrable to use for_each_netdev() loop

^ permalink raw reply

* Re: [Patch][RFC] Disabling per-tgid stats on task exit in taskstats
From: Paul Jackson @ 2006-07-03 16:31 UTC (permalink / raw)
  To: Shailabh Nagar
  Cc: akpm, Valdis.Kletnieks, jlan, balbir, csturtiv, linux-kernel,
	hadi, netdev
In-Reply-To: <44A93179.2080303@watson.ibm.com>

Shailabh wrote:
> I don't know if there are buffer overflow 
> issues in passing a string

I don't know if this comment applies to "the standard netlink way of
passing it up using NLA_STRING", but the way I deal with buffer length
issues in the cpuset code is to insist that the user code express the
list in no fewer than 100 + 6 * NR_CPUS bytes:

>From kernel/cpuset.c:

        /* Crude upper limit on largest legitimate cpulist user might write. */
        if (nbytes > 100 + 6 * NR_CPUS)
                return -E2BIG;

This lets the user specify the buffer size passed in, but prevents
them from trying a denial of service attack on the kernel by trying
to pass in a huge buffer.

If the user can't figure out how to write the desired cpulist in
that size, then tough toenails.

-- 
                  I won't rest till it's the best ...
                  Programmer, Linux Scalability
                  Paul Jackson <pj@sgi.com> 1.925.600.0401

^ permalink raw reply

* Re: [PATCH 9/15] pcmcia: hostap_cs.c - 0xc00f, 0x0000 conflicts with pcnet_cs
From: Pavel Roskin @ 2006-07-03 16:57 UTC (permalink / raw)
  To: Dominik Brodowski; +Cc: netdev, linux-pcmcia, hostap, linville, jkmaline
In-Reply-To: <20060703085603.GA9465@dominikbrodowski.de>

Hi Dominik,

On Mon, 2006-07-03 at 10:56 +0200, Dominik Brodowski wrote:

> Like this?

Yes, but I usually drop revisions from the matched IDs, especially in
presence of the chip ID.  Why would we exclude "RevB" if it happens to
be ISL37300P based?  So the new entries would be:

	PCMCIA_DEVICE_PROD_ID123(
		"Allied Telesyn", "AT-WCL452 Wireless PCMCIA Radio",
		"Ver. 1.00",
		0x5cd01705, 0x4271660f, 0x9d08ee12),
	PCMCIA_DEVICE_PROD_ID123(
		"corega", "WL PCCL-11", "ISL37300P",
		0xa21501a, 0x59868926, 0xc9049a39),

-- 
Regards,
Pavel Roskin


^ permalink raw reply

* [PATCH 0/4] d80211: fix receiving
From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw)
  To: netdev

This patch series fixes receiving when multiple virtual interfaces are
active.

It is also available in a 'devel' branch of git tree at
git://git.kernel.org/pub/scm/linux/kernel/git/jbenc/dscape.git

-- 
Jiri Benc
SUSE Labs

^ permalink raw reply

* [PATCH 1/4] d80211: better deallocation of mdev
From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20060703192335.935001000.midnight@suse.cz>

Master device and ieee80211_local are allocated separately now, so master
device can be freed by the same function as other virtual interfaces.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c       |    2 +-
 net/d80211/ieee80211_iface.c |    3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

de609aa3e039b91ebebbec45d4bddd1134a71948
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index f1e42d4..fe1003b 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -4536,7 +4536,7 @@ void ieee80211_free_hw(struct net_device
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 
-	free_netdev(dev);
+	ieee80211_if_free(dev);
 	ieee80211_dev_free(local);
 }
 
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 5abd713..566bb36 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -337,7 +337,8 @@ void ieee80211_if_free(struct net_device
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 
-	BUG_ON(dev == local->mdev || dev == local->apdev);
+	/* local->apdev must be NULL when freeing management interface */
+	BUG_ON(dev == local->apdev);
 	free_netdev(dev);
 }
 
-- 
1.3.0


^ permalink raw reply related

* [PATCH 2/4] d80211: fix receiving through virtual interfaces
From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20060703192335.935001000.midnight@suse.cz>

This fixes several problems with receiving when multiple interfaces are
present or when some interface is in promiscious mode:

- Packet type (PACKET_HOST and PACKET_OTHER_HOST) is set correctly now.
- Failed decryption of a frame is reported only once for each frame.
- Failed decryption of a frame not destined to the interface (e.g. when the
  interface is in promisc mode) is not reported.
- Channel utilization is counted correctly (i.e. once for each frame only,
  independently on number of active virtual interfaces). To achieve this,
  ieee80211_rx_handlers needed to be separated into new
  ieee80211_rx_handlers and ieee80211_rx_pre_handlers structures.

Defragmentation still doesn't work correctly in promisc mode. This is fixed
by subsequent patches.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c   |  171 +++++++++++++++++++++++++++++++---------------
 net/d80211/ieee80211_i.h |    5 +
 net/d80211/wpa.c         |    4 +
 3 files changed, 124 insertions(+), 56 deletions(-)

6cc76c3c2c5de4e1ad40a8b82201eff5eab81939
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index fe1003b..52316f9 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2463,27 +2463,15 @@ ieee80211_rx_h_data(struct ieee80211_txr
 		memcpy(ehdr->h_source, src, ETH_ALEN);
                 ehdr->h_proto = len;
 	}
-
-        if (rx->sta && !rx->sta->assoc_ap &&
-	    !(rx->sta && (rx->sta->flags & WLAN_STA_WDS)))
-                skb->dev = rx->sta->dev;
-        else
-                skb->dev = dev;
+	skb->dev = dev;
 
         skb2 = NULL;
-        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-        /*
-         * don't count the master since the low level code
-         * counts it already for us.
-         */
-        if (skb->dev != sdata->master) {
-		sdata->stats.rx_packets++;
-		sdata->stats.rx_bytes += skb->len;
-        }
+	sdata->stats.rx_packets++;
+	sdata->stats.rx_bytes += skb->len;
 
 	if (local->bridge_packets && (sdata->type == IEEE80211_IF_TYPE_AP
-	    || sdata->type == IEEE80211_IF_TYPE_VLAN)) {
+	    || sdata->type == IEEE80211_IF_TYPE_VLAN) && rx->u.rx.ra_match) {
 		if (is_multicast_ether_addr(skb->data)) {
 			/* send multicast frames both to higher layers in
 			 * local net stack and back to the wireless media */
@@ -2760,13 +2748,14 @@ #endif /* IEEE80211_VERBOSE_DEBUG_PS */
 
 
 static ieee80211_txrx_result
-ieee80211_rx_h_ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
+ieee80211_rx_h_ps_poll(struct ieee80211_txrx_data *rx)
 {
 	struct sk_buff *skb;
 	int no_pending_pkts;
 
 	if (likely(!rx->sta || WLAN_FC_GET_TYPE(rx->fc) != WLAN_FC_TYPE_CTRL ||
-		   WLAN_FC_GET_STYPE(rx->fc) != WLAN_FC_STYPE_PSPOLL))
+		   WLAN_FC_GET_STYPE(rx->fc) != WLAN_FC_STYPE_PSPOLL ||
+		   !rx->u.rx.ra_match))
 		return TXRX_CONTINUE;
 
 	skb = skb_dequeue(&rx->sta->tx_filtered);
@@ -3042,8 +3031,10 @@ ieee80211_rx_h_check(struct ieee80211_tx
 		if (unlikely(rx->fc & WLAN_FC_RETRY &&
 			     rx->sta->last_seq_ctrl[rx->u.rx.queue] ==
 			     hdr->seq_ctrl)) {
-			rx->local->dot11FrameDuplicateCount++;
-			rx->sta->num_duplicates++;
+			if (rx->u.rx.ra_match) {
+				rx->local->dot11FrameDuplicateCount++;
+				rx->sta->num_duplicates++;
+			}
 			return TXRX_DROP;
 		} else
 			rx->sta->last_seq_ctrl[rx->u.rx.queue] = hdr->seq_ctrl;
@@ -3057,7 +3048,9 @@ ieee80211_rx_h_check(struct ieee80211_tx
 		return TXRX_DROP;
 	}
 
-	if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0)
+	if (rx->fc & WLAN_FC_TODS)
+		rx->skb->pkt_type = PACKET_OTHERHOST;
+	else if (memcmp(rx->dev->dev_addr, hdr->addr1, ETH_ALEN) == 0)
 		rx->skb->pkt_type = PACKET_HOST;
 	else if (is_multicast_ether_addr(hdr->addr1)) {
 		if (is_broadcast_ether_addr(hdr->addr1))
@@ -3080,8 +3073,10 @@ ieee80211_rx_h_check(struct ieee80211_tx
 		       WLAN_FC_GET_STYPE(rx->fc) == WLAN_FC_STYPE_PSPOLL)) &&
 		     rx->sdata->type != IEEE80211_IF_TYPE_IBSS &&
 		     (!rx->sta || !(rx->sta->flags & WLAN_STA_ASSOC)))) {
-		if (!(rx->fc & WLAN_FC_FROMDS) && !(rx->fc & WLAN_FC_TODS)) {
-			/* Drop IBSS frames silently. */
+		if ((!(rx->fc & WLAN_FC_FROMDS) && !(rx->fc & WLAN_FC_TODS)) ||
+		    !rx->u.rx.ra_match) {
+			/* Drop IBSS frames and frames for other hosts
+			 * silently. */
 			return TXRX_DROP;
 		}
 
@@ -3113,6 +3108,8 @@ ieee80211_rx_h_check(struct ieee80211_tx
 				rx->key = rx->sdata->keys[keyidx];
 			}
 			if (!rx->key) {
+				if (!rx->u.rx.ra_match)
+					return TXRX_DROP;
 				printk(KERN_DEBUG "%s: RX WEP frame with "
 				       "unknown keyidx %d (A1=" MACSTR " A2="
 				       MACSTR " A3=" MACSTR ")\n",
@@ -3128,7 +3125,7 @@ ieee80211_rx_h_check(struct ieee80211_tx
 		}
         }
 
-	if (rx->fc & WLAN_FC_ISWEP && rx->key) {
+	if (rx->fc & WLAN_FC_ISWEP && rx->key && rx->u.rx.ra_match) {
 		rx->key->tx_rx_count++;
 		if (unlikely(rx->local->key_tx_rx_threshold &&
 			     rx->key->tx_rx_count >
@@ -3168,6 +3165,10 @@ ieee80211_rx_h_sta_process(struct ieee80
 		 */
 		sta->last_rx = jiffies;
 	}
+
+	if (!rx->u.rx.ra_match)
+		return TXRX_CONTINUE;
+
 	sta->rx_fragments++;
 	sta->rx_bytes += rx->skb->len;
 	sta->last_rssi = rx->u.rx.status->ssi;
@@ -3203,7 +3204,7 @@ ieee80211_rx_h_wep_weak_iv_detection(str
 {
 	if (!rx->sta || !(rx->fc & WLAN_FC_ISWEP) ||
 	    WLAN_FC_GET_TYPE(rx->fc) != WLAN_FC_TYPE_DATA || !rx->key ||
-	    rx->key->alg != ALG_WEP)
+	    rx->key->alg != ALG_WEP || !rx->u.rx.ra_match)
 		return TXRX_CONTINUE;
 
 	/* Check for weak IVs, if hwaccel did not remove IV from the frame */
@@ -3260,7 +3261,7 @@ static ieee80211_txrx_result
 ieee80211_rx_h_802_1x_pae(struct ieee80211_txrx_data *rx)
 {
 	if (rx->sdata->eapol && ieee80211_is_eapol(rx->skb) &&
-	    rx->sdata->type != IEEE80211_IF_TYPE_STA) {
+	    rx->sdata->type != IEEE80211_IF_TYPE_STA && rx->u.rx.ra_match) {
 		/* Pass both encrypted and unencrypted EAPOL frames to user
 		 * space for processing. */
 		ieee80211_rx_mgmt(rx->dev, rx->skb, rx->u.rx.status,
@@ -3313,6 +3314,10 @@ static ieee80211_txrx_result
 ieee80211_rx_h_mgmt(struct ieee80211_txrx_data *rx)
 {
         struct ieee80211_sub_if_data *sdata;
+
+	if (!rx->u.rx.ra_match)
+		return TXRX_DROP;
+
 	sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
 	if ((sdata->type == IEEE80211_IF_TYPE_STA ||
 	     sdata->type == IEEE80211_IF_TYPE_IBSS) &&
@@ -3351,7 +3356,8 @@ ieee80211_rx_h_passive_scan(struct ieee8
                 fc = le16_to_cpu(hdr->frame_control);
 
                 if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON &&
+		    rx->dev == local->mdev) {
 			local->scan.rx_beacon++;
 			/* Need to trim FCS here because it is normally
 			 * removed only after this passive scan handler. */
@@ -3502,14 +3508,16 @@ static void ieee80211_rx_michael_mic_rep
 	rx->skb = NULL;
 }
 
-static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
-						struct ieee80211_txrx_data *rx,
-						struct sta_info *sta)
+static inline ieee80211_txrx_result __ieee80211_invoke_rx_handlers(
+				struct ieee80211_local *local,
+				ieee80211_rx_handler *handlers,
+				struct ieee80211_txrx_data *rx,
+				struct sta_info *sta)
 {
 	ieee80211_rx_handler *handler;
         ieee80211_txrx_result res = TXRX_DROP;
 
-	for (handler = local->rx_handlers; *handler != NULL; handler++) {
+	for (handler = handlers; *handler != NULL; handler++) {
 		res = (*handler)(rx);
 		if (res != TXRX_CONTINUE) {
 			if (res == TXRX_DROP) {
@@ -3523,8 +3531,19 @@ static inline void ieee80211_invoke_rx_h
 		}
 	}
 
+	if (res == TXRX_DROP) {
+		dev_kfree_skb(rx->skb);
+	}
+	return res;
+}
 
-	if (res == TXRX_DROP || *handler == NULL)
+static inline void ieee80211_invoke_rx_handlers(struct ieee80211_local *local,
+						ieee80211_rx_handler *handlers,
+						struct ieee80211_txrx_data *rx,
+						struct sta_info *sta)
+{
+	if (__ieee80211_invoke_rx_handlers(local, handlers, rx, sta) ==
+	    TXRX_CONTINUE)
 		dev_kfree_skb(rx->skb);
 }
 
@@ -3568,37 +3587,57 @@ void __ieee80211_rx(struct net_device *d
 	if (unlikely(local->sta_scanning || local->scan.in_scan))
 		rx.u.rx.in_scan = 1;
 
+	if (__ieee80211_invoke_rx_handlers(local, local->rx_pre_handlers, &rx,
+					   sta) != TXRX_CONTINUE)
+		goto end;
+	skb = rx.skb;
+
 	if (sta && !sta->assoc_ap && !(sta->flags & WLAN_STA_WDS) &&
 	    !local->iff_promiscs && !multicast) {
 		rx.dev = sta->dev;
 		rx.sdata = IEEE80211_DEV_TO_SUB_IF(rx.dev);
-		ieee80211_invoke_rx_handlers(local, &rx, sta);
+		rx.u.rx.ra_match = 1;
+		ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
+					     sta);
 	} else {
 		struct ieee80211_sub_if_data *prev = NULL;
 		struct sk_buff *skb_new;
 		u8 *bssid = ieee80211_get_bssid(hdr, skb->len);
 
 		list_for_each_entry(sdata, &local->sub_if_list, list) {
+			rx.u.rx.ra_match = 1;
 			switch (sdata->type) {
 			case IEEE80211_IF_TYPE_STA:
-				if (!bssid || memcmp(sdata->u.sta.bssid,
-						     bssid, ETH_ALEN) != 0)
-					continue;
-				if (!multicast && !sdata->promisc &&
-				    memcmp(sdata->dev->dev_addr, hdr->addr1,
-					   ETH_ALEN) != 0)
+				if (!bssid)
 					continue;
+				if (!ieee80211_bssid_match(bssid,
+							sdata->u.sta.bssid)) {
+					if (!rx.u.rx.in_scan)
+						continue;
+					rx.u.rx.ra_match = 0;
+				} else if (!multicast &&
+					   memcmp(sdata->dev->dev_addr,
+						  hdr->addr1, ETH_ALEN) != 0) {
+					if (!sdata->promisc)
+						continue;
+					rx.u.rx.ra_match = 0;
+				}
 				break;
 			case IEEE80211_IF_TYPE_IBSS:
-				if (!bssid ||
-				    !ieee80211_bssid_match(bssid,
-							   sdata->u.sta.bssid))
-					continue;
-				if (!multicast && !sdata->promisc &&
-				    memcmp(sdata->dev->dev_addr, hdr->addr1,
-					   ETH_ALEN) != 0)
+				if (!bssid)
 					continue;
-				if (sta == NULL) {
+				if (!ieee80211_bssid_match(bssid,
+							sdata->u.sta.bssid)) {
+					if (!rx.u.rx.in_scan)
+						continue;
+					rx.u.rx.ra_match = 0;
+				} else if (!multicast &&
+					   memcmp(sdata->dev->dev_addr,
+						  hdr->addr1, ETH_ALEN) != 0) {
+					if (!sdata->promisc)
+						continue;
+					rx.u.rx.ra_match = 0;
+				} else if (sta == NULL) {
 					sta = rx.sta =
 						ieee80211_ibss_add_sta(dev, skb, bssid,
 								       hdr->addr2);
@@ -3610,10 +3649,12 @@ void __ieee80211_rx(struct net_device *d
 					if (memcmp(sdata->dev->dev_addr,
 						   hdr->addr1, ETH_ALEN) != 0)
 						continue;
-				} else if (!rx.u.rx.in_scan &&
-					   !ieee80211_bssid_match(bssid,
-							sdata->dev->dev_addr))
-					continue;
+				} else if (!ieee80211_bssid_match(bssid,
+							sdata->dev->dev_addr)) {
+					if (!rx.u.rx.in_scan)
+						continue;
+					rx.u.rx.ra_match = 0;
+				}
 				if (sdata->dev == sdata->master &&
 				    !rx.u.rx.in_scan)
 					/* do not receive anything via
@@ -3643,7 +3684,9 @@ void __ieee80211_rx(struct net_device *d
 				rx.skb = skb_new;
 				rx.dev = prev->dev;
 				rx.sdata = prev;
-				ieee80211_invoke_rx_handlers(local, &rx, sta);
+				ieee80211_invoke_rx_handlers(local,
+							     local->rx_handlers,
+							     &rx, sta);
 			}
 			prev = sdata;
 		}
@@ -3651,7 +3694,8 @@ void __ieee80211_rx(struct net_device *d
 			rx.skb = skb;
 			rx.dev = prev->dev;
 			rx.sdata = prev;
-			ieee80211_invoke_rx_handlers(local, &rx, sta);
+			ieee80211_invoke_rx_handlers(local, local->rx_handlers,
+						     &rx, sta);
 		} else
 			dev_kfree_skb(skb);
 	}
@@ -3765,11 +3809,17 @@ ieee80211_rx_h_load_stats(struct ieee802
         local->channel_use_raw += load;
 	if (rx->sta)
 		rx->sta->channel_use_raw += load;
-        rx->sdata->channel_use_raw += load;
+	rx->u.rx.load = load;
 
 	return TXRX_CONTINUE;
 }
 
+static ieee80211_txrx_result
+ieee80211_rx_h_if_stats(struct ieee80211_txrx_data *rx)
+{
+	rx->sdata->channel_use_raw += rx->u.rx.load;
+	return TXRX_CONTINUE;
+}
 
 static void ieee80211_stat_refresh(unsigned long data)
 {
@@ -4113,10 +4163,18 @@ #endif /* IEEE80211_LEDS */
 /* TODO: implement register/unregister functions for adding TX/RX handlers
  * into ordered list */
 
-static ieee80211_rx_handler ieee80211_rx_handlers[] =
+/* rx_pre handlers don't have dev and sdata fields available in
+ * ieee80211_txrx_data */
+static ieee80211_rx_handler ieee80211_rx_pre_handlers[] =
 {
 	ieee80211_rx_h_parse_qos,
 	ieee80211_rx_h_load_stats,
+	NULL
+};
+
+static ieee80211_rx_handler ieee80211_rx_handlers[] =
+{
+	ieee80211_rx_h_if_stats,
 	ieee80211_rx_h_monitor,
 	ieee80211_rx_h_passive_scan,
 	ieee80211_rx_h_check,
@@ -4126,7 +4184,7 @@ static ieee80211_rx_handler ieee80211_rx
 	ieee80211_rx_h_wep_weak_iv_detection,
 	ieee80211_rx_h_wep_decrypt,
 	ieee80211_rx_h_defragment,
-	ieee80211_rx_h_ieee80211_rx_h_ps_poll,
+	ieee80211_rx_h_ps_poll,
 	ieee80211_rx_h_michael_mic_verify,
 	/* this must be after decryption - so header is counted in MPDU mic
 	 * must be before pae and data, so QOS_DATA format frames
@@ -4284,6 +4342,7 @@ struct net_device *ieee80211_alloc_hw(si
 			   NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST);
 
 	local->mdev = mdev;
+	local->rx_pre_handlers = ieee80211_rx_pre_handlers;
         local->rx_handlers = ieee80211_rx_handlers;
         local->tx_handlers = ieee80211_tx_handlers;
 
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 7ffeae2..3f4d00e 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -137,7 +137,11 @@ struct ieee80211_txrx_data {
 			struct ieee80211_rx_status *status;
 			int sent_ps_buffered;
 			int queue;
+			int load;
 			int in_scan:1;
+			int ra_match:1; /* frame is destined to interface
+					 * currently processed (including
+					 * multicast frames) */
 		} rx;
 	} u;
 #ifdef CONFIG_HOSTAPD_WPA_TESTING
@@ -413,6 +417,7 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
 	struct ieee80211_passive_scan scan;
 
 
+	ieee80211_rx_handler *rx_pre_handlers;
 	ieee80211_rx_handler *rx_handlers;
         ieee80211_tx_handler *tx_handlers;
 
diff --git a/net/d80211/wpa.c b/net/d80211/wpa.c
index 04856a9..37f5af4 100644
--- a/net/d80211/wpa.c
+++ b/net/d80211/wpa.c
@@ -235,6 +235,10 @@ #endif /* CONFIG_HOSTAPD_WPA_TESTING */
 #ifdef CONFIG_HOSTAPD_WPA_TESTING
 		int i;
 #endif /* CONFIG_HOSTAPD_WPA_TESTING */
+
+		if (!rx->u.rx.ra_match)
+			return TXRX_DROP;
+
 		printk(KERN_DEBUG "%s: invalid Michael MIC in data frame from "
 		       MACSTR "\n", rx->dev->name, MAC2STR(sa));
 #ifdef CONFIG_HOSTAPD_WPA_TESTING
-- 
1.3.0


^ permalink raw reply related

* [PATCH 3/4] d80211: fix defragmentation
From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20060703192335.935001000.midnight@suse.cz>

When multiple virtual interfaces are active and some of them is in promisc
mode, defragmentation does not work. Fix it by introducing separate fragment
table for each virtual interface.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c       |   26 +++++++++++---------------
 net/d80211/ieee80211_i.h     |    8 ++++----
 net/d80211/ieee80211_iface.c |    5 +++++
 3 files changed, 20 insertions(+), 19 deletions(-)

9b8e66f2aee1f620da25453255cf58e8744519a6
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 52316f9..7b0b4c1 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2812,17 +2812,17 @@ #endif /* IEEE80211_VERBOSE_DEBUG_PS */
 
 
 static inline struct ieee80211_fragment_entry *
-ieee80211_reassemble_add(struct ieee80211_local *local,
+ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata,
 			 unsigned int frag, unsigned int seq, int rx_queue,
 			 struct sk_buff **skb)
 {
         struct ieee80211_fragment_entry *entry;
 	int idx;
 
-	idx = local->fragment_next;
-	entry = &local->fragments[local->fragment_next++];
-	if (local->fragment_next >= IEEE80211_FRAGMENT_MAX)
-		local->fragment_next = 0;
+	idx = sdata->fragment_next;
+	entry = &sdata->fragments[sdata->fragment_next++];
+	if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
+		sdata->fragment_next = 0;
 
 	if (entry->skb) {
 #ifdef CONFIG_D80211_DEBUG
@@ -2831,7 +2831,7 @@ #ifdef CONFIG_D80211_DEBUG
 		printk(KERN_DEBUG "%s: RX reassembly removed oldest "
 		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
 		       "addr1=" MACSTR " addr2=" MACSTR "\n",
-		       local->mdev->name, idx,
+		       sdata->dev->name, idx,
 		       jiffies - entry->first_frag_time, entry->seq,
 		       entry->last_frag, MAC2STR(hdr->addr1),
 		       MAC2STR(hdr->addr2));
@@ -2852,14 +2852,14 @@ #endif /* CONFIG_D80211_DEBUG */
 
 
 static inline struct ieee80211_fragment_entry *
-ieee80211_reassemble_find(struct ieee80211_local *local,
+ieee80211_reassemble_find(struct ieee80211_sub_if_data *sdata,
 			  u16 fc, unsigned int frag, unsigned int seq,
 			  int rx_queue, struct ieee80211_hdr *hdr)
 {
 	struct ieee80211_fragment_entry *entry;
         int i, idx;
 
-	idx = local->fragment_next;
+	idx = sdata->fragment_next;
 	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
 		struct ieee80211_hdr *f_hdr;
 		u16 f_fc;
@@ -2868,7 +2868,7 @@ ieee80211_reassemble_find(struct ieee802
 		if (idx < 0)
 			idx = IEEE80211_FRAGMENT_MAX - 1;
 
-		entry = &local->fragments[idx];
+		entry = &sdata->fragments[idx];
 		if (!entry->skb || entry->seq != seq ||
 		    entry->rx_queue != rx_queue ||
 		    entry->last_frag + 1 != frag)
@@ -2918,7 +2918,7 @@ ieee80211_rx_h_defragment(struct ieee802
 
 	if (frag == 0) {
 		/* This is the first fragment of a new frame. */
-		entry = ieee80211_reassemble_add(rx->local, frag, seq,
+		entry = ieee80211_reassemble_add(rx->sdata, frag, seq,
 						 rx->u.rx.queue, &(rx->skb));
 		if (rx->key && rx->key->alg == ALG_CCMP &&
 		    (rx->fc & WLAN_FC_ISWEP)) {
@@ -2935,7 +2935,7 @@ ieee80211_rx_h_defragment(struct ieee802
 	/* This is a fragment for a frame that should already be pending in
 	 * fragment cache. Add this fragment to the end of the pending entry.
 	 */
-	entry = ieee80211_reassemble_find(rx->local, rx->fc, frag, seq,
+	entry = ieee80211_reassemble_find(rx->sdata, rx->fc, frag, seq,
 					  rx->u.rx.queue, hdr);
 	if (!entry) {
 		I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
@@ -4573,10 +4573,6 @@ void ieee80211_unregister_hw(struct net_
 				  &local->class_dev.kobj);
 	ieee80211_dev_sysfs_del(local);
 
-	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
-		if (local->fragments[i].skb)
-			dev_kfree_skb(local->fragments[i].skb);
-
 	for (i = 0; i < NUM_IEEE80211_MODES; i++) {
 		kfree(local->supp_rates[i]);
 		kfree(local->basic_rates[i]);
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 3f4d00e..6a952bd 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -307,6 +307,10 @@ struct ieee80211_sub_if_data {
 	int ieee802_1x; /* IEEE 802.1X PAE - drop packet to/from unauthorized
 			 * port */
 
+	/* Fragment table for host-based reassembly */
+	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
+	unsigned int fragment_next;
+
 #define NUM_DEFAULT_KEYS 4
         struct ieee80211_key *keys[NUM_DEFAULT_KEYS];
         struct ieee80211_key *default_key;
@@ -406,10 +410,6 @@ #define IEEE80211_IRQSAFE_QUEUE_LIMIT 12
 				  * or RX before generating a rekey
 				  * notification; 0 = notification disabled. */
 
-	/* Fragment table for host-based reassembly */
-	struct ieee80211_fragment_entry	fragments[IEEE80211_FRAGMENT_MAX];
-	unsigned int fragment_next;
-
 	int bridge_packets; /* bridge packets between associated stations and
 			     * deliver multicast frames both back to wireless
 			     * media and to the local net stack */
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index 566bb36..f49ce8a 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -336,9 +336,14 @@ int ieee80211_if_remove(struct net_devic
 void ieee80211_if_free(struct net_device *dev)
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
+	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+	int i;
 
 	/* local->apdev must be NULL when freeing management interface */
 	BUG_ON(dev == local->apdev);
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+		if (sdata->fragments[i].skb)
+			dev_kfree_skb(sdata->fragments[i].skb);
 	free_netdev(dev);
 }
 
-- 
1.3.0


^ permalink raw reply related

* [PATCH 4/4] d80211: optimize defragmentation
From: Jiri Benc @ 2006-07-03 17:24 UTC (permalink / raw)
  To: netdev
In-Reply-To: <20060703192335.935001000.midnight@suse.cz>

Optimize defragmentation by storing all fragments in skb queue and
reallocating skb only once all fragments are received.

Signed-off-by: Jiri Benc <jbenc@suse.cz>

---

 net/d80211/ieee80211.c       |   46 ++++++++++++++++++++++--------------------
 net/d80211/ieee80211_i.h     |    3 ++-
 net/d80211/ieee80211_iface.c |   19 ++++++++++++++---
 3 files changed, 41 insertions(+), 27 deletions(-)

240090e43ed16ad95dd2c7865a681b26f739efc0
diff --git a/net/d80211/ieee80211.c b/net/d80211/ieee80211.c
index 7b0b4c1..1494603 100644
--- a/net/d80211/ieee80211.c
+++ b/net/d80211/ieee80211.c
@@ -2824,10 +2824,10 @@ ieee80211_reassemble_add(struct ieee8021
 	if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX)
 		sdata->fragment_next = 0;
 
-	if (entry->skb) {
+	if (!skb_queue_empty(&entry->skb_list)) {
 #ifdef CONFIG_D80211_DEBUG
 		struct ieee80211_hdr *hdr =
-			(struct ieee80211_hdr *) entry->skb->data;
+			(struct ieee80211_hdr *) entry->skb_list.next->data;
 		printk(KERN_DEBUG "%s: RX reassembly removed oldest "
 		       "fragment entry (idx=%d age=%lu seq=%d last_frag=%d "
 		       "addr1=" MACSTR " addr2=" MACSTR "\n",
@@ -2836,16 +2836,17 @@ #ifdef CONFIG_D80211_DEBUG
 		       entry->last_frag, MAC2STR(hdr->addr1),
 		       MAC2STR(hdr->addr2));
 #endif /* CONFIG_D80211_DEBUG */
-		dev_kfree_skb(entry->skb);
+		__skb_queue_purge(&entry->skb_list);
 	}
 
-	entry->skb = *skb;
+	__skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */
 	*skb = NULL;
 	entry->first_frag_time = jiffies;
 	entry->seq = seq;
 	entry->rx_queue = rx_queue;
         entry->last_frag = frag;
 	entry->ccmp = 0;
+	entry->extra_len = 0;
 
 	return entry;
 }
@@ -2869,12 +2870,12 @@ ieee80211_reassemble_find(struct ieee802
 			idx = IEEE80211_FRAGMENT_MAX - 1;
 
 		entry = &sdata->fragments[idx];
-		if (!entry->skb || entry->seq != seq ||
+		if (skb_queue_empty(&entry->skb_list) || entry->seq != seq ||
 		    entry->rx_queue != rx_queue ||
 		    entry->last_frag + 1 != frag)
 			continue;
 
-		f_hdr = (struct ieee80211_hdr *) entry->skb->data;
+		f_hdr = (struct ieee80211_hdr *) entry->skb_list.next->data;
 		f_fc = le16_to_cpu(f_hdr->frame_control);
 
 		if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_GET_TYPE(f_fc) ||
@@ -2883,8 +2884,7 @@ ieee80211_reassemble_find(struct ieee802
 			continue;
 
 		if (entry->first_frag_time + 2 * HZ < jiffies) {
-			dev_kfree_skb(entry->skb);
-			entry->skb = NULL;
+			__skb_queue_purge(&entry->skb_list);
 			continue;
 		}
 		return entry;
@@ -2901,6 +2901,7 @@ ieee80211_rx_h_defragment(struct ieee802
 	u16 sc;
 	unsigned int frag, seq;
 	struct ieee80211_fragment_entry *entry;
+	struct sk_buff *skb;
 
 	hdr = (struct ieee80211_hdr *) rx->skb->data;
 	sc = le16_to_cpu(hdr->seq_ctrl);
@@ -2968,30 +2969,30 @@ ieee80211_rx_h_defragment(struct ieee802
 		memcpy(entry->last_pn, pn, CCMP_PN_LEN);
 	}
 
-	/* TODO: could gather list of skb's and reallocate data buffer only
-	 * after finding out the total length of the frame */
 	skb_pull(rx->skb, ieee80211_get_hdrlen(rx->fc));
-	if (skb_tailroom(entry->skb) < rx->skb->len) {
+	__skb_queue_tail(&entry->skb_list, rx->skb);
+	entry->last_frag = frag;
+	entry->extra_len += rx->skb->len;
+	if (rx->fc & WLAN_FC_MOREFRAG) {
+		rx->skb = NULL;
+		return TXRX_QUEUED;
+	}
+
+	rx->skb = __skb_dequeue(&entry->skb_list);
+	if (skb_tailroom(rx->skb) < entry->extra_len) {
 		I802_DEBUG_INC(rx->local->rx_expand_skb_head2);
-		if (unlikely(pskb_expand_head(entry->skb, 0, rx->skb->len,
+		if (unlikely(pskb_expand_head(rx->skb, 0, entry->extra_len,
 					      GFP_ATOMIC))) {
 			I802_DEBUG_INC(rx->local->rx_handlers_drop_defrag);
+			__skb_queue_purge(&entry->skb_list);
 			return TXRX_DROP;
 		}
 	}
-	memcpy(skb_put(entry->skb, rx->skb->len), rx->skb->data, rx->skb->len);
-	entry->last_frag = frag;
-	dev_kfree_skb(rx->skb);
-
-	if (rx->fc & WLAN_FC_MOREFRAG) {
-                rx->skb = NULL;
-		return TXRX_QUEUED;
-	}
+	while ((skb = __skb_dequeue(&entry->skb_list)))
+		memcpy(skb_put(rx->skb, skb->len), skb->data, skb->len);
 
 	/* Complete frame has been reassembled - process it now */
-	rx->skb = entry->skb;
 	rx->fragmented = 1;
-        entry->skb = NULL;
 
  out:
 	if (rx->sta)
@@ -4392,6 +4393,7 @@ struct net_device *ieee80211_alloc_hw(si
         sdata->dev = mdev;
         sdata->master = mdev;
         sdata->local = local;
+	ieee80211_if_sdata_init(sdata);
         list_add_tail(&sdata->list, &local->sub_if_list);
 
 	tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
diff --git a/net/d80211/ieee80211_i.h b/net/d80211/ieee80211_i.h
index 6a952bd..b4e294c 100644
--- a/net/d80211/ieee80211_i.h
+++ b/net/d80211/ieee80211_i.h
@@ -62,7 +62,8 @@ struct ieee80211_fragment_entry {
 	unsigned int seq;
 	unsigned int rx_queue;
 	unsigned int last_frag;
-	struct sk_buff *skb;
+	unsigned int extra_len;
+	struct sk_buff_head skb_list;
 	int ccmp; /* Whether fragments were encrypted with CCMP */
 	u8 last_pn[6]; /* PN of the last fragment if CCMP was used */
 };
diff --git a/net/d80211/ieee80211_iface.c b/net/d80211/ieee80211_iface.c
index f49ce8a..f64b4de 100644
--- a/net/d80211/ieee80211_iface.c
+++ b/net/d80211/ieee80211_iface.c
@@ -18,9 +18,22 @@ #include "sta_info.h"
 
 void ieee80211_if_sdata_init(struct ieee80211_sub_if_data *sdata)
 {
+	int i;
+
 	/* Default values for sub-interface parameters */
 	sdata->drop_unencrypted = 0;
 	sdata->eapol = 1;
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
+		skb_queue_head_init(&sdata->fragments[i].skb_list);
+}
+
+static void ieee80211_if_sdata_deinit(struct ieee80211_sub_if_data *sdata)
+{
+	int i;
+
+	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++) {
+		__skb_queue_purge(&sdata->fragments[i].skb_list);
+	}
 }
 
 /* Must be called with rtnl lock held. */
@@ -212,6 +225,7 @@ void ieee80211_if_reinit(struct net_devi
 	int i;
 
 	ASSERT_RTNL();
+	ieee80211_if_sdata_deinit(sdata);
 	for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
 		if (!sdata->keys[i])
 			continue;
@@ -337,13 +351,10 @@ void ieee80211_if_free(struct net_device
 {
 	struct ieee80211_local *local = dev->ieee80211_ptr;
 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-	int i;
 
 	/* local->apdev must be NULL when freeing management interface */
 	BUG_ON(dev == local->apdev);
-	for (i = 0; i < IEEE80211_FRAGMENT_MAX; i++)
-		if (sdata->fragments[i].skb)
-			dev_kfree_skb(sdata->fragments[i].skb);
+	ieee80211_if_sdata_deinit(sdata);
 	free_netdev(dev);
 }
 
-- 
1.3.0


^ permalink raw reply related

* [PATCH] drivers/net/*: conversion to pci_register_driver()
From: Alexey Dobriyan @ 2006-07-03 17:39 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Christophe Lucas, netdev

From: Christophe Lucas <c.lucas@ifrance.com>

Signed-off-by: Christophe Lucas <c.lucas@ifrance.com>
Signed-off-by: Domen Puncer <domen@coderock.org>
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
---

 drivers/net/3c59x.c                           |    2 +-
 drivers/net/8139cp.c                          |    2 +-
 drivers/net/8139too.c                         |    2 +-
 drivers/net/acenic.c                          |    2 +-
 drivers/net/amd8111e.c                        |    2 +-
 drivers/net/arcnet/com20020-pci.c             |    2 +-
 drivers/net/b44.c                             |    2 +-
 drivers/net/bnx2.c                            |    2 +-
 drivers/net/cassini.c                         |    2 +-
 drivers/net/chelsio/cxgb2.c                   |    2 +-
 drivers/net/defxx.c                           |    2 +-
 drivers/net/dl2k.c                            |    2 +-
 drivers/net/e100.c                            |    2 +-
 drivers/net/e1000/e1000_main.c                |    2 +-
 drivers/net/eepro100.c                        |    2 +-
 drivers/net/epic100.c                         |    2 +-
 drivers/net/fealnx.c                          |    2 +-
 drivers/net/forcedeth.c                       |    2 +-
 drivers/net/hp100.c                           |    2 +-
 drivers/net/ixgb/ixgb_main.c                  |    2 +-
 drivers/net/natsemi.c                         |    2 +-
 drivers/net/ne2k-pci.c                        |    2 +-
 drivers/net/ns83820.c                         |    2 +-
 drivers/net/pci-skeleton.c                    |    2 +-
 drivers/net/pcnet32.c                         |    2 +-
 drivers/net/r8169.c                           |    2 +-
 drivers/net/rrunner.c                         |    2 +-
 drivers/net/s2io.c                            |    2 +-
 drivers/net/saa9730.c                         |    2 +-
 drivers/net/sis190.c                          |    2 +-
 drivers/net/sis900.c                          |    2 +-
 drivers/net/sk98lin/skge.c                    |    2 +-
 drivers/net/skfp/skfddi.c                     |    2 +-
 drivers/net/skge.c                            |    2 +-
 drivers/net/starfire.c                        |    2 +-
 drivers/net/sundance.c                        |    2 +-
 drivers/net/sungem.c                          |    2 +-
 drivers/net/sunhme.c                          |    2 +-
 drivers/net/tc35815.c                         |    2 +-
 drivers/net/tg3.c                             |    2 +-
 drivers/net/tokenring/3c359.c                 |    2 +-
 drivers/net/tokenring/lanstreamer.c           |    2 +-
 drivers/net/tokenring/olympic.c               |    2 +-
 drivers/net/tulip/de2104x.c                   |    2 +-
 drivers/net/tulip/de4x5.c                     |    2 +-
 drivers/net/tulip/dmfe.c                      |    2 +-
 drivers/net/tulip/tulip_core.c                |    2 +-
 drivers/net/tulip/uli526x.c                   |    2 +-
 drivers/net/tulip/winbond-840.c               |    2 +-
 drivers/net/tulip/xircom_tulip_cb.c           |    2 +-
 drivers/net/typhoon.c                         |    2 +-
 drivers/net/via-rhine.c                       |    2 +-
 drivers/net/via-velocity.c                    |    2 +-
 drivers/net/wan/dscc4.c                       |    2 +-
 drivers/net/wan/farsync.c                     |    2 +-
 drivers/net/wan/lmc/lmc_main.c                |    2 +-
 drivers/net/wan/pc300_drv.c                   |    2 +-
 drivers/net/wan/pci200syn.c                   |    2 +-
 drivers/net/wan/wanxl.c                       |    2 +-
 drivers/net/wireless/atmel_pci.c              |    2 +-
 drivers/net/wireless/ipw2100.c                |    2 +-
 drivers/net/wireless/ipw2200.c                |    2 +-
 drivers/net/wireless/orinoco_nortel.c         |    2 +-
 drivers/net/wireless/orinoco_pci.c            |    2 +-
 drivers/net/wireless/orinoco_plx.c            |    2 +-
 drivers/net/wireless/orinoco_tmd.c            |    2 +-
 drivers/net/wireless/prism54/islpci_hotplug.c |    2 +-
 drivers/net/yellowfin.c                       |    2 +-
 68 files changed, 68 insertions(+), 68 deletions(-)

--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -3335,7 +3335,7 @@ static int __init vortex_init(void)
 {
 	int pci_rc, eisa_rc;
 
-	pci_rc = pci_module_init(&vortex_driver);
+	pci_rc = pci_register_driver(&vortex_driver);
 	eisa_rc = vortex_eisa_init();
 
 	if (pci_rc == 0)
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -2095,7 +2095,7 @@ static int __init cp_init (void)
 #ifdef MODULE
 	printk("%s", version);
 #endif
-	return pci_module_init (&cp_driver);
+	return pci_register_driver (&cp_driver);
 }
 
 static void __exit cp_exit (void)
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -2626,7 +2626,7 @@ #ifdef MODULE
 	printk (KERN_INFO RTL8139_DRIVER_NAME "\n");
 #endif
 
-	return pci_module_init (&rtl8139_pci_driver);
+	return pci_register_driver (&rtl8139_pci_driver);
 }
 
 
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -725,7 +725,7 @@ static struct pci_driver acenic_pci_driv
 
 static int __init acenic_init(void)
 {
-	return pci_module_init(&acenic_pci_driver);
+	return pci_register_driver(&acenic_pci_driver);
 }
 
 static void __exit acenic_exit(void)
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -2158,7 +2158,7 @@ static struct pci_driver amd8111e_driver
 
 static int __init amd8111e_init(void)
 {
-	return pci_module_init(&amd8111e_driver);
+	return pci_register_driver(&amd8111e_driver);
 }
 
 static void __exit amd8111e_cleanup(void)
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -177,7 +177,7 @@ static struct pci_driver com20020pci_dri
 static int __init com20020pci_init(void)
 {
 	BUGLVL(D_NORMAL) printk(VERSION);
-	return pci_module_init(&com20020pci_driver);
+	return pci_register_driver(&com20020pci_driver);
 }
 
 static void __exit com20020pci_cleanup(void)
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -2357,7 +2357,7 @@ static int __init b44_init(void)
 	dma_desc_align_mask = ~(dma_desc_align_size - 1);
 	dma_desc_sync_size = max_t(unsigned int, dma_desc_align_size, sizeof(struct dma_desc));
 
-	return pci_module_init(&b44_driver);
+	return pci_register_driver(&b44_driver);
 }
 
 static void __exit b44_cleanup(void)
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -6015,7 +6015,7 @@ static struct pci_driver bnx2_pci_driver
 
 static int __init bnx2_init(void)
 {
-	return pci_module_init(&bnx2_pci_driver);
+	return pci_register_driver(&bnx2_pci_driver);
 }
 
 static void __exit bnx2_cleanup(void)
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -5250,7 +5250,7 @@ static int __init cas_init(void)
 	else
 		link_transition_timeout = 0;
 
-	return pci_module_init(&cas_driver);
+	return pci_register_driver(&cas_driver);
 }
 
 static void __exit cas_cleanup(void)
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -1243,7 +1243,7 @@ static struct pci_driver driver = {
 
 static int __init t1_init_module(void)
 {
-	return pci_module_init(&driver);
+	return pci_register_driver(&driver);
 }
 
 static void __exit t1_cleanup_module(void)
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -3444,7 +3444,7 @@ static int __init dfx_init(void)
 {
 	int rc_pci, rc_eisa;
 
-	rc_pci = pci_module_init(&dfx_driver);
+	rc_pci = pci_register_driver(&dfx_driver);
 	if (rc_pci >= 0) dfx_have_pci = 1;
 	
 	rc_eisa = dfx_eisa_init();
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -1854,7 +1854,7 @@ static struct pci_driver rio_driver = {
 static int __init
 rio_init (void)
 {
-	return pci_module_init (&rio_driver);
+	return pci_register_driver (&rio_driver);
 }
 
 static void __exit
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -2873,7 +2873,7 @@ static int __init e100_init_module(void)
 		printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
 		printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT);
 	}
-	return pci_module_init(&e100_driver);
+	return pci_register_driver(&e100_driver);
 }
 
 static void __exit e100_cleanup_module(void)
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -239,7 +239,7 @@ e1000_init_module(void)
 
 	printk(KERN_INFO "%s\n", e1000_copyright);
 
-	ret = pci_module_init(&e1000_driver);
+	ret = pci_register_driver(&e1000_driver);
 
 	return ret;
 }
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -2385,7 +2385,7 @@ static int __init eepro100_init_module(v
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init(&eepro100_driver);
+	return pci_register_driver(&eepro100_driver);
 }
 
 static void __exit eepro100_cleanup_module(void)
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1655,7 +1655,7 @@ #ifdef MODULE
 		version, version2, version3);
 #endif
 
-	return pci_module_init (&epic_driver);
+	return pci_register_driver (&epic_driver);
 }
 
 
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1982,7 +1982,7 @@ #ifdef MODULE
 	printk(version);
 #endif
 
-	return pci_module_init(&fealnx_driver);
+	return pci_register_driver(&fealnx_driver);
 }
 
 static void __exit fealnx_exit(void)
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -4513,7 +4513,7 @@ static struct pci_driver driver = {
 static int __init init_nic(void)
 {
 	printk(KERN_INFO "forcedeth.c: Reverse Engineered nForce ethernet driver. Version %s.\n", FORCEDETH_VERSION);
-	return pci_module_init(&driver);
+	return pci_register_driver(&driver);
 }
 
 static void __exit exit_nic(void)
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -3032,7 +3032,7 @@ #ifdef CONFIG_EISA
 		goto out2;
 #endif
 #ifdef CONFIG_PCI
-	err = pci_module_init(&hp100_pci_driver);
+	err = pci_register_driver(&hp100_pci_driver);
 	if (err && err != -ENODEV) 
 		goto out3;
 #endif
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -162,7 +162,7 @@ ixgb_init_module(void)
 
 	printk(KERN_INFO "%s\n", ixgb_copyright);
 
-	return pci_module_init(&ixgb_driver);
+	return pci_register_driver(&ixgb_driver);
 }
 
 module_init(ixgb_init_module);
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -3357,7 +3357,7 @@ #ifdef MODULE
 	printk(version);
 #endif
 
-	return pci_module_init (&natsemi_driver);
+	return pci_register_driver (&natsemi_driver);
 }
 
 static void __exit natsemi_exit_mod (void)
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -701,7 +701,7 @@ static int __init ne2k_pci_init(void)
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init (&ne2k_driver);
+	return pci_register_driver (&ne2k_driver);
 }
 
 
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -2175,7 +2175,7 @@ #endif
 static int __init ns83820_init(void)
 {
 	printk(KERN_INFO "ns83820.c: National Semiconductor DP83820 10/100/1000 driver.\n");
-	return pci_module_init(&driver);
+	return pci_register_driver(&driver);
 }
 
 static void __exit ns83820_exit(void)
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -1962,7 +1962,7 @@ static int __init netdrv_init_module (vo
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init (&netdrv_pci_driver);
+	return pci_register_driver (&netdrv_pci_driver);
 }
 
 
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -2725,7 +2725,7 @@ static int __init pcnet32_init_module(vo
 		tx_start = tx_start_pt;
 
 	/* find the PCI devices */
-	if (!pci_module_init(&pcnet32_driver))
+	if (!pci_register_driver(&pcnet32_driver))
 		pcnet32_have_pci = 1;
 
 	/* should we find any remaining VLbus devices ? */
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -2817,7 +2817,7 @@ #endif
 static int __init
 rtl8169_init_module(void)
 {
-	return pci_module_init(&rtl8169_pci_driver);
+	return pci_register_driver(&rtl8169_pci_driver);
 }
 
 static void __exit
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1736,7 +1736,7 @@ static struct pci_driver rr_driver = {
 
 static int __init rr_init_module(void)
 {
-	return pci_module_init(&rr_driver);
+	return pci_register_driver(&rr_driver);
 }
 
 static void __exit rr_cleanup_module(void)
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -7274,7 +7274,7 @@ static void __devexit s2io_rem_nic(struc
 
 int __init s2io_starter(void)
 {
-	return pci_module_init(&s2io_driver);
+	return pci_register_driver(&s2io_driver);
 }
 
 /**
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -1131,7 +1131,7 @@ static struct pci_driver saa9730_driver 
 
 static int __init saa9730_init(void)
 {
-	return pci_module_init(&saa9730_driver);
+	return pci_register_driver(&saa9730_driver);
 }
 
 static void __exit saa9730_cleanup(void)
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -1871,7 +1871,7 @@ static struct pci_driver sis190_pci_driv
 
 static int __init sis190_init_module(void)
 {
-	return pci_module_init(&sis190_pci_driver);
+	return pci_register_driver(&sis190_pci_driver);
 }
 
 static void __exit sis190_cleanup_module(void)
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -2495,7 +2495,7 @@ #ifdef MODULE
 	printk(version);
 #endif
 
-	return pci_module_init(&sis900_pci_driver);
+	return pci_register_driver(&sis900_pci_driver);
 }
 
 static void __exit sis900_cleanup_module(void)
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -5133,7 +5133,7 @@ static struct pci_driver skge_driver = {
 
 static int __init skge_init(void)
 {
-	return pci_module_init(&skge_driver);
+	return pci_register_driver(&skge_driver);
 }
 
 static void __exit skge_exit(void)
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -2280,7 +2280,7 @@ static struct pci_driver skfddi_pci_driv
 
 static int __init skfd_init(void)
 {
-	return pci_module_init(&skfddi_pci_driver);
+	return pci_register_driver(&skfddi_pci_driver);
 }
 
 static void __exit skfd_exit(void)
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -3511,7 +3511,7 @@ #endif
 
 static int __init skge_init_module(void)
 {
-	return pci_module_init(&skge_driver);
+	return pci_register_driver(&skge_driver);
 }
 
 static void __exit skge_cleanup_module(void)
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -2170,7 +2170,7 @@ #endif
 		return -ENODEV;
 	}
 
-	return pci_module_init (&starfire_driver);
+	return pci_register_driver (&starfire_driver);
 }
 
 
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1814,7 +1814,7 @@ static int __init sundance_init(void)
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init(&sundance_driver);
+	return pci_register_driver(&sundance_driver);
 }
 
 static void __exit sundance_exit(void)
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -3194,7 +3194,7 @@ #endif /* CONFIG_PM */
 
 static int __init gem_init(void)
 {
-	return pci_module_init(&gem_driver);
+	return pci_register_driver(&gem_driver);
 }
 
 static void __exit gem_cleanup(void)
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -3275,7 +3275,7 @@ static struct pci_driver hme_pci_driver 
 
 static int __init happy_meal_pci_init(void)
 {
-	return pci_module_init(&hme_pci_driver);
+	return pci_register_driver(&hme_pci_driver);
 }
 
 static void happy_meal_pci_exit(void)
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -1725,7 +1725,7 @@ static struct pci_driver tc35815_driver 
 
 static int __init tc35815_init_module(void)
 {
-	return pci_module_init(&tc35815_driver);
+	return pci_register_driver(&tc35815_driver);
 }
 
 static void __exit tc35815_cleanup_module(void)
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -11739,7 +11739,7 @@ static struct pci_driver tg3_driver = {
 
 static int __init tg3_init(void)
 {
-	return pci_module_init(&tg3_driver);
+	return pci_register_driver(&tg3_driver);
 }
 
 static void __exit tg3_cleanup(void)
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -1815,7 +1815,7 @@ static struct pci_driver xl_3c359_driver
 
 static int __init xl_pci_init (void)
 {
-	return pci_module_init (&xl_3c359_driver);
+	return pci_register_driver (&xl_3c359_driver);
 }
 
 
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -1998,7 +1998,7 @@ static struct pci_driver streamer_pci_dr
 };
 
 static int __init streamer_init_module(void) {
-  return pci_module_init(&streamer_pci_driver);
+  return pci_register_driver(&streamer_pci_driver);
 }
 
 static void __exit streamer_cleanup_module(void) {
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -1771,7 +1771,7 @@ static struct pci_driver olympic_driver 
 
 static int __init olympic_pci_init(void) 
 {
-	return pci_module_init (&olympic_driver) ; 
+	return pci_register_driver (&olympic_driver);
 }
 
 static void __exit olympic_pci_cleanup(void)
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -2172,7 +2172,7 @@ static int __init de_init (void)
 #ifdef MODULE
 	printk("%s", version);
 #endif
-	return pci_module_init (&de_driver);
+	return pci_register_driver (&de_driver);
 }
 
 static void __exit de_exit (void)
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -5754,7 +5754,7 @@ static int __init de4x5_module_init (voi
 	int err = 0;
 
 #ifdef CONFIG_PCI
-	err = pci_module_init (&de4x5_pci_driver);
+	err = pci_register_driver (&de4x5_pci_driver);
 #endif
 #ifdef CONFIG_EISA
 	err |= eisa_driver_register (&de4x5_eisa_driver);
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -2039,7 +2039,7 @@ static int __init dmfe_init_module(void)
 	if (HPNA_NoiseFloor > 15)
 		HPNA_NoiseFloor = 0;
 
-	rc = pci_module_init(&dmfe_driver);
+	rc = pci_register_driver(&dmfe_driver);
 	if (rc < 0)
 		return rc;
 
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1849,7 +1849,7 @@ #endif
 	tulip_max_interrupt_work = max_interrupt_work;
 
 	/* probe for and init boards */
-	return pci_module_init (&tulip_driver);
+	return pci_register_driver (&tulip_driver);
 }
 
 
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -1725,7 +1725,7 @@ static int __init uli526x_init_module(vo
 		break;
 	}
 
-	rc = pci_module_init(&uli526x_driver);
+	rc = pci_register_driver(&uli526x_driver);
 	if (rc < 0)
 		return rc;
 
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -1692,7 +1692,7 @@ #endif
 static int __init w840_init(void)
 {
 	printk(version);
-	return pci_module_init(&w840_driver);
+	return pci_register_driver(&w840_driver);
 }
 
 static void __exit w840_exit(void)
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -1726,7 +1726,7 @@ static int __init xircom_init(void)
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init(&xircom_driver);
+	return pci_register_driver(&xircom_driver);
 }
 
 
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -2660,7 +2660,7 @@ #endif
 static int __init
 typhoon_init(void)
 {
-	return pci_module_init(&typhoon_driver);
+	return pci_register_driver(&typhoon_driver);
 }
 
 static void __exit
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -2046,7 +2046,7 @@ static int __init rhine_init(void)
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init(&rhine_driver);
+	return pci_register_driver(&rhine_driver);
 }
 
 
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -2252,7 +2252,7 @@ static int __init velocity_init_module(v
 	int ret;
 
 	velocity_register_notifier();
-	ret = pci_module_init(&velocity_driver);
+	ret = pci_register_driver(&velocity_driver);
 	if (ret < 0)
 		velocity_unregister_notifier();
 	return ret;
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -2062,7 +2062,7 @@ static struct pci_driver dscc4_driver = 
 
 static int __init dscc4_init_module(void)
 {
-	return pci_module_init(&dscc4_driver);
+	return pci_register_driver(&dscc4_driver);
 }
 
 static void __exit dscc4_cleanup_module(void)
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -2697,7 +2697,7 @@ fst_init(void)
 	for (i = 0; i < FST_MAX_CARDS; i++)
 		fst_card_array[i] = NULL;
 	spin_lock_init(&fst_work_q_lock);
-	return pci_module_init(&fst_driver);
+	return pci_register_driver(&fst_driver);
 }
 
 static void __exit
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -1790,7 +1790,7 @@ static struct pci_driver lmc_driver = {
 
 static int __init init_lmc(void)
 {
-    return pci_module_init(&lmc_driver);
+    return pci_register_driver(&lmc_driver);
 }
 
 static void __exit exit_lmc(void)
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -3677,7 +3677,7 @@ static struct pci_driver cpc_driver = {
 
 static int __init cpc_init(void)
 {
-	return pci_module_init(&cpc_driver);
+	return pci_register_driver(&cpc_driver);
 }
 
 static void __exit cpc_cleanup_module(void)
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -476,7 +476,7 @@ #endif
 		printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n");
 		return -EINVAL;
 	}
-	return pci_module_init(&pci200_pci_driver);
+	return pci_register_driver(&pci200_pci_driver);
 }
 
 
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -834,7 +834,7 @@ static int __init wanxl_init_module(void
 #ifdef MODULE
 	printk(KERN_INFO "%s\n", version);
 #endif
-	return pci_module_init(&wanxl_pci_driver);
+	return pci_register_driver(&wanxl_pci_driver);
 }
 
 static void __exit wanxl_cleanup_module(void)
--- a/drivers/net/wireless/atmel_pci.c
+++ b/drivers/net/wireless/atmel_pci.c
@@ -76,7 +76,7 @@ static void __devexit atmel_pci_remove(s
 
 static int __init atmel_init_module(void)
 {
-	return pci_module_init(&atmel_driver);
+	return pci_register_driver(&atmel_driver);
 }
 
 static void __exit atmel_cleanup_module(void)
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -6531,7 +6531,7 @@ static int __init ipw2100_init(void)
 	printk(KERN_INFO DRV_NAME ": %s, %s\n", DRV_DESCRIPTION, DRV_VERSION);
 	printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
 
-	ret = pci_module_init(&ipw2100_pci_driver);
+	ret = pci_register_driver(&ipw2100_pci_driver);
 
 #ifdef CONFIG_IPW2100_DEBUG
 	ipw2100_debug_level = debug;
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -11774,7 +11774,7 @@ static int __init ipw_init(void)
 	printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
 	printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
 
-	ret = pci_module_init(&ipw_driver);
+	ret = pci_register_driver(&ipw_driver);
 	if (ret) {
 		IPW_ERROR("Unable to initialize PCI module\n");
 		return ret;
--- a/drivers/net/wireless/orinoco_nortel.c
+++ b/drivers/net/wireless/orinoco_nortel.c
@@ -304,7 +304,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int __init orinoco_nortel_init(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
-	return pci_module_init(&orinoco_nortel_driver);
+	return pci_register_driver(&orinoco_nortel_driver);
 }
 
 static void __exit orinoco_nortel_exit(void)
--- a/drivers/net/wireless/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco_pci.c
@@ -244,7 +244,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int __init orinoco_pci_init(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
-	return pci_module_init(&orinoco_pci_driver);
+	return pci_register_driver(&orinoco_pci_driver);
 }
 
 static void __exit orinoco_pci_exit(void)
--- a/drivers/net/wireless/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco_plx.c
@@ -351,7 +351,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int __init orinoco_plx_init(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
-	return pci_module_init(&orinoco_plx_driver);
+	return pci_register_driver(&orinoco_plx_driver);
 }
 
 static void __exit orinoco_plx_exit(void)
--- a/drivers/net/wireless/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco_tmd.c
@@ -228,7 +228,7 @@ MODULE_LICENSE("Dual MPL/GPL");
 static int __init orinoco_tmd_init(void)
 {
 	printk(KERN_DEBUG "%s\n", version);
-	return pci_module_init(&orinoco_tmd_driver);
+	return pci_register_driver(&orinoco_tmd_driver);
 }
 
 static void __exit orinoco_tmd_exit(void)
--- a/drivers/net/wireless/prism54/islpci_hotplug.c
+++ b/drivers/net/wireless/prism54/islpci_hotplug.c
@@ -313,7 +313,7 @@ prism54_module_init(void)
 
 	__bug_on_wrong_struct_sizes ();
 
-	return pci_module_init(&prism54_driver);
+	return pci_register_driver(&prism54_driver);
 }
 
 /* by the time prism54_module_exit() terminates, as a postcondition
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1457,7 +1457,7 @@ static int __init yellowfin_init (void)
 #ifdef MODULE
 	printk(version);
 #endif
-	return pci_module_init (&yellowfin_driver);
+	return pci_register_driver (&yellowfin_driver);
 }
 
 


^ permalink raw reply

* Re: [patch 1/7] net_device list cleanup: core
From: Christoph Hellwig @ 2006-07-03 17:46 UTC (permalink / raw)
  To: Andrey Savochkin
  Cc: netdev, Kirill Korotaev, Eric W. Biederman, Alexey Kuznetsov
In-Reply-To: <20060630150823.A22285@castle.nmd.msu.ru>

On Mon, Jul 03, 2006 at 12:18:51PM +0400, Andrey Savochkin wrote:
> Cleanup of net_device list use in net_dev core and IP.
> The cleanup consists of
>  - converting the to list_head, to make the list double-linked (thus making
>    remove operation O(1)), and list walks more readable;
>  - introducing of for_each_netdev wrapper over list_for_each.

When you change all this please make sure dev_base_head is never directly
accessed anymore, not even through macros and dev_base_head is not exported
anymore.  That's the only way to keep drivers messing with it.

Yes, it's a little more work as you need to audit all drivers to see what
they are doing and find suitable abstractions but it's a must have that
should have been done a lot earlier.


^ permalink raw reply

* [PATCH 1/3] mv643xx fixes - Disable interrupts on all ports during initialization
From: Brent Cook @ 2006-07-03 18:11 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev
In-Reply-To: <44A54F5B.4030902@garzik.org>

That's the last time I hand-edit a patch - this is really more of a workaround 
since I've learned that the interrupts should have been disabled by the 
firmware anyway. But, it doesn't hurt. Updated description

This patch disable interrupts on all ports during initialization. The
current driver assumes that the firmware has already disabled all interrupts 
on all ports. We have encountered some boards that do not always disable
interrupts (XES XPedite 6200 for instance) on a soft reset on all ethernet 
ports. This patch prevents a kernel panic if a packet is received before the 
DMA ring buffers are setup for a port on which interrupts are left enabled by 
the firmware.

Signed-off-by: Brent Cook <bcook@bpointsys.com>

Index: current/drivers/net/mv643xx_eth.c
===================================================================
--- current/drivers/net/mv643xx_eth.c	(revision 101)
+++ current/drivers/net/mv643xx_eth.c	(working copy)
@@ -777,6 +777,12 @@
 	unsigned int size;
 	int err;
 
+	/* Mask all interrupts on ethernet port */
+	mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num),
+		ETH_INT_MASK_ALL);
+	/* wait for previous write to complete */
+	mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
+
 	err = request_irq(dev->irq, mv643xx_eth_int_handler,
 			SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev);
 	if (err) {

^ permalink raw reply

* hi
From: Neal Sidhwaney @ 2006-07-03 20:07 UTC (permalink / raw)
  To: netdev

subscribe net-dev
---

^ permalink raw reply

* [Ubuntu PATCH] via-ircc: fix memory leak
From: Randy Dunlap @ 2006-07-03 20:48 UTC (permalink / raw)
  To: samuel, lkml; +Cc: akpm, netdev

From: Chuck Short <chuck@maggie>

[UBUNTU: via-ircc] Fix memory leak.

Coverity id# 653

patch location:
http://www.kernel.org/git/?p=linux/kernel/git/bcollins/ubuntu-dapper.git;a=commitdiff;h=a1f34cb68b16807ed9d5ebb0f6a6ec5ff8a5fc78

Signed-off-by: Chuck Short <zulcss@gmail.com>
Signed-off-by: Ben Collins <bcollins@ubuntu.com>
---
 drivers/net/irda/via-ircc.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

--- linux-2617-g21.orig/drivers/net/irda/via-ircc.c
+++ linux-2617-g21/drivers/net/irda/via-ircc.c
@@ -1220,8 +1220,13 @@ static int upload_rxdata(struct via_ircc
 
 	IRDA_DEBUG(2, "%s(): len=%x\n", __FUNCTION__, len);
 
+	if ((len - 4) < 2) {
+		self->stats.rx_dropped++;
+		return FALSE;
+	}
+
 	skb = dev_alloc_skb(len + 1);
-	if ((skb == NULL) || ((len - 4) < 2)) {
+	if (skb == NULL) {
 		self->stats.rx_dropped++;
 		return FALSE;
 	}




^ permalink raw reply

* skge error; hangs w/ hardware memory hole
From: Martin Michlmayr @ 2006-07-03 20:52 UTC (permalink / raw)
  To: Stephen Hemminger, netdev; +Cc: linux-kernel, 341801, asd, kevin

We received the following bug report at http://bugs.debian.org/341801

| I have a Asus A8V with 4GB of RAM. When I turn on the hardware memory
| hole in the BIOS, the skge driver prints out this message:
|       skge hardware error detected (status 0xc00)
| and then does not work. Setting debug=16 doesn't really show anything.

Another users confirms this bug, saying:

| I'm running kernel 2.6.15-1-amd64-generic version 2.6.15-6, and see
| the very same thing.
| So I have to turn off the memory remapping feature that allows the
| system to see all 4 gig of memory, and thus lose the use of about 200
| megabytes of memory.
| Hardware: ASUS A8V Deluxe, 4G RAM, Athlon 64 3200+ CPU.

This problem has probably been there forever and also happens with the
sk98lin driver:

| With sk98lin under both 2.6.12 and 2.6.17 I get the following message,
| repeated countless times, and finally a hang: [this is copied from
| screen on to a sheet a paper and re-typed, beware typos]:

| eth0: Adapter failed
| eth0: -- ERROR --
| class: Hardware failure
| Nr: 0x264
| Msg: unexpected IRQ Status error

The bug is still present in 2.6.17 -mm6:

| -mm6 does not work with skge and the hardware memory hole. It gave
| these messages:

| skge eth0: enabling interface
| skge 0000:00:0a.0: PCI error cmd=0x117 status=0x22b0
| skge unable to clear error (so ignoring them)
| skge eth0: Link is up at 1000 Mbps, full duplex, flow control tx and rx

| DHCP never managed to get an IP address.

Any idea what to do about this?
-- 
Martin Michlmayr
http://www.cyrius.com/

^ permalink raw reply

* Re: [Patch][RFC] Disabling per-tgid stats on task exit in taskstats
From: Shailabh Nagar @ 2006-07-03 21:11 UTC (permalink / raw)
  To: Andrew Morton
  Cc: pj, Valdis.Kletnieks, jlan, balbir, csturtiv, linux-kernel, hadi,
	netdev
In-Reply-To: <20060630205148.4f66b125.akpm@osdl.org>

Andrew Morton wrote:

>On Fri, 30 Jun 2006 23:37:10 -0400
>Shailabh Nagar <nagar@watson.ibm.com> wrote:
>
>  
>
>>>Set aside the implementation details and ask "what is a good design"?
>>>
>>>A kernel-wide constant, whether determined at build-time or by a /proc poke
>>>isn't a nice design.
>>>
>>>Can we permit userspace to send in a netlink message describing a cpumask? 
>>>That's back-compatible.
>>> 
>>>
>>>      
>>>
>>Yes, that should be doable. And passing in a cpumask is much better 
>>since we no longer
>>have to maintain mappings.
>>
>>So the strawman is:
>>Listener bind()s to genetlink using its real pid.
>>Sends a separate "registration" message with cpumask to listen to. 
>>Kernel stores (real) pid and cpumask.
>>During task exit, kernel goes through each registered listener (small 
>>list) and decides which
>>one needs to get this exit data and calls a genetlink_unicast to each 
>>one that does need it.
>>
>>If number of listeners is small, the lookups should be swift enough. If 
>>it grows large, we
>>can consider a fancier lookup (but there I go again, delving into 
>>implementation too early :-)
>>    
>>
>
>We'll need a map.
>
>1024 CPUs, 1024 listeners, 1000 exits/sec/CPU and we're up to a million
>operations per second per CPU.  Meltdown.
>
>But it's a pretty simple map.  A per-cpu array of pointers to the head of a
>linked list.  One lock for each CPU's list.
>  
>
Here's a patch that implements the above ideas.

A listener register's interest by specifying a cpumask in the
cpulist format (comma separated ranges of cpus). The listener's pid
is entered into per-cpu lists for those cpus and exit events from those
cpus go to the listeners using netlink unicasts.

Please comment.

Andrew, this is not being proposed for inclusion yet since there is 
atleast one more issue that needs to be resolved:

What happens when a listener exits without doing deregistration
(or if the listener attempts to register another cpumask while a current
registration is still active).

More on that in a separate thread.

--Shailabh



On systems with a large number of cpus, with even a modest rate of
tasks exiting per cpu, the volume of taskstats data sent on thread exit
can overflow a userspace listener's buffers.

One approach to avoiding overflow is to allow listeners to get data for
a limited and specific set of cpus. By scaling the number of listeners
and/or the cpus they monitor, userspace can handle the statistical data
overload more gracefully.

In this patch, each listener registers to listen to a specific set of
cpus by specifying a cpumask.  The interest is recorded per-cpu. When
a task exits on a cpu, its taskstats data is unicast to each listener
interested in that cpu.

Thanks to Andrew Morton for pointing out the various scalability and
general concerns of previous attempts and for suggesting this design.

Signed-Off-By: Shailabh Nagar <nagar@watson.ibm.com>

 include/linux/taskstats.h      |    4 -
 include/linux/taskstats_kern.h |   12 ---
 kernel/taskstats.c             |  136 +++++++++++++++++++++++++++++++++++++++--
 3 files changed, 135 insertions(+), 17 deletions(-)

Index: linux-2.6.17-mm3equiv/include/linux/taskstats.h
===================================================================
--- linux-2.6.17-mm3equiv.orig/include/linux/taskstats.h	2006-06-30 19:03:40.000000000 -0400
+++ linux-2.6.17-mm3equiv/include/linux/taskstats.h	2006-07-01 23:53:01.000000000 -0400
@@ -87,8 +87,6 @@ struct taskstats {
 };


-#define TASKSTATS_LISTEN_GROUP	0x1
-
 /*
  * Commands sent from userspace
  * Not versioned. New commands should only be inserted at the enum's end
@@ -120,6 +118,8 @@ enum {
 	TASKSTATS_CMD_ATTR_UNSPEC = 0,
 	TASKSTATS_CMD_ATTR_PID,
 	TASKSTATS_CMD_ATTR_TGID,
+	TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
+	TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
 	__TASKSTATS_CMD_ATTR_MAX,
 };

Index: linux-2.6.17-mm3equiv/include/linux/taskstats_kern.h
===================================================================
--- linux-2.6.17-mm3equiv.orig/include/linux/taskstats_kern.h	2006-06-30 11:57:14.000000000 -0400
+++ linux-2.6.17-mm3equiv/include/linux/taskstats_kern.h	2006-07-01 23:53:01.000000000 -0400
@@ -19,20 +19,14 @@ enum {
 #ifdef CONFIG_TASKSTATS
 extern kmem_cache_t *taskstats_cache;
 extern struct mutex taskstats_exit_mutex;
-
-static inline int taskstats_has_listeners(void)
-{
-	if (!genl_sock)
-		return 0;
-	return netlink_has_listeners(genl_sock, TASKSTATS_LISTEN_GROUP);
-}
-
+DECLARE_PER_CPU(struct list_head, listener_list);

 static inline void taskstats_exit_alloc(struct taskstats **ptidstats)
 {
 	*ptidstats = NULL;
-	if (taskstats_has_listeners())
+	if (!list_empty(&get_cpu_var(listener_list)))
 		*ptidstats = kmem_cache_zalloc(taskstats_cache, SLAB_KERNEL);
+	put_cpu_var(listener_list);
 }

 static inline void taskstats_exit_free(struct taskstats *tidstats)
Index: linux-2.6.17-mm3equiv/kernel/taskstats.c
===================================================================
--- linux-2.6.17-mm3equiv.orig/kernel/taskstats.c	2006-06-30 23:38:39.000000000 -0400
+++ linux-2.6.17-mm3equiv/kernel/taskstats.c	2006-07-02 00:16:18.000000000 -0400
@@ -19,6 +19,8 @@
 #include <linux/kernel.h>
 #include <linux/taskstats_kern.h>
 #include <linux/delayacct.h>
+#include <linux/cpumask.h>
+#include <linux/percpu.h>
 #include <net/genetlink.h>
 #include <asm/atomic.h>

@@ -26,6 +28,9 @@ static DEFINE_PER_CPU(__u32, taskstats_s
 static int family_registered = 0;
 kmem_cache_t *taskstats_cache;

+DEFINE_PER_CPU(struct list_head, listener_list);
+static DEFINE_PER_CPU(struct rw_semaphore, listener_list_sem);
+
 static struct genl_family family = {
 	.id		= GENL_ID_GENERATE,
 	.name		= TASKSTATS_GENL_NAME,
@@ -37,9 +42,19 @@ static struct nla_policy taskstats_cmd_g
 __read_mostly = {
 	[TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
 	[TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
-};
+	[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
+	[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};

+struct listener {
+	struct list_head list;
+	pid_t pid;
+};

+enum actions {
+	REGISTER,
+	DEREGISTER
+};
+
 static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
 			void **replyp, size_t size)
 {
@@ -77,6 +92,8 @@ static int prepare_reply(struct genl_inf
 static int send_reply(struct sk_buff *skb, pid_t pid, int event)
 {
 	struct genlmsghdr *genlhdr = nlmsg_data((struct nlmsghdr *)skb->data);
+	struct rw_semaphore *sem;
+	struct list_head *p, *head;
 	void *reply;
 	int rc;

@@ -88,9 +105,30 @@ static int send_reply(struct sk_buff *sk
 		return rc;
 	}

-	if (event == TASKSTATS_MSG_MULTICAST)
-		return genlmsg_multicast(skb, pid, TASKSTATS_LISTEN_GROUP);
-	return genlmsg_unicast(skb, pid);
+	if (event == TASKSTATS_MSG_UNICAST)
+		return genlmsg_unicast(skb, pid);
+
+	/*
+	 * Taskstats multicast is unicasts to listeners who have registered
+	 * interest in this cpu
+	 */
+	sem = &get_cpu_var(listener_list_sem);
+	head = &get_cpu_var(listener_list);
+
+	down_read(sem);
+	list_for_each(p, head) {
+		int ret;
+		struct listener *s = list_entry(p, struct listener, list);
+		ret = genlmsg_unicast(skb, s->pid);
+		if (ret)
+			rc = ret;
+	}
+	up_read(sem);
+
+	put_cpu_var(listener_list);
+	put_cpu_var(listener_list_sem);
+
+	return rc;
 }

 static int fill_pid(pid_t pid, struct task_struct *pidtsk,
@@ -201,8 +239,73 @@ ret:
 	return;
 }

+static int add_del_listener(pid_t pid, cpumask_t *maskp, int isadd)
+{
+	struct listener *s;
+	unsigned int cpu, mycpu;
+	cpumask_t mask;
+	struct rw_semaphore *sem;
+	struct list_head *head, *p;

-static int taskstats_send_stats(struct sk_buff *skb, struct genl_info *info)
+	memcpy(&mask, maskp, sizeof(cpumask_t));
+	if (cpus_empty(mask))
+		return -EINVAL;
+
+	mycpu = get_cpu();
+	put_cpu();
+	if (isadd == REGISTER) {
+		for_each_cpu_mask(cpu, mask) {
+			if (!cpu_possible(cpu))
+				continue;
+			if (cpu == mycpu)
+				preempt_disable();
+
+			sem = &per_cpu(listener_list_sem, cpu);
+			head = &per_cpu(listener_list, cpu);
+
+			s = kmalloc(sizeof(struct listener), GFP_KERNEL);
+			if (!s)
+				return -ENOMEM;
+			s->pid = pid;
+			INIT_LIST_HEAD(&s->list);
+
+			down_write(sem);
+			list_add(&s->list, head);
+			up_write(sem);
+
+			if (cpu == mycpu)
+				preempt_enable();
+		}
+	} else {
+		for_each_cpu_mask(cpu, mask) {
+			struct list_head *tmp;
+
+			if (!cpu_possible(cpu))
+				continue;
+			if (cpu == mycpu)
+				preempt_disable();
+
+			sem = &per_cpu(listener_list_sem, cpu);
+			head = &per_cpu(listener_list, cpu);
+
+			down_write(sem);
+			list_for_each_safe(p, tmp, head) {
+				s = list_entry(p, struct listener, list);
+				if (s->pid == pid) {
+					list_del(&s->list);
+					break;
+				}
+			}
+			up_write(sem);
+
+			if (cpu == mycpu)
+				preempt_enable();
+		}
+	}
+	return 0;
+}
+
+static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
 {
 	int rc = 0;
 	struct sk_buff *rep_skb;
@@ -210,6 +313,21 @@ static int taskstats_send_stats(struct s
 	void *reply;
 	size_t size;
 	struct nlattr *na;
+	cpumask_t mask;
+
+	if (info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK]) {
+		na = info->attrs[TASKSTATS_CMD_ATTR_REGISTER_CPUMASK];
+		cpulist_parse((char *)nla_data(na), mask);
+		rc = add_del_listener(info->snd_pid, &mask, REGISTER);
+		return rc;
+	}
+
+	if (info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK]) {
+		na = info->attrs[TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK];
+		cpulist_parse((char *)nla_data(na), mask);
+		rc = add_del_listener(info->snd_pid, &mask, DEREGISTER);
+		return rc;
+	}

 	/*
 	 * Size includes space for nested attributes
@@ -334,7 +452,7 @@ ret:

 static struct genl_ops taskstats_ops = {
 	.cmd		= TASKSTATS_CMD_GET,
-	.doit		= taskstats_send_stats,
+	.doit		= taskstats_user_cmd,
 	.policy		= taskstats_cmd_get_policy,
 };

@@ -349,6 +467,7 @@ void __init taskstats_init_early(void)
 static int __init taskstats_init(void)
 {
 	int rc;
+	unsigned int i;

 	rc = genl_register_family(&family);
 	if (rc)
@@ -358,6 +477,11 @@ static int __init taskstats_init(void)
 	rc = genl_register_ops(&family, &taskstats_ops);
 	if (rc < 0)
 		goto err;
+
+	for_each_possible_cpu(i) {
+		INIT_LIST_HEAD(&(per_cpu(listener_list, i)));
+		init_rwsem(&(per_cpu(listener_list_sem, i)));
+	}

 	return 0;
 err:




^ permalink raw reply

* Re: Two I/O memory regions in /proc/iomem for a NIC
From: Lennert Buytenhek @ 2006-07-03 21:30 UTC (permalink / raw)
  To: John Que; +Cc: netdev
In-Reply-To: <ada605fb0607020837q5573299ke05864e130169bed@mail.gmail.com>

On Sun, Jul 02, 2006 at 06:37:18PM +0300, John Que wrote:

> Could a single call to
> pci_request_regions(pdev, driver_name)
> result in that we see 2 regions afterwards when running
> cat /proc/iomem?

Sure.  Take a look at the output of 'lspci -v' some time.  On my
machine, for example, I have:

05:11.0 Ethernet controller: Intel Corporation 82546GB Gigabit Ethernet Controller (rev 03)
        Subsystem: Intel Corporation PRO/1000 MT Dual Port Network Connection
        Flags: bus master, 66Mhz, medium devsel, latency 64, IRQ 10
        Memory at cffc0000 (64-bit, non-prefetchable) [size=128K]   <===
        Memory at cff00000 (64-bit, non-prefetchable) [size=256K]   <===
        I/O ports at e400 [size=64]
        Expansion ROM at cfec0000 [disabled] [size=256K]
        Capabilities: <available only to root>

05:11.1 Ethernet controller: Intel Corporation 82546GB Gigabit Ethernet Controller (rev 03)
        Subsystem: Intel Corporation PRO/1000 MT Dual Port Network Connection
        Flags: bus master, 66Mhz, medium devsel, latency 64, IRQ 11
        Memory at cffe0000 (64-bit, non-prefetchable) [size=128K]   <===
        Memory at cff80000 (64-bit, non-prefetchable) [size=256K]   <===
        I/O ports at e800 [size=64]
        Expansion ROM at cff40000 [disabled] [size=256K]
        Capabilities: <available only to root>

As you can see, each port of the dual-port card has two memory regions,
four a total of 4 memory regions.


cheers,
Lennert

^ permalink raw reply


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