From e912b1142be8f1e2c71c71001dc992c6e5eb2ec1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jul 2009 19:36:05 +0000 Subject: net: sk_prot_alloc() should not blindly overwrite memory Some sockets use SLAB_DESTROY_BY_RCU, and our RCU code correctness depends on sk->sk_nulls_node.next being always valid. A NULL value is not allowed as it might fault a lockless reader. Current sk_prot_alloc() implementation doesnt respect this hypothesis, calling kmem_cache_alloc() with __GFP_ZERO. Just call memset() around the forbidden field. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/sock.c b/net/core/sock.c index 6354863..ba5d211 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -939,8 +939,23 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, struct kmem_cache *slab; slab = prot->slab; - if (slab != NULL) - sk = kmem_cache_alloc(slab, priority); + if (slab != NULL) { + sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO); + if (!sk) + return sk; + if (priority & __GFP_ZERO) { + /* + * caches using SLAB_DESTROY_BY_RCU should let + * sk_node.next un-modified. Special care is taken + * when initializing object to zero. + */ + if (offsetof(struct sock, sk_node.next) != 0) + memset(sk, 0, offsetof(struct sock, sk_node.next)); + memset(&sk->sk_node.pprev, 0, + prot->obj_size - offsetof(struct sock, + sk_node.pprev)); + } + } else sk = kmalloc(prot->obj_size, priority); -- cgit v0.10.2 From e51a67a9c8a2ea5c563f8c2ba6613fe2100ffe67 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jul 2009 14:20:42 +0000 Subject: net: ip_push_pending_frames() fix After commit 2b85a34e911bf483c27cfdd124aeb1605145dc80 (net: No more expensive sock_hold()/sock_put() on each tx) we do not take any more references on sk->sk_refcnt on outgoing packets. I forgot to delete two __sock_put() from ip_push_pending_frames() and ip6_push_pending_frames(). Reported-by: Emil S Tantilov Signed-off-by: Eric Dumazet Tested-by: Emil S Tantilov Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 2470262..7d08210 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -1243,7 +1243,6 @@ int ip_push_pending_frames(struct sock *sk) skb->len += tmp_skb->len; skb->data_len += tmp_skb->len; skb->truesize += tmp_skb->truesize; - __sock_put(tmp_skb->sk); tmp_skb->destructor = NULL; tmp_skb->sk = NULL; } diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7c76e3d..87f8419 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1484,7 +1484,6 @@ int ip6_push_pending_frames(struct sock *sk) skb->len += tmp_skb->len; skb->data_len += tmp_skb->len; skb->truesize += tmp_skb->truesize; - __sock_put(tmp_skb->sk); tmp_skb->destructor = NULL; tmp_skb->sk = NULL; } -- cgit v0.10.2 From f2ba025b2036e52a176cddcf91b15ac2b10c644a Mon Sep 17 00:00:00 2001 From: Sascha Hlusiak Date: Sat, 11 Jul 2009 20:30:52 -0700 Subject: sit: fix regression: do not release skb->dst before xmit The sit module makes use of skb->dst in it's xmit function, so since 93f154b594fe47 ("net: release dst entry in dev_hard_start_xmit()") sit tunnels are broken, because the flag IFF_XMIT_DST_RELEASE is not unset. This patch unsets that flag for sit devices to fix this regression. Signed-off-by: Sascha Hlusiak Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 68e5230..98b7327d 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -1018,6 +1018,7 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); dev->flags = IFF_NOARP; + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->iflink = 0; dev->addr_len = 4; dev->features |= NETIF_F_NETNS_LOCAL; -- cgit v0.10.2 From 240c102d9c54fee7fdc87a4ef2fabc7eb539e00a Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 9 Jul 2009 17:54:35 +0000 Subject: netdev: restore MAC address set and validate operations alloc_etherdev() used to install default implementations of these operations, but they must now be explicitly installed in struct net_device_ops. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 6f42ad7..87fde32 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -1142,7 +1142,8 @@ static const struct net_device_ops ixp4xx_netdev_ops = { .ndo_start_xmit = eth_xmit, .ndo_set_multicast_list = eth_set_mcast_list, .ndo_do_ioctl = eth_ioctl, - + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static int __devinit eth_init_one(struct platform_device *pdev) diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 147c4b0..c7d18860 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3081,6 +3081,7 @@ static const struct net_device_ops ehea_netdev_ops = { #endif .ndo_get_stats = ehea_get_stats, .ndo_set_mac_address = ehea_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_set_multicast_list = ehea_set_multicast_list, .ndo_change_mtu = ehea_change_mtu, .ndo_vlan_rx_register = ehea_vlan_rx_register, diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 4ae1d25..43d813e 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -156,6 +156,8 @@ static const struct net_device_ops gfar_netdev_ops = { .ndo_tx_timeout = gfar_timeout, .ndo_do_ioctl = gfar_ioctl, .ndo_vlan_rx_register = gfar_vlan_rx_register, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gfar_netpoll, #endif diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 7a62f78..b79f776 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -270,6 +270,8 @@ static const struct net_device_ops plip_netdev_ops = { .ndo_stop = plip_close, .ndo_start_xmit = plip_tx_packet, .ndo_do_ioctl = plip_ioctl, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; /* Entry point of PLIP driver. diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index d1a5fb4..a3932c9 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1411,6 +1411,7 @@ static const struct net_device_ops gelic_netdevice_ops = { .ndo_set_multicast_list = gelic_net_set_multi, .ndo_change_mtu = gelic_net_change_mtu, .ndo_tx_timeout = gelic_net_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gelic_net_poll_controller, diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index b6b3ca9..6932b08 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -2707,6 +2707,7 @@ static const struct net_device_ops gelic_wl_netdevice_ops = { .ndo_set_multicast_list = gelic_net_set_multi, .ndo_change_mtu = gelic_net_change_mtu, .ndo_tx_timeout = gelic_net_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = gelic_net_poll_controller, diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index a82fb2a..bc74db0 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1017,6 +1017,7 @@ static const struct net_device_ops vnet_ops = { .ndo_stop = vnet_close, .ndo_set_multicast_list = vnet_set_rx_mode, .ndo_set_mac_address = vnet_set_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = vnet_tx_timeout, .ndo_change_mtu = vnet_change_mtu, .ndo_start_xmit = vnet_start_xmit, diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index e013147..238bea1 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -999,6 +999,8 @@ static const struct net_device_ops kaweth_netdev_ops = { .ndo_tx_timeout = kaweth_tx_timeout, .ndo_set_multicast_list = kaweth_set_rx_mode, .ndo_get_stats = kaweth_netdev_stats, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static int kaweth_probe( diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 73acbd2..9bea2af 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1493,6 +1493,8 @@ static const struct net_device_ops pegasus_netdev_ops = { .ndo_set_multicast_list = pegasus_set_multicast, .ndo_get_stats = pegasus_netdev_stats, .ndo_tx_timeout = pegasus_tx_timeout, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, }; static struct usb_driver pegasus_driver = { diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c index 345593c..a370e51 100644 --- a/drivers/net/wireless/orinoco/main.c +++ b/drivers/net/wireless/orinoco/main.c @@ -2521,6 +2521,8 @@ static const struct net_device_ops orinoco_netdev_ops = { .ndo_start_xmit = orinoco_xmit, .ndo_set_multicast_list = orinoco_set_multicast_list, .ndo_change_mtu = orinoco_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = orinoco_tx_timeout, .ndo_get_stats = orinoco_get_stats, }; @@ -2555,7 +2557,6 @@ struct net_device priv->wireless_data.spy_data = &priv->spy_data; dev->wireless_data = &priv->wireless_data; #endif - /* we use the default eth_mac_addr for setting the MAC addr */ /* Reserve space in skb for the SNAP header */ dev->hard_header_len += ENCAPS_OVERHEAD; -- cgit v0.10.2 From 635ecaa70e862f85f652581305fe0074810893be Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 9 Jul 2009 17:59:01 +0000 Subject: netdev: restore MTU change operation alloc_etherdev() used to install a default implementation of this operation, but it must now be explicitly installed in struct net_device_ops. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 8ae72ec..0e2ba21 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -908,6 +908,7 @@ static const struct net_device_ops rtl8139_netdev_ops = { .ndo_open = rtl8139_open, .ndo_stop = rtl8139_close, .ndo_get_stats = rtl8139_get_stats, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = rtl8139_set_mac_address, .ndo_start_xmit = rtl8139_start_xmit, diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index 87fde32..3fe0987 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -1142,6 +1142,7 @@ static const struct net_device_ops ixp4xx_netdev_ops = { .ndo_start_xmit = eth_xmit, .ndo_set_multicast_list = eth_set_mcast_list, .ndo_do_ioctl = eth_ioctl, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index c7d18860..e8d46cc 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -3080,6 +3080,7 @@ static const struct net_device_ops ehea_netdev_ops = { .ndo_poll_controller = ehea_netpoll, #endif .ndo_get_stats = ehea_get_stats, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = ehea_set_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_set_multicast_list = ehea_set_multicast_list, diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 0f19b74..d4b9807 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1642,6 +1642,7 @@ static const struct net_device_ops fec_netdev_ops = { .ndo_stop = fec_enet_close, .ndo_start_xmit = fec_enet_start_xmit, .ndo_set_multicast_list = set_multicast_list, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = fec_timeout, .ndo_set_mac_address = fec_set_mac_address, diff --git a/drivers/net/plip.c b/drivers/net/plip.c index b79f776..2ca8b0d 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -270,6 +270,7 @@ static const struct net_device_ops plip_netdev_ops = { .ndo_stop = plip_close, .ndo_start_xmit = plip_tx_packet, .ndo_do_ioctl = plip_ioctl, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index fdcbaf8..1c70e99 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -1774,6 +1774,7 @@ static const struct net_device_ops smc_netdev_ops = { .ndo_start_xmit = smc_hard_start_xmit, .ndo_tx_timeout = smc_timeout, .ndo_set_multicast_list = smc_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c index 66067f9..94b6d26 100644 --- a/drivers/net/smsc911x.c +++ b/drivers/net/smsc911x.c @@ -1779,6 +1779,7 @@ static const struct net_device_ops smsc911x_netdev_ops = { .ndo_get_stats = smsc911x_get_stats, .ndo_set_multicast_list = smsc911x_set_multicast_list, .ndo_do_ioctl = smsc911x_do_ioctl, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = smsc911x_set_mac_address, #ifdef CONFIG_NET_POLL_CONTROLLER diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index bc74db0..f1e5e45 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1016,6 +1016,7 @@ static const struct net_device_ops vnet_ops = { .ndo_open = vnet_open, .ndo_stop = vnet_close, .ndo_set_multicast_list = vnet_set_rx_mode, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = vnet_set_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_tx_timeout = vnet_tx_timeout, diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 238bea1..1f9ec29 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -999,6 +999,7 @@ static const struct net_device_ops kaweth_netdev_ops = { .ndo_tx_timeout = kaweth_tx_timeout, .ndo_set_multicast_list = kaweth_set_rx_mode, .ndo_get_stats = kaweth_netdev_stats, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 9bea2af..631d269a 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -1493,6 +1493,7 @@ static const struct net_device_ops pegasus_netdev_ops = { .ndo_set_multicast_list = pegasus_set_multicast, .ndo_get_stats = pegasus_netdev_stats, .ndo_tx_timeout = pegasus_tx_timeout, + .ndo_change_mtu = eth_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index d3489a3..88c30a5 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -621,6 +621,7 @@ static const struct net_device_ops rhine_netdev_ops = { .ndo_start_xmit = rhine_start_tx, .ndo_get_stats = rhine_get_stats, .ndo_set_multicast_list = rhine_set_rx_mode, + .ndo_change_mtu = eth_change_mtu, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = eth_mac_addr, .ndo_do_ioctl = netdev_ioctl, -- cgit v0.10.2 From adeab1afb7de89555c69aab5ca21300c14af6369 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Sun, 12 Jul 2009 21:09:20 -0700 Subject: NET: Fix locking issues in PPP, 6pack, mkiss and strip line disciplines. Guido Trentalancia reports: I am trying to use the kiss driver in the Linux kernel that is being shipped with Fedora 10 but unfortunately I get the following oops: mkiss: AX.25 Multikiss, Hans Albas PE1AYX mkiss: ax0: crc mode is auto. ADDRCONF(NETDEV_CHANGE): ax0: link becomes ready ------------[ cut here ]------------ WARNING: at kernel/softirq.c:77 __local_bh_disable+0x2f/0x83() (Not tainted) [...] unloaded: microcode] Pid: 0, comm: swapper Not tainted 2.6.27.25-170.2.72.fc10.i686 #1 [] warn_on_slowpath+0x65/0x8b [] ? _spin_unlock_irqrestore+0x22/0x38 [] ? __enqueue_entity+0xe3/0xeb [] ? enqueue_entity+0x203/0x20b [] ? enqueue_task_fair+0x3b/0x3f [] ? resched_task+0x3a/0x6e [] ? _spin_unlock_irqrestore+0x22/0x38 [] ? _spin_lock_bh+0xb/0x16 [] __local_bh_disable+0x2f/0x83 [] local_bh_disable+0xb/0xd [] _spin_lock_bh+0xb/0x16 [] mkiss_receive_buf+0x2fb/0x3a6 [mkiss] [] flush_to_ldisc+0xf7/0x198 [] tty_flip_buffer_push+0x41/0x51 [] ftdi_process_read+0x375/0x4ad [ftdi_sio] [] ftdi_read_bulk_callback+0x130/0x138 [ftdi_sio] [] usb_hcd_giveback_urb+0x63/0x93 [] uhci_giveback_urb+0xe5/0x15f [] uhci_scan_schedule+0x52e/0x767 [] ? psmouse_handle_byte+0xc/0xe5 [] ? acpi_ev_gpe_detect+0xd6/0xe1 [] uhci_irq+0x110/0x125 [] usb_hcd_irq+0x40/0xa3 [] handle_IRQ_event+0x2f/0x64 [] handle_level_irq+0x74/0xbe [] ? handle_level_irq+0x0/0xbe [] do_IRQ+0xc7/0xfe [] common_interrupt+0x28/0x30 [] ? acpi_idle_enter_simple+0x162/0x19d [] cpuidle_idle_call+0x60/0x92 [] cpu_idle+0x101/0x134 [] rest_init+0x4e/0x50 ======================= ---[ end trace b7cc8076093467ad ]--- ------------[ cut here ]------------ WARNING: at kernel/softirq.c:136 _local_bh_enable_ip+0x3d/0xc4() [...] Pid: 0, comm: swapper Tainted: G W 2.6.27.25-170.2.72.fc10.i686 [] warn_on_slowpath+0x65/0x8b [] ? _spin_unlock_irqrestore+0x22/0x38 [] ? __enqueue_entity+0xe3/0xeb [] ? enqueue_entity+0x203/0x20b [] ? enqueue_task_fair+0x3b/0x3f [] ? resched_task+0x3a/0x6e [] ? _spin_unlock_irqrestore+0x22/0x38 [] ? _spin_lock_bh+0xb/0x16 [] ? mkiss_receive_buf+0x33d/0x3a6 [mkiss] [] _local_bh_enable_ip+0x3d/0xc4 [] local_bh_enable_ip+0x8/0xa [] _spin_unlock_bh+0x11/0x13 [] mkiss_receive_buf+0x33d/0x3a6 [mkiss] [] flush_to_ldisc+0xf7/0x198 [] tty_flip_buffer_push+0x41/0x51 [] ftdi_process_read+0x375/0x4ad [ftdi_sio] [] ftdi_read_bulk_callback+0x130/0x138 [ftdi_sio] [] usb_hcd_giveback_urb+0x63/0x93 [] uhci_giveback_urb+0xe5/0x15f [] uhci_scan_schedule+0x52e/0x767 [] ? psmouse_handle_byte+0xc/0xe5 [] ? acpi_ev_gpe_detect+0xd6/0xe1 [] uhci_irq+0x110/0x125 [] usb_hcd_irq+0x40/0xa3 [] handle_IRQ_event+0x2f/0x64 [] handle_level_irq+0x74/0xbe [] ? handle_level_irq+0x0/0xbe [] do_IRQ+0xc7/0xfe [] common_interrupt+0x28/0x30 [] ? acpi_idle_enter_simple+0x162/0x19d [] cpuidle_idle_call+0x60/0x92 [] cpu_idle+0x101/0x134 [] rest_init+0x4e/0x50 ======================= ---[ end trace b7cc8076093467ad ]--- mkiss: ax0: Trying crc-smack mkiss: ax0: Trying crc-flexnet The issue was, that the locking code in mkiss was assuming it was only ever being called in process or bh context. Fixed by converting the involved locking code to use irq-safe locks. Review of other networking line disciplines shows that 6pack, both sync and async PPP and STRIP have similar issues. The ppp_async one is the most interesting one as it sorts out half of the issue as far back as 2004 in commit http://git.kernel.org/?p=linux/kernel/git/tglx/history.git;a=commitdiff;h=2996d8deaeddd01820691a872550dc0cfba0c37d Signed-off-by: Ralf Baechle Reported-by: Guido Trentalancia Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 1551600..913a564 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -398,13 +398,14 @@ static DEFINE_RWLOCK(disc_data_lock); static struct sixpack *sp_get(struct tty_struct *tty) { + unsigned long flags; struct sixpack *sp; - read_lock(&disc_data_lock); + read_lock_irqsave(&disc_data_lock, flags); sp = tty->disc_data; if (sp) atomic_inc(&sp->refcnt); - read_unlock(&disc_data_lock); + read_unlock_irqrestore(&disc_data_lock, flags); return sp; } @@ -688,12 +689,13 @@ out: */ static void sixpack_close(struct tty_struct *tty) { + unsigned long flags; struct sixpack *sp; - write_lock(&disc_data_lock); + write_lock_irqsave(&disc_data_lock, flags); sp = tty->disc_data; tty->disc_data = NULL; - write_unlock(&disc_data_lock); + write_unlock_irqrestore(&disc_data_lock, flags); if (!sp) return; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index fda2fc8..a728650 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -244,15 +244,16 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, /* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ static void ax_bump(struct mkiss *ax) { + unsigned long flags; struct sk_buff *skb; int count; - spin_lock_bh(&ax->buflock); + spin_lock_irqsave(&ax->buflock, flags); if (ax->rbuff[0] > 0x0f) { if (ax->rbuff[0] & 0x80) { if (check_crc_16(ax->rbuff, ax->rcount) < 0) { ax->dev->stats.rx_errors++; - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); return; } @@ -267,7 +268,7 @@ static void ax_bump(struct mkiss *ax) } else if (ax->rbuff[0] & 0x20) { if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { ax->dev->stats.rx_errors++; - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); return; } if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { @@ -294,7 +295,7 @@ static void ax_bump(struct mkiss *ax) printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); ax->dev->stats.rx_dropped++; - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); return; } @@ -303,11 +304,13 @@ static void ax_bump(struct mkiss *ax) netif_rx(skb); ax->dev->stats.rx_packets++; ax->dev->stats.rx_bytes += count; - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); } static void kiss_unesc(struct mkiss *ax, unsigned char s) { + unsigned long flags; + switch (s) { case END: /* drop keeptest bit = VSV */ @@ -334,18 +337,18 @@ static void kiss_unesc(struct mkiss *ax, unsigned char s) break; } - spin_lock_bh(&ax->buflock); + spin_lock_irqsave(&ax->buflock, flags); if (!test_bit(AXF_ERROR, &ax->flags)) { if (ax->rcount < ax->buffsize) { ax->rbuff[ax->rcount++] = s; - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); return; } ax->dev->stats.rx_over_errors++; set_bit(AXF_ERROR, &ax->flags); } - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); } static int ax_set_mac_address(struct net_device *dev, void *addr) @@ -367,6 +370,7 @@ static void ax_changedmtu(struct mkiss *ax) { struct net_device *dev = ax->dev; unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; + unsigned long flags; int len; len = dev->mtu * 2; @@ -392,7 +396,7 @@ static void ax_changedmtu(struct mkiss *ax) return; } - spin_lock_bh(&ax->buflock); + spin_lock_irqsave(&ax->buflock, flags); oxbuff = ax->xbuff; ax->xbuff = xbuff; @@ -423,7 +427,7 @@ static void ax_changedmtu(struct mkiss *ax) ax->mtu = dev->mtu + 73; ax->buffsize = len; - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); kfree(oxbuff); kfree(orbuff); @@ -433,6 +437,7 @@ static void ax_changedmtu(struct mkiss *ax) static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) { struct mkiss *ax = netdev_priv(dev); + unsigned long flags; unsigned char *p; int actual, count; @@ -449,7 +454,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) p = icp; - spin_lock_bh(&ax->buflock); + spin_lock_irqsave(&ax->buflock, flags); if ((*p & 0x0f) != 0) { /* Configuration Command (kissparms(1). * Protocol spec says: never append CRC. @@ -479,7 +484,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->crcauto = (cmd ? 0 : 1); printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); } - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); netif_start_queue(dev); return; @@ -512,7 +517,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) count = kiss_esc(p, (unsigned char *)ax->xbuff, len); } } - spin_unlock_bh(&ax->buflock); + spin_unlock_irqrestore(&ax->buflock, flags); set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->ops->write(ax->tty, ax->xbuff, count); @@ -704,13 +709,14 @@ static DEFINE_RWLOCK(disc_data_lock); static struct mkiss *mkiss_get(struct tty_struct *tty) { + unsigned long flags; struct mkiss *ax; - read_lock(&disc_data_lock); + read_lock_irqsave(&disc_data_lock, flags); ax = tty->disc_data; if (ax) atomic_inc(&ax->refcnt); - read_unlock(&disc_data_lock); + read_unlock_irqrestore(&disc_data_lock, flags); return ax; } @@ -809,12 +815,13 @@ out: static void mkiss_close(struct tty_struct *tty) { + unsigned long flags; struct mkiss *ax; - write_lock(&disc_data_lock); + write_lock_irqsave(&disc_data_lock, flags); ax = tty->disc_data; tty->disc_data = NULL; - write_unlock(&disc_data_lock); + write_unlock_irqrestore(&disc_data_lock, flags); if (!ax) return; diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 17c116b..1fd319b 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -132,13 +132,15 @@ static DEFINE_RWLOCK(disc_data_lock); static struct asyncppp *ap_get(struct tty_struct *tty) { + unsigned long flags; struct asyncppp *ap; - read_lock(&disc_data_lock); + read_lock_irqsave(&disc_data_lock, flags); ap = tty->disc_data; if (ap != NULL) atomic_inc(&ap->refcnt); - read_unlock(&disc_data_lock); + read_unlock_irqrestore(&disc_data_lock, flags); + return ap; } @@ -215,12 +217,13 @@ ppp_asynctty_open(struct tty_struct *tty) static void ppp_asynctty_close(struct tty_struct *tty) { + unsigned long flags; struct asyncppp *ap; - write_lock_irq(&disc_data_lock); + write_lock_irqsave(&disc_data_lock, flags); ap = tty->disc_data; tty->disc_data = NULL; - write_unlock_irq(&disc_data_lock); + write_unlock_irqrestore(&disc_data_lock, flags); if (!ap) return; diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index aa3d39f..1b3f75f 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -182,13 +182,15 @@ static DEFINE_RWLOCK(disc_data_lock); static struct syncppp *sp_get(struct tty_struct *tty) { + unsigned long flags; struct syncppp *ap; - read_lock(&disc_data_lock); + read_lock_irqsave(&disc_data_lock, flags); ap = tty->disc_data; if (ap != NULL) atomic_inc(&ap->refcnt); - read_unlock(&disc_data_lock); + read_unlock_irqrestore(&disc_data_lock, flags); + return ap; } @@ -262,12 +264,13 @@ ppp_sync_open(struct tty_struct *tty) static void ppp_sync_close(struct tty_struct *tty) { + unsigned long flags; struct syncppp *ap; - write_lock_irq(&disc_data_lock); + write_lock_irqsave(&disc_data_lock, flags); ap = tty->disc_data; tty->disc_data = NULL; - write_unlock_irq(&disc_data_lock); + write_unlock_irqrestore(&disc_data_lock, flags); if (!ap) return; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 38366a5..3d39f65 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -856,6 +856,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) unsigned char *orbuff = strip_info->rx_buff; unsigned char *osbuff = strip_info->sx_buff; unsigned char *otbuff = strip_info->tx_buff; + unsigned long flags; if (new_mtu > MAX_SEND_MTU) { printk(KERN_ERR @@ -864,11 +865,11 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } - spin_lock_bh(&strip_lock); + spin_lock_irqsave(&strip_lock, flags); if (!allocate_buffers(strip_info, new_mtu)) { printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", strip_info->dev->name); - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); return -ENOMEM; } @@ -892,7 +893,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) } } strip_info->tx_head = strip_info->tx_buff; - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", strip_info->dev->name, old_mtu, strip_info->mtu); @@ -983,10 +984,13 @@ static void strip_seq_neighbours(struct seq_file *seq, const MetricomNodeTable * table, const char *title) { - /* We wrap this in a do/while loop, so if the table changes */ - /* while we're reading it, we just go around and try again. */ + unsigned long flags; struct timeval t; + /* + * We wrap this in a do/while loop, so if the table changes + * while we're reading it, we just go around and try again. + */ do { int i; t = table->timestamp; @@ -995,9 +999,9 @@ static void strip_seq_neighbours(struct seq_file *seq, for (i = 0; i < table->num_nodes; i++) { MetricomNode node; - spin_lock_bh(&strip_lock); + spin_lock_irqsave(&strip_lock, flags); node = table->node[i]; - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); seq_printf(seq, " %s\n", node.c); } } while (table->timestamp.tv_sec != t.tv_sec @@ -1536,6 +1540,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) static int strip_xmit(struct sk_buff *skb, struct net_device *dev) { struct strip *strip_info = netdev_priv(dev); + unsigned long flags; if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", @@ -1574,11 +1579,11 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) strip_info->dev->name, sx_pps_count / 8); } - spin_lock_bh(&strip_lock); + spin_lock_irqsave(&strip_lock, flags); strip_send(strip_info, skb); - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); if (skb) dev_kfree_skb(skb); @@ -2263,12 +2268,13 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, { struct strip *strip_info = tty->disc_data; const unsigned char *end = cp + count; + unsigned long flags; if (!strip_info || strip_info->magic != STRIP_MAGIC || !netif_running(strip_info->dev)) return; - spin_lock_bh(&strip_lock); + spin_lock_irqsave(&strip_lock, flags); #if 0 { struct timeval tv; @@ -2335,7 +2341,7 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, } cp++; } - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); } @@ -2523,9 +2529,11 @@ static void strip_dev_setup(struct net_device *dev) static void strip_free(struct strip *strip_info) { - spin_lock_bh(&strip_lock); + unsigned long flags; + + spin_lock_irqsave(&strip_lock, flags); list_del_rcu(&strip_info->list); - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); strip_info->magic = 0; @@ -2539,6 +2547,7 @@ static void strip_free(struct strip *strip_info) static struct strip *strip_alloc(void) { struct list_head *n; + unsigned long flags; struct net_device *dev; struct strip *strip_info; @@ -2562,7 +2571,7 @@ static struct strip *strip_alloc(void) strip_info->idle_timer.function = strip_IdleTask; - spin_lock_bh(&strip_lock); + spin_lock_irqsave(&strip_lock, flags); rescan: /* * Search the list to find where to put our new entry @@ -2581,7 +2590,7 @@ static struct strip *strip_alloc(void) sprintf(dev->name, "st%ld", dev->base_addr); list_add_tail_rcu(&strip_info->list, &strip_list); - spin_unlock_bh(&strip_lock); + spin_unlock_irqrestore(&strip_lock, flags); return strip_info; } -- cgit v0.10.2 From 41796e91a2a30fd82a0fd561022489b61f8a3188 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Sun, 12 Jul 2009 13:12:37 +0000 Subject: atlx: duplicate testing of MCAST flag Fix duplicate testing of MCAST flag Signed-off-by: Roel Kluin Acked-by: Jay Cliburn Signed-off-by: David S. Miller diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index c734b19..204db96 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -2071,7 +2071,7 @@ static int atl2_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE)) return -EOPNOTSUPP; - if (wol->wolopts & (WAKE_MCAST|WAKE_BCAST|WAKE_MCAST)) + if (wol->wolopts & (WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)) return -EOPNOTSUPP; /* these settings will always override what we currently have */ -- cgit v0.10.2 From c8159b2db1b49f6bda4429008c85108e2da60712 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 13 Jul 2009 11:11:41 -0700 Subject: igb: gcc-3.4.6 fix forward declaration of inline function should be avoided, or old gcc cannot compile. Reported-by: Teck Choon Giam Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index be48029..adb09d3 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -127,14 +127,48 @@ static void igb_restore_vlan(struct igb_adapter *); static void igb_ping_all_vfs(struct igb_adapter *); static void igb_msg_task(struct igb_adapter *); static int igb_rcv_msg_from_vf(struct igb_adapter *, u32); -static inline void igb_set_rah_pool(struct e1000_hw *, int , int); static void igb_set_mc_list_pools(struct igb_adapter *, int, u16); static void igb_vmm_control(struct igb_adapter *); -static inline void igb_set_vmolr(struct e1000_hw *, int); -static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int); static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *); static void igb_restore_vf_multicasts(struct igb_adapter *adapter); +static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn) +{ + u32 reg_data; + + reg_data = rd32(E1000_VMOLR(vfn)); + reg_data |= E1000_VMOLR_BAM | /* Accept broadcast */ + E1000_VMOLR_ROPE | /* Accept packets matched in UTA */ + E1000_VMOLR_ROMPE | /* Accept packets matched in MTA */ + E1000_VMOLR_AUPE | /* Accept untagged packets */ + E1000_VMOLR_STRVLAN; /* Strip vlan tags */ + wr32(E1000_VMOLR(vfn), reg_data); +} + +static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, + int vfn) +{ + struct e1000_hw *hw = &adapter->hw; + u32 vmolr; + + vmolr = rd32(E1000_VMOLR(vfn)); + vmolr &= ~E1000_VMOLR_RLPML_MASK; + vmolr |= size | E1000_VMOLR_LPE; + wr32(E1000_VMOLR(vfn), vmolr); + + return 0; +} + +static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry) +{ + u32 reg_data; + + reg_data = rd32(E1000_RAH(entry)); + reg_data &= ~E1000_RAH_POOL_MASK; + reg_data |= E1000_RAH_POOL_1 << pool;; + wr32(E1000_RAH(entry), reg_data); +} + #ifdef CONFIG_PM static int igb_suspend(struct pci_dev *, pm_message_t); static int igb_resume(struct pci_dev *); @@ -5418,43 +5452,6 @@ static void igb_io_resume(struct pci_dev *pdev) igb_get_hw_control(adapter); } -static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn) -{ - u32 reg_data; - - reg_data = rd32(E1000_VMOLR(vfn)); - reg_data |= E1000_VMOLR_BAM | /* Accept broadcast */ - E1000_VMOLR_ROPE | /* Accept packets matched in UTA */ - E1000_VMOLR_ROMPE | /* Accept packets matched in MTA */ - E1000_VMOLR_AUPE | /* Accept untagged packets */ - E1000_VMOLR_STRVLAN; /* Strip vlan tags */ - wr32(E1000_VMOLR(vfn), reg_data); -} - -static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size, - int vfn) -{ - struct e1000_hw *hw = &adapter->hw; - u32 vmolr; - - vmolr = rd32(E1000_VMOLR(vfn)); - vmolr &= ~E1000_VMOLR_RLPML_MASK; - vmolr |= size | E1000_VMOLR_LPE; - wr32(E1000_VMOLR(vfn), vmolr); - - return 0; -} - -static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry) -{ - u32 reg_data; - - reg_data = rd32(E1000_RAH(entry)); - reg_data &= ~E1000_RAH_POOL_MASK; - reg_data |= E1000_RAH_POOL_1 << pool;; - wr32(E1000_RAH(entry), reg_data); -} - static void igb_set_mc_list_pools(struct igb_adapter *adapter, int entry_count, u16 total_rar_filters) { -- cgit v0.10.2 From ee686ca919193d7c1f87f907e732df5e2f942523 Mon Sep 17 00:00:00 2001 From: Andreas Jaggi Date: Tue, 14 Jul 2009 09:35:59 -0700 Subject: gre: fix ToS/DiffServ inherit bug Fixes two bugs: - ToS/DiffServ inheritance was unintentionally activated when using impair fixed ToS values - ECN bit was lost during ToS/DiffServ inheritance Signed-off-by: Andreas Jaggi Signed-off-by: David S. Miller diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 44e2a3d..cb4a0f4 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -735,10 +735,10 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } tos = tiph->tos; - if (tos&1) { + if (tos == 1) { + tos = 0; if (skb->protocol == htons(ETH_P_IP)) tos = old_iph->tos; - tos &= ~1; } { -- cgit v0.10.2 From bc23283c7bc90958927abe26eedc562701743a88 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Mon, 13 Jul 2009 11:23:39 +0000 Subject: NET: phy_device, fix lock imbalance Don't forget to unlock a mutex in phy_scan_fixups on a fail path. Signed-off-by: Jiri Slaby Signed-off-by: David S. Miller diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index eba937c..b10fedd 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -134,8 +134,10 @@ int phy_scan_fixups(struct phy_device *phydev) err = fixup->run(phydev); - if (err < 0) + if (err < 0) { + mutex_unlock(&phy_fixup_lock); return err; + } } } mutex_unlock(&phy_fixup_lock); -- cgit v0.10.2 From 79fbe134832ebb70a49d8802cfeb2401dc35bb38 Mon Sep 17 00:00:00 2001 From: Dongdong Deng Date: Sun, 12 Jul 2009 20:27:06 +0000 Subject: drivers/net: using spin_lock_irqsave() in net_send_packet() spin_unlock_irq() will enable interrupt in net_send_packet(), this patch changes it to spin_lock_irqsave/spin_lock_irqrestore, so that it doesn't enable interrupts when already disabled, and netconsole would work properly over cs89x0/isa-skeleton. Call trace: netconsole write_msg() { ... -> spin_lock_irqsave(); -> netpoll_send_udp() -> netpoll_send_skb() -> net_send_packet() ->... -> spin_unlock_irqrestore(); ... } Signed-off-by: Dongdong Deng Signed-off-by: David S. Miller diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 3eee666..55445f9 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -1524,6 +1524,7 @@ static void net_timeout(struct net_device *dev) static int net_send_packet(struct sk_buff *skb, struct net_device *dev) { struct net_local *lp = netdev_priv(dev); + unsigned long flags; if (net_debug > 3) { printk("%s: sent %d byte packet of type %x\n", @@ -1535,7 +1536,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) ask the chip to start transmitting before the whole packet has been completely uploaded. */ - spin_lock_irq(&lp->lock); + spin_lock_irqsave(&lp->lock, flags); netif_stop_queue(dev); /* initiate a transmit sequence */ @@ -1549,13 +1550,13 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * we're waiting for TxOk, so return 1 and requeue this packet. */ - spin_unlock_irq(&lp->lock); + spin_unlock_irqrestore(&lp->lock, flags); if (net_debug) printk("cs89x0: Tx buffer not free!\n"); return NETDEV_TX_BUSY; } /* Write the contents of the packet */ writewords(dev->base_addr, TX_FRAME_PORT,skb->data,(skb->len+1) >>1); - spin_unlock_irq(&lp->lock); + spin_unlock_irqrestore(&lp->lock, flags); lp->stats.tx_bytes += skb->len; dev->trans_start = jiffies; dev_kfree_skb (skb); diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index 73585fd..d12377b 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -430,7 +430,8 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * hardware interrupt handler. Queue flow control is * thus managed under this lock as well. */ - spin_lock_irq(&np->lock); + unsigned long flags; + spin_lock_irqsave(&np->lock, flags); add_to_tx_ring(np, skb, length); dev->trans_start = jiffies; @@ -446,7 +447,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev) * is when the transmit statistics are updated. */ - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); #else /* This is the case for older hardware which takes * a single transmit buffer at a time, and it is -- cgit v0.10.2 From 8660c1240ec6016522b882c88751cb4ce40bf0e8 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 13 Jul 2009 22:48:16 +0000 Subject: skbuff.h: Fix comment for NET_IP_ALIGN Use the correct function call for skb_reserve in the comment for NET_IP_ALIGN. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index b47b3f0..f2c69a2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1342,12 +1342,12 @@ static inline int skb_network_offset(const struct sk_buff *skb) * shifting the start of the packet by 2 bytes. Drivers should do this * with: * - * skb_reserve(NET_IP_ALIGN); + * skb_reserve(skb, NET_IP_ALIGN); * * The downside to this alignment of the IP header is that the DMA is now * unaligned. On some architectures the cost of an unaligned DMA is high * and this cost outweighs the gains made by aligning the IP header. - * + * * Since this trade off varies between architectures, we allow NET_IP_ALIGN * to be overridden. */ -- cgit v0.10.2 From 252aa9d94a04252046f3a382e6aca1b5c95921d8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 14 Jul 2009 13:13:41 -0700 Subject: Revert "NET: Fix locking issues in PPP, 6pack, mkiss and strip line disciplines." This reverts commit adeab1afb7de89555c69aab5ca21300c14af6369. As Alan Cox explained, the TTY layer changes that went recently to get rid of the tty->low_latency stuff fixes this already, and even for -stable it's the ->low_latency changes that should go in to fix this, rather than this patch. Signed-off-by: David S. Miller diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 913a564..1551600 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -398,14 +398,13 @@ static DEFINE_RWLOCK(disc_data_lock); static struct sixpack *sp_get(struct tty_struct *tty) { - unsigned long flags; struct sixpack *sp; - read_lock_irqsave(&disc_data_lock, flags); + read_lock(&disc_data_lock); sp = tty->disc_data; if (sp) atomic_inc(&sp->refcnt); - read_unlock_irqrestore(&disc_data_lock, flags); + read_unlock(&disc_data_lock); return sp; } @@ -689,13 +688,12 @@ out: */ static void sixpack_close(struct tty_struct *tty) { - unsigned long flags; struct sixpack *sp; - write_lock_irqsave(&disc_data_lock, flags); + write_lock(&disc_data_lock); sp = tty->disc_data; tty->disc_data = NULL; - write_unlock_irqrestore(&disc_data_lock, flags); + write_unlock(&disc_data_lock); if (!sp) return; diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index a728650..fda2fc8 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -244,16 +244,15 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, /* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ static void ax_bump(struct mkiss *ax) { - unsigned long flags; struct sk_buff *skb; int count; - spin_lock_irqsave(&ax->buflock, flags); + spin_lock_bh(&ax->buflock); if (ax->rbuff[0] > 0x0f) { if (ax->rbuff[0] & 0x80) { if (check_crc_16(ax->rbuff, ax->rcount) < 0) { ax->dev->stats.rx_errors++; - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); return; } @@ -268,7 +267,7 @@ static void ax_bump(struct mkiss *ax) } else if (ax->rbuff[0] & 0x20) { if (check_crc_flex(ax->rbuff, ax->rcount) < 0) { ax->dev->stats.rx_errors++; - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); return; } if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) { @@ -295,7 +294,7 @@ static void ax_bump(struct mkiss *ax) printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n", ax->dev->name); ax->dev->stats.rx_dropped++; - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); return; } @@ -304,13 +303,11 @@ static void ax_bump(struct mkiss *ax) netif_rx(skb); ax->dev->stats.rx_packets++; ax->dev->stats.rx_bytes += count; - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); } static void kiss_unesc(struct mkiss *ax, unsigned char s) { - unsigned long flags; - switch (s) { case END: /* drop keeptest bit = VSV */ @@ -337,18 +334,18 @@ static void kiss_unesc(struct mkiss *ax, unsigned char s) break; } - spin_lock_irqsave(&ax->buflock, flags); + spin_lock_bh(&ax->buflock); if (!test_bit(AXF_ERROR, &ax->flags)) { if (ax->rcount < ax->buffsize) { ax->rbuff[ax->rcount++] = s; - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); return; } ax->dev->stats.rx_over_errors++; set_bit(AXF_ERROR, &ax->flags); } - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); } static int ax_set_mac_address(struct net_device *dev, void *addr) @@ -370,7 +367,6 @@ static void ax_changedmtu(struct mkiss *ax) { struct net_device *dev = ax->dev; unsigned char *xbuff, *rbuff, *oxbuff, *orbuff; - unsigned long flags; int len; len = dev->mtu * 2; @@ -396,7 +392,7 @@ static void ax_changedmtu(struct mkiss *ax) return; } - spin_lock_irqsave(&ax->buflock, flags); + spin_lock_bh(&ax->buflock); oxbuff = ax->xbuff; ax->xbuff = xbuff; @@ -427,7 +423,7 @@ static void ax_changedmtu(struct mkiss *ax) ax->mtu = dev->mtu + 73; ax->buffsize = len; - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); kfree(oxbuff); kfree(orbuff); @@ -437,7 +433,6 @@ static void ax_changedmtu(struct mkiss *ax) static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) { struct mkiss *ax = netdev_priv(dev); - unsigned long flags; unsigned char *p; int actual, count; @@ -454,7 +449,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) p = icp; - spin_lock_irqsave(&ax->buflock, flags); + spin_lock_bh(&ax->buflock); if ((*p & 0x0f) != 0) { /* Configuration Command (kissparms(1). * Protocol spec says: never append CRC. @@ -484,7 +479,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) ax->crcauto = (cmd ? 0 : 1); printk(KERN_INFO "mkiss: %s: crc mode %s %d\n", ax->dev->name, (len) ? "set to" : "is", cmd); } - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); netif_start_queue(dev); return; @@ -517,7 +512,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len) count = kiss_esc(p, (unsigned char *)ax->xbuff, len); } } - spin_unlock_irqrestore(&ax->buflock, flags); + spin_unlock_bh(&ax->buflock); set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags); actual = ax->tty->ops->write(ax->tty, ax->xbuff, count); @@ -709,14 +704,13 @@ static DEFINE_RWLOCK(disc_data_lock); static struct mkiss *mkiss_get(struct tty_struct *tty) { - unsigned long flags; struct mkiss *ax; - read_lock_irqsave(&disc_data_lock, flags); + read_lock(&disc_data_lock); ax = tty->disc_data; if (ax) atomic_inc(&ax->refcnt); - read_unlock_irqrestore(&disc_data_lock, flags); + read_unlock(&disc_data_lock); return ax; } @@ -815,13 +809,12 @@ out: static void mkiss_close(struct tty_struct *tty) { - unsigned long flags; struct mkiss *ax; - write_lock_irqsave(&disc_data_lock, flags); + write_lock(&disc_data_lock); ax = tty->disc_data; tty->disc_data = NULL; - write_unlock_irqrestore(&disc_data_lock, flags); + write_unlock(&disc_data_lock); if (!ax) return; diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 1fd319b..17c116b 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -132,15 +132,13 @@ static DEFINE_RWLOCK(disc_data_lock); static struct asyncppp *ap_get(struct tty_struct *tty) { - unsigned long flags; struct asyncppp *ap; - read_lock_irqsave(&disc_data_lock, flags); + read_lock(&disc_data_lock); ap = tty->disc_data; if (ap != NULL) atomic_inc(&ap->refcnt); - read_unlock_irqrestore(&disc_data_lock, flags); - + read_unlock(&disc_data_lock); return ap; } @@ -217,13 +215,12 @@ ppp_asynctty_open(struct tty_struct *tty) static void ppp_asynctty_close(struct tty_struct *tty) { - unsigned long flags; struct asyncppp *ap; - write_lock_irqsave(&disc_data_lock, flags); + write_lock_irq(&disc_data_lock); ap = tty->disc_data; tty->disc_data = NULL; - write_unlock_irqrestore(&disc_data_lock, flags); + write_unlock_irq(&disc_data_lock); if (!ap) return; diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 1b3f75f..aa3d39f 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -182,15 +182,13 @@ static DEFINE_RWLOCK(disc_data_lock); static struct syncppp *sp_get(struct tty_struct *tty) { - unsigned long flags; struct syncppp *ap; - read_lock_irqsave(&disc_data_lock, flags); + read_lock(&disc_data_lock); ap = tty->disc_data; if (ap != NULL) atomic_inc(&ap->refcnt); - read_unlock_irqrestore(&disc_data_lock, flags); - + read_unlock(&disc_data_lock); return ap; } @@ -264,13 +262,12 @@ ppp_sync_open(struct tty_struct *tty) static void ppp_sync_close(struct tty_struct *tty) { - unsigned long flags; struct syncppp *ap; - write_lock_irqsave(&disc_data_lock, flags); + write_lock_irq(&disc_data_lock); ap = tty->disc_data; tty->disc_data = NULL; - write_unlock_irqrestore(&disc_data_lock, flags); + write_unlock_irq(&disc_data_lock); if (!ap) return; diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 3d39f65..38366a5 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -856,7 +856,6 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) unsigned char *orbuff = strip_info->rx_buff; unsigned char *osbuff = strip_info->sx_buff; unsigned char *otbuff = strip_info->tx_buff; - unsigned long flags; if (new_mtu > MAX_SEND_MTU) { printk(KERN_ERR @@ -865,11 +864,11 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } - spin_lock_irqsave(&strip_lock, flags); + spin_lock_bh(&strip_lock); if (!allocate_buffers(strip_info, new_mtu)) { printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", strip_info->dev->name); - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); return -ENOMEM; } @@ -893,7 +892,7 @@ static int strip_change_mtu(struct net_device *dev, int new_mtu) } } strip_info->tx_head = strip_info->tx_buff; - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", strip_info->dev->name, old_mtu, strip_info->mtu); @@ -984,13 +983,10 @@ static void strip_seq_neighbours(struct seq_file *seq, const MetricomNodeTable * table, const char *title) { - unsigned long flags; + /* We wrap this in a do/while loop, so if the table changes */ + /* while we're reading it, we just go around and try again. */ struct timeval t; - /* - * We wrap this in a do/while loop, so if the table changes - * while we're reading it, we just go around and try again. - */ do { int i; t = table->timestamp; @@ -999,9 +995,9 @@ static void strip_seq_neighbours(struct seq_file *seq, for (i = 0; i < table->num_nodes; i++) { MetricomNode node; - spin_lock_irqsave(&strip_lock, flags); + spin_lock_bh(&strip_lock); node = table->node[i]; - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); seq_printf(seq, " %s\n", node.c); } } while (table->timestamp.tv_sec != t.tv_sec @@ -1540,7 +1536,6 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) static int strip_xmit(struct sk_buff *skb, struct net_device *dev) { struct strip *strip_info = netdev_priv(dev); - unsigned long flags; if (!netif_running(dev)) { printk(KERN_ERR "%s: xmit call when iface is down\n", @@ -1579,11 +1574,11 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) strip_info->dev->name, sx_pps_count / 8); } - spin_lock_irqsave(&strip_lock, flags); + spin_lock_bh(&strip_lock); strip_send(strip_info, skb); - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); if (skb) dev_kfree_skb(skb); @@ -2268,13 +2263,12 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, { struct strip *strip_info = tty->disc_data; const unsigned char *end = cp + count; - unsigned long flags; if (!strip_info || strip_info->magic != STRIP_MAGIC || !netif_running(strip_info->dev)) return; - spin_lock_irqsave(&strip_lock, flags); + spin_lock_bh(&strip_lock); #if 0 { struct timeval tv; @@ -2341,7 +2335,7 @@ static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, } cp++; } - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); } @@ -2529,11 +2523,9 @@ static void strip_dev_setup(struct net_device *dev) static void strip_free(struct strip *strip_info) { - unsigned long flags; - - spin_lock_irqsave(&strip_lock, flags); + spin_lock_bh(&strip_lock); list_del_rcu(&strip_info->list); - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); strip_info->magic = 0; @@ -2547,7 +2539,6 @@ static void strip_free(struct strip *strip_info) static struct strip *strip_alloc(void) { struct list_head *n; - unsigned long flags; struct net_device *dev; struct strip *strip_info; @@ -2571,7 +2562,7 @@ static struct strip *strip_alloc(void) strip_info->idle_timer.function = strip_IdleTask; - spin_lock_irqsave(&strip_lock, flags); + spin_lock_bh(&strip_lock); rescan: /* * Search the list to find where to put our new entry @@ -2590,7 +2581,7 @@ static struct strip *strip_alloc(void) sprintf(dev->name, "st%ld", dev->base_addr); list_add_tail_rcu(&strip_info->list, &strip_list); - spin_unlock_irqrestore(&strip_lock, flags); + spin_unlock_bh(&strip_lock); return strip_info; } -- cgit v0.10.2