From 3f1f7cf08ddf10ef7fbf06d881582c95b9747f4e Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 1 Jul 2009 11:32:10 +0200 Subject: netfilter: add netfilter git to MAINTAINERS Signed-off-by: Joe Perches Signed-off-by: Patrick McHardy diff --git a/MAINTAINERS b/MAINTAINERS index fa2a16d..a5042dea 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4044,6 +4044,7 @@ L: netfilter@vger.kernel.org L: coreteam@netfilter.org W: http://www.netfilter.org/ W: http://www.iptables.org/ +T: git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git S: Supported F: include/linux/netfilter* F: include/linux/netfilter/ -- cgit v0.10.2 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 From f7e5cc0c40dff92bad2894153f675c6c542ba2f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Tue, 14 Jul 2009 23:10:21 +0000 Subject: net/can bugfix: use after free bug in can protocol drivers Fix a use after free bug in can protocol drivers The release functions of the can protocol drivers lack a call to sock_orphan() which leads to referencing freed memory under certain circumstances. This patch fixes a bug reported here: https://lists.berlios.de/pipermail/socketcan-users/2009-July/000985.html Signed-off-by: Lothar Wassmann Acked-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/net/can/bcm.c b/net/can/bcm.c index 95d7f32..1d17e41 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -1469,6 +1469,9 @@ static int bcm_release(struct socket *sock) bo->ifindex = 0; } + sock_orphan(sk); + sock->sk = NULL; + release_sock(sk); sock_put(sk); diff --git a/net/can/raw.c b/net/can/raw.c index 6aa154e..3482546 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -306,6 +306,9 @@ static int raw_release(struct socket *sock) ro->bound = 0; ro->count = 0; + sock_orphan(sk); + sock->sk = NULL; + release_sock(sk); sock_put(sk); -- cgit v0.10.2 From b13bb2e9933b9dfa25c81d959d847c843481111e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lothar=20Wa=C3=9Fmann?= Date: Tue, 14 Jul 2009 23:12:25 +0000 Subject: net/can: add module alias to can protocol drivers Add appropriate MODULE_ALIAS() to facilitate autoloading of can protocol drivers Signed-off-by: Lothar Wassmann Acked-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/net/can/bcm.c b/net/can/bcm.c index 1d17e41..72720c7 100644 --- a/net/can/bcm.c +++ b/net/can/bcm.c @@ -75,6 +75,7 @@ static __initdata const char banner[] = KERN_INFO MODULE_DESCRIPTION("PF_CAN broadcast manager protocol"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Oliver Hartkopp "); +MODULE_ALIAS("can-proto-2"); /* easy access to can_frame payload */ static inline u64 GET_U64(const struct can_frame *cp) diff --git a/net/can/raw.c b/net/can/raw.c index 3482546..f4cc445 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -62,6 +62,7 @@ static __initdata const char banner[] = MODULE_DESCRIPTION("PF_CAN raw protocol"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Urs Thuermann "); +MODULE_ALIAS("can-proto-1"); #define MASK_ALL 0 -- cgit v0.10.2 From aa6a03eb0ae859c1371555ef381de4c96ca1e4e6 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 16 Jul 2009 14:01:54 +0200 Subject: netfilter: xt_osf: fix nf_log_packet() arguments The first argument is the address family, the second one the hook number. Signed-off-by: Patrick McHardy diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 863e409..0f482e2 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -330,7 +330,8 @@ static bool xt_osf_match_packet(const struct sk_buff *skb, fcount++; if (info->flags & XT_OSF_LOG) - nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL, + nf_log_packet(p->family, p->hooknum, skb, + p->in, p->out, NULL, "%s [%s:%s] : %pi4:%d -> %pi4:%d hops=%d\n", f->genre, f->version, f->subtype, &ip->saddr, ntohs(tcp->source), @@ -345,7 +346,7 @@ static bool xt_osf_match_packet(const struct sk_buff *skb, rcu_read_unlock(); if (!fcount && (info->flags & XT_OSF_LOG)) - nf_log_packet(p->hooknum, 0, skb, p->in, p->out, NULL, + nf_log_packet(p->family, p->hooknum, skb, p->in, p->out, NULL, "Remote OS is not known: %pi4:%u -> %pi4:%u\n", &ip->saddr, ntohs(tcp->source), &ip->daddr, ntohs(tcp->dest)); -- cgit v0.10.2 From 941297f443f871b8c3372feccf27a8733f6ce9e9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 16 Jul 2009 14:03:40 +0200 Subject: netfilter: nf_conntrack: nf_conntrack_alloc() fixes When a slab cache uses SLAB_DESTROY_BY_RCU, we must be careful when allocating objects, since slab allocator could give a freed object still used by lockless readers. In particular, nf_conntrack RCU lookups rely on ct->tuplehash[xxx].hnnode.next being always valid (ie containing a valid 'nulls' value, or a valid pointer to next object in hash chain.) kmem_cache_zalloc() setups object with NULL values, but a NULL value is not valid for ct->tuplehash[xxx].hnnode.next. Fix is to call kmem_cache_alloc() and do the zeroing ourself. As spotted by Patrick, we also need to make sure lookup keys are committed to memory before setting refcount to 1, or a lockless reader could get a reference on the old version of the object. Its key re-check could then pass the barrier. Signed-off-by: Eric Dumazet Signed-off-by: Patrick McHardy diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt index 93cb28d..18f9651 100644 --- a/Documentation/RCU/rculist_nulls.txt +++ b/Documentation/RCU/rculist_nulls.txt @@ -83,11 +83,12 @@ not detect it missed following items in original chain. obj = kmem_cache_alloc(...); lock_chain(); // typically a spin_lock() obj->key = key; -atomic_inc(&obj->refcnt); /* * we need to make sure obj->key is updated before obj->next + * or obj->refcnt */ smp_wmb(); +atomic_set(&obj->refcnt, 1); hlist_add_head_rcu(&obj->obj_node, list); unlock_chain(); // typically a spin_unlock() @@ -159,6 +160,10 @@ out: obj = kmem_cache_alloc(cachep); lock_chain(); // typically a spin_lock() obj->key = key; +/* + * changes to obj->key must be visible before refcnt one + */ +smp_wmb(); atomic_set(&obj->refcnt, 1); /* * insert obj in RCU way (readers might be traversing chain) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 7508f11..b5869b9 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -561,23 +561,38 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, } } - ct = kmem_cache_zalloc(nf_conntrack_cachep, gfp); + /* + * Do not use kmem_cache_zalloc(), as this cache uses + * SLAB_DESTROY_BY_RCU. + */ + ct = kmem_cache_alloc(nf_conntrack_cachep, gfp); if (ct == NULL) { pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n"); atomic_dec(&net->ct.count); return ERR_PTR(-ENOMEM); } - + /* + * Let ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.next + * and ct->tuplehash[IP_CT_DIR_REPLY].hnnode.next unchanged. + */ + memset(&ct->tuplehash[IP_CT_DIR_MAX], 0, + sizeof(*ct) - offsetof(struct nf_conn, tuplehash[IP_CT_DIR_MAX])); spin_lock_init(&ct->lock); - atomic_set(&ct->ct_general.use, 1); ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple = *orig; + ct->tuplehash[IP_CT_DIR_ORIGINAL].hnnode.pprev = NULL; ct->tuplehash[IP_CT_DIR_REPLY].tuple = *repl; + ct->tuplehash[IP_CT_DIR_REPLY].hnnode.pprev = NULL; /* Don't set timer yet: wait for confirmation */ setup_timer(&ct->timeout, death_by_timeout, (unsigned long)ct); #ifdef CONFIG_NET_NS ct->ct_net = net; #endif + /* + * changes to lookup keys must be done before setting refcnt to 1 + */ + smp_wmb(); + atomic_set(&ct->ct_general.use, 1); return ct; } EXPORT_SYMBOL_GPL(nf_conntrack_alloc); -- cgit v0.10.2 From c5ad4f592e27d782faea0a787d9181f192a69ef0 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Sun, 12 Jul 2009 11:40:34 +0000 Subject: atl1c: add missing parentheses Parentheses are required or the comparison occurs before the bitand. Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h index e1658ef..2a1120a 100644 --- a/drivers/net/atl1c/atl1c.h +++ b/drivers/net/atl1c/atl1c.h @@ -188,14 +188,14 @@ struct atl1c_tpd_ext_desc { #define RRS_HDS_TYPE_DATA 2 #define RRS_IS_NO_HDS_TYPE(flag) \ - (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == 0) + ((((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK) == 0) #define RRS_IS_HDS_HEAD(flag) \ - (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \ + ((((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK) == \ RRS_HDS_TYPE_HEAD) #define RRS_IS_HDS_DATA(flag) \ - (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \ + ((((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK) == \ RRS_HDS_TYPE_DATA) /* rrs word 3 bit 0:31 */ @@ -245,7 +245,7 @@ struct atl1c_tpd_ext_desc { #define RRS_PACKET_TYPE_802_3 1 #define RRS_PACKET_TYPE_ETH 0 #define RRS_PACKET_IS_ETH(word) \ - (((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK == \ + ((((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK) == \ RRS_PACKET_TYPE_ETH) #define RRS_RXD_IS_VALID(word) \ ((((word) >> RRS_RXD_UPDATED_SHIFT) & RRS_RXD_UPDATED_MASK) == 1) -- cgit v0.10.2 From 37b76c697f4ac082e9923dfa8e8aecc8bc54a8e1 Mon Sep 17 00:00:00 2001 From: roel kluin Date: Sun, 12 Jul 2009 12:57:38 +0000 Subject: atl1c: misplaced parenthesis Fix misplaced parenthesis Signed-off-by: Roel Kluin Signed-off-by: David S. Miller diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c index cd547a2..a383122 100644 --- a/drivers/net/atl1c/atl1c_main.c +++ b/drivers/net/atl1c/atl1c_main.c @@ -1689,7 +1689,7 @@ static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que, if (likely(RRS_RXD_IS_VALID(rrs->word3))) { rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) & RRS_RX_RFD_CNT_MASK; - if (unlikely(rfd_num) != 1) + if (unlikely(rfd_num != 1)) /* TODO support mul rfd*/ if (netif_msg_rx_err(adapter)) dev_warn(&pdev->dev, -- cgit v0.10.2 From e36b9d16c6a6d0f59803b3ef04ff3c22c3844c10 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 15 Jul 2009 04:56:31 +0000 Subject: bonding: clean muticast addresses when device changes type Bonding device forbids slave device of different types under the same master. However, it is possible for a bonding master to change type during its lifetime. This can be either from ARPHRD_ETHER to ARPHRD_INFINIBAND or the other way arround. The change of type requires device level multicast address cleanup because device level multicast addresses depend on the device type. The patch adds a call to dev_close() before the bonding master changes type and dev_open() just after that. In the example below I enslaved an IPoIB device (ib0) under bond0. Since each bonding master starts as device of type ARPHRD_ETHER by default, a change of type occurs when ib0 is enslaved. This is how /proc/net/dev_mcast looks like without the patch 5 bond0 1 0 00ffffffff12601bffff000000000001ff96ca05 5 bond0 1 0 01005e000116 5 bond0 1 0 01005e7ffffd 5 bond0 1 0 01005e000001 5 bond0 1 0 333300000001 6 ib0 1 0 00ffffffff12601bffff000000000001ff96ca05 6 ib0 1 0 333300000001 6 ib0 1 0 01005e000001 6 ib0 1 0 01005e7ffffd 6 ib0 1 0 01005e000116 6 ib0 1 0 00ffffffff12401bffff00000000000000000001 6 ib0 1 0 00ffffffff12601bffff00000000000000000001 and this is how it looks like after the patch. 5 bond0 1 0 00ffffffff12601bffff000000000001ff96ca05 5 bond0 1 0 00ffffffff12601bffff00000000000000000001 5 bond0 1 0 00ffffffff12401bffff0000000000000ffffffd 5 bond0 1 0 00ffffffff12401bffff00000000000000000116 5 bond0 1 0 00ffffffff12401bffff00000000000000000001 6 ib0 1 0 00ffffffff12601bffff000000000001ff96ca05 6 ib0 1 0 00ffffffff12401bffff00000000000000000116 6 ib0 1 0 00ffffffff12401bffff0000000000000ffffffd 6 ib0 2 0 00ffffffff12401bffff00000000000000000001 6 ib0 2 0 00ffffffff12601bffff00000000000000000001 Signed-off-by: Moni Shoua Signed-off-by: Jay Vosburgh Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d927f71..aa1be1f 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1459,8 +1459,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * ether type (eg ARPHRD_ETHER and ARPHRD_INFINIBAND) share the same bond */ if (bond->slave_cnt == 0) { - if (slave_dev->type != ARPHRD_ETHER) - bond_setup_by_slave(bond_dev, slave_dev); + if (bond_dev->type != slave_dev->type) { + dev_close(bond_dev); + pr_debug("%s: change device type from %d to %d\n", + bond_dev->name, bond_dev->type, slave_dev->type); + if (slave_dev->type != ARPHRD_ETHER) + bond_setup_by_slave(bond_dev, slave_dev); + else + ether_setup(bond_dev); + dev_open(bond_dev); + } } else if (bond_dev->type != slave_dev->type) { pr_err(DRV_NAME ": %s ether type (%d) is different " "from other slaves (%d), can not enslave it.\n", -- cgit v0.10.2 From 303d67c288319768b19ed8dbed429fef7eb7c275 Mon Sep 17 00:00:00 2001 From: Krzysztof Halasa Date: Tue, 14 Jul 2009 11:01:54 +0000 Subject: E100: work around the driver using streaming DMA mapping for RX descriptors. E100 places it's RX packet descriptors inside skb->data and uses them with bidirectional streaming DMA mapping. Unfortunately it fails to transfer skb->data ownership to the device after it reads the descriptor's status, breaking on non-coherent (e.g., ARM) platforms. This have to be converted to use coherent memory for the descriptors. Signed-off-by: Krzysztof Halasa Acked-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/e100.c b/drivers/net/e100.c index efa680f..41b648a 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1897,6 +1897,9 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, if (ioread8(&nic->csr->scb.status) & rus_no_res) nic->ru_running = RU_SUSPENDED; + pci_dma_sync_single_for_device(nic->pdev, rx->dma_addr, + sizeof(struct rfd), + PCI_DMA_BIDIRECTIONAL); return -ENODATA; } -- cgit v0.10.2 From 4dc6dc7162c08b9965163c9ab3f9375d4adff2c7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 15 Jul 2009 23:13:10 +0000 Subject: net: sock_copy() fixes Commit e912b1142be8f1e2c71c71001dc992c6e5eb2ec1 (net: sk_prot_alloc() should not blindly overwrite memory) took care of not zeroing whole new socket at allocation time. sock_copy() is another spot where we should be very careful. We should not set refcnt to a non null value, until we are sure other fields are correctly setup, or a lockless reader could catch this socket by mistake, while not fully (re)initialized. This patch puts sk_node & sk_refcnt to the very beginning of struct sock to ease sock_copy() & sk_prot_alloc() job. We add appropriate smp_wmb() before sk_refcnt initializations to match our RCU requirements (changes to sock keys should be committed to memory before sk_refcnt setting) Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/include/net/sock.h b/include/net/sock.h index 2c0da92..950409d 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -104,15 +104,15 @@ struct net; /** * struct sock_common - minimal network layer representation of sockets + * @skc_node: main hash linkage for various protocol lookup tables + * @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol + * @skc_refcnt: reference count + * @skc_hash: hash value used with various protocol lookup tables * @skc_family: network address family * @skc_state: Connection state * @skc_reuse: %SO_REUSEADDR setting * @skc_bound_dev_if: bound device index if != 0 - * @skc_node: main hash linkage for various protocol lookup tables - * @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol * @skc_bind_node: bind hash linkage for various protocol lookup tables - * @skc_refcnt: reference count - * @skc_hash: hash value used with various protocol lookup tables * @skc_prot: protocol handlers inside a network family * @skc_net: reference to the network namespace of this socket * @@ -120,17 +120,21 @@ struct net; * for struct sock and struct inet_timewait_sock. */ struct sock_common { - unsigned short skc_family; - volatile unsigned char skc_state; - unsigned char skc_reuse; - int skc_bound_dev_if; + /* + * first fields are not copied in sock_copy() + */ union { struct hlist_node skc_node; struct hlist_nulls_node skc_nulls_node; }; - struct hlist_node skc_bind_node; atomic_t skc_refcnt; + unsigned int skc_hash; + unsigned short skc_family; + volatile unsigned char skc_state; + unsigned char skc_reuse; + int skc_bound_dev_if; + struct hlist_node skc_bind_node; struct proto *skc_prot; #ifdef CONFIG_NET_NS struct net *skc_net; @@ -208,15 +212,17 @@ struct sock { * don't add nothing before this first member (__sk_common) --acme */ struct sock_common __sk_common; +#define sk_node __sk_common.skc_node +#define sk_nulls_node __sk_common.skc_nulls_node +#define sk_refcnt __sk_common.skc_refcnt + +#define sk_copy_start __sk_common.skc_hash +#define sk_hash __sk_common.skc_hash #define sk_family __sk_common.skc_family #define sk_state __sk_common.skc_state #define sk_reuse __sk_common.skc_reuse #define sk_bound_dev_if __sk_common.skc_bound_dev_if -#define sk_node __sk_common.skc_node -#define sk_nulls_node __sk_common.skc_nulls_node #define sk_bind_node __sk_common.skc_bind_node -#define sk_refcnt __sk_common.skc_refcnt -#define sk_hash __sk_common.skc_hash #define sk_prot __sk_common.skc_prot #define sk_net __sk_common.skc_net kmemcheck_bitfield_begin(flags); diff --git a/net/core/sock.c b/net/core/sock.c index ba5d211..d9eec15 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -919,13 +919,19 @@ static inline void sock_lock_init(struct sock *sk) af_family_keys + sk->sk_family); } +/* + * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet, + * even temporarly, because of RCU lookups. sk_node should also be left as is. + */ static void sock_copy(struct sock *nsk, const struct sock *osk) { #ifdef CONFIG_SECURITY_NETWORK void *sptr = nsk->sk_security; #endif - - memcpy(nsk, osk, osk->sk_prot->obj_size); + BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) != + sizeof(osk->sk_node) + sizeof(osk->sk_refcnt)); + memcpy(&nsk->sk_copy_start, &osk->sk_copy_start, + osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start)); #ifdef CONFIG_SECURITY_NETWORK nsk->sk_security = sptr; security_sk_clone(osk, nsk); @@ -1140,6 +1146,11 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) newsk->sk_err = 0; newsk->sk_priority = 0; + /* + * Before updating sk_refcnt, we must commit prior changes to memory + * (Documentation/RCU/rculist_nulls.txt for details) + */ + smp_wmb(); atomic_set(&newsk->sk_refcnt, 2); /* @@ -1855,6 +1866,11 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_stamp = ktime_set(-1L, 0); + /* + * Before updating sk_refcnt, we must commit prior changes to memory + * (Documentation/RCU/rculist_nulls.txt for details) + */ + smp_wmb(); atomic_set(&sk->sk_refcnt, 1); atomic_set(&sk->sk_wmem_alloc, 1); atomic_set(&sk->sk_drops, 0); -- cgit v0.10.2 From 3d1454dd93e84ad1394b6b1646f13795e9f6928e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 16 Jul 2009 13:20:57 +0000 Subject: sky2: revert shutdown changes The commit changes to shutdown path broke startup on some systems. revert commit c0bad0f2e4366d5bbfe0c4a7a80bca8f4b05272b Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index daf961a..ba768df 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1151,14 +1151,7 @@ stopped: /* reset the Rx prefetch unit */ sky2_write32(hw, Y2_QADDR(rxq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); - - /* Reset the RAM Buffer receive queue */ - sky2_write8(hw, RB_ADDR(rxq, RB_CTRL), RB_RST_SET); - - /* Reset Rx MAC FIFO */ - sky2_write8(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), GMF_RST_SET); - - sky2_read8(hw, B0_CTST); + mmiowb(); } /* Clean out receive buffer area, assumes receiver hardware stopped */ -- cgit v0.10.2 From 86e713a06ab3e5b15a3189485ce33aa21b9e52ca Mon Sep 17 00:00:00 2001 From: Lucy Liu Date: Thu, 16 Jul 2009 13:43:10 +0000 Subject: ixgbe: clear mac address data block in DCB mode This change clears the address data block memory space, which is needed for the 82598 which does not have a SAN MAC. Signed-off-by: Lucy Liu Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 7c5978a..5b8dab2 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -175,6 +175,8 @@ static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); int i, j; + memset(perm_addr, 0xff, MAX_ADDR_LEN); + for (i = 0; i < netdev->addr_len; i++) perm_addr[i] = adapter->hw.mac.perm_addr[i]; -- cgit v0.10.2 From 869f1c54e9aecde1dfd4349832ce9415a596be8e Mon Sep 17 00:00:00 2001 From: Lucy Liu Date: Thu, 16 Jul 2009 13:43:31 +0000 Subject: ixgbe: Remove DPRINTK messages in DCB mode Remove debug DPRINTK in DCB mode netlink interface. Signed-off-by: Lucy Liu Acked-by: Peter P Waskiewicz Jr Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 5b8dab2..da2c851 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -106,8 +106,6 @@ static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); - DPRINTK(DRV, INFO, "Get DCB Admin Mode.\n"); - return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); } @@ -116,8 +114,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) u8 err = 0; struct ixgbe_adapter *adapter = netdev_priv(netdev); - DPRINTK(DRV, INFO, "Set DCB Admin Mode.\n"); - if (state > 0) { /* Turn on DCB */ if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) -- cgit v0.10.2 From 7fefe6a88494b00b151b5ca7bb84daaa781bbca7 Mon Sep 17 00:00:00 2001 From: Vincent CUISSARD Date: Thu, 16 Jul 2009 06:08:58 +0000 Subject: cdc-eem: bad crc checking When the driver received an EEM packet with CRC option enabled, driver must compute and check the CRC of the Ethernet data. Previous version computes CRC on Ethernet data plus the original CRC value. Skbuff is correctly trimed but the old length is used when CRC is computed. Signed-off-by: Vincent CUISSARD Signed-off-by: David S. Miller diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index cd35d50..45cebfb 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -311,7 +311,7 @@ static int eem_rx_fixup(struct usbnet *dev, struct sk_buff *skb) * bmCRC = 0 : CRC = 0xDEADBEEF */ if (header & BIT(14)) - crc2 = ~crc32_le(~0, skb2->data, len); + crc2 = ~crc32_le(~0, skb2->data, skb2->len); else crc2 = 0xdeadbeef; -- cgit v0.10.2