X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fcore%2Fdev.c;h=9ac8c41ea1c68a3f1b857e436839d44440ae369d;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=65b3541fc2f35bec93cdb056a975702f0898df45;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/core/dev.c b/net/core/dev.c index 65b3541fc..9ac8c41ea 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -74,7 +74,7 @@ #include #include -#include +#include #include #include #include @@ -108,13 +108,13 @@ #include #include #include +#include #ifdef CONFIG_NET_RADIO #include /* Note : will define WIRELESS_EXT */ #include #endif /* CONFIG_NET_RADIO */ -#include -#include #include +#include /* This define, if set, will randomly drop a packet when congestion * is more than moderate. It helps fairness in the multi-interface @@ -156,7 +156,7 @@ * 86DD IPv6 */ -static spinlock_t ptype_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(ptype_lock); static struct list_head ptype_base[16]; /* 16 way hashed list */ static struct list_head ptype_all; /* Taps */ @@ -185,8 +185,8 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0); * semaphore held. */ struct net_device *dev_base; -struct net_device **dev_tail = &dev_base; -rwlock_t dev_base_lock = RW_LOCK_UNLOCKED; +static struct net_device **dev_tail = &dev_base; +DEFINE_RWLOCK(dev_base_lock); EXPORT_SYMBOL(dev_base); EXPORT_SYMBOL(dev_base_lock); @@ -363,7 +363,7 @@ static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; * returns 0 on error and 1 on success. This is a generic routine to * all netdevices. */ -int netdev_boot_setup_add(char *name, struct ifmap *map) +static int netdev_boot_setup_add(char *name, struct ifmap *map) { struct netdev_boot_setup *s; int i; @@ -522,35 +522,6 @@ struct net_device *dev_get_by_name(const char *name) return dev; } -/* - Return value is changed to int to prevent illegal usage in future. - It is still legal to use to check for device existence. - - User should understand, that the result returned by this function - is meaningless, if it was not issued under rtnl semaphore. - */ - -/** - * dev_get - test if a device exists - * @name: name to test for - * - * Test if a name exists. Returns true if the name is found. In order - * to be sure the name is not allocated or removed during the test the - * caller must hold the rtnl semaphore. - * - * This function exists only for back compatibility with older - * drivers. - */ -int __dev_get(const char *name) -{ - struct net_device *dev; - - read_lock(&dev_base_lock); - dev = __dev_get_by_name(name); - read_unlock(&dev_base_lock); - return dev != NULL; -} - /** * __dev_get_by_index - find a device by its ifindex * @ifindex: index of device @@ -625,26 +596,17 @@ struct net_device *dev_getbyhwaddr(unsigned short type, char *ha) return dev; } -struct net_device *__dev_getfirstbyhwtype(unsigned short type) -{ - struct net_device *dev; - - for (dev = dev_base; dev; dev = dev->next) - if (dev->type == type) - break; - return dev; -} - -EXPORT_SYMBOL(__dev_getfirstbyhwtype); - struct net_device *dev_getfirstbyhwtype(unsigned short type) { struct net_device *dev; rtnl_lock(); - dev = __dev_getfirstbyhwtype(type); - if (dev) - dev_hold(dev); + for (dev = dev_base; dev; dev = dev->next) { + if (dev->type == type) { + dev_hold(dev); + break; + } + } rtnl_unlock(); return dev; } @@ -667,32 +629,14 @@ struct net_device * dev_get_by_flags(unsigned short if_flags, unsigned short mas struct net_device *dev; read_lock(&dev_base_lock); - dev = __dev_get_by_flags(if_flags, mask); - if (dev) - dev_hold(dev); - read_unlock(&dev_base_lock); - return dev; -} - -/** - * __dev_get_by_flags - find any device with given flags - * @if_flags: IFF_* values - * @mask: bitmask of bits in if_flags to check - * - * Search for any interface with the given flags. Returns NULL if a device - * is not found or a pointer to the device. The caller must hold either - * the RTNL semaphore or @dev_base_lock. - */ - -struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short mask) -{ - struct net_device *dev; - for (dev = dev_base; dev != NULL; dev = dev->next) { - if (((dev->flags ^ if_flags) & mask) == 0) - return dev; + if (((dev->flags ^ if_flags) & mask) == 0) { + dev_hold(dev); + break; + } } - return NULL; + read_unlock(&dev_base_lock); + return dev; } /** @@ -702,7 +646,7 @@ struct net_device *__dev_get_by_flags(unsigned short if_flags, unsigned short ma * Network device names need to be valid file names to * to allow sysfs to work */ -int dev_valid_name(const char *name) +static int dev_valid_name(const char *name) { return !(*name == '\0' || !strcmp(name, ".") @@ -1059,6 +1003,29 @@ int call_netdevice_notifiers(unsigned long val, void *v) return notifier_call_chain(&netdev_chain, val, v); } +/* When > 0 there are consumers of rx skb time stamps */ +static atomic_t netstamp_needed = ATOMIC_INIT(0); + +void net_enable_timestamp(void) +{ + atomic_inc(&netstamp_needed); +} + +void net_disable_timestamp(void) +{ + atomic_dec(&netstamp_needed); +} + +static inline void net_timestamp(struct timeval *stamp) +{ + if (atomic_read(&netstamp_needed)) + do_gettimeofday(stamp); + else { + stamp->tv_sec = 0; + stamp->tv_usec = 0; + } +} + /* * Support routine. Sends outgoing frames to any network * taps currently in use. @@ -1108,34 +1075,34 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) * Invalidate hardware checksum when packet is to be mangled, and * complete checksum manually on outgoing path. */ -int skb_checksum_help(struct sk_buff **pskb, int inward) +int skb_checksum_help(struct sk_buff *skb, int inward) { unsigned int csum; - int ret = 0, offset = (*pskb)->h.raw - (*pskb)->data; + int ret = 0, offset = skb->h.raw - skb->data; if (inward) { - (*pskb)->ip_summed = CHECKSUM_NONE; + skb->ip_summed = CHECKSUM_NONE; goto out; } - if (skb_cloned(*pskb)) { - ret = pskb_expand_head(*pskb, 0, 0, GFP_ATOMIC); + if (skb_cloned(skb)) { + ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); if (ret) goto out; } - if (offset > (int)(*pskb)->len) + if (offset > (int)skb->len) BUG(); - csum = skb_checksum(*pskb, offset, (*pskb)->len-offset, 0); + csum = skb_checksum(skb, offset, skb->len-offset, 0); - offset = (*pskb)->tail - (*pskb)->h.raw; + offset = skb->tail - skb->h.raw; if (offset <= 0) BUG(); - if ((*pskb)->csum + 2 > offset) + if (skb->csum + 2 > offset) BUG(); - *(u16*)((*pskb)->h.raw + (*pskb)->csum) = csum_fold(csum); - (*pskb)->ip_summed = CHECKSUM_NONE; + *(u16*)(skb->h.raw + skb->csum) = csum_fold(csum); + skb->ip_summed = CHECKSUM_NONE; out: return ret; } @@ -1154,7 +1121,7 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb) return 0; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - if (skb_shinfo(skb)->frags[i].page >= highmem_start_page) + if (PageHighMem(skb_shinfo(skb)->frags[i].page)) return 1; return 0; @@ -1237,13 +1204,6 @@ int __skb_linearize(struct sk_buff *skb, int gfp_mask) } \ } -static inline void qdisc_run(struct net_device *dev) -{ - while (!netif_queue_stopped(dev) && - qdisc_restart(dev)<0) - /* NOTHING */; -} - /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -1284,10 +1244,9 @@ int dev_queue_xmit(struct sk_buff *skb) (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) && (!(dev->features & NETIF_F_IP_CSUM) || skb->protocol != htons(ETH_P_IP)))) - if (skb_checksum_help(&skb, 0)) + if (skb_checksum_help(skb, 0)) goto out_kfree_skb; - /* Disable soft irqs for various locks below. Also * stops preemption for RCU. */ @@ -1355,7 +1314,6 @@ int dev_queue_xmit(struct sk_buff *skb) if (net_ratelimit()) printk(KERN_CRIT "Virtual device %s asks to " "queue packet!\n", dev->name); - goto out_enetdown; } else { /* Recursion is detected! It is possible, * unfortunately */ @@ -1364,10 +1322,13 @@ int dev_queue_xmit(struct sk_buff *skb) "%s, fix it urgently!\n", dev->name); } } -out_enetdown: + rc = -ENETDOWN; + local_bh_enable(); + out_kfree_skb: kfree_skb(skb); + return rc; out: local_bh_enable(); return rc; @@ -1392,66 +1353,6 @@ int mod_cong = 290; DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, }; -#ifdef CONFIG_NET_HW_FLOWCONTROL -atomic_t netdev_dropping = ATOMIC_INIT(0); -static unsigned long netdev_fc_mask = 1; -unsigned long netdev_fc_xoff; -spinlock_t netdev_fc_lock = SPIN_LOCK_UNLOCKED; - -static struct -{ - void (*stimul)(struct net_device *); - struct net_device *dev; -} netdev_fc_slots[BITS_PER_LONG]; - -int netdev_register_fc(struct net_device *dev, - void (*stimul)(struct net_device *dev)) -{ - int bit = 0; - unsigned long flags; - - spin_lock_irqsave(&netdev_fc_lock, flags); - if (netdev_fc_mask != ~0UL) { - bit = ffz(netdev_fc_mask); - netdev_fc_slots[bit].stimul = stimul; - netdev_fc_slots[bit].dev = dev; - set_bit(bit, &netdev_fc_mask); - clear_bit(bit, &netdev_fc_xoff); - } - spin_unlock_irqrestore(&netdev_fc_lock, flags); - return bit; -} - -void netdev_unregister_fc(int bit) -{ - unsigned long flags; - - spin_lock_irqsave(&netdev_fc_lock, flags); - if (bit > 0) { - netdev_fc_slots[bit].stimul = NULL; - netdev_fc_slots[bit].dev = NULL; - clear_bit(bit, &netdev_fc_mask); - clear_bit(bit, &netdev_fc_xoff); - } - spin_unlock_irqrestore(&netdev_fc_lock, flags); -} - -static void netdev_wakeup(void) -{ - unsigned long xoff; - - spin_lock(&netdev_fc_lock); - xoff = netdev_fc_xoff; - netdev_fc_xoff = 0; - while (xoff) { - int i = ffz(~xoff); - xoff &= ~(1 << i); - netdev_fc_slots[i].stimul(netdev_fc_slots[i].dev); - } - spin_unlock(&netdev_fc_lock); -} -#endif - static void get_sample_stats(int cpu) { #ifdef RAND_LIE @@ -1561,13 +1462,8 @@ enqueue: return queue->cng_level; } - if (queue->throttle) { + if (queue->throttle) queue->throttle = 0; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (atomic_dec_and_test(&netdev_dropping)) - netdev_wakeup(); -#endif - } netif_rx_schedule(&queue->backlog_dev); goto enqueue; @@ -1576,9 +1472,6 @@ enqueue: if (!queue->throttle) { queue->throttle = 1; __get_cpu_var(netdev_rx_stat).throttled++; -#ifdef CONFIG_NET_HW_FLOWCONTROL - atomic_inc(&netdev_dropping); -#endif } drop: @@ -1589,6 +1482,21 @@ drop: return NET_RX_DROP; } +int netif_rx_ni(struct sk_buff *skb) +{ + int err; + + preempt_disable(); + err = netif_rx(skb); + if (local_softirq_pending()) + do_softirq(); + preempt_enable(); + + return err; +} + +EXPORT_SYMBOL(netif_rx_ni); + static __inline__ void skb_bond(struct sk_buff *skb) { struct net_device *dev = skb->dev; @@ -1684,7 +1592,7 @@ static __inline__ int handle_bridge(struct sk_buff **pskb, * the ingress scheduler, you just cant add policies on ingress. * */ -int ing_filter(struct sk_buff *skb) +static int ing_filter(struct sk_buff *skb) { struct Qdisc *q; struct net_device *dev = skb->dev; @@ -1835,16 +1743,6 @@ static int process_backlog(struct net_device *backlog_dev, int *budget) if (work >= quota || jiffies - start_time > 1) break; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (queue->throttle && - queue->input_pkt_queue.qlen < no_cong_thresh ) { - queue->throttle = 0; - if (atomic_dec_and_test(&netdev_dropping)) { - netdev_wakeup(); - break; - } - } -#endif } backlog_dev->quota -= work; @@ -1859,13 +1757,8 @@ job_done: smp_mb__before_clear_bit(); netif_poll_enable(backlog_dev); - if (queue->throttle) { + if (queue->throttle) queue->throttle = 0; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (atomic_dec_and_test(&netdev_dropping)) - netdev_wakeup(); -#endif - } local_irq_enable(); return 0; } @@ -2452,8 +2345,11 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return dev_set_mtu(dev, ifr->ifr_mtu); case SIOCGIFHWADDR: - memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, - min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); + if (!dev->addr_len) + memset(ifr->ifr_hwaddr.sa_data, 0, sizeof ifr->ifr_hwaddr.sa_data); + else + memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, + min(sizeof ifr->ifr_hwaddr.sa_data, (size_t) dev->addr_len)); ifr->ifr_hwaddr.sa_family = dev->type; return 0; @@ -2754,7 +2650,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) /* Follow me in net/core/wireless.c */ ret = wireless_process_ioctl(&ifr, cmd); rtnl_unlock(); - if (!ret && IW_IS_GET(cmd) && + if (IW_IS_GET(cmd) && copy_to_user(arg, &ifr, sizeof(struct ifreq))) ret = -EFAULT; @@ -2773,7 +2669,7 @@ int dev_ioctl(unsigned int cmd, void __user *arg) * number. The caller must hold the rtnl semaphore or the * dev_base_lock to be sure it remains unique. */ -int dev_new_index(void) +static int dev_new_index(void) { static int ifindex; for (;;) { @@ -2787,7 +2683,7 @@ int dev_new_index(void) static int dev_boot_phase = 1; /* Delayed registration/unregisteration */ -static spinlock_t net_todo_list_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(net_todo_list_lock); static struct list_head net_todo_list = LIST_HEAD_INIT(net_todo_list); static inline void net_set_todo(struct net_device *dev) @@ -2806,8 +2702,7 @@ static inline void net_set_todo(struct net_device *dev) * chain. 0 is returned on success. A negative errno code is returned * on a failure to set up the device, or if the name is a duplicate. * - * Callers must hold the rtnl semaphore. See the comment at the - * end of Space.c for details about the locking. You may want + * Callers must hold the rtnl semaphore. You may want * register_netdev() instead of this. * * BUGS: @@ -2880,6 +2775,14 @@ int register_netdevice(struct net_device *dev) dev->features &= ~NETIF_F_SG; } + /* TSO requires that SG is present as well. */ + if ((dev->features & NETIF_F_TSO) && + !(dev->features & NETIF_F_SG)) { + printk("%s: Dropping NETIF_F_TSO since no SG feature.\n", + dev->name); + dev->features &= ~NETIF_F_TSO; + } + /* * nil rebuild_header routine, * that should be never called and used as just bug trap. @@ -2920,6 +2823,51 @@ out_err: goto out; } +/** + * register_netdev - register a network device + * @dev: device to register + * + * Take a completed network device structure and add it to the kernel + * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier + * chain. 0 is returned on success. A negative errno code is returned + * on a failure to set up the device, or if the name is a duplicate. + * + * This is a wrapper around register_netdev that takes the rtnl semaphore + * and expands the device name if you passed a format string to + * alloc_netdev. + */ +int register_netdev(struct net_device *dev) +{ + int err; + + rtnl_lock(); + + /* + * If the name is a format string the caller wants us to do a + * name allocation. + */ + if (strchr(dev->name, '%')) { + err = dev_alloc_name(dev, dev->name); + if (err < 0) + goto out; + } + + /* + * Back compatibility hook. Kill this one in 2.5 + */ + if (dev->name[0] == 0 || dev->name[0] == ' ') { + err = dev_alloc_name(dev, "eth%d"); + if (err < 0) + goto out; + } + + err = register_netdevice(dev); +out: + rtnl_unlock(); + return err; +} +EXPORT_SYMBOL(register_netdev); + /* * netdev_wait_allrefs - wait until all references are gone. * @@ -2960,8 +2908,7 @@ static void netdev_wait_allrefs(struct net_device *dev) rebroadcast_time = jiffies; } - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ / 4); + msleep(250); if (time_after(jiffies, warning_time + 10 * HZ)) { printk(KERN_EMERG "unregister_netdevice: " @@ -3062,6 +3009,46 @@ out: up(&net_todo_run_mutex); } +/** + * alloc_netdev - allocate network device + * @sizeof_priv: size of private data to allocate space for + * @name: device name format string + * @setup: callback to initialize device + * + * Allocates a struct net_device with private data area for driver use + * and performs basic initialization. + */ +struct net_device *alloc_netdev(int sizeof_priv, const char *name, + void (*setup)(struct net_device *)) +{ + void *p; + struct net_device *dev; + int alloc_size; + + /* ensure 32-byte alignment of both the device and private area */ + alloc_size = (sizeof(*dev) + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST; + alloc_size += sizeof_priv + NETDEV_ALIGN_CONST; + + p = kmalloc(alloc_size, GFP_KERNEL); + if (!p) { + printk(KERN_ERR "alloc_dev: Unable to allocate device.\n"); + return NULL; + } + memset(p, 0, alloc_size); + + dev = (struct net_device *) + (((long)p + NETDEV_ALIGN_CONST) & ~NETDEV_ALIGN_CONST); + dev->padded = (char *)dev - (char *)p; + + if (sizeof_priv) + dev->priv = netdev_priv(dev); + + setup(dev); + strcpy(dev->name, name); + return dev; +} +EXPORT_SYMBOL(alloc_netdev); + /** * free_netdev - free network device * @dev: device @@ -3104,8 +3091,7 @@ void synchronize_net(void) * from the kernel tables. On success 0 is returned, on a failure * a negative errno code is returned. * - * Callers must hold the rtnl semaphore. See the comment at the - * end of Space.c for details about the locking. You may want + * Callers must hold the rtnl semaphore. You may want * unregister_netdev() instead of this. */ @@ -3183,6 +3169,27 @@ int unregister_netdevice(struct net_device *dev) return 0; } +/** + * unregister_netdev - remove device from the kernel + * @dev: device + * + * This function shuts down a device interface and removes it + * from the kernel tables. On success 0 is returned, on a failure + * a negative errno code is returned. + * + * This is just a wrapper for unregister_netdevice that takes + * the rtnl semaphore. In general you want to use this and not + * unregister_netdevice. + */ +void unregister_netdev(struct net_device *dev) +{ + rtnl_lock(); + unregister_netdevice(dev); + rtnl_unlock(); +} + +EXPORT_SYMBOL(unregister_netdev); + #ifdef CONFIG_HOTPLUG_CPU static int dev_cpu_callback(struct notifier_block *nfb, unsigned long action, @@ -3305,30 +3312,23 @@ out: subsys_initcall(net_dev_init); -EXPORT_SYMBOL(__dev_get); -EXPORT_SYMBOL(__dev_get_by_flags); EXPORT_SYMBOL(__dev_get_by_index); EXPORT_SYMBOL(__dev_get_by_name); EXPORT_SYMBOL(__dev_remove_pack); EXPORT_SYMBOL(__skb_linearize); -EXPORT_SYMBOL(call_netdevice_notifiers); EXPORT_SYMBOL(dev_add_pack); EXPORT_SYMBOL(dev_alloc_name); EXPORT_SYMBOL(dev_close); EXPORT_SYMBOL(dev_get_by_flags); EXPORT_SYMBOL(dev_get_by_index); EXPORT_SYMBOL(dev_get_by_name); -EXPORT_SYMBOL(dev_getbyhwaddr); EXPORT_SYMBOL(dev_ioctl); -EXPORT_SYMBOL(dev_new_index); EXPORT_SYMBOL(dev_open); EXPORT_SYMBOL(dev_queue_xmit); -EXPORT_SYMBOL(dev_queue_xmit_nit); EXPORT_SYMBOL(dev_remove_pack); EXPORT_SYMBOL(dev_set_allmulti); EXPORT_SYMBOL(dev_set_promiscuity); EXPORT_SYMBOL(dev_change_flags); -EXPORT_SYMBOL(dev_change_name); EXPORT_SYMBOL(dev_set_mtu); EXPORT_SYMBOL(free_netdev); EXPORT_SYMBOL(netdev_boot_setup_check); @@ -3343,6 +3343,8 @@ EXPORT_SYMBOL(skb_checksum_help); EXPORT_SYMBOL(synchronize_net); EXPORT_SYMBOL(unregister_netdevice); EXPORT_SYMBOL(unregister_netdevice_notifier); +EXPORT_SYMBOL(net_enable_timestamp); +EXPORT_SYMBOL(net_disable_timestamp); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) EXPORT_SYMBOL(br_handle_frame_hook); @@ -3351,16 +3353,5 @@ EXPORT_SYMBOL(br_handle_frame_hook); #ifdef CONFIG_KMOD EXPORT_SYMBOL(dev_load); #endif -#ifdef CONFIG_NET_HW_FLOWCONTROL -EXPORT_SYMBOL(netdev_dropping); -EXPORT_SYMBOL(netdev_fc_xoff); -EXPORT_SYMBOL(netdev_register_fc); -EXPORT_SYMBOL(netdev_unregister_fc); -#endif - -#ifdef CONFIG_NET_CLS_ACT -EXPORT_SYMBOL(ing_filter); -#endif - EXPORT_PER_CPU_SYMBOL(softnet_data);