diff options
| author | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
|---|---|---|
| committer | Wim Van Sebroeck <wim@iguana.be> | 2007-05-11 19:03:13 +0000 | 
| commit | 5c34202b8bf942da411b6599668a76b07449bbfd (patch) | |
| tree | 5719c361321eaddc8e4f1b0c8a7994f0e9a6fdd3 /net/core | |
| parent | 0d4804b31f91cfbcff6d62af0bc09a893a1c8ae0 (diff) | |
| parent | 1f8a6b658a943b4f04a1fc7b3a420360202c86cd (diff) | |
Merge /pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'net/core')
| -rw-r--r-- | net/core/dev.c | 105 | ||||
| -rw-r--r-- | net/core/dev_mcast.c | 5 | ||||
| -rw-r--r-- | net/core/flow.c | 2 | ||||
| -rw-r--r-- | net/core/link_watch.c | 166 | ||||
| -rw-r--r-- | net/core/netpoll.c | 1 | ||||
| -rw-r--r-- | net/core/pktgen.c | 1 | ||||
| -rw-r--r-- | net/core/rtnetlink.c | 7 | 
7 files changed, 169 insertions, 118 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index eb999003bbb..8301e2ac747 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -156,13 +156,13 @@ static spinlock_t net_dma_event_lock;  #endif  /* - * The @dev_base list is protected by @dev_base_lock and the rtnl + * The @dev_base_head list is protected by @dev_base_lock and the rtnl   * semaphore.   *   * Pure readers hold dev_base_lock for reading.   *   * Writers must hold the rtnl semaphore while they loop through the - * dev_base list, and hold dev_base_lock for writing when they do the + * dev_base_head list, and hold dev_base_lock for writing when they do the   * actual updates.  This allows pure readers to access the list even   * while a writer is preparing to update it.   * @@ -174,11 +174,10 @@ 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; +LIST_HEAD(dev_base_head);  DEFINE_RWLOCK(dev_base_lock); -EXPORT_SYMBOL(dev_base); +EXPORT_SYMBOL(dev_base_head);  EXPORT_SYMBOL(dev_base_lock);  #define NETDEV_HASHBITS	8 @@ -567,26 +566,38 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha)  	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); +struct net_device *__dev_getfirstbyhwtype(unsigned short type) +{ +	struct net_device *dev; + +	ASSERT_RTNL(); +	for_each_netdev(dev) +		if (dev->type == type) +			return dev; + +	return NULL; +} + +EXPORT_SYMBOL(__dev_getfirstbyhwtype); +  struct net_device *dev_getfirstbyhwtype(unsigned short type)  {  	struct net_device *dev;  	rtnl_lock(); -	for (dev = dev_base; dev; dev = dev->next) { -		if (dev->type == type) { -			dev_hold(dev); -			break; -		} -	} +	dev = __dev_getfirstbyhwtype(type); +	if (dev) +		dev_hold(dev);  	rtnl_unlock();  	return dev;  } @@ -606,17 +617,19 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);  struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mask)  { -	struct net_device *dev; +	struct net_device *dev, *ret; +	ret = NULL;  	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); +			ret = dev;  			break;  		}  	}  	read_unlock(&dev_base_lock); -	return dev; +	return ret;  }  /** @@ -682,7 +695,7 @@ int dev_alloc_name(struct net_device *dev, const char *name)  		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) @@ -964,7 +977,7 @@ int register_netdevice_notifier(struct notifier_block *nb)  	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) @@ -2038,7 +2051,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; @@ -2070,26 +2083,28 @@ static int dev_ifconf(char __user *arg)   *	This is invoked by the /proc filesystem handler to display a device   *	in detail.   */ -static struct net_device *dev_get_idx(loff_t pos) +void *dev_seq_start(struct seq_file *seq, loff_t *pos)  { +	loff_t off;  	struct net_device *dev; -	loff_t i; -	for (i = 0, dev = dev_base; dev && i < pos; ++i, dev = dev->next); +	read_lock(&dev_base_lock); +	if (!*pos) +		return SEQ_START_TOKEN; -	return i == pos ? dev : NULL; -} +	off = 1; +	for_each_netdev(dev) +		if (off++ == *pos) +			return dev; -void *dev_seq_start(struct seq_file *seq, loff_t *pos) -{ -	read_lock(&dev_base_lock); -	return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN; +	return NULL;  }  void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)  {  	++*pos; -	return v == SEQ_START_TOKEN ? dev_base : ((struct net_device *)v)->next; +	return v == SEQ_START_TOKEN ? +		first_net_device() : next_net_device((struct net_device *)v);  }  void dev_seq_stop(struct seq_file *seq, void *v) @@ -2362,9 +2377,9 @@ static int __init dev_proc_init(void)  out:  	return rc;  out_softnet: -	proc_net_remove("softnet_stat"); -out_dev2:  	proc_net_remove("ptype"); +out_dev2: +	proc_net_remove("softnet_stat");  out_dev:  	proc_net_remove("dev");  	goto out; @@ -3071,11 +3086,9 @@ int register_netdevice(struct net_device *dev)  	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));  	dev_hold(dev); @@ -3349,8 +3362,6 @@ void synchronize_net(void)  void unregister_netdevice(struct net_device *dev)  { -	struct net_device *d, **dp; -  	BUG_ON(dev_boot_phase);  	ASSERT_RTNL(); @@ -3370,19 +3381,11 @@ void unregister_netdevice(struct net_device *dev)  		dev_close(dev);  	/* 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); -			break; -		} -	} -	BUG_ON(!d); +	write_lock_bh(&dev_base_lock); +	list_del(&dev->dev_list); +	hlist_del(&dev->name_hlist); +	hlist_del(&dev->index_hlist); +	write_unlock_bh(&dev_base_lock);  	dev->reg_state = NETREG_UNREGISTERING; @@ -3447,7 +3450,7 @@ static int dev_cpu_callback(struct notifier_block *nfb,  	unsigned int cpu, oldcpu = (unsigned long)ocpu;  	struct softnet_data *sd, *oldsd; -	if (action != CPU_DEAD) +	if (action != CPU_DEAD && action != CPU_DEAD_FROZEN)  		return NOTIFY_OK;  	local_irq_disable(); diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 7d57bf77f3a..5a54053386c 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -223,7 +223,7 @@ static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)  	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;  	} @@ -232,9 +232,8 @@ static void *dev_mc_seq_start(struct seq_file *seq, loff_t *pos)  static void *dev_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos)  { -	struct net_device *dev = v;  	++*pos; -	return dev->next; +	return next_net_device((struct net_device *)v);  }  static void dev_mc_seq_stop(struct seq_file *seq, void *v) diff --git a/net/core/flow.c b/net/core/flow.c index 5d25697920b..051430545a0 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -338,7 +338,7 @@ static int flow_cache_cpu(struct notifier_block *nfb,  			  unsigned long action,  			  void *hcpu)  { -	if (action == CPU_DEAD) +	if (action == CPU_DEAD || action == CPU_DEAD_FROZEN)  		__flow_cache_shrink((unsigned long)hcpu, 0);  	return NOTIFY_OK;  } diff --git a/net/core/link_watch.c b/net/core/link_watch.c index e3c26a9ccad..a5e372b9ec4 100644 --- a/net/core/link_watch.c +++ b/net/core/link_watch.c @@ -19,7 +19,6 @@  #include <linux/rtnetlink.h>  #include <linux/jiffies.h>  #include <linux/spinlock.h> -#include <linux/list.h>  #include <linux/slab.h>  #include <linux/workqueue.h>  #include <linux/bitops.h> @@ -27,8 +26,7 @@  enum lw_bits { -	LW_RUNNING = 0, -	LW_SE_USED +	LW_URGENT = 0,  };  static unsigned long linkwatch_flags; @@ -37,17 +35,9 @@ static unsigned long linkwatch_nextevent;  static void linkwatch_event(struct work_struct *dummy);  static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); -static LIST_HEAD(lweventlist); +static struct net_device *lweventlist;  static DEFINE_SPINLOCK(lweventlist_lock); -struct lw_event { -	struct list_head list; -	struct net_device *dev; -}; - -/* Avoid kmalloc() for most systems */ -static struct lw_event singleevent; -  static unsigned char default_operstate(const struct net_device *dev)  {  	if (!netif_carrier_ok(dev)) @@ -87,25 +77,102 @@ static void rfc2863_policy(struct net_device *dev)  } -/* Must be called with the rtnl semaphore held */ -void linkwatch_run_queue(void) +static int linkwatch_urgent_event(struct net_device *dev)  { -	struct list_head head, *n, *next; +	return netif_running(dev) && netif_carrier_ok(dev) && +	       dev->qdisc != dev->qdisc_sleeping; +} + + +static void linkwatch_add_event(struct net_device *dev) +{ +	unsigned long flags; + +	spin_lock_irqsave(&lweventlist_lock, flags); +	dev->link_watch_next = lweventlist; +	lweventlist = dev; +	spin_unlock_irqrestore(&lweventlist_lock, flags); +} + + +static void linkwatch_schedule_work(int urgent) +{ +	unsigned long delay = linkwatch_nextevent - jiffies; + +	if (test_bit(LW_URGENT, &linkwatch_flags)) +		return; + +	/* Minimise down-time: drop delay for up event. */ +	if (urgent) { +		if (test_and_set_bit(LW_URGENT, &linkwatch_flags)) +			return; +		delay = 0; +	} + +	/* If we wrap around we'll delay it by at most HZ. */ +	if (delay > HZ) +		delay = 0; + +	/* +	 * This is true if we've scheduled it immeditately or if we don't +	 * need an immediate execution and it's already pending. +	 */ +	if (schedule_delayed_work(&linkwatch_work, delay) == !delay) +		return; + +	/* Don't bother if there is nothing urgent. */ +	if (!test_bit(LW_URGENT, &linkwatch_flags)) +		return; + +	/* It's already running which is good enough. */ +	if (!cancel_delayed_work(&linkwatch_work)) +		return; + +	/* Otherwise we reschedule it again for immediate exection. */ +	schedule_delayed_work(&linkwatch_work, 0); +} + + +static void __linkwatch_run_queue(int urgent_only) +{ +	struct net_device *next; + +	/* +	 * Limit the number of linkwatch events to one +	 * per second so that a runaway driver does not +	 * cause a storm of messages on the netlink +	 * socket.  This limit does not apply to up events +	 * while the device qdisc is down. +	 */ +	if (!urgent_only) +		linkwatch_nextevent = jiffies + HZ; +	/* Limit wrap-around effect on delay. */ +	else if (time_after(linkwatch_nextevent, jiffies + HZ)) +		linkwatch_nextevent = jiffies; + +	clear_bit(LW_URGENT, &linkwatch_flags);  	spin_lock_irq(&lweventlist_lock); -	list_replace_init(&lweventlist, &head); +	next = lweventlist; +	lweventlist = NULL;  	spin_unlock_irq(&lweventlist_lock); -	list_for_each_safe(n, next, &head) { -		struct lw_event *event = list_entry(n, struct lw_event, list); -		struct net_device *dev = event->dev; +	while (next) { +		struct net_device *dev = next; -		if (event == &singleevent) { -			clear_bit(LW_SE_USED, &linkwatch_flags); -		} else { -			kfree(event); +		next = dev->link_watch_next; + +		if (urgent_only && !linkwatch_urgent_event(dev)) { +			linkwatch_add_event(dev); +			continue;  		} +		/* +		 * Make sure the above read is complete since it can be +		 * rewritten as soon as we clear the bit below. +		 */ +		smp_mb__before_clear_bit(); +  		/* We are about to handle this device,  		 * so new events can be accepted  		 */ @@ -124,58 +191,39 @@ void linkwatch_run_queue(void)  		dev_put(dev);  	} + +	if (lweventlist) +		linkwatch_schedule_work(0);  } -static void linkwatch_event(struct work_struct *dummy) +/* Must be called with the rtnl semaphore held */ +void linkwatch_run_queue(void)  { -	/* Limit the number of linkwatch events to one -	 * per second so that a runaway driver does not -	 * cause a storm of messages on the netlink -	 * socket -	 */ -	linkwatch_nextevent = jiffies + HZ; -	clear_bit(LW_RUNNING, &linkwatch_flags); +	__linkwatch_run_queue(0); +} + +static void linkwatch_event(struct work_struct *dummy) +{  	rtnl_lock(); -	linkwatch_run_queue(); +	__linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies));  	rtnl_unlock();  }  void linkwatch_fire_event(struct net_device *dev)  { -	if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { -		unsigned long flags; -		struct lw_event *event; - -		if (test_and_set_bit(LW_SE_USED, &linkwatch_flags)) { -			event = kmalloc(sizeof(struct lw_event), GFP_ATOMIC); - -			if (unlikely(event == NULL)) { -				clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); -				return; -			} -		} else { -			event = &singleevent; -		} +	int urgent = linkwatch_urgent_event(dev); +	if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {  		dev_hold(dev); -		event->dev = dev; - -		spin_lock_irqsave(&lweventlist_lock, flags); -		list_add_tail(&event->list, &lweventlist); -		spin_unlock_irqrestore(&lweventlist_lock, flags); -		if (!test_and_set_bit(LW_RUNNING, &linkwatch_flags)) { -			unsigned long delay = linkwatch_nextevent - jiffies; +		linkwatch_add_event(dev); +	} else if (!urgent) +		return; -			/* If we wrap around we'll delay it by at most HZ. */ -			if (delay > HZ) -				delay = 0; -			schedule_delayed_work(&linkwatch_work, delay); -		} -	} +	linkwatch_schedule_work(urgent);  }  EXPORT_SYMBOL(linkwatch_fire_event); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index b316435b0e2..758dafe284c 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -9,7 +9,6 @@   * Copyright (C) 2002  Red Hat, Inc.   */ -#include <linux/smp_lock.h>  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/string.h> diff --git a/net/core/pktgen.c b/net/core/pktgen.c index b92a322872a..9cd3a1cb60e 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -117,7 +117,6 @@  #include <linux/module.h>  #include <linux/moduleparam.h>  #include <linux/kernel.h> -#include <linux/smp_lock.h>  #include <linux/mutex.h>  #include <linux/sched.h>  #include <linux/slab.h> diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index cec11110915..8c971a2efe2 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -539,13 +539,16 @@ static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)  	int s_idx = cb->args[0];  	struct net_device *dev; -	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 (rtnl_fill_ifinfo(skb, dev, NULL, 0, RTM_NEWLINK,  				     NETLINK_CB(cb->skb).pid,  				     cb->nlh->nlmsg_seq, 0, NLM_F_MULTI) <= 0)  			break; +cont: +		idx++;  	}  	cb->args[0] = idx;  | 
