# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet 1.488 -> 1.489 # drivers/video/neofb.c 1.12 -> 1.13 # net/core/dev.c 1.32 -> 1.34 # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 02/06/09 dent@xxxxxxxxxxxxxxxx 1.489 # Merge air.metanode.org:/mnt/.data/data/bk/linux-2.5 # into air.metanode.org:/mnt/.data/data/bk/linux-patch-net_cleanup # -------------------------------------------- # diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Sun Jun 9 23:03:33 2002 +++ b/net/core/dev.c Sun Jun 9 23:03:33 2002 @@ -108,11 +108,65 @@ #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); #endif +#define SUPPORT_2_2_PROTO 1 + +#if SUPPORT_2_2_PROTO +/* + * Deliver skb to an old protocol, which is not threaded well + * or which do not understand shared skbs. + */ +static int _deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int last) +{ + static spinlock_t net_bh_lock = SPIN_LOCK_UNLOCKED; + int ret = NET_RX_DROP; + + if (!last) { + skb = skb_clone(skb, GFP_ATOMIC); + if (!skb) + return ret; + } + if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { + kfree_skb(skb); + return ret; + } + + /* The assumption (correct one) is that old protocols + did not depened on BHs different of NET_BH and TIMER_BH. + */ + + /* Emulate NET_BH with special spinlock */ + spin_lock(&net_bh_lock); + + /* Disable timers and wait for all timers completion */ + tasklet_disable(bh_task_vec + TIMER_BH); + + ret = pt->func(skb, skb->dev, pt); + + tasklet_hi_enable(bh_task_vec + TIMER_BH); + spin_unlock(&net_bh_lock); + + return ret; +} +#endif + +static inline int _deliver_to_proto(struct sk_buff *skb, struct packet_type *pt, int is_last) +{ +#if SUPPORT_2_2_PROTO + if (!pt->data) { + return _deliver_to_old_ones(pt, skb, is_last); + } else { +#endif + if (!is_last) + skb = skb_get(skb); + return pt->func(skb, skb->dev, pt); +#if SUPPORT_2_2_PROTO + } +#endif + + return 0; +} /* This define, if set, will randomly drop a packet when congestion * is more than moderate. It helps fairness in the multi-interface @@ -130,13 +184,13 @@ NET_PROFILE_DEFINE(softnet_process) const char *if_port_text[] = { - "unknown", - "BNC", - "10baseT", - "AUI", - "100baseT", - "100baseTX", - "100baseFX" + "unknown", + "BNC", + "10baseT", + "AUI", + "100baseT", + "100baseTX", + "100baseFX" }; /* @@ -178,7 +232,7 @@ #ifdef CONFIG_HOTPLUG static int net_run_sbin_hotplug(struct net_device *dev, char *action); #else -#define net_run_sbin_hotplug(dev, action) ({ 0; }) +#define net_run_sbin_hotplug(dev, action) (0) #endif /* @@ -293,7 +347,7 @@ goto out; } } - printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt); + printk(KERN_WARNING "%p not found.\n", pt); out: br_write_unlock_bh(BR_NETPROTO_LOCK); } @@ -655,8 +709,8 @@ static int default_rebuild_header(struct sk_buff *skb) { - printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n", - skb->dev ? skb->dev->name : "NULL!!!"); + printk(KERN_WARNING "%s: called for device %s -- BUG!\n", + __func__, skb->dev ? skb->dev->name : "NULL!!!"); kfree_skb(skb); return 1; } @@ -902,9 +956,10 @@ if (skb2->nh.raw < skb2->data || skb2->nh.raw > skb2->tail) { if (net_ratelimit()) - printk(KERN_DEBUG "protocol %04x is " - "buggy, dev %s\n", - skb2->protocol, dev->name); + printk(KERN_DEBUG "%s: protocol %04x " + "is buggy, dev %s\n", + __func__, skb2->protocol, + dev->name); skb2->nh.raw = skb2->data; } @@ -1033,7 +1088,7 @@ Either shot noqueue qdisc, it is even simpler 8) */ if (dev->flags & IFF_UP) { - int cpu = smp_processor_id(); + uint cpu = smp_processor_id(); if (dev->xmit_lock_owner != cpu) { /* @@ -1060,15 +1115,17 @@ dev->xmit_lock_owner = -1; spin_unlock_bh(&dev->xmit_lock); if (net_ratelimit()) - printk(KERN_DEBUG "Virtual device %s asks to " - "queue packet!\n", dev->name); + printk(KERN_DEBUG "%s: Virtual device %s asks " + "to queue packet!\n", + __func__, dev->name); goto out_enetdown; } else { /* Recursion is detected! It is possible, * unfortunately */ if (net_ratelimit()) - printk(KERN_DEBUG "Dead loop on virtual device " - "%s, fix it urgently!\n", dev->name); + printk(KERN_DEBUG "%s: Dead loop on virtual " + "device %s, fix it urgently!\n", + __func__, dev->name); } } spin_unlock_bh(&dev->queue_lock); @@ -1159,48 +1216,48 @@ } #endif -static void get_sample_stats(int cpu) +static void get_sample_stats(uint cpu) { + struct softnet_data *queue = &softnet_data[cpu]; #ifdef RAND_LIE unsigned long rd; int rq; #endif - int blog = softnet_data[cpu].input_pkt_queue.qlen; - int avg_blog = softnet_data[cpu].avg_blog; + int blog = queue->input_pkt_queue.qlen; + int avg_blog = queue->avg_blog; avg_blog = (avg_blog >> 1) + (blog >> 1); if (avg_blog > mod_cong) { /* Above moderate congestion levels. */ - softnet_data[cpu].cng_level = NET_RX_CN_HIGH; + queue->cng_level = NET_RX_CN_HIGH; #ifdef RAND_LIE rd = net_random(); rq = rd % netdev_max_backlog; if (rq < avg_blog) /* unlucky bastard */ - softnet_data[cpu].cng_level = NET_RX_DROP; + queue->cng_level = NET_RX_DROP; #endif } else if (avg_blog > lo_cong) { - softnet_data[cpu].cng_level = NET_RX_CN_MOD; + queue->cng_level = NET_RX_CN_MOD; #ifdef RAND_LIE rd = net_random(); rq = rd % netdev_max_backlog; if (rq < avg_blog) /* unlucky bastard */ - softnet_data[cpu].cng_level = NET_RX_CN_HIGH; + queue->cng_level = NET_RX_CN_HIGH; #endif } else if (avg_blog > no_cong) - softnet_data[cpu].cng_level = NET_RX_CN_LOW; + queue->cng_level = NET_RX_CN_LOW; else /* no congestion */ - softnet_data[cpu].cng_level = NET_RX_SUCCESS; + queue->cng_level = NET_RX_SUCCESS; - softnet_data[cpu].avg_blog = avg_blog; + queue->avg_blog = avg_blog; } #ifdef OFFLINE_SAMPLE static void sample_queue(unsigned long dummy) { -/* 10 ms 0r 1ms -- i dont care -- JHS */ - int next_tick = 1; - int cpu = smp_processor_id(); + uint cpu = smp_processor_id(); + int next_tick = 1; /* 10 ms 0r 1ms -- i dont care -- JHS */ get_sample_stats(cpu); next_tick += jiffies; @@ -1208,6 +1265,28 @@ } #endif +static inline void _queue_unthrottle(struct softnet_data *queue) +{ + if (queue->throttle) { + queue->throttle = 0; +#ifdef CONFIG_NET_HW_FLOWCONTROL + if (atomic_dec_and_test(&netdev_dropping)) + netdev_wakeup(); +#endif + } +} + +static inline void _queue_throttle(struct softnet_data *queue) +{ + if (!queue->throttle) { + queue->throttle = 1; + netdev_rx_stat[smp_processor_id()].throttled++; +#ifdef CONFIG_NET_HW_FLOWCONTROL + atomic_inc(&netdev_dropping); +#endif + } +} + /** * netif_rx - post buffer to the network code @@ -1229,101 +1308,51 @@ int netif_rx(struct sk_buff *skb) { - int this_cpu = smp_processor_id(); - struct softnet_data *queue; + uint cpu = smp_processor_id(); + struct softnet_data *queue = &softnet_data[cpu]; + struct netif_rx_stats *stats = &netdev_rx_stat[cpu]; unsigned long flags; if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); - /* The code is rearranged so that the path is the most - short when CPU is congested, but is still operating. - */ - queue = &softnet_data[this_cpu]; - local_irq_save(flags); - netdev_rx_stat[this_cpu].total++; + /* + * changed the optimized code with the goto instruction, + * back to the normalized version. gcc3 will generate + * the same output for both cases. -tm + */ + stats->total++; if (queue->input_pkt_queue.qlen <= netdev_max_backlog) { - if (queue->input_pkt_queue.qlen) { + if (likely(queue->input_pkt_queue.qlen)) { if (queue->throttle) goto drop; - -enqueue: - dev_hold(skb->dev); - __skb_queue_tail(&queue->input_pkt_queue, skb); - local_irq_restore(flags); -#ifndef OFFLINE_SAMPLE - get_sample_stats(this_cpu); -#endif - return queue->cng_level; + } else { + _queue_unthrottle(queue); + netif_rx_schedule(&queue->backlog_dev); } - if (queue->throttle) { - queue->throttle = 0; -#ifdef CONFIG_NET_HW_FLOWCONTROL - if (atomic_dec_and_test(&netdev_dropping)) - netdev_wakeup(); + dev_hold(skb->dev); + __skb_queue_tail(&queue->input_pkt_queue, skb); + local_irq_restore(flags); +#ifndef OFFLINE_SAMPLE + get_sample_stats(cpu); #endif - } - netif_rx_schedule(&queue->backlog_dev); - goto enqueue; + return queue->cng_level; } - if (!queue->throttle) { - queue->throttle = 1; - netdev_rx_stat[this_cpu].throttled++; -#ifdef CONFIG_NET_HW_FLOWCONTROL - atomic_inc(&netdev_dropping); -#endif - } + _queue_throttle(queue); drop: - netdev_rx_stat[this_cpu].dropped++; + stats->dropped++; local_irq_restore(flags); kfree_skb(skb); return NET_RX_DROP; } -/* Deliver skb to an old protocol, which is not threaded well - or which do not understand shared skbs. - */ -static int deliver_to_old_ones(struct packet_type *pt, - struct sk_buff *skb, int last) -{ - static spinlock_t net_bh_lock = SPIN_LOCK_UNLOCKED; - int ret = NET_RX_DROP; - - if (!last) { - skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) - goto out; - } - if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC)) - goto out_kfree; - - /* The assumption (correct one) is that old protocols - did not depened on BHs different of NET_BH and TIMER_BH. - */ - - /* Emulate NET_BH with special spinlock */ - spin_lock(&net_bh_lock); - - /* Disable timers and wait for all timers completion */ - tasklet_disable(bh_task_vec+TIMER_BH); - - ret = pt->func(skb, skb->dev, pt); - - tasklet_hi_enable(bh_task_vec+TIMER_BH); - spin_unlock(&net_bh_lock); -out: - return ret; -out_kfree: - kfree_skb(skb); - goto out; -} static __inline__ void skb_bond(struct sk_buff *skb) { @@ -1335,14 +1364,14 @@ static void net_tx_action(struct softirq_action *h) { - int cpu = smp_processor_id(); + struct softnet_data *queue = &softnet_data[smp_processor_id()]; - if (softnet_data[cpu].completion_queue) { + if (queue->completion_queue) { struct sk_buff *clist; local_irq_disable(); - clist = softnet_data[cpu].completion_queue; - softnet_data[cpu].completion_queue = NULL; + clist = queue->completion_queue; + queue->completion_queue = NULL; local_irq_enable(); while (clist) { @@ -1354,12 +1383,12 @@ } } - if (softnet_data[cpu].output_queue) { + if (queue->output_queue) { struct net_device *head; local_irq_disable(); - head = softnet_data[cpu].output_queue; - softnet_data[cpu].output_queue = NULL; + head = queue->output_queue; + queue->output_queue = NULL; local_irq_enable(); while (head) { @@ -1397,40 +1426,12 @@ void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL; #endif -static __inline__ int handle_bridge(struct sk_buff *skb, - struct packet_type *pt_prev) -{ - int ret = NET_RX_DROP; - - 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); - } - } - - br_handle_frame_hook(skb); - return ret; -} - - -#ifdef CONFIG_NET_DIVERT -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 */ - int netif_receive_skb(struct sk_buff *skb) { struct packet_type *ptype, *pt_prev; int ret = NET_RX_DROP; unsigned short type = skb->protocol; + struct net_device *dev = skb->dev; if (!skb->stamp.tv_sec) do_gettimeofday(&skb->stamp); @@ -1449,59 +1450,52 @@ skb->h.raw = skb->nh.raw = skb->data; pt_prev = NULL; + /* deliver skb to TAPs */ + 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); - } - } + if (!ptype->dev || ptype->dev == dev) { + if (pt_prev) + ret = _deliver_to_proto (skb, pt_prev, 0); pt_prev = ptype; } } #ifdef CONFIG_NET_DIVERT - if (skb->dev->divert && skb->dev->divert->divert) - ret = handle_diverter(skb); -#endif /* CONFIG_NET_DIVERT */ + /* do possible injection/rejection of packets */ + if (dev->divert && dev->divert->divert) { + divert_frame(skb); + } +#endif #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) - if (skb->dev->br_port && br_handle_frame_hook) { - return handle_bridge(skb, pt_prev); + /* bridge the packet to the bridge interface */ + if (dev->br_port && br_handle_frame_hook) { + if (pt_prev) + ret = _deliver_to_proto(skb, pt_prev, 1); + + br_handle_frame_hook(skb); + + return ret; } #endif + /* deliver skb to registered protocols (e.g. IP) */ 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); - } - } + if (ptype->type != type) + continue; + if (!ptype->dev || ptype->dev == dev) { + if (pt_prev) + ret = _deliver_to_proto(skb, pt_prev, 0); pt_prev = ptype; } } 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); - } + ret = _deliver_to_proto(skb, pt_prev, 1); } else { kfree_skb(skb); - /* Jamal, now you will not able to escape explaining + /* + * Jamal, now you will not able to escape explaining * me how you were going to use this. :-) */ ret = NET_RX_DROP; @@ -1512,11 +1506,10 @@ static int process_backlog(struct net_device *backlog_dev, int *budget) { - int work = 0; + struct softnet_data *queue = &softnet_data[smp_processor_id()]; int quota = min(backlog_dev->quota, *budget); - int this_cpu = smp_processor_id(); - struct softnet_data *queue = &softnet_data[this_cpu]; unsigned long start_time = jiffies; + int work = 0; for (;;) { struct sk_buff *skb; @@ -1575,8 +1568,9 @@ static void net_rx_action(struct softirq_action *h) { - int this_cpu = smp_processor_id(); - struct softnet_data *queue = &softnet_data[this_cpu]; + uint cpu = smp_processor_id(); + struct softnet_data *queue = &softnet_data[cpu]; + struct netif_rx_stats *stats = &netdev_rx_stat[cpu]; unsigned long start_time = jiffies; int budget = netdev_max_backlog; @@ -1613,8 +1607,8 @@ return; softnet_break: - netdev_rx_stat[this_cpu].time_squeeze++; - __cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ); + stats->time_squeeze++; + __cpu_raise_softirq(cpu, NET_RX_SOFTIRQ); goto out; } @@ -1817,25 +1811,27 @@ static int dev_proc_stats(char *buffer, char **start, off_t offset, int length, int *eof, void *data) { - int i, lcpu; + struct netif_rx_stats *stats; + uint cpu; int len = 0; - for (lcpu = 0; lcpu < smp_num_cpus; lcpu++) { - i = cpu_logical_map(lcpu); + for (cpu = 0; cpu < smp_num_cpus; cpu++) { + stats = &netdev_rx_stat[cpu_logical_map(cpu)]; + len += sprintf(buffer + len, "%08x %08x %08x %08x %08x %08x " "%08x %08x %08x\n", - netdev_rx_stat[i].total, - netdev_rx_stat[i].dropped, - netdev_rx_stat[i].time_squeeze, - netdev_rx_stat[i].throttled, - netdev_rx_stat[i].fastroute_hit, - netdev_rx_stat[i].fastroute_success, - netdev_rx_stat[i].fastroute_defer, - netdev_rx_stat[i].fastroute_deferred_out, + stats->total, + stats->dropped, + stats->time_squeeze, + stats->throttled, + stats->fastroute_hit, + stats->fastroute_success, + stats->fastroute_defer, + stats->fastroute_deferred_out, #if 0 - netdev_rx_stat[i].fastroute_latency_reduction + stats->fastroute_latency_reduction #else - netdev_rx_stat[i].cpu_collision + stats->cpu_collision #endif ); } @@ -2522,7 +2518,7 @@ return 0; } #ifdef NET_REFCNT_DEBUG - printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name, + printk(KERN_DEBUG "%s: %s%s.\n", __func__, dev->name, (dev->features & NETIF_F_DYNALLOC)?"":", old style"); #endif if (dev->destructor) @@ -2567,8 +2563,8 @@ } } if (!d) { - printk(KERN_DEBUG "unregister_netdevice: device %s/%p never " - "was registered\n", dev->name, dev); + printk(KERN_DEBUG "%s: device %s/%p was never registered\n", + __func__, dev->name, dev); return -ENODEV; } @@ -2610,9 +2606,9 @@ if (dev->features & NETIF_F_DYNALLOC) { #ifdef NET_REFCNT_DEBUG if (atomic_read(&dev->refcnt) != 1) - printk(KERN_DEBUG "unregister_netdevice: holding %s " - "refcnt=%d\n", - dev->name, atomic_read(&dev->refcnt) - 1); + printk(KERN_DEBUG "%s: holding %s refcnt=%d\n", + __func__, dev->name, + atomic_read(&dev->refcnt) - 1); #endif goto out; } @@ -2622,8 +2618,8 @@ goto out; #ifdef NET_REFCNT_DEBUG - printk(KERN_DEBUG "unregister_netdevice: waiting %s refcnt=%d\n", - dev->name, atomic_read(&dev->refcnt)); + printk(KERN_DEBUG "%s: waiting %s refcnt=%d\n", + __func__, dev->name, atomic_read(&dev->refcnt)); #endif /* EXPLANATION. If dev->refcnt is not now 1 (our own reference) @@ -2661,8 +2657,8 @@ schedule_timeout(HZ / 4); current->state = TASK_RUNNING; if ((jiffies - warning_time) > 10 * HZ) { - printk(KERN_EMERG "unregister_netdevice: waiting for " - "%s to become free. Usage count = %d\n", + printk(KERN_EMERG "waiting for %s to become free. " + "Usage count = %d\n", dev->name, atomic_read(&dev->refcnt)); warning_time = jiffies; } @@ -2842,24 +2838,21 @@ static int net_run_sbin_hotplug(struct net_device *dev, char *action) { char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32]; - int i; sprintf(ifname, "INTERFACE=%s", dev->name); sprintf(action_str, "ACTION=%s", action); - i = 0; - argv[i++] = hotplug_path; - argv[i++] = "net"; - argv[i] = 0; + argv[0] = hotplug_path; + argv[1] = "net"; + argv[2] = NULL; - i = 0; /* minimal command environment */ - envp [i++] = "HOME=/"; - envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; - envp [i++] = ifname; - envp [i++] = action_str; - envp [i] = 0; + envp [0] = "HOME=/"; + envp [1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + envp [2] = ifname; + envp [3] = action_str; + envp [4] = NULL; - return call_usermodehelper(argv [0], argv, envp); + return call_usermodehelper(argv[0], argv, envp); } #endif