From b90662acf3a490418248c6db0572c6f4056deb1c Mon Sep 17 00:00:00 2001 From: Bart De Schuymer Date: Thu, 22 Aug 2002 17:55:31 +0000 Subject: update to 2.4.20-pre4 --- kernel/linux/net/core/dev.c | 435 +++++++++++++++++++------------------------- 1 file changed, 186 insertions(+), 249 deletions(-) (limited to 'kernel/linux/net/core') diff --git a/kernel/linux/net/core/dev.c b/kernel/linux/net/core/dev.c index eb2aeda..405d110 100644 --- a/kernel/linux/net/core/dev.c +++ b/kernel/linux/net/core/dev.c @@ -102,6 +102,7 @@ #include #if defined(CONFIG_NET_RADIO) || defined(CONFIG_NET_PCMCIA_RADIO) #include /* Note : will define WIRELESS_EXT */ +#include #endif /* CONFIG_NET_RADIO || CONFIG_NET_PCMCIA_RADIO */ #ifdef CONFIG_PLIP extern int plip_init(void); @@ -444,7 +445,7 @@ struct net_device *dev_get_by_name(const char *name) /* Return value is changed to int to prevent illegal usage in future. - It is still legal to use to check for device existance. + 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. @@ -797,6 +798,19 @@ int dev_close(struct net_device *dev) clear_bit(__LINK_STATE_START, &dev->state); + /* Synchronize to scheduled poll. We cannot touch poll list, + * it can be even on different cpu. So just clear netif_running(), + * and wait when poll really will happen. Actually, the best place + * for this is inside dev->stop() after device stopped its irq + * engine, but this requires more changes in devices. */ + + smp_mb__after_clear_bit(); /* Commit netif_running(). */ + while (test_bit(__LINK_STATE_RX_SCHED, &dev->state)) { + /* No hurry. */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(1); + } + /* * Call the device specific close. This cannot fail. * Only if device is UP @@ -1071,6 +1085,7 @@ int dev_queue_xmit(struct sk_buff *skb) =======================================================================*/ int netdev_max_backlog = 300; +int weight_p = 64; /* old backlog weight */ /* These numbers are selected based on intuition and some * experimentatiom, if you have more scientific way of doing this * please go ahead and fix things. @@ -1236,13 +1251,11 @@ int netif_rx(struct sk_buff *skb) enqueue: dev_hold(skb->dev); __skb_queue_tail(&queue->input_pkt_queue,skb); - /* Runs from irqs or BH's, no need to wake BH */ - cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); local_irq_restore(flags); #ifndef OFFLINE_SAMPLE get_sample_stats(this_cpu); #endif - return softnet_data[this_cpu].cng_level; + return queue->cng_level; } if (queue->throttle) { @@ -1252,6 +1265,8 @@ enqueue: netdev_wakeup(); #endif } + + netif_rx_schedule(&queue->blog_dev); goto enqueue; } @@ -1307,19 +1322,12 @@ static int deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int return ret; } -/* Reparent skb to master device. This function is called - * only from net_rx_action under BR_NETPROTO_LOCK. It is misuse - * of BR_NETPROTO_LOCK, but it is OK for now. - */ static __inline__ void skb_bond(struct sk_buff *skb) { struct net_device *dev = skb->dev; - - if (dev->master) { - dev_hold(dev->master); + + if (dev->master) skb->dev = dev->master; - dev_put(dev); - } } static void net_tx_action(struct softirq_action *h) @@ -1394,143 +1402,163 @@ static __inline__ int handle_bridge(struct sk_buff *skb, if (pt_prev) { if (!pt_prev->data) - deliver_to_old_ones(pt_prev, skb, 0); + ret = deliver_to_old_ones(pt_prev, skb, 0); else { atomic_inc(&skb->users); - pt_prev->func(skb, skb->dev, pt_prev); + ret = pt_prev->func(skb, skb->dev, pt_prev); } } - ret = br_handle_frame_hook(skb); return ret; } #ifdef CONFIG_NET_DIVERT -static inline void handle_diverter(struct sk_buff *skb) +static inline int handle_diverter(struct sk_buff *skb) { /* if diversion is supported on device, then divert */ if (skb->dev->divert && skb->dev->divert->divert) divert_frame(skb); + return 0; } #endif /* CONFIG_NET_DIVERT */ - -static void net_rx_action(struct softirq_action *h) +int netif_receive_skb(struct sk_buff *skb) { - int this_cpu = smp_processor_id(); - struct softnet_data *queue = &softnet_data[this_cpu]; - unsigned long start_time = jiffies; - int bugdet = netdev_max_backlog; - - br_read_lock(BR_NETPROTO_LOCK); - - for (;;) { - struct sk_buff *skb; - struct net_device *rx_dev; - - local_irq_disable(); - skb = __skb_dequeue(&queue->input_pkt_queue); - local_irq_enable(); + struct packet_type *ptype, *pt_prev; + int ret = NET_RX_DROP; + unsigned short type = skb->protocol; - if (skb == NULL) - break; + if (skb->stamp.tv_sec == 0) + do_gettimeofday(&skb->stamp); - skb_bond(skb); + skb_bond(skb); - rx_dev = skb->dev; + netdev_rx_stat[smp_processor_id()].total++; #ifdef CONFIG_NET_FASTROUTE - if (skb->pkt_type == PACKET_FASTROUTE) { - netdev_rx_stat[this_cpu].fastroute_deferred_out++; - dev_queue_xmit(skb); - dev_put(rx_dev); - continue; - } + if (skb->pkt_type == PACKET_FASTROUTE) { + netdev_rx_stat[smp_processor_id()].fastroute_deferred_out++; + return dev_queue_xmit(skb); + } #endif - skb->h.raw = skb->nh.raw = skb->data; - { - struct packet_type *ptype, *pt_prev; - unsigned short type = skb->protocol; - - pt_prev = NULL; - for (ptype = ptype_all; ptype; ptype = ptype->next) { - if (!ptype->dev || ptype->dev == skb->dev) { - if (pt_prev) { - if (!pt_prev->data) { - deliver_to_old_ones(pt_prev, skb, 0); - } else { - atomic_inc(&skb->users); - pt_prev->func(skb, - skb->dev, - pt_prev); - } - } - pt_prev = ptype; + + skb->h.raw = skb->nh.raw = skb->data; + + pt_prev = NULL; + for (ptype = ptype_all; ptype; ptype = ptype->next) { + if (!ptype->dev || ptype->dev == skb->dev) { + if (pt_prev) { + if (!pt_prev->data) { + ret = deliver_to_old_ones(pt_prev, skb, 0); + } else { + atomic_inc(&skb->users); + ret = pt_prev->func(skb, skb->dev, pt_prev); } } + pt_prev = ptype; + } + } #ifdef CONFIG_NET_DIVERT - if (skb->dev->divert && skb->dev->divert->divert) - handle_diverter(skb); + if (skb->dev->divert && skb->dev->divert->divert) + ret = handle_diverter(skb); #endif /* CONFIG_NET_DIVERT */ - #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) - if (skb->dev->br_port != NULL && - br_handle_frame_hook != NULL) { - if (handle_bridge(skb, pt_prev) == 0) { - dev_put(rx_dev); - continue; - } - } + if (skb->dev->br_port != NULL && + br_handle_frame_hook != NULL) { + int ret; + + ret = handle_bridge(skb, pt_prev); + if (br_handle_frame_hook(skb) == 0) + return ret; + } #endif - for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { - if (ptype->type == type && - (!ptype->dev || ptype->dev == skb->dev)) { - if (pt_prev) { - if (!pt_prev->data) - deliver_to_old_ones(pt_prev, skb, 0); - else { - atomic_inc(&skb->users); - pt_prev->func(skb, - skb->dev, - pt_prev); - } - } - pt_prev = ptype; + for (ptype=ptype_base[ntohs(type)&15];ptype;ptype=ptype->next) { + if (ptype->type == type && + (!ptype->dev || ptype->dev == skb->dev)) { + if (pt_prev) { + if (!pt_prev->data) { + ret = deliver_to_old_ones(pt_prev, skb, 0); + } else { + atomic_inc(&skb->users); + ret = pt_prev->func(skb, skb->dev, pt_prev); } } + pt_prev = ptype; + } + } - if (pt_prev) { - if (!pt_prev->data) - deliver_to_old_ones(pt_prev, skb, 1); - else - pt_prev->func(skb, skb->dev, pt_prev); - } else - kfree_skb(skb); + if (pt_prev) { + if (!pt_prev->data) { + ret = deliver_to_old_ones(pt_prev, skb, 1); + } else { + ret = pt_prev->func(skb, skb->dev, pt_prev); } + } else { + kfree_skb(skb); + /* Jamal, now you will not able to escape explaining + * me how you were going to use this. :-) + */ + ret = NET_RX_DROP; + } - dev_put(rx_dev); + return ret; +} - if (bugdet-- < 0 || jiffies - start_time > 1) - goto softnet_break; +static int process_backlog(struct net_device *blog_dev, int *budget) +{ + int work = 0; + int quota = min(blog_dev->quota, *budget); + int this_cpu = smp_processor_id(); + struct softnet_data *queue = &softnet_data[this_cpu]; + unsigned long start_time = jiffies; + + for (;;) { + struct sk_buff *skb; + struct net_device *dev; + + local_irq_disable(); + skb = __skb_dequeue(&queue->input_pkt_queue); + if (skb == NULL) + goto job_done; + local_irq_enable(); + + dev = skb->dev; + + netif_receive_skb(skb); + + dev_put(dev); + + work++; + + if (work >= quota || jiffies - start_time > 1) + break; #ifdef CONFIG_NET_HW_FLOWCONTROL - if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) { - if (atomic_dec_and_test(&netdev_dropping)) { - queue->throttle = 0; - netdev_wakeup(); - goto softnet_break; + if (queue->throttle && queue->input_pkt_queue.qlen < no_cong_thresh ) { + if (atomic_dec_and_test(&netdev_dropping)) { + queue->throttle = 0; + netdev_wakeup(); + break; + } } - } #endif - } - br_read_unlock(BR_NETPROTO_LOCK); - local_irq_disable(); + blog_dev->quota -= work; + *budget -= work; + return -1; + +job_done: + blog_dev->quota -= work; + *budget -= work; + + list_del(&blog_dev->poll_list); + clear_bit(__LINK_STATE_RX_SCHED, &blog_dev->state); + if (queue->throttle) { queue->throttle = 0; #ifdef CONFIG_NET_HW_FLOWCONTROL @@ -1539,21 +1567,53 @@ static void net_rx_action(struct softirq_action *h) #endif } local_irq_enable(); + return 0; +} - NET_PROFILE_LEAVE(softnet_process); - return; +static void net_rx_action(struct softirq_action *h) +{ + int this_cpu = smp_processor_id(); + struct softnet_data *queue = &softnet_data[this_cpu]; + unsigned long start_time = jiffies; + int budget = netdev_max_backlog; -softnet_break: + br_read_lock(BR_NETPROTO_LOCK); + local_irq_disable(); + + while (!list_empty(&queue->poll_list)) { + struct net_device *dev; + + if (budget <= 0 || jiffies - start_time > 1) + goto softnet_break; + + local_irq_enable(); + + dev = list_entry(queue->poll_list.next, struct net_device, poll_list); + + if (dev->quota <= 0 || dev->poll(dev, &budget)) { + local_irq_disable(); + list_del(&dev->poll_list); + list_add_tail(&dev->poll_list, &queue->poll_list); + if (dev->quota < 0) + dev->quota += dev->weight; + else + dev->quota = dev->weight; + } else { + dev_put(dev); + local_irq_disable(); + } + } + + local_irq_enable(); br_read_unlock(BR_NETPROTO_LOCK); + return; - local_irq_disable(); +softnet_break: netdev_rx_stat[this_cpu].time_squeeze++; - /* This already runs in BH context, no need to wake up BH's */ - cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); - local_irq_enable(); + __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); - NET_PROFILE_LEAVE(softnet_process); - return; + local_irq_enable(); + br_read_unlock(BR_NETPROTO_LOCK); } static gifconf_func_t * gifconf_list [NPROTO]; @@ -1797,122 +1857,6 @@ static int dev_proc_stats(char *buffer, char **start, off_t offset, #endif /* CONFIG_PROC_FS */ -#ifdef WIRELESS_EXT -#ifdef CONFIG_PROC_FS - -/* - * Print one entry of /proc/net/wireless - * This is a clone of /proc/net/dev (just above) - */ -static int sprintf_wireless_stats(char *buffer, struct net_device *dev) -{ - /* Get stats from the driver */ - struct iw_statistics *stats = (dev->get_wireless_stats ? - dev->get_wireless_stats(dev) : - (struct iw_statistics *) NULL); - int size; - - if (stats != (struct iw_statistics *) NULL) { - size = sprintf(buffer, - "%6s: %04x %3d%c %3d%c %3d%c %6d %6d %6d %6d %6d %6d\n", - dev->name, - stats->status, - stats->qual.qual, - stats->qual.updated & 1 ? '.' : ' ', - stats->qual.level, - stats->qual.updated & 2 ? '.' : ' ', - stats->qual.noise, - stats->qual.updated & 4 ? '.' : ' ', - stats->discard.nwid, - stats->discard.code, - stats->discard.fragment, - stats->discard.retries, - stats->discard.misc, - stats->miss.beacon); - stats->qual.updated = 0; - } - else - size = 0; - - return size; -} - -/* - * Print info for /proc/net/wireless (print all entries) - * This is a clone of /proc/net/dev (just above) - */ -static int dev_get_wireless_info(char * buffer, char **start, off_t offset, - int length) -{ - int len = 0; - off_t begin = 0; - off_t pos = 0; - int size; - - struct net_device * dev; - - size = sprintf(buffer, - "Inter-| sta-| Quality | Discarded packets | Missed\n" - " face | tus | link level noise | nwid crypt frag retry misc | beacon\n" - ); - - pos += size; - len += size; - - read_lock(&dev_base_lock); - for (dev = dev_base; dev != NULL; dev = dev->next) { - size = sprintf_wireless_stats(buffer + len, dev); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - break; - } - read_unlock(&dev_base_lock); - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - if (len < 0) - len = 0; - - return len; -} -#endif /* CONFIG_PROC_FS */ - -/* - * Allow programatic access to /proc/net/wireless even if /proc - * doesn't exist... Also more efficient... - */ -static inline int dev_iwstats(struct net_device *dev, struct ifreq *ifr) -{ - /* Get stats from the driver */ - struct iw_statistics *stats = (dev->get_wireless_stats ? - dev->get_wireless_stats(dev) : - (struct iw_statistics *) NULL); - - if (stats != (struct iw_statistics *) NULL) { - struct iwreq * wrq = (struct iwreq *)ifr; - - /* Copy statistics to the user buffer */ - if(copy_to_user(wrq->u.data.pointer, stats, - sizeof(struct iw_statistics))) - return -EFAULT; - - /* Check if we need to clear the update flag */ - if(wrq->u.data.flags != 0) - stats->qual.updated = 0; - return(0); - } else - return -EOPNOTSUPP; -} -#endif /* WIRELESS_EXT */ - /** * netdev_set_master - set up master/slave pair * @slave: slave device @@ -2210,11 +2154,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); return 0; -#ifdef WIRELESS_EXT - case SIOCGIWSTATS: - return dev_iwstats(dev, ifr); -#endif /* WIRELESS_EXT */ - /* * Unknown or private ioctl */ @@ -2240,17 +2179,6 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd) return -EOPNOTSUPP; } -#ifdef WIRELESS_EXT - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - if (dev->do_ioctl) { - if (!netif_device_present(dev)) - return -ENODEV; - return dev->do_ioctl(dev, ifr, cmd); - } - return -EOPNOTSUPP; - } -#endif /* WIRELESS_EXT */ - } return -EINVAL; } @@ -2432,7 +2360,8 @@ int dev_ioctl(unsigned int cmd, void *arg) } dev_load(ifr.ifr_name); rtnl_lock(); - ret = dev_ifsioc(&ifr, cmd); + /* Follow me in net/core/wireless.c */ + ret = wireless_process_ioctl(&ifr, cmd); rtnl_unlock(); if (!ret && IW_IS_GET(cmd) && copy_to_user(arg, &ifr, sizeof(struct ifreq))) @@ -2738,6 +2667,7 @@ int unregister_netdevice(struct net_device *dev) extern void net_device_init(void); extern void ip_auto_config(void); +struct proc_dir_entry *proc_net_drivers; #ifdef CONFIG_NET_DIVERT extern void dv_init(void); #endif /* CONFIG_NET_DIVERT */ @@ -2755,6 +2685,7 @@ int __init net_dev_init(void) if (!dev_boot_phase) return 0; + #ifdef CONFIG_NET_DIVERT dv_init(); #endif /* CONFIG_NET_DIVERT */ @@ -2772,8 +2703,13 @@ int __init net_dev_init(void) queue->cng_level = 0; queue->avg_blog = 10; /* arbitrary non-zero */ queue->completion_queue = NULL; + INIT_LIST_HEAD(&queue->poll_list); + set_bit(__LINK_STATE_START, &queue->blog_dev.state); + queue->blog_dev.weight = weight_p; + queue->blog_dev.poll = process_backlog; + atomic_set(&queue->blog_dev.refcnt, 1); } - + #ifdef CONFIG_NET_PROFILE net_profile_init(); NET_PROFILE_REGISTER(dev_queue_xmit); @@ -2856,7 +2792,9 @@ int __init net_dev_init(void) #ifdef CONFIG_PROC_FS proc_net_create("dev", 0, dev_get_info); create_proc_read_entry("net/softnet_stat", 0, 0, dev_proc_stats, NULL); + proc_net_drivers = proc_mkdir("net/drivers", 0); #ifdef WIRELESS_EXT + /* Available in net/core/wireless.c */ proc_net_create("wireless", 0, dev_get_wireless_info); #endif /* WIRELESS_EXT */ #endif /* CONFIG_PROC_FS */ @@ -2872,7 +2810,6 @@ int __init net_dev_init(void) #ifdef CONFIG_NET_SCHED pktsched_init(); #endif - /* * Initialise network devices */ -- cgit v1.2.3