The following commit has been merged in the master branch: commit 06f4e926d256d902dd9a53dcb400fd74974ce087 Merge: 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 d93515611bbc70c2fe4db232e5feb448ed8e4cc9 Author: Linus Torvalds torvalds@linux-foundation.org Date: Fri May 20 13:43:21 2011 -0700
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits) macvlan: fix panic if lowerdev in a bond tg3: Add braces around 5906 workaround. tg3: Fix NETIF_F_LOOPBACK error macvlan: remove one synchronize_rcu() call networking: NET_CLS_ROUTE4 depends on INET irda: Fix error propagation in ircomm_lmp_connect_response() irda: Kill set but unused variable 'bytes' in irlan_check_command_param() irda: Kill set but unused variable 'clen' in ircomm_connect_indication() rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport() be2net: Kill set but unused variable 'req' in lancer_fw_download() irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication() atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined. rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer(). rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler() rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection() rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window() pkt_sched: Kill set but unused variable 'protocol' in tc_classify() isdn: capi: Use pr_debug() instead of ifdefs. tg3: Update version to 3.119 tg3: Apply rx_discards fix to 5719/5720 ...
Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c as per Davem.
diff --combined Documentation/feature-removal-schedule.txt index f6a24e8,46679e4..4cba260 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@@ -35,17 -35,6 +35,6 @@@ Who: Luis R. Rodriguez <lrodriguez@athe
---------------------------
- What: AR9170USB - When: 2.6.40 - - Why: This driver is deprecated and the firmware is no longer - maintained. The replacement driver "carl9170" has been - around for a while, so the devices are still supported. - - Who: Christian Lamparter chunkeey@googlemail.com - - --------------------------- - What: IRQF_SAMPLE_RANDOM Check: IRQF_SAMPLE_RANDOM When: July 2009 @@@ -387,6 -376,26 +376,6 @@@ Who: Tejun Heo <tj@kernel.org
----------------------------
-What: Support for lcd_switch and display_get in asus-laptop driver -When: March 2010 -Why: These two features use non-standard interfaces. There are the - only features that really need multiple path to guess what's - the right method name on a specific laptop. - - Removing them will allow to remove a lot of code an significantly - clean the drivers. - - This will affect the backlight code which won't be able to know - if the backlight is on or off. The platform display file will also be - write only (like the one in eeepc-laptop). - - This should'nt affect a lot of user because they usually know - when their display is on or off. - -Who: Corentin Chary corentin.chary@gmail.com - ----------------------------- - What: sysfs-class-rfkill state file When: Feb 2014 Files: net/rfkill/core.c @@@ -405,16 -414,6 +394,6 @@@ Who: anybody or Florian Mickler <flori
----------------------------
- What: capifs - When: February 2011 - Files: drivers/isdn/capi/capifs.* - Why: udev fully replaces this special file system that only contains CAPI - NCCI TTY device nodes. User space (pppdcapiplugin) works without - noticing the difference. - Who: Jan Kiszka jan.kiszka@web.de - - ---------------------------- - What: KVM paravirt mmu host support When: January 2011 Why: The paravirt mmu host support is slower than non-paravirt mmu, both @@@ -460,6 -459,14 +439,6 @@@ Who: Thomas Gleixner <tglx@linutronix.d
----------------------------
-What: The acpi_sleep=s4_nonvs command line option -When: 2.6.37 -Files: arch/x86/kernel/acpi/sleep.c -Why: superseded by acpi_sleep=nonvs -Who: Rafael J. Wysocki rjw@sisk.pl - ----------------------------- - What: PCI DMA unmap state API When: August 2012 Why: PCI DMA unmap state API (include/linux/pci-dma.h) was replaced diff --combined MAINTAINERS index d76d63a,e23cbd1..49a0bf3 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -185,9 -185,10 +185,9 @@@ F: Documentation/filesystems/9p.tx F: fs/9p/
A2232 SERIAL BOARD DRIVER -M: Enver Haase A2232@gmx.net L: linux-m68k@lists.linux-m68k.org -S: Maintained -F: drivers/char/ser_a2232* +S: Orphan +F: drivers/staging/generic_serial/ser_a2232*
AACRAID SCSI RAID DRIVER M: Adaptec OEM Raid Solutions aacraid@adaptec.com @@@ -405,8 -406,8 +405,8 @@@ S: Maintaine F: sound/oss/aedsp16.c
AFFS FILE SYSTEM -M: Roman Zippel zippel@linux-m68k.org -S: Maintained +L: linux-fsdevel@vger.kernel.org +S: Orphan F: Documentation/filesystems/affs.txt F: fs/affs/
@@@ -877,13 -878,6 +877,13 @@@ F: arch/arm/mach-mv78xx0 F: arch/arm/mach-orion5x/ F: arch/arm/plat-orion/
+ARM/Orion SoC/Technologic Systems TS-78xx platform support +M: Alexander Clouter alex@digriz.org.uk +L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) +W: http://www.digriz.org.uk/ts78xx/kernel +S: Maintained +F: arch/arm/mach-orion5x/ts78xx-* + ARM/MIOA701 MACHINE SUPPORT M: Robert Jarzmik robert.jarzmik@free.fr L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) @@@ -1032,13 -1026,12 +1032,13 @@@ W: http://www.fluff.org/ben/linux S: Maintained F: arch/arm/mach-s3c64xx/
-ARM/S5P ARM ARCHITECTURES +ARM/S5P EXYNOS ARM ARCHITECTURES M: Kukjin Kim kgene.kim@samsung.com L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) S: Maintained F: arch/arm/mach-s5p*/ +F: arch/arm/mach-exynos*/
ARM/SAMSUNG MOBILE MACHINE SUPPORT M: Kyungmin Park kyungmin.park@samsung.com @@@ -1071,7 -1064,7 +1071,7 @@@ F: arch/arm/mach-shmobile F: drivers/sh/
ARM/TELECHIPS ARM ARCHITECTURE -M: "Hans J. Koch" hjk@linutronix.de +M: "Hans J. Koch" hjk@hansjkoch.de L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Maintained F: arch/arm/plat-tcc/ @@@ -1232,13 -1225,6 +1232,6 @@@ W: http://wireless.kernel.org/en/users/ S: Supported F: drivers/net/wireless/ath/ath9k/
- ATHEROS AR9170 WIRELESS DRIVER - M: Christian Lamparter chunkeey@web.de - L: linux-wireless@vger.kernel.org - W: http://wireless.kernel.org/en/users/Drivers/ar9170 - S: Obsolete - F: drivers/net/wireless/ath/ar9170/ - CARL9170 LINUX COMMUNITY WIRELESS DRIVER M: Christian Lamparter chunkeey@googlemail.com L: linux-wireless@vger.kernel.org @@@ -1831,10 -1817,11 +1824,10 @@@ S: Maintaine F: drivers/platform/x86/compal-laptop.c
COMPUTONE INTELLIPORT MULTIPORT CARD -M: "Michael H. Warfield" mhw@wittsend.com W: http://www.wittsend.com/computone.html -S: Maintained +S: Orphan F: Documentation/serial/computone.txt -F: drivers/char/ip2/ +F: drivers/staging/tty/ip2/
CONEXANT ACCESSRUNNER USB DRIVER M: Simon Arlott cxacru@fire.lp0.eu @@@ -2017,7 -2004,7 +2010,7 @@@ F: drivers/net/wan/cycx CYCLADES ASYNC MUX DRIVER W: http://www.cyclades.com/ S: Orphan -F: drivers/char/cyclades.c +F: drivers/tty/cyclades.c F: include/linux/cyclades.h
CYCLADES PC300 DRIVER @@@ -2131,8 -2118,8 +2124,8 @@@ L: Eng.Linux@digi.co W: http://www.digi.com S: Orphan F: Documentation/serial/digiepca.txt -F: drivers/char/epca* -F: drivers/char/digi* +F: drivers/staging/tty/epca* +F: drivers/staging/tty/digi*
DIOLAN U2C-12 I2C DRIVER M: Guenter Roeck guenter.roeck@ericsson.com @@@ -2809,23 -2796,42 +2802,23 @@@ GPIO SUBSYSTE M: Grant Likely grant.likely@secretlab.ca S: Maintained T: git git://git.secretlab.ca/git/linux-2.6.git -F: Documentation/gpio/gpio.txt +F: Documentation/gpio.txt F: drivers/gpio/ F: include/linux/gpio*
+GRE DEMULTIPLEXER DRIVER +M: Dmitry Kozlov xeb@mail.ru +L: netdev@vger.kernel.org +S: Maintained +F: net/ipv4/gre.c +F: include/net/gre.h + GRETH 10/100/1G Ethernet MAC device driver M: Kristoffer Glembo kristoffer@gaisler.com L: netdev@vger.kernel.org S: Maintained F: drivers/net/greth*
-HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER -M: Frank Seidel frank@f-seidel.de -L: platform-driver-x86@vger.kernel.org -W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ -S: Maintained -F: drivers/platform/x86/hdaps.c - -HWPOISON MEMORY FAILURE HANDLING -M: Andi Kleen andi@firstfloor.org -L: linux-mm@kvack.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison -S: Maintained -F: mm/memory-failure.c -F: mm/hwpoison-inject.c - -HYPERVISOR VIRTUAL CONSOLE DRIVER -L: linuxppc-dev@lists.ozlabs.org -S: Odd Fixes -F: drivers/tty/hvc/ - -iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER -M: Peter Jones pjones@redhat.com -M: Konrad Rzeszutek Wilk konrad@kernel.org -S: Maintained -F: drivers/firmware/iscsi_ibft* - GSPCA FINEPIX SUBDRIVER M: Frank Zago frank@zago.net L: linux-media@vger.kernel.org @@@ -2876,26 -2882,6 +2869,26 @@@ T: git git://git.kernel.org/pub/scm/lin S: Maintained F: drivers/media/video/gspca/
+HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER +M: Frank Seidel frank@f-seidel.de +L: platform-driver-x86@vger.kernel.org +W: http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/ +S: Maintained +F: drivers/platform/x86/hdaps.c + +HWPOISON MEMORY FAILURE HANDLING +M: Andi Kleen andi@firstfloor.org +L: linux-mm@kvack.org +T: git git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6.git hwpoison +S: Maintained +F: mm/memory-failure.c +F: mm/hwpoison-inject.c + +HYPERVISOR VIRTUAL CONSOLE DRIVER +L: linuxppc-dev@lists.ozlabs.org +S: Odd Fixes +F: drivers/tty/hvc/ + HARDWARE MONITORING M: Jean Delvare khali@linux-fr.org M: Guenter Roeck guenter.roeck@ericsson.com @@@ -2946,8 -2932,8 +2939,8 @@@ F: drivers/block/cciss F: include/linux/cciss_ioctl.h
HFS FILESYSTEM -M: Roman Zippel zippel@linux-m68k.org -S: Maintained +L: linux-fsdevel@vger.kernel.org +S: Orphan F: Documentation/filesystems/hfs.txt F: fs/hfs/
@@@ -3363,6 -3349,12 +3356,12 @@@ F: Documentation/wimax/README.i2400 F: drivers/net/wimax/i2400m/ F: include/linux/wimax/i2400m.h
+ INTEL WIRELESS 3945ABG/BG, 4965AGN (iwlegacy) + M: Stanislaw Gruszka sgruszka@redhat.com + L: linux-wireless@vger.kernel.org + S: Supported + F: drivers/net/wireless/iwlegacy/ + INTEL WIRELESS WIFI LINK (iwlwifi) M: Wey-Yi Guy wey-yi.w.guy@intel.com M: Intel Linux Wireless ilw@linux.intel.com @@@ -3479,12 -3471,6 +3478,12 @@@ F: Documentation/isapnp.tx F: drivers/pnp/isapnp/ F: include/linux/isapnp.h
+iSCSI BOOT FIRMWARE TABLE (iBFT) DRIVER +M: Peter Jones pjones@redhat.com +M: Konrad Rzeszutek Wilk konrad@kernel.org +S: Maintained +F: drivers/firmware/iscsi_ibft* + ISCSI M: Mike Christie michaelc@cs.wisc.edu L: open-iscsi@googlegroups.com @@@ -3814,7 -3800,7 +3813,7 @@@ M: Rusty Russell <rusty@rustcorp.com.au L: lguest@lists.ozlabs.org W: http://lguest.ozlabs.org/ S: Odd Fixes -F: Documentation/lguest/ +F: Documentation/virtual/lguest/ F: arch/x86/lguest/ F: drivers/lguest/ F: include/linux/lguest*.h @@@ -4001,6 -3987,7 +4000,6 @@@ F: arch/m32r
M68K ARCHITECTURE M: Geert Uytterhoeven geert@linux-m68k.org -M: Roman Zippel zippel@linux-m68k.org L: linux-m68k@lists.linux-m68k.org W: http://www.linux-m68k.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/geert/linux-m68k.git @@@ -4090,7 -4077,7 +4089,7 @@@ F: drivers/video/matrox/matroxfb_ F: include/linux/matroxfb.h
MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER -M: "Hans J. Koch" hjk@linutronix.de +M: "Hans J. Koch" hjk@hansjkoch.de L: lm-sensors@lm-sensors.org S: Maintained F: Documentation/hwmon/max6650 @@@ -4205,7 -4192,7 +4204,7 @@@ MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL C M: Jiri Slaby jirislaby@gmail.com S: Maintained F: Documentation/serial/moxa-smartio -F: drivers/char/mxser.* +F: drivers/tty/mxser.*
MSI LAPTOP SUPPORT M: "Lee, Chun-Yi" jlee@novell.com @@@ -4247,7 -4234,7 +4246,7 @@@ F: sound/oss/msnd
MULTITECH MULTIPORT CARD (ISICOM) S: Orphan -F: drivers/char/isicom.c +F: drivers/tty/isicom.c F: include/linux/isicom.h
MUSB MULTIPOINT HIGH SPEED DUAL-ROLE CONTROLLER @@@ -4385,6 -4372,7 +4384,7 @@@ S: Maintaine F: net/ipv4/ F: net/ipv6/ F: include/net/ip* + F: arch/x86/net/*
NETWORKING [LABELED] (NetLabel, CIPSO, Labeled IPsec, SECMARK) M: Paul Moore paul.moore@hp.com @@@ -4995,13 -4983,6 +4995,13 @@@ F: Documentation/pps F: drivers/pps/ F: include/linux/pps*.h
+PPTP DRIVER +M: Dmitry Kozlov xeb@mail.ru +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/pptp.c +W: http://sourceforge.net/projects/accel-pptp + PREEMPTIBLE KERNEL M: Robert Love rml@tech9.net L: kpreempt-tech@lists.sourceforge.net @@@ -5293,14 -5274,14 +5293,14 @@@ F: drivers/memstick/host/r592. RISCOM8 DRIVER S: Orphan F: Documentation/serial/riscom8.txt -F: drivers/char/riscom8* +F: drivers/staging/tty/riscom8*
ROCKETPORT DRIVER P: Comtrol Corp. W: http://www.comtrol.com S: Maintained F: Documentation/serial/rocket.txt -F: drivers/char/rocket* +F: drivers/tty/rocket*
ROSE NETWORK LAYER M: Ralf Baechle ralf@linux-mips.org @@@ -5410,7 -5391,7 +5410,7 @@@ F: drivers/media/video/*7146 F: include/media/*7146*
SAMSUNG AUDIO (ASoC) DRIVERS -M: Jassi Brar jassi.brar@samsung.com +M: Jassi Brar jassisinghbrar@gmail.com L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/samsung @@@ -5431,7 -5412,6 +5431,7 @@@ F: include/linux/timex. F: kernel/time/clocksource.c F: kernel/time/time*.c F: kernel/time/ntp.c +F: drivers/clocksource
TLG2300 VIDEO4LINUX-2 DRIVER M: Huang Shijie shijie8@gmail.com @@@ -5612,9 -5592,9 +5612,9 @@@ F: include/linux/ata. F: include/linux/libata.h
SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER -M: Jayamohan Kallickal jayamohank@serverengines.com +M: Jayamohan Kallickal jayamohan.kallickal@emulex.com L: linux-scsi@vger.kernel.org -W: http://www.serverengines.com +W: http://www.emulex.com S: Supported F: drivers/scsi/be2iscsi/
@@@ -5832,6 -5812,13 +5832,13 @@@ S: Maintaine F: drivers/ssb/ F: include/linux/ssb/
+ BROADCOM SPECIFIC AMBA DRIVER (BCMA) + M: Rafał Miłecki zajec5@gmail.com + L: linux-wireless@vger.kernel.org + S: Maintained + F: drivers/bcma/ + F: include/linux/bcma/ + SONY VAIO CONTROL DEVICE DRIVER M: Mattia Dongili malattia@linux.it L: platform-driver-x86@vger.kernel.org @@@ -5937,9 -5924,10 +5944,9 @@@ F: arch/arm/mach-spear6xx/spear600. F: arch/arm/mach-spear6xx/spear600_evb.c
SPECIALIX IO8+ MULTIPORT SERIAL CARD DRIVER -M: Roger Wolff R.E.Wolff@BitWizard.nl -S: Supported +S: Orphan F: Documentation/serial/specialix.txt -F: drivers/char/specialix* +F: drivers/staging/tty/specialix*
SPI SUBSYSTEM M: David Brownell dbrownell@users.sourceforge.net @@@ -5984,6 -5972,7 +5991,6 @@@ F: arch/alpha/kernel/srm_env.
STABLE BRANCH M: Greg Kroah-Hartman greg@kroah.com -M: Chris Wright chrisw@sous-sol.org L: stable@kernel.org S: Maintained
@@@ -6267,8 -6256,7 +6274,8 @@@ M: Greg Ungerer <gerg@uclinux.org W: http://www.uclinux.org/ L: uclinux-dev@uclinux.org (subscribers-only) S: Maintained -F: arch/m68knommu/ +F: arch/m68k/*/*_no.* +F: arch/m68k/include/asm/*_no.*
UCLINUX FOR RENESAS H8/300 (H8300) M: Yoshinori Sato ysato@users.sourceforge.jp @@@ -6632,13 -6620,13 +6639,13 @@@ L: user-mode-linux-devel@lists.sourcefo L: user-mode-linux-user@lists.sourceforge.net W: http://user-mode-linux.sourceforge.net S: Maintained -F: Documentation/uml/ +F: Documentation/virtual/uml/ F: arch/um/ F: fs/hostfs/ F: fs/hppfs/
USERSPACE I/O (UIO) -M: "Hans J. Koch" hjk@linutronix.de +M: "Hans J. Koch" hjk@hansjkoch.de M: Greg Kroah-Hartman gregkh@suse.de S: Maintained F: Documentation/DocBook/uio-howto.tmpl @@@ -6936,18 -6924,6 +6943,18 @@@ T: git git://git.kernel.org/pub/scm/lin S: Maintained F: drivers/platform/x86
+XEN HYPERVISOR INTERFACE +M: Jeremy Fitzhardinge jeremy.fitzhardinge@citrix.com +M: Konrad Rzeszutek Wilk konrad.wilk@oracle.com +L: xen-devel@lists.xensource.com (moderated for non-subscribers) +L: virtualization@lists.linux-foundation.org +S: Supported +F: arch/x86/xen/ +F: drivers/*/xen-*front.c +F: drivers/xen/ +F: arch/x86/include/asm/xen/ +F: include/xen/ + XEN NETWORK BACKEND DRIVER M: Ian Campbell ian.campbell@citrix.com L: xen-devel@lists.xensource.com (moderated for non-subscribers) @@@ -6969,6 -6945,18 +6976,6 @@@ S: Supporte F: arch/x86/xen/*swiotlb* F: drivers/xen/*swiotlb*
-XEN HYPERVISOR INTERFACE -M: Jeremy Fitzhardinge jeremy.fitzhardinge@citrix.com -M: Konrad Rzeszutek Wilk konrad.wilk@oracle.com -L: xen-devel@lists.xensource.com (moderated for non-subscribers) -L: virtualization@lists.linux-foundation.org -S: Supported -F: arch/x86/xen/ -F: drivers/*/xen-*front.c -F: drivers/xen/ -F: arch/x86/include/asm/xen/ -F: include/xen/ - XFS FILESYSTEM P: Silicon Graphics Inc M: Alex Elder aelder@sgi.com @@@ -7038,6 -7026,20 +7045,6 @@@ M: "Maciej W. Rozycki" <macro@linux-mip S: Maintained F: drivers/tty/serial/zs.*
-GRE DEMULTIPLEXER DRIVER -M: Dmitry Kozlov xeb@mail.ru -L: netdev@vger.kernel.org -S: Maintained -F: net/ipv4/gre.c -F: include/net/gre.h - -PPTP DRIVER -M: Dmitry Kozlov xeb@mail.ru -L: netdev@vger.kernel.org -S: Maintained -F: drivers/net/pptp.c -W: http://sourceforge.net/projects/accel-pptp - THE REST M: Linus Torvalds torvalds@linux-foundation.org L: linux-kernel@vger.kernel.org diff --combined arch/x86/Kconfig index 4168e5d,2096cf1..880fcb6 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@@ -8,7 -8,6 +8,7 @@@ config 64BI
config X86_32 def_bool !64BIT + select CLKSRC_I8253
config X86_64 def_bool 64BIT @@@ -72,6 -71,8 +72,7 @@@ config X8 select GENERIC_IRQ_SHOW select IRQ_FORCED_THREADING select USE_GENERIC_SMP_HELPERS if SMP - select ARCH_NO_SYSDEV_OPS + select HAVE_BPF_JIT if (X86_64 && NET)
config INSTRUCTION_DECODER def_bool (KPROBES || PERF_EVENTS) @@@ -112,14 -113,7 +113,14 @@@ config MM def_bool y
config ZONE_DMA - def_bool y + bool "DMA memory allocation support" if EXPERT + default y + help + DMA memory allocation support allows devices with less than 32-bit + addressing to allocate within the first 16MB of address space. + Disable if no such devices will be used. + + If unsure, say Y.
config SBUS bool @@@ -372,6 -366,17 +373,6 @@@ config X86_U # Following is an alphabetically sorted list of 32 bit extended platforms # Please maintain the alphabetic order if and when there are additions
-config X86_ELAN - bool "AMD Elan" - depends on X86_32 - depends on X86_EXTENDED_PLATFORM - ---help--- - Select this for an AMD Elan processor. - - Do not use this option for K6/Athlon/Opteron processors! - - If unsure, choose "PC-compatible" instead. - config X86_INTEL_CE bool "CE4100 TV platform" depends on PCI @@@ -686,7 -691,6 +687,7 @@@ config AMD_IOMM bool "AMD IOMMU support" select SWIOTLB select PCI_MSI + select PCI_IOV depends on X86_64 && PCI && ACPI ---help--- With this option you can enable support for AMD IOMMU hardware in @@@ -1171,7 -1175,7 +1172,7 @@@ comment "NUMA (Summit) requires SMP, 64 config AMD_NUMA def_bool y prompt "Old style AMD Opteron NUMA detection" - depends on X86_64 && NUMA && PCI + depends on NUMA && PCI ---help--- Enable AMD NUMA node topology detection. You should say Y here if you have a multi processor AMD system. This uses an old method to @@@ -1198,7 -1202,7 +1199,7 @@@ config NODES_SPAN_OTHER_NODE
config NUMA_EMU bool "NUMA emulation" - depends on X86_64 && NUMA + depends on NUMA ---help--- Enable NUMA emulation. A flat machine will be split into virtual nodes when booted with "numa=fake=N", where N is the @@@ -1220,10 -1224,6 +1221,10 @@@ config HAVE_ARCH_BOOTME def_bool y depends on X86_32 && NUMA
+config HAVE_ARCH_ALLOC_REMAP + def_bool y + depends on X86_32 && NUMA + config ARCH_HAVE_MEMORY_PRESENT def_bool y depends on X86_32 && DISCONTIGMEM @@@ -1232,9 -1232,13 +1233,9 @@@ config NEED_NODE_MEMMAP_SIZ def_bool y depends on X86_32 && (DISCONTIGMEM || SPARSEMEM)
-config HAVE_ARCH_ALLOC_REMAP - def_bool y - depends on X86_32 && NUMA - config ARCH_FLATMEM_ENABLE def_bool y - depends on X86_32 && ARCH_SELECT_MEMORY_MODEL && !NUMA + depends on X86_32 && !NUMA
config ARCH_DISCONTIGMEM_ENABLE def_bool y @@@ -1244,16 -1248,20 +1245,16 @@@ config ARCH_DISCONTIGMEM_DEFAUL def_bool y depends on NUMA && X86_32
-config ARCH_PROC_KCORE_TEXT - def_bool y - depends on X86_64 && PROC_KCORE - -config ARCH_SPARSEMEM_DEFAULT - def_bool y - depends on X86_64 - config ARCH_SPARSEMEM_ENABLE def_bool y depends on X86_64 || NUMA || (EXPERIMENTAL && X86_32) || X86_32_NON_STANDARD select SPARSEMEM_STATIC if X86_32 select SPARSEMEM_VMEMMAP_ENABLE if X86_64
+config ARCH_SPARSEMEM_DEFAULT + def_bool y + depends on X86_64 + config ARCH_SELECT_MEMORY_MODEL def_bool y depends on ARCH_SPARSEMEM_ENABLE @@@ -1262,10 -1270,6 +1263,10 @@@ config ARCH_MEMORY_PROB def_bool X86_64 depends on MEMORY_HOTPLUG
+config ARCH_PROC_KCORE_TEXT + def_bool y + depends on X86_64 && PROC_KCORE + config ILLEGAL_POINTER_VALUE hex default 0 if X86_32 @@@ -1700,6 -1704,10 +1701,6 @@@ config ARCH_ENABLE_MEMORY_HOTREMOV def_bool y depends on MEMORY_HOTPLUG
-config HAVE_ARCH_EARLY_PFN_TO_NID - def_bool X86_64 - depends on NUMA - config USE_PERCPU_NUMA_NODE_ID def_bool y depends on NUMA @@@ -1841,7 -1849,7 +1842,7 @@@ config APM_ALLOW_INT
endif # APM
-source "arch/x86/kernel/cpu/cpufreq/Kconfig" +source "drivers/cpufreq/Kconfig"
source "drivers/cpuidle/Kconfig"
@@@ -2069,7 -2077,7 +2070,7 @@@ config OLP depends on !X86_PAE select GPIOLIB select OF - select OF_PROMTREE if PROC_DEVICETREE + select OF_PROMTREE ---help--- Add support for detecting the unique features of the OLPC XO hardware. diff --combined drivers/Kconfig index 557a469,aca7067..61631ed --- a/drivers/Kconfig +++ b/drivers/Kconfig @@@ -68,6 -68,8 +68,8 @@@ source "drivers/watchdog/Kconfig
source "drivers/ssb/Kconfig"
+ source "drivers/bcma/Kconfig" + source "drivers/mfd/Kconfig"
source "drivers/regulator/Kconfig" @@@ -119,7 -121,4 +121,7 @@@ source "drivers/platform/Kconfig source "drivers/clk/Kconfig"
source "drivers/hwspinlock/Kconfig" + +source "drivers/clocksource/Kconfig" + endmenu diff --combined drivers/infiniband/hw/cxgb4/cm.c index d7ee70f,6aa53cd..f660cd0 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@@ -315,8 -315,9 +315,9 @@@ static struct rtable *find_route(struc __be16 peer_port, u8 tos) { struct rtable *rt; + struct flowi4 fl4;
- rt = ip_route_output_ports(&init_net, NULL, peer_ip, local_ip, + rt = ip_route_output_ports(&init_net, &fl4, NULL, peer_ip, local_ip, peer_port, local_port, IPPROTO_TCP, tos, 0); if (IS_ERR(rt)) @@@ -1198,7 -1199,9 +1199,7 @@@ static int pass_open_rpl(struct c4iw_de } PDBG("%s ep %p status %d error %d\n", __func__, ep, rpl->status, status2errno(rpl->status)); - ep->com.wr_wait.ret = status2errno(rpl->status); - ep->com.wr_wait.done = 1; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status));
return 0; } @@@ -1232,7 -1235,9 +1233,7 @@@ static int close_listsrv_rpl(struct c4i struct c4iw_listen_ep *ep = lookup_stid(t, stid);
PDBG("%s ep %p\n", __func__, ep); - ep->com.wr_wait.ret = status2errno(rpl->status); - ep->com.wr_wait.done = 1; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, status2errno(rpl->status)); return 0; }
@@@ -1462,7 -1467,7 +1463,7 @@@ static int peer_close(struct c4iw_dev * struct c4iw_qp_attributes attrs; int disconnect = 1; int release = 0; - int closing = 0; + int abort = 0; struct tid_info *t = dev->rdev.lldi.tids; unsigned int tid = GET_TID(hdr);
@@@ -1488,22 -1493,23 +1489,22 @@@ * in rdma connection migration (see c4iw_accept_cr()). */ __state_set(&ep->com, CLOSING); - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); break; case MPA_REP_SENT: __state_set(&ep->com, CLOSING); - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; PDBG("waking up ep %p tid %u\n", ep, ep->hwtid); - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET); break; case FPDU_MODE: start_ep_timer(ep); __state_set(&ep->com, CLOSING); - closing = 1; + attrs.next_state = C4IW_QP_STATE_CLOSING; + abort = c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, + C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); peer_close_upcall(ep); + disconnect = 1; break; case ABORTING: disconnect = 0; @@@ -1531,6 -1537,11 +1532,6 @@@ BUG_ON(1); } mutex_unlock(&ep->com.mutex); - if (closing) { - attrs.next_state = C4IW_QP_STATE_CLOSING; - c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, - C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); - } if (disconnect) c4iw_ep_disconnect(ep, 0, GFP_KERNEL); if (release) @@@ -1571,7 -1582,9 +1572,7 @@@ static int peer_abort(struct c4iw_dev * /* * Wake up any threads in rdma_init() or rdma_fini(). */ - ep->com.wr_wait.done = 1; - ep->com.wr_wait.ret = -ECONNRESET; - wake_up(&ep->com.wr_wait.wait); + c4iw_wake_up(&ep->com.wr_wait, -ECONNRESET);
mutex_lock(&ep->com.mutex); switch (ep->com.state) { @@@ -1698,14 -1711,14 +1699,14 @@@ static int terminate(struct c4iw_dev *d ep = lookup_tid(t, tid); BUG_ON(!ep);
- if (ep->com.qp) { + if (ep && ep->com.qp) { printk(KERN_WARNING MOD "TERM received tid %u qpid %u\n", tid, ep->com.qp->wq.sq.qid); attrs.next_state = C4IW_QP_STATE_TERMINATE; c4iw_modify_qp(ep->com.qp->rhp, ep->com.qp, C4IW_QP_ATTR_NEXT_STATE, &attrs, 1); } else - printk(KERN_WARNING MOD "TERM received tid %u no qp\n", tid); + printk(KERN_WARNING MOD "TERM received tid %u no ep/qp\n", tid);
return 0; } @@@ -2284,8 -2297,14 +2285,8 @@@ static int fw6_msg(struct c4iw_dev *dev ret = (int)((be64_to_cpu(rpl->data[0]) >> 8) & 0xff); wr_waitp = (struct c4iw_wr_wait *)(__force unsigned long) rpl->data[1]; PDBG("%s wr_waitp %p ret %u\n", __func__, wr_waitp, ret); - if (wr_waitp) { - if (ret) - wr_waitp->ret = -ret; - else - wr_waitp->ret = 0; - wr_waitp->done = 1; - wake_up(&wr_waitp->wait); - } + if (wr_waitp) + c4iw_wake_up(wr_waitp, ret ? -ret : 0); kfree_skb(skb); break; case 2: diff --combined drivers/net/acenic.c index 01560bb,82260ca..d7c1bfe4 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@@ -68,7 -68,6 +68,7 @@@ #include <linux/sockios.h> #include <linux/firmware.h> #include <linux/slab.h> +#include <linux/prefetch.h>
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #include <linux/if_vlan.h> @@@ -2659,15 -2658,15 +2659,15 @@@ static int ace_get_settings(struct net_
link = readl(®s->GigLnkState); if (link & LNK_1000MB) - ecmd->speed = SPEED_1000; + ethtool_cmd_speed_set(ecmd, SPEED_1000); else { link = readl(®s->FastLnkState); if (link & LNK_100MB) - ecmd->speed = SPEED_100; + ethtool_cmd_speed_set(ecmd, SPEED_100); else if (link & LNK_10MB) - ecmd->speed = SPEED_10; + ethtool_cmd_speed_set(ecmd, SPEED_10); else - ecmd->speed = 0; + ethtool_cmd_speed_set(ecmd, 0); } if (link & LNK_FULL_DUPLEX) ecmd->duplex = DUPLEX_FULL; @@@ -2719,9 -2718,9 +2719,9 @@@ static int ace_set_settings(struct net_ link |= LNK_TX_FLOW_CTL_Y; if (ecmd->autoneg == AUTONEG_ENABLE) link |= LNK_NEGOTIATE; - if (ecmd->speed != speed) { + if (ethtool_cmd_speed(ecmd) != speed) { link &= ~(LNK_1000MB | LNK_100MB | LNK_10MB); - switch (speed) { + switch (ethtool_cmd_speed(ecmd)) { case SPEED_1000: link |= LNK_1000MB; break; diff --combined drivers/net/arm/etherh.c index fbfb5b4,e252cd5..03e217a --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@@ -527,7 -527,7 +527,7 @@@ static void __init etherh_banner(void * Read the ethernet address string from the on board rom. * This is an ascii string... */ -static int __init etherh_addr(char *addr, struct expansion_card *ec) +static int __devinit etherh_addr(char *addr, struct expansion_card *ec) { struct in_chunk_dir cd; char *s; @@@ -591,10 -591,11 +591,11 @@@ static void etherh_get_drvinfo(struct n static int etherh_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { cmd->supported = etherh_priv(dev)->supported; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_HALF; cmd->port = dev->if_port == IF_PORT_10BASET ? PORT_TP : PORT_BNC; - cmd->autoneg = dev->flags & IFF_AUTOMEDIA ? AUTONEG_ENABLE : AUTONEG_DISABLE; + cmd->autoneg = (dev->flags & IFF_AUTOMEDIA ? + AUTONEG_ENABLE : AUTONEG_DISABLE); return 0; }
@@@ -655,7 -656,7 +656,7 @@@ static const struct net_device_ops ethe static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16];
-static int __init +static int __devinit etherh_probe(struct expansion_card *ec, const struct ecard_id *id) { const struct etherh_data *data = id->data; diff --combined drivers/net/ehea/ehea_main.c index 2c60435,ba763e0..6a0a8fc --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@@ -41,7 -41,6 +41,7 @@@ #include <linux/memory.h> #include <asm/kexec.h> #include <linux/mutex.h> +#include <linux/prefetch.h>
#include <net/ip.h>
@@@ -3263,10 -3262,12 +3263,12 @@@ struct ehea_port *ehea_setup_single_por dev->netdev_ops = &ehea_netdev_ops; ehea_set_ethtool_ops(dev);
+ dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO + | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_LRO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER - | NETIF_F_LLTX; + | NETIF_F_LLTX | NETIF_F_RXCSUM; dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
if (use_lro) diff --combined drivers/net/fs_enet/fs_enet-main.c index 5131e61,a938894..21abb5c --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@@ -956,8 -956,6 +956,6 @@@ static const struct ethtool_ops fs_etht .get_link = ethtool_op_get_link, .get_msglevel = fs_get_msglevel, .set_msglevel = fs_set_msglevel, - .set_tx_csum = ethtool_op_set_tx_csum, /* local! */ - .set_sg = ethtool_op_set_sg, .get_regs = fs_get_regs, };
@@@ -998,10 -996,8 +996,10 @@@ static const struct net_device_ops fs_e #endif };
+static struct of_device_id fs_enet_match[]; static int __devinit fs_enet_probe(struct platform_device *ofdev) { + const struct of_device_id *match; struct net_device *ndev; struct fs_enet_private *fep; struct fs_platform_info *fpi; @@@ -1009,15 -1005,14 +1007,15 @@@ const u8 *mac_addr; int privsize, len, ret = -ENODEV;
- if (!ofdev->dev.of_match) + match = of_match_device(fs_enet_match, &ofdev->dev); + if (!match) return -EINVAL;
fpi = kzalloc(sizeof(*fpi), GFP_KERNEL); if (!fpi) return -ENOMEM;
- if (!IS_FEC(ofdev->dev.of_match)) { + if (!IS_FEC(match)) { data = of_get_property(ofdev->dev.of_node, "fsl,cpm-command", &len); if (!data || len != 4) goto out_free_fpi; @@@ -1052,7 -1047,7 +1050,7 @@@ fep->dev = &ofdev->dev; fep->ndev = ndev; fep->fpi = fpi; - fep->ops = ofdev->dev.of_match->data; + fep->ops = match->data;
ret = fep->ops->setup_data(ndev); if (ret) diff --combined drivers/net/ixgbe/ixgbe_main.c index e145f2c,2dce3d0..fa01b0b --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@@ -51,8 -51,12 +51,12 @@@ char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = "Intel(R) 10 Gigabit PCI Express Network Driver"; - - #define DRV_VERSION "3.2.9-k2" + #define MAJ 3 + #define MIN 3 + #define BUILD 8 + #define KFIX 2 + #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ + __stringify(BUILD) "-k" __stringify(KFIX) const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = "Copyright (c) 1999-2011 Intel Corporation."; @@@ -120,6 -124,10 +124,10 @@@ static DEFINE_PCI_DEVICE_TABLE(ixgbe_pc board_82599 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X540T), board_X540 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP_SF2), + board_82599 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_LS), + board_82599 },
/* required last entry */ {0, } @@@ -185,6 -193,22 +193,22 @@@ static inline void ixgbe_disable_sriov( adapter->flags &= ~IXGBE_FLAG_SRIOV_ENABLED; }
+ static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter) + { + if (!test_bit(__IXGBE_DOWN, &adapter->state) && + !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state)) + schedule_work(&adapter->service_task); + } + + static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter) + { + BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state)); + + /* flush memory to make sure state is correct before next watchog */ + smp_mb__before_clear_bit(); + clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state); + } + struct ixgbe_reg_info { u32 ofs; char *name; @@@ -811,7 -835,19 +835,19 @@@ static inline bool ixgbe_check_tx_hang( #define DESC_NEEDED (TXD_USE_COUNT(IXGBE_MAX_DATA_PER_TXD) /* skb->data */ + \ MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1) /* for context */
- static void ixgbe_tx_timeout(struct net_device *netdev); + /** + * ixgbe_tx_timeout_reset - initiate reset due to Tx timeout + * @adapter: driver private struct + **/ + static void ixgbe_tx_timeout_reset(struct ixgbe_adapter *adapter) + { + + /* Do the reset outside of interrupt context */ + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + ixgbe_service_event_schedule(adapter); + } + }
/** * ixgbe_clean_tx_irq - Reclaim resources after transmit completes @@@ -893,7 -929,7 +929,7 @@@ static bool ixgbe_clean_tx_irq(struct i adapter->tx_timeout_count + 1, tx_ring->queue_index);
/* schedule immediate reset if we believe we hung */ - ixgbe_tx_timeout(adapter->netdev); + ixgbe_tx_timeout_reset(adapter);
/* the adapter is about to reset, no point in enabling stuff */ return true; @@@ -943,8 -979,6 +979,6 @@@ static void ixgbe_update_rx_dca(struct rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN; rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN; rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN); - rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN | - IXGBE_DCA_RXCTRL_DESC_HSRO_EN); IXGBE_WRITE_REG(hw, IXGBE_DCA_RXCTRL(reg_idx), rxctrl); }
@@@ -962,7 -996,6 +996,6 @@@ static void ixgbe_update_tx_dca(struct txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK; txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(reg_idx), txctrl); break; case ixgbe_mac_82599EB: @@@ -972,7 -1005,6 +1005,6 @@@ txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) << IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599); txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN; - txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN; IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL_82599(reg_idx), txctrl); break; default: @@@ -1061,8 -1093,14 +1093,14 @@@ static int __ixgbe_notify_dca(struct de
return 0; } - #endif /* CONFIG_IXGBE_DCA */ + + static inline void ixgbe_rx_hash(union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) + { + skb->rxhash = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); + } + /** * ixgbe_receive_skb - Send a completed packet up the stack * @adapter: board private structure @@@ -1454,6 -1492,8 +1492,8 @@@ static void ixgbe_clean_rx_irq(struct i }
ixgbe_rx_checksum(adapter, rx_desc, skb); + if (adapter->netdev->features & NETIF_F_RXHASH) + ixgbe_rx_hash(rx_desc, skb);
/* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; @@@ -1787,35 -1827,51 +1827,51 @@@ static void ixgbe_set_itr_msix(struct i }
/** - * ixgbe_check_overtemp_task - worker thread to check over tempurature - * @work: pointer to work_struct containing our data + * ixgbe_check_overtemp_subtask - check for over tempurature + * @adapter: pointer to adapter **/ - static void ixgbe_check_overtemp_task(struct work_struct *work) + static void ixgbe_check_overtemp_subtask(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; u32 eicr = adapter->interrupt_event;
- if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE)) + if (test_bit(__IXGBE_DOWN, &adapter->state)) return;
+ if (!(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + !(adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_EVENT)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_TEMP_SENSOR_EVENT; + switch (hw->device_id) { - case IXGBE_DEV_ID_82599_T3_LOM: { - u32 autoneg; - bool link_up = false; + case IXGBE_DEV_ID_82599_T3_LOM: + /* + * Since the warning interrupt is for both ports + * we don't have to check if: + * - This interrupt wasn't for our port. + * - We may have missed the interrupt so always have to + * check if we got a LSC + */ + if (!(eicr & IXGBE_EICR_GPI_SDP0) && + !(eicr & IXGBE_EICR_LSC)) + return; + + if (!(eicr & IXGBE_EICR_LSC) && hw->mac.ops.check_link) { + u32 autoneg; + bool link_up = false;
- if (hw->mac.ops.check_link) hw->mac.ops.check_link(hw, &autoneg, &link_up, false);
- if (((eicr & IXGBE_EICR_GPI_SDP0) && (!link_up)) || - (eicr & IXGBE_EICR_LSC)) - /* Check if this is due to overtemp */ - if (hw->phy.ops.check_overtemp(hw) == IXGBE_ERR_OVERTEMP) - break; - return; - } + if (link_up) + return; + } + + /* Check if this is not due to overtemp */ + if (hw->phy.ops.check_overtemp(hw) != IXGBE_ERR_OVERTEMP) + return; + + break; default: if (!(eicr & IXGBE_EICR_GPI_SDP0)) return; @@@ -1825,8 -1881,8 +1881,8 @@@ "Network adapter has been stopped because it has over heated. " "Restart the computer. If the problem persists, " "power off the system and replace the adapter\n"); - /* write to clear the interrupt */ - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP0); + + adapter->interrupt_event = 0; }
static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) @@@ -1848,15 -1904,19 +1904,19 @@@ static void ixgbe_check_sfp_event(struc if (eicr & IXGBE_EICR_GPI_SDP2) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - schedule_work(&adapter->sfp_config_module_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; + ixgbe_service_event_schedule(adapter); + } }
if (eicr & IXGBE_EICR_GPI_SDP1) { /* Clear the interrupt */ IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); - if (!test_bit(__IXGBE_DOWN, &adapter->state)) - schedule_work(&adapter->multispeed_fiber_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + ixgbe_service_event_schedule(adapter); + } } }
@@@ -1870,7 -1930,7 +1930,7 @@@ static void ixgbe_check_lsc(struct ixgb if (!test_bit(__IXGBE_DOWN, &adapter->state)) { IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_LSC); IXGBE_WRITE_FLUSH(hw); - schedule_work(&adapter->watchdog_task); + ixgbe_service_event_schedule(adapter); } }
@@@ -1898,26 -1958,32 +1958,32 @@@ static irqreturn_t ixgbe_msix_lsc(int i
switch (hw->mac.type) { case ixgbe_mac_82599EB: case ixgbe_mac_X540: /* Handle Flow Director Full threshold interrupt */ if (eicr & IXGBE_EICR_FLOW_DIR) { + int reinit_count = 0; int i; - IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_FLOW_DIR); - /* Disable transmits before FDIR Re-initialization */ - netif_tx_stop_all_queues(netdev); for (i = 0; i < adapter->num_tx_queues; i++) { - struct ixgbe_ring *tx_ring = - adapter->tx_ring[i]; + struct ixgbe_ring *ring = adapter->tx_ring[i]; if (test_and_clear_bit(__IXGBE_TX_FDIR_INIT_DONE, - &tx_ring->state)) - schedule_work(&adapter->fdir_reinit_task); + &ring->state)) + reinit_count++; + } + if (reinit_count) { + /* no more flow director interrupts until after init */ + IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EIMC_FLOW_DIR); + eicr &= ~IXGBE_EICR_FLOW_DIR; + adapter->flags2 |= IXGBE_FLAG2_FDIR_REQUIRES_REINIT; + ixgbe_service_event_schedule(adapter); + } + } + ixgbe_check_sfp_event(adapter, eicr); + if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && + ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->interrupt_event = eicr; + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT; + ixgbe_service_event_schedule(adapter); } } break; @@@ -1927,8 -1993,10 +1993,10 @@@
ixgbe_check_fan_failure(adapter, eicr);
+ /* re-enable the original interrupt state, no lsc, no queues */ if (!test_bit(__IXGBE_DOWN, &adapter->state)) - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); + IXGBE_WRITE_REG(hw, IXGBE_EIMS, eicr & + ~(IXGBE_EIMS_LSC | IXGBE_EIMS_RTX_QUEUE));
return IRQ_HANDLED; } @@@ -2513,8 -2581,11 +2581,11 @@@ static irqreturn_t ixgbe_intr(int irq, ixgbe_check_sfp_event(adapter, eicr); if ((adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) && ((eicr & IXGBE_EICR_GPI_SDP0) || (eicr & IXGBE_EICR_LSC))) { - adapter->interrupt_event = eicr; - schedule_work(&adapter->check_overtemp_task); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + adapter->interrupt_event = eicr; + adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_EVENT; + ixgbe_service_event_schedule(adapter); + } } break; default: @@@ -2731,7 -2802,7 +2802,7 @@@ void ixgbe_configure_tx_ring(struct ixg
/* poll to verify queue is enabled */ do { - msleep(1); + usleep_range(1000, 2000); txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); } while (--wait_loop && !(txdctl & IXGBE_TXDCTL_ENABLE)); if (!wait_loop) @@@ -3023,7 -3094,7 +3094,7 @@@ static void ixgbe_rx_desc_queue_enable( return;
do { - msleep(1); + usleep_range(1000, 2000); rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); } while (--wait_loop && !(rxdctl & IXGBE_RXDCTL_ENABLE));
@@@ -3178,7 -3249,9 +3249,9 @@@ static void ixgbe_configure_virtualizat /* enable Tx loopback for VF/PF communication */ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN); /* Enable MAC Anti-Spoofing */ - hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0), + hw->mac.ops.set_mac_anti_spoofing(hw, + (adapter->antispoofing_enabled = + (adapter->num_vfs != 0)), adapter->num_vfs); }
@@@ -3487,7 -3560,7 +3560,7 @@@ static int ixgbe_write_uc_addr_list(str struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; unsigned int vfn = adapter->num_vfs; - unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1); + unsigned int rar_entries = IXGBE_MAX_PF_MACVLANS; int count = 0;
/* return ENOMEM indicating insufficient memory for addresses */ @@@ -3760,31 -3833,16 +3833,16 @@@ static inline bool ixgbe_is_sfp(struct **/ static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter) { - struct ixgbe_hw *hw = &adapter->hw; + /* + * We are assuming the worst case scenerio here, and that + * is that an SFP was inserted/removed after the reset + * but before SFP detection was enabled. As such the best + * solution is to just start searching as soon as we start + */ + if (adapter->hw.mac.type == ixgbe_mac_82598EB) + adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP;
- if (hw->phy.multispeed_fiber) { - /* - * In multispeed fiber setups, the device may not have - * had a physical connection when the driver loaded. - * If that's the case, the initial link configuration - * couldn't get the MAC into 10G or 1G mode, so we'll - * never have a link status change interrupt fire. - * We need to try and force an autonegotiation - * session, then bring up link. - */ - if (hw->mac.ops.setup_sfp) - hw->mac.ops.setup_sfp(hw); - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) - schedule_work(&adapter->multispeed_fiber_task); - } else { - /* - * Direct Attach Cu and non-multispeed fiber modules - * still need to be configured properly prior to - * attempting link. - */ - if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK)) - schedule_work(&adapter->sfp_config_module_task); - } + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; }
/** @@@ -3860,9 -3918,10 +3918,10 @@@ static void ixgbe_setup_gpie(struct ixg if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) gpie |= IXGBE_SDP1_GPIEN;
- if (hw->mac.type == ixgbe_mac_82599EB) + if (hw->mac.type == ixgbe_mac_82599EB) { gpie |= IXGBE_SDP1_GPIEN; gpie |= IXGBE_SDP2_GPIEN; + }
IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); } @@@ -3913,17 -3972,6 +3972,6 @@@ static int ixgbe_up_complete(struct ixg e_crit(drv, "Fan has stopped, replace the adapter\n"); }
- /* - * For hot-pluggable SFP+ devices, a new SFP+ module may have - * arrived before interrupts were enabled but after probe. Such - * devices wouldn't have their type identified yet. We need to - * kick off the SFP+ module setup first, then try to bring up link. - * If we're not hot-pluggable SFP+, we just need to configure link - * and bring it up. - */ - if (hw->phy.type == ixgbe_phy_none) - schedule_work(&adapter->sfp_config_module_task); - /* enable transmits */ netif_tx_start_all_queues(adapter->netdev);
@@@ -3931,7 -3979,7 +3979,7 @@@ * link up interrupt but shouldn't be a problem */ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; adapter->link_check_timeout = jiffies; - mod_timer(&adapter->watchdog_timer, jiffies); + mod_timer(&adapter->service_timer, jiffies);
/* Set PF Reset Done bit so PF/VF Mail Ops can work */ ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); @@@ -3944,8 -3992,11 +3992,11 @@@ void ixgbe_reinit_locked(struct ixgbe_adapter *adapter) { WARN_ON(in_interrupt()); + /* put off any impending NetWatchDogTimeout */ + adapter->netdev->trans_start = jiffies; + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) - msleep(1); + usleep_range(1000, 2000); ixgbe_down(adapter); /* * If SR-IOV enabled then wait a bit before bringing the adapter @@@ -3972,10 -4023,20 +4023,20 @@@ void ixgbe_reset(struct ixgbe_adapter * struct ixgbe_hw *hw = &adapter->hw; int err;
+ /* lock SFP init bit to prevent race conditions with the watchdog */ + while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + usleep_range(1000, 2000); + + /* clear all SFP and link config related flags while holding SFP_INIT */ + adapter->flags2 &= ~(IXGBE_FLAG2_SEARCH_FOR_SFP | + IXGBE_FLAG2_SFP_NEEDS_RESET); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + err = hw->mac.ops.init_hw(hw); switch (err) { case 0: case IXGBE_ERR_SFP_NOT_PRESENT: + case IXGBE_ERR_SFP_NOT_SUPPORTED: break; case IXGBE_ERR_MASTER_REQUESTS_PENDING: e_dev_err("master disable timed out\n"); @@@ -3993,6 -4054,8 +4054,8 @@@ e_dev_err("Hardware Error: %d\n", err); }
+ clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + /* reprogram the RAR[0] in case user changed it. */ hw->mac.ops.set_rar(hw, 0, hw->mac.addr, adapter->num_vfs, IXGBE_RAH_AV); @@@ -4121,26 -4184,12 +4184,12 @@@ void ixgbe_down(struct ixgbe_adapter *a struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; u32 rxctrl; - u32 txdctl; int i; int num_q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
/* signal that we are down to the interrupt handler */ set_bit(__IXGBE_DOWN, &adapter->state);
- /* disable receive for all VFs and wait one second */ - if (adapter->num_vfs) { - /* ping all the active vfs to let them know we are going down */ - ixgbe_ping_all_vfs(adapter); - - /* Disable all VFTE/VFRE TX/RX */ - ixgbe_disable_tx_rx(adapter); - - /* Mark all the VFs as inactive */ - for (i = 0 ; i < adapter->num_vfs; i++) - adapter->vfinfo[i].clear_to_send = 0; - } - /* disable receives */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxctrl & ~IXGBE_RXCTRL_RXEN); @@@ -4150,15 -4199,11 +4199,11 @@@ /* this call also flushes the previous write */ ixgbe_disable_rx_queue(adapter, adapter->rx_ring[i]);
- msleep(10); + usleep_range(10000, 20000);
netif_tx_stop_all_queues(netdev);
- clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->sfp_timer); - del_timer_sync(&adapter->watchdog_timer); - cancel_work_sync(&adapter->watchdog_task); - + /* call carrier off first to avoid false dev_watchdog timeouts */ netif_carrier_off(netdev); netif_tx_disable(netdev);
@@@ -4166,6 -4211,25 +4211,25 @@@
ixgbe_napi_disable_all(adapter);
+ adapter->flags2 &= ~(IXGBE_FLAG2_FDIR_REQUIRES_REINIT | + IXGBE_FLAG2_RESET_REQUESTED); + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + + del_timer_sync(&adapter->service_timer); + + /* disable receive for all VFs and wait one second */ + if (adapter->num_vfs) { + /* ping all the active vfs to let them know we are going down */ + ixgbe_ping_all_vfs(adapter); + + /* Disable all VFTE/VFRE TX/RX */ + ixgbe_disable_tx_rx(adapter); + + /* Mark all the VFs as inactive */ + for (i = 0 ; i < adapter->num_vfs; i++) + adapter->vfinfo[i].clear_to_send = 0; + } + /* Cleanup the affinity_hint CPU mask memory and callback */ for (i = 0; i < num_q_vectors; i++) { struct ixgbe_q_vector *q_vector = adapter->q_vector[i]; @@@ -4175,21 -4239,13 +4239,13 @@@ free_cpumask_var(q_vector->affinity_mask); }
/* disable transmits in the hardware now that interrupts are off */ for (i = 0; i < adapter->num_tx_queues; i++) { u8 reg_idx = adapter->tx_ring[i]->reg_idx; - txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(reg_idx)); - IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), - (txdctl & ~IXGBE_TXDCTL_ENABLE)); + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(reg_idx), IXGBE_TXDCTL_SWFLSH); } - /* Disable the Tx DMA engine on 82599 */ + + /* Disable the Tx DMA engine on 82599 and X540 */ switch (hw->mac.type) { case ixgbe_mac_82599EB: case ixgbe_mac_X540: @@@ -4201,9 -4257,6 +4257,6 @@@ break; }
- /* clear n-tuple filters that are cached */ - ethtool_ntuple_flush(netdev); - if (!pci_channel_offline(adapter->pdev)) ixgbe_reset(adapter);
@@@ -4267,25 -4320,8 +4320,8 @@@ static void ixgbe_tx_timeout(struct net { struct ixgbe_adapter *adapter = netdev_priv(netdev);
- adapter->tx_timeout_count++; - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); - } - - static void ixgbe_reset_task(struct work_struct *work) - { - struct ixgbe_adapter *adapter; - adapter = container_of(work, struct ixgbe_adapter, reset_task); - - /* If we're already down or resetting, just bail */ - if (test_bit(__IXGBE_DOWN, &adapter->state) || - test_bit(__IXGBE_RESETTING, &adapter->state)) - return; - - ixgbe_dump(adapter); - netdev_err(adapter->netdev, "Reset adapter\n"); - ixgbe_reinit_locked(adapter); + ixgbe_tx_timeout_reset(adapter); }
/** @@@ -4567,8 -4603,8 +4603,8 @@@ static inline bool ixgbe_cache_ring_rss #ifdef CONFIG_IXGBE_DCB
/* ixgbe_get_first_reg_idx - Return first register index associated with ring */ - void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc, - unsigned int *tx, unsigned int *rx) + static void ixgbe_get_first_reg_idx(struct ixgbe_adapter *adapter, u8 tc, + unsigned int *tx, unsigned int *rx) { struct net_device *dev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; @@@ -5100,6 -5136,11 +5136,6 @@@ err_set_interrupt return err; }
-static void ring_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ixgbe_ring, rcu)); -} - /** * ixgbe_clear_interrupt_scheme - Clear the current interrupt scheme settings * @adapter: board private structure to clear interrupt scheme on @@@ -5121,7 -5162,7 +5157,7 @@@ void ixgbe_clear_interrupt_scheme(struc /* ixgbe_get_stats64() might access this ring, we must wait * a grace period before freeing it. */ - call_rcu(&ring->rcu, ring_free_rcu); + kfree_rcu(ring, rcu); adapter->rx_ring[i] = NULL; }
@@@ -5133,57 -5174,6 +5169,6 @@@ }
/** - * ixgbe_sfp_timer - worker thread to find a missing module - * @data: pointer to our adapter struct - **/ - static void ixgbe_sfp_timer(unsigned long data) - { - struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; - - /* - * Do the sfp_timer outside of interrupt context due to the - * delays that sfp+ detection requires - */ - schedule_work(&adapter->sfp_task); - } - - /** - * ixgbe_sfp_task - worker thread to find a missing module - * @work: pointer to work_struct containing our data - **/ - static void ixgbe_sfp_task(struct work_struct *work) - { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - sfp_task); - struct ixgbe_hw *hw = &adapter->hw; - - if ((hw->phy.type == ixgbe_phy_nl) && - (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { - s32 ret = hw->phy.ops.identify_sfp(hw); - if (ret == IXGBE_ERR_SFP_NOT_PRESENT) - goto reschedule; - ret = hw->phy.ops.reset(hw); - if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported " - "SFP+ module type was detected.\n"); - e_dev_err("Reload the driver after installing a " - "supported module.\n"); - unregister_netdev(adapter->netdev); - } else { - e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type); - } - /* don't need this routine any more */ - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - } - return; - reschedule: - if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); - } - - /** * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) * @adapter: board private structure to initialize * @@@ -5899,8 -5889,13 +5884,13 @@@ void ixgbe_update_stats(struct ixgbe_ad hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH); hwstats->tor += IXGBE_READ_REG(hw, IXGBE_TORH); break; - case ixgbe_mac_82599EB: case ixgbe_mac_X540: + /* OS2BMC stats are X540 only*/ + hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC); + hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC); + hwstats->b2ospc += IXGBE_READ_REG(hw, IXGBE_B2OSPC); + hwstats->b2ogprc += IXGBE_READ_REG(hw, IXGBE_B2OGPRC); + case ixgbe_mac_82599EB: hwstats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL); IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */ hwstats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL); @@@ -5974,23 -5969,66 +5964,66 @@@ }
/** - * ixgbe_watchdog - Timer Call-back - * @data: pointer to adapter cast into an unsigned long + * ixgbe_fdir_reinit_subtask - worker thread to reinit FDIR filter table + * @adapter - pointer to the device adapter structure **/ - static void ixgbe_watchdog(unsigned long data) + static void ixgbe_fdir_reinit_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; struct ixgbe_hw *hw = &adapter->hw; - u64 eics = 0; int i;
- /* - * Do the watchdog outside of interrupt context due to the lovely - * delays that some of the newer hardware requires - */ + if (!(adapter->flags2 & IXGBE_FLAG2_FDIR_REQUIRES_REINIT)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_FDIR_REQUIRES_REINIT;
+ /* if interface is down do nothing */ if (test_bit(__IXGBE_DOWN, &adapter->state)) - goto watchdog_short_circuit; + return; + + /* do nothing if we are not using signature filters */ + if (!(adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE)) + return; + + adapter->fdir_overflow++; + + if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_bit(__IXGBE_TX_FDIR_INIT_DONE, + &(adapter->tx_ring[i]->state)); + /* re-enable flow director interrupts */ + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_FLOW_DIR); + } else { + e_err(probe, "failed to finish FDIR re-initialization, " + "ignored adding FDIR ATR filters\n"); + } + } + + /** + * ixgbe_check_hang_subtask - check for hung queues and dropped interrupts + * @adapter - pointer to the device adapter structure + * + * This function serves two purposes. First it strobes the interrupt lines + * in order to make certain interrupts are occuring. Secondly it sets the + * bits needed to check for TX hangs. As a result we should immediately + * determine if a hang has occured. + */ + static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter) + { + struct ixgbe_hw *hw = &adapter->hw; + u64 eics = 0; + int i; + + /* If we're down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + + /* Force detection of hung controller */ + if (netif_carrier_ok(adapter->netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) + set_check_for_tx_hang(adapter->tx_ring[i]); + }
if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { /* @@@ -6000,108 -6038,172 +6033,172 @@@ */ IXGBE_WRITE_REG(hw, IXGBE_EICS, (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER)); - goto watchdog_reschedule; - } - - /* get one bit for every active tx/rx interrupt vector */ - for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { - struct ixgbe_q_vector *qv = adapter->q_vector[i]; - if (qv->rxr_count || qv->txr_count) - eics |= ((u64)1 << i); + } else { + /* get one bit for every active tx/rx interrupt vector */ + for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) { + struct ixgbe_q_vector *qv = adapter->q_vector[i]; + if (qv->rxr_count || qv->txr_count) + eics |= ((u64)1 << i); + } }
- /* Cause software interrupt to ensure rx rings are cleaned */ + /* Cause software interrupt to ensure rings are cleaned */ ixgbe_irq_rearm_queues(adapter, eics);
}
/** - * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_update_link - update the link status + * @adapter - pointer to the device adapter structure + * @link_speed - pointer to a u32 to store the link_speed **/ - static void ixgbe_multispeed_fiber_task(struct work_struct *work) + static void ixgbe_watchdog_update_link(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - multispeed_fiber_task); struct ixgbe_hw *hw = &adapter->hw; - u32 autoneg; - bool negotiation; + u32 link_speed = adapter->link_speed; + bool link_up = adapter->link_up; + int i;
- adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK; - autoneg = hw->phy.autoneg_advertised; - if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) - hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); - hw->mac.autotry_restart = false; - if (hw->mac.ops.setup_link) - hw->mac.ops.setup_link(hw, autoneg, negotiation, true); - adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; - adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK; + if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) + return; + + if (hw->mac.ops.check_link) { + hw->mac.ops.check_link(hw, &link_speed, &link_up, false); + } else { + /* always assume link is up, if no check link function */ + link_speed = IXGBE_LINK_SPEED_10GB_FULL; + link_up = true; + } + if (link_up) { + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + hw->mac.ops.fc_enable(hw, i); + } else { + hw->mac.ops.fc_enable(hw, 0); + } + } + + if (link_up || + time_after(jiffies, (adapter->link_check_timeout + + IXGBE_TRY_LINK_TIMEOUT))) { + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; + IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); + IXGBE_WRITE_FLUSH(hw); + } + + adapter->link_up = link_up; + adapter->link_speed = link_speed; }
/** - * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_link_is_up - update netif_carrier status and + * print link up message + * @adapter - pointer to the device adapter structure **/ - static void ixgbe_sfp_config_module_task(struct work_struct *work) + static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - sfp_config_module_task); + struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; - u32 err; + u32 link_speed = adapter->link_speed; + bool flow_rx, flow_tx;
- adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK; + /* only continue if link was previously down */ + if (netif_carrier_ok(netdev)) + return;
- /* Time for electrical oscillations to settle down */ - msleep(100); - err = hw->phy.ops.identify_sfp(hw); + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP;
- if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported SFP+ " - "module type was detected.\n"); - e_dev_err("Reload the driver after installing a supported " - "module.\n"); - unregister_netdev(adapter->netdev); - return; + switch (hw->mac.type) { + case ixgbe_mac_82598EB: { + u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); + u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); + flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); + flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); + } + break; + case ixgbe_mac_X540: + case ixgbe_mac_82599EB: { + u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); + u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); + flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); + flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); + } + break; + default: + flow_tx = false; + flow_rx = false; + break; } - if (hw->mac.ops.setup_sfp) - hw->mac.ops.setup_sfp(hw); + e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gbps" : + (link_speed == IXGBE_LINK_SPEED_100_FULL ? + "100 Mbps" : + "unknown speed"))), + ((flow_rx && flow_tx) ? "RX/TX" : + (flow_rx ? "RX" : + (flow_tx ? "TX" : "None"))));
- if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)) - /* This will also work for DA Twinax connections */ - schedule_work(&adapter->multispeed_fiber_task); - adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK; + netif_carrier_on(netdev); + #ifdef HAVE_IPLINK_VF_CONFIG + ixgbe_check_vf_rate_limit(adapter); + #endif /* HAVE_IPLINK_VF_CONFIG */ }
/** - * ixgbe_fdir_reinit_task - worker thread to reinit FDIR filter table - * @work: pointer to work_struct containing our data + * ixgbe_watchdog_link_is_down - update netif_carrier status and + * print link down message + * @adapter - pointer to the adapter structure **/ - static void ixgbe_fdir_reinit_task(struct work_struct *work) + static void ixgbe_watchdog_link_is_down(struct ixgbe_adapter* adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - fdir_reinit_task); + struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; + + adapter->link_up = false; + adapter->link_speed = 0; + + /* only continue if link was up previously */ + if (!netif_carrier_ok(netdev)) + return; + + /* poll for SFP+ cable when link is down */ + if (ixgbe_is_sfp(hw) && hw->mac.type == ixgbe_mac_82598EB) + adapter->flags2 |= IXGBE_FLAG2_SEARCH_FOR_SFP; + + e_info(drv, "NIC Link is Down\n"); + netif_carrier_off(netdev); + } + + /** + * ixgbe_watchdog_flush_tx - flush queues on link down + * @adapter - pointer to the device adapter structure + **/ + static void ixgbe_watchdog_flush_tx(struct ixgbe_adapter *adapter) + { int i; + int some_tx_pending = 0;
- if (ixgbe_reinit_fdir_tables_82599(hw) == 0) { - for (i = 0; i < adapter->num_tx_queues; i++) - set_bit(__IXGBE_TX_FDIR_INIT_DONE, - &(adapter->tx_ring[i]->state)); - } else { - e_err(probe, "failed to finish FDIR re-initialization, " - "ignored adding FDIR ATR filters\n"); + if (!netif_carrier_ok(adapter->netdev)) { + for (i = 0; i < adapter->num_tx_queues; i++) { + struct ixgbe_ring *tx_ring = adapter->tx_ring[i]; + if (tx_ring->next_to_use != tx_ring->next_to_clean) { + some_tx_pending = 1; + break; + } + } + + if (some_tx_pending) { + /* We've lost link, so the controller stops DMA, + * but we've got queued Tx work that's never going + * to get done, so reset controller to flush Tx. + * (Do the reset outside of interrupt context). + */ + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + } } - /* Done FDIR Re-initialization, enable transmits */ - netif_tx_start_all_queues(adapter->netdev); }
static void ixgbe_spoof_check(struct ixgbe_adapter *adapter) @@@ -6124,133 -6226,186 +6221,186 @@@ e_warn(drv, "%d Spoofed packets detected\n", ssvpc); }
- static DEFINE_MUTEX(ixgbe_watchdog_lock); + /** + * ixgbe_watchdog_subtask - check and bring link up + * @adapter - pointer to the device adapter structure + **/ + static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter) + { + /* if interface is down do nothing */ + if (test_bit(__IXGBE_DOWN, &adapter->state)) + return; + + ixgbe_watchdog_update_link(adapter); + + if (adapter->link_up) + ixgbe_watchdog_link_is_up(adapter); + else + ixgbe_watchdog_link_is_down(adapter); + + ixgbe_spoof_check(adapter); + ixgbe_update_stats(adapter); + + ixgbe_watchdog_flush_tx(adapter); + }
/** - * ixgbe_watchdog_task - worker thread to bring link up - * @work: pointer to work_struct containing our data + * ixgbe_sfp_detection_subtask - poll for SFP+ cable + * @adapter - the ixgbe adapter structure **/ - static void ixgbe_watchdog_task(struct work_struct *work) + static void ixgbe_sfp_detection_subtask(struct ixgbe_adapter *adapter) { - struct ixgbe_adapter *adapter = container_of(work, - struct ixgbe_adapter, - watchdog_task); - struct net_device *netdev = adapter->netdev; struct ixgbe_hw *hw = &adapter->hw; - u32 link_speed; - bool link_up; - int i; - struct ixgbe_ring *tx_ring; - int some_tx_pending = 0; + s32 err;
- mutex_lock(&ixgbe_watchdog_lock); + /* not searching for SFP so there is nothing to do here */ + if (!(adapter->flags2 & IXGBE_FLAG2_SEARCH_FOR_SFP) && + !(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET)) + return;
- link_up = adapter->link_up; - link_speed = adapter->link_speed; + /* someone else is in init, wait until next service event */ + if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + return;
- if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { - hw->mac.ops.check_link(hw, &link_speed, &link_up, false); - if (link_up) { - #ifdef CONFIG_DCB - if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { - for (i = 0; i < MAX_TRAFFIC_CLASS; i++) - hw->mac.ops.fc_enable(hw, i); - } else { - hw->mac.ops.fc_enable(hw, 0); - } - #else - hw->mac.ops.fc_enable(hw, 0); - #endif - } + err = hw->phy.ops.identify_sfp(hw); + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto sfp_out;
- if (link_up || - time_after(jiffies, (adapter->link_check_timeout + - IXGBE_TRY_LINK_TIMEOUT))) { - adapter->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMC_LSC); - } - adapter->link_up = link_up; - adapter->link_speed = link_speed; + if (err == IXGBE_ERR_SFP_NOT_PRESENT) { + /* If no cable is present, then we need to reset + * the next time we find a good cable. */ + adapter->flags2 |= IXGBE_FLAG2_SFP_NEEDS_RESET; }
- if (link_up) { - if (!netif_carrier_ok(netdev)) { - bool flow_rx, flow_tx; - - switch (hw->mac.type) { - case ixgbe_mac_82598EB: { - u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL); - u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); - flow_rx = !!(frctl & IXGBE_FCTRL_RFCE); - flow_tx = !!(rmcs & IXGBE_RMCS_TFCE_802_3X); - } - break; - case ixgbe_mac_82599EB: - case ixgbe_mac_X540: { - u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); - u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG); - flow_rx = !!(mflcn & IXGBE_MFLCN_RFCE); - flow_tx = !!(fccfg & IXGBE_FCCFG_TFCE_802_3X); - } - break; - default: - flow_tx = false; - flow_rx = false; - break; - } + /* exit on error */ + if (err) + goto sfp_out;
- e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : - (link_speed == IXGBE_LINK_SPEED_100_FULL ? - "100 Mbps" : - "unknown speed"))), - ((flow_rx && flow_tx) ? "RX/TX" : - (flow_rx ? "RX" : - (flow_tx ? "TX" : "None")))); - - netif_carrier_on(netdev); - ixgbe_check_vf_rate_limit(adapter); - } else { - /* Force detection of hung controller */ - for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = adapter->tx_ring[i]; - set_check_for_tx_hang(tx_ring); - } - } - } else { - adapter->link_up = false; - adapter->link_speed = 0; - if (netif_carrier_ok(netdev)) { - e_info(drv, "NIC Link is Down\n"); - netif_carrier_off(netdev); - } - } + /* exit if reset not needed */ + if (!(adapter->flags2 & IXGBE_FLAG2_SFP_NEEDS_RESET)) + goto sfp_out;
- if (!netif_carrier_ok(netdev)) { - for (i = 0; i < adapter->num_tx_queues; i++) { - tx_ring = adapter->tx_ring[i]; - if (tx_ring->next_to_use != tx_ring->next_to_clean) { - some_tx_pending = 1; - break; - } - } + adapter->flags2 &= ~IXGBE_FLAG2_SFP_NEEDS_RESET;
- if (some_tx_pending) { - /* We've lost link, so the controller stops DMA, - * but we've got queued Tx work that's never going - * to get done, so reset controller to flush Tx. - * (Do the reset outside of interrupt context). - */ - schedule_work(&adapter->reset_task); - } + /* + * A module may be identified correctly, but the EEPROM may not have + * support for that module. setup_sfp() will fail in that case, so + * we should not allow that module to load. + */ + if (hw->mac.type == ixgbe_mac_82598EB) + err = hw->phy.ops.reset(hw); + else + err = hw->mac.ops.setup_sfp(hw); + + if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) + goto sfp_out; + + adapter->flags |= IXGBE_FLAG_NEED_LINK_CONFIG; + e_info(probe, "detected SFP+: %d\n", hw->phy.sfp_type); + + sfp_out: + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + + if ((err == IXGBE_ERR_SFP_NOT_SUPPORTED) && + (adapter->netdev->reg_state == NETREG_REGISTERED)) { + e_dev_err("failed to initialize because an unsupported " + "SFP+ module type was detected.\n"); + e_dev_err("Reload the driver after installing a " + "supported module.\n"); + unregister_netdev(adapter->netdev); } + }
- ixgbe_spoof_check(adapter); - ixgbe_update_stats(adapter); - mutex_unlock(&ixgbe_watchdog_lock); + /** + * ixgbe_sfp_link_config_subtask - set up link SFP after module install + * @adapter - the ixgbe adapter structure + **/ + static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter) + { + struct ixgbe_hw *hw = &adapter->hw; + u32 autoneg; + bool negotiation; + + if (!(adapter->flags & IXGBE_FLAG_NEED_LINK_CONFIG)) + return; + + /* someone else is in init, wait until next service event */ + if (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) + return; + + adapter->flags &= ~IXGBE_FLAG_NEED_LINK_CONFIG; + + autoneg = hw->phy.autoneg_advertised; + if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) + hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + hw->mac.autotry_restart = false; + if (hw->mac.ops.setup_link) + hw->mac.ops.setup_link(hw, autoneg, negotiation, true); + + adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + adapter->link_check_timeout = jiffies; + clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state); + } + + /** + * ixgbe_service_timer - Timer Call-back + * @data: pointer to adapter cast into an unsigned long + **/ + static void ixgbe_service_timer(unsigned long data) + { + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + unsigned long next_event_offset; + + /* poll faster when waiting for link */ + if (adapter->flags & IXGBE_FLAG_NEED_LINK_UPDATE) + next_event_offset = HZ / 10; + else + next_event_offset = HZ * 2; + + /* Reset the timer */ + mod_timer(&adapter->service_timer, next_event_offset + jiffies); + + ixgbe_service_event_schedule(adapter); + } + + static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) + { + if (!(adapter->flags2 & IXGBE_FLAG2_RESET_REQUESTED)) + return; + + adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED; + + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + + ixgbe_dump(adapter); + netdev_err(adapter->netdev, "Reset adapter\n"); + adapter->tx_timeout_count++; + + ixgbe_reinit_locked(adapter); + } + + /** + * ixgbe_service_task - manages and runs subtasks + * @work: pointer to work_struct containing our data + **/ + static void ixgbe_service_task(struct work_struct *work) + { + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + service_task); + + ixgbe_reset_subtask(adapter); + ixgbe_sfp_detection_subtask(adapter); + ixgbe_sfp_link_config_subtask(adapter); + ixgbe_check_overtemp_subtask(adapter); + ixgbe_watchdog_subtask(adapter); + ixgbe_fdir_reinit_subtask(adapter); + ixgbe_check_hang_subtask(adapter); + + ixgbe_service_event_complete(adapter); }
static int ixgbe_tso(struct ixgbe_adapter *adapter, @@@ -7089,6 -7244,8 +7239,8 @@@ static void __devinit ixgbe_probe_vf(st #ifdef CONFIG_PCI_IOV struct ixgbe_hw *hw = &adapter->hw; int err; + int num_vf_macvlans, i; + struct vf_macvlans *mv_list;
if (hw->mac.type == ixgbe_mac_82598EB || !max_vfs) return; @@@ -7105,6 -7262,26 +7257,26 @@@ e_err(probe, "Failed to enable PCI sriov: %d\n", err); goto err_novfs; } + + num_vf_macvlans = hw->mac.num_rar_entries - + (IXGBE_MAX_PF_MACVLANS + 1 + adapter->num_vfs); + + adapter->mv_list = mv_list = kcalloc(num_vf_macvlans, + sizeof(struct vf_macvlans), + GFP_KERNEL); + if (mv_list) { + /* Initialize list of VF macvlans */ + INIT_LIST_HEAD(&adapter->vf_mvs.l); + for (i = 0; i < num_vf_macvlans; i++) { + mv_list->vf = -1; + mv_list->free = true; + mv_list->rar_entry = hw->mac.num_rar_entries - + (i + adapter->num_vfs + 1); + list_add(&mv_list->l, &adapter->vf_mvs.l); + mv_list++; + } + } + /* If call to enable VFs succeeded then allocate memory * for per VF control structures. */ @@@ -7275,22 -7452,6 +7447,6 @@@ static int __devinit ixgbe_probe(struc hw->phy.mdio.mdio_read = ixgbe_mdio_read; hw->phy.mdio.mdio_write = ixgbe_mdio_write;
- /* set up this timer and work struct before calling get_invariants - * which might start the timer - */ - init_timer(&adapter->sfp_timer); - adapter->sfp_timer.function = ixgbe_sfp_timer; - adapter->sfp_timer.data = (unsigned long) adapter; - - INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); - - /* multispeed fiber has its own tasklet, called from GPI SDP1 context */ - INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task); - - /* a new SFP+ module arrival, called from GPI SDP2 context */ - INIT_WORK(&adapter->sfp_config_module_task, - ixgbe_sfp_config_module_task); - ii->get_invariants(hw);
/* setup the private structure */ @@@ -7324,17 -7485,9 +7480,9 @@@ hw->phy.reset_if_overtemp = false; if (err == IXGBE_ERR_SFP_NOT_PRESENT && hw->mac.type == ixgbe_mac_82598EB) { - /* - * Start a kernel thread to watch for a module to arrive. - * Only do this for 82598, since 82599 will generate - * interrupts on module arrival. - */ - set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - mod_timer(&adapter->sfp_timer, - round_jiffies(jiffies + (2 * HZ))); err = 0; } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { - e_dev_err("failed to initialize because an unsupported SFP+ " + e_dev_err("failed to load because an unsupported SFP+ " "module type was detected.\n"); e_dev_err("Reload the driver after installing a supported " "module.\n"); @@@ -7356,9 -7509,16 +7504,16 @@@ netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_GRO; + netdev->features |= NETIF_F_RXHASH;
- if (adapter->hw.mac.type == ixgbe_mac_82599EB) + switch (adapter->hw.mac.type) { + case ixgbe_mac_82599EB: + case ixgbe_mac_X540: netdev->features |= NETIF_F_SCTP_CSUM; + break; + default: + break; + }
netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO6; @@@ -7419,17 -7579,19 +7574,19 @@@ (hw->mac.type == ixgbe_mac_82599EB)))) hw->mac.ops.disable_tx_laser(hw);
- init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = ixgbe_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; + setup_timer(&adapter->service_timer, &ixgbe_service_timer, + (unsigned long) adapter);
- INIT_WORK(&adapter->reset_task, ixgbe_reset_task); - INIT_WORK(&adapter->watchdog_task, ixgbe_watchdog_task); + INIT_WORK(&adapter->service_task, ixgbe_service_task); + clear_bit(__IXGBE_SERVICE_SCHED, &adapter->state);
err = ixgbe_init_interrupt_scheme(adapter); if (err) goto err_sw_init;
+ if (!(adapter->flags & IXGBE_FLAG_RSS_ENABLED)) + netdev->features &= ~NETIF_F_RXHASH; + switch (pdev->device) { case IXGBE_DEV_ID_82599_SFP: /* Only this subdevice supports WOL */ @@@ -7458,8 -7620,8 +7615,8 @@@
/* print bus type/speed/width info */ e_dev_info("(PCI Express:%s:%s) %pM\n", - (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0Gb/s" : - hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5Gb/s" : + (hw->bus.speed == ixgbe_bus_speed_5000 ? "5.0GT/s" : + hw->bus.speed == ixgbe_bus_speed_2500 ? "2.5GT/s" : "Unknown"), (hw->bus.width == ixgbe_bus_width_pcie_x8 ? "Width x8" : hw->bus.width == ixgbe_bus_width_pcie_x4 ? "Width x4" : @@@ -7508,13 -7670,6 +7665,6 @@@ /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev);
- if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - INIT_WORK(&adapter->fdir_reinit_task, ixgbe_fdir_reinit_task); - - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - INIT_WORK(&adapter->check_overtemp_task, - ixgbe_check_overtemp_task); #ifdef CONFIG_IXGBE_DCA if (dca_add_requester(&pdev->dev) == 0) { adapter->flags |= IXGBE_FLAG_DCA_ENABLED; @@@ -7541,11 -7696,7 +7691,7 @@@ err_sw_init err_eeprom: if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) ixgbe_disable_sriov(adapter); - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->sfp_timer); - cancel_work_sync(&adapter->sfp_task); - cancel_work_sync(&adapter->multispeed_fiber_task); - cancel_work_sync(&adapter->sfp_config_module_task); + adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; iounmap(hw->hw_addr); err_ioremap: free_netdev(netdev); @@@ -7573,24 -7724,7 +7719,7 @@@ static void __devexit ixgbe_remove(stru struct net_device *netdev = adapter->netdev;
set_bit(__IXGBE_DOWN, &adapter->state); - - /* - * The timers may be rescheduled, so explicitly disable them - * from being rescheduled. - */ - clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); - del_timer_sync(&adapter->watchdog_timer); - del_timer_sync(&adapter->sfp_timer); - - cancel_work_sync(&adapter->watchdog_task); - cancel_work_sync(&adapter->sfp_task); - cancel_work_sync(&adapter->multispeed_fiber_task); - cancel_work_sync(&adapter->sfp_config_module_task); - if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || - adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE) - cancel_work_sync(&adapter->fdir_reinit_task); - if (adapter->flags2 & IXGBE_FLAG2_TEMP_SENSOR_CAPABLE) - cancel_work_sync(&adapter->check_overtemp_task); + cancel_work_sync(&adapter->service_task);
#ifdef CONFIG_IXGBE_DCA if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) { diff --combined drivers/net/macvlan.c index d8e4e69,bbcf80a..d72a706 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@@ -70,16 -70,17 +70,17 @@@ static void macvlan_hash_add(struct mac hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]); }
- static void macvlan_hash_del(struct macvlan_dev *vlan) + static void macvlan_hash_del(struct macvlan_dev *vlan, bool sync) { hlist_del_rcu(&vlan->hlist); - synchronize_rcu(); + if (sync) + synchronize_rcu(); }
static void macvlan_hash_change_addr(struct macvlan_dev *vlan, const unsigned char *addr) { - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, true); /* Now that we are unhashed it is safe to change the device * address without confusing packet delivery. */ @@@ -345,7 -346,7 +346,7 @@@ static int macvlan_stop(struct net_devi dev_uc_del(lowerdev, dev->dev_addr);
hash_del: - macvlan_hash_del(vlan); + macvlan_hash_del(vlan, !dev->dismantle); return 0; }
@@@ -415,7 -416,7 +416,7 @@@ static struct lock_class_key macvlan_ne #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ - NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO) + NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM)
#define MACVLAN_STATE_MASK \ ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT)) @@@ -517,12 -518,6 +518,6 @@@ static void macvlan_ethtool_get_drvinfo snprintf(drvinfo->version, 32, "0.1"); }
- static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) - { - const struct macvlan_dev *vlan = netdev_priv(dev); - return dev_ethtool_get_rx_csum(vlan->lowerdev); - } - static int macvlan_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { @@@ -530,18 -525,10 +525,10 @@@ return dev_ethtool_get_settings(vlan->lowerdev, cmd); }
static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, .get_settings = macvlan_ethtool_get_settings, - .get_rx_csum = macvlan_ethtool_get_rx_csum, .get_drvinfo = macvlan_ethtool_get_drvinfo, - .get_flags = macvlan_ethtool_get_flags, };
static const struct net_device_ops macvlan_netdev_ops = { @@@ -598,18 -585,26 +585,18 @@@ static int macvlan_port_create(struct n err = netdev_rx_handler_register(dev, macvlan_handle_frame, port); if (err) kfree(port); - - dev->priv_flags |= IFF_MACVLAN_PORT; + else + dev->priv_flags |= IFF_MACVLAN_PORT; return err; }
-static void macvlan_port_rcu_free(struct rcu_head *head) -{ - struct macvlan_port *port; - - port = container_of(head, struct macvlan_port, rcu); - kfree(port); -} - static void macvlan_port_destroy(struct net_device *dev) { struct macvlan_port *port = macvlan_port_get(dev);
dev->priv_flags &= ~IFF_MACVLAN_PORT; netdev_rx_handler_unregister(dev); - call_rcu(&port->rcu, macvlan_port_rcu_free); + kfree_rcu(port, rcu); }
static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) @@@ -791,6 -786,7 +778,7 @@@ static int macvlan_device_event(struct struct net_device *dev = ptr; struct macvlan_dev *vlan, *next; struct macvlan_port *port; + LIST_HEAD(list_kill);
if (!macvlan_port_exists(dev)) return NOTIFY_DONE; @@@ -816,7 -812,9 +804,9 @@@ break;
list_for_each_entry_safe(vlan, next, &port->vlans, list) - vlan->dev->rtnl_link_ops->dellink(vlan->dev, NULL); + vlan->dev->rtnl_link_ops->dellink(vlan->dev, &list_kill); + unregister_netdevice_many(&list_kill); + list_del(&list_kill); break; case NETDEV_PRE_TYPE_CHANGE: /* Forbid underlaying device to change its type. */ diff --combined drivers/net/sunhme.c index bff2f79,d381a0f..30aad54 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@@ -1383,7 -1383,7 +1383,7 @@@ force_link if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { hp->sw_bmcr = BMCR_SPEED100; } else { - if (ep->speed == SPEED_100) + if (ethtool_cmd_speed(ep) == SPEED_100) hp->sw_bmcr = BMCR_SPEED100; else hp->sw_bmcr = 0; @@@ -2401,6 -2401,7 +2401,7 @@@ static void happy_meal_set_multicast(st static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct happy_meal *hp = netdev_priv(dev); + u32 speed;
cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@@ -2420,10 -2421,9 +2421,9 @@@
if (hp->sw_bmcr & BMCR_ANENABLE) { cmd->autoneg = AUTONEG_ENABLE; - cmd->speed = - (hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? - SPEED_100 : SPEED_10; - if (cmd->speed == SPEED_100) + speed = ((hp->sw_lpa & (LPA_100HALF | LPA_100FULL)) ? + SPEED_100 : SPEED_10); + if (speed == SPEED_100) cmd->duplex = (hp->sw_lpa & (LPA_100FULL)) ? DUPLEX_FULL : DUPLEX_HALF; @@@ -2433,13 -2433,12 +2433,12 @@@ DUPLEX_FULL : DUPLEX_HALF; } else { cmd->autoneg = AUTONEG_DISABLE; - cmd->speed = - (hp->sw_bmcr & BMCR_SPEED100) ? - SPEED_100 : SPEED_10; + speed = (hp->sw_bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; cmd->duplex = (hp->sw_bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; } + ethtool_cmd_speed_set(cmd, speed); return 0; }
@@@ -2452,8 -2451,8 +2451,8 @@@ static int hme_set_settings(struct net_ cmd->autoneg != AUTONEG_DISABLE) return -EINVAL; if (cmd->autoneg == AUTONEG_DISABLE && - ((cmd->speed != SPEED_100 && - cmd->speed != SPEED_10) || + ((ethtool_cmd_speed(cmd) != SPEED_100 && + ethtool_cmd_speed(cmd) != SPEED_10) || (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL))) return -EINVAL; @@@ -2788,7 -2787,8 +2787,8 @@@ static int __devinit happy_meal_sbus_pr dev->ethtool_ops = &hme_ethtool_ops;
/* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM;
dev->irq = op->archdata.irqs[0];
@@@ -3113,7 -3113,8 +3113,8 @@@ static int __devinit happy_meal_pci_pro dev->dma = 0;
/* Happy Meal can do it all... */ - dev->features |= NETIF_F_SG | NETIF_F_HW_CSUM; + dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM; + dev->features |= dev->hw_features | NETIF_F_RXCSUM;
#if defined(CONFIG_SBUS) && defined(CONFIG_PCI) /* Hook up PCI register/descriptor accessors. */ @@@ -3237,18 -3238,15 +3238,18 @@@ static void happy_meal_pci_exit(void #endif
#ifdef CONFIG_SBUS +static const struct of_device_id hme_sbus_match[]; static int __devinit hme_sbus_probe(struct platform_device *op) { + const struct of_device_id *match; struct device_node *dp = op->dev.of_node; const char *model = of_get_property(dp, "model", NULL); int is_qfe;
- if (!op->dev.of_match) + match = of_match_device(hme_sbus_match, &op->dev); + if (!match) return -EINVAL; - is_qfe = (op->dev.of_match->data != NULL); + is_qfe = (match->data != NULL);
if (!is_qfe && model && !strcmp(model, "SUNW,sbus-qfe")) is_qfe = 1; diff --combined drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 6623656,cd05019..ab255fb --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@@ -664,7 -664,7 +664,7 @@@ static void bnx2fc_link_speed_update(st struct fcoe_port *port = lport_priv(lport); struct bnx2fc_hba *hba = port->priv; struct net_device *netdev = hba->netdev; - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_cmd ecmd;
if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= @@@ -675,12 -675,15 +675,15 @@@ if (ecmd.supported & SUPPORTED_10000baseT_Full) lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
- if (ecmd.speed == SPEED_1000) + switch (ethtool_cmd_speed(&ecmd)) { + case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) + break; + case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; + break; + } } - return; } static int bnx2fc_link_ok(struct fc_lport *lport) { @@@ -1130,7 -1133,7 +1133,7 @@@ static void bnx2fc_interface_release(st struct net_device *phys_dev;
hba = container_of(kref, struct bnx2fc_hba, kref); - BNX2FC_HBA_DBG(hba->ctlr.lp, "Interface is being released\n"); + BNX2FC_MISC_DBG("Interface is being released\n");
netdev = hba->netdev; phys_dev = hba->phys_dev; @@@ -1254,17 -1257,20 +1257,17 @@@ setup_err static struct fc_lport *bnx2fc_if_create(struct bnx2fc_hba *hba, struct device *parent, int npiv) { - struct fc_lport *lport = NULL; + struct fc_lport *lport, *n_port; struct fcoe_port *port; struct Scsi_Host *shost; struct fc_vport *vport = dev_to_vport(parent); int rc = 0;
/* Allocate Scsi_Host structure */ - if (!npiv) { - lport = libfc_host_alloc(&bnx2fc_shost_template, - sizeof(struct fcoe_port)); - } else { - lport = libfc_vport_create(vport, - sizeof(struct fcoe_port)); - } + if (!npiv) + lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); + else + lport = libfc_vport_create(vport, sizeof(*port));
if (!lport) { printk(KERN_ERR PFX "could not allocate scsi host structure\n"); @@@ -1282,6 -1288,7 +1285,6 @@@ goto lp_config_err;
if (npiv) { - vport = dev_to_vport(parent); printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n", vport->node_name, vport->port_name); fc_set_wwnn(lport, vport->node_name); @@@ -1310,17 -1317,12 +1313,17 @@@ fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
/* Allocate exchange manager */ - if (!npiv) { + if (!npiv) rc = bnx2fc_em_config(lport); - if (rc) { - printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); - goto shost_err; - } + else { + shost = vport_to_shost(vport); + n_port = shost_priv(shost); + rc = fc_exch_mgr_list_clone(n_port, lport); + } + + if (rc) { + printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); + goto shost_err; }
bnx2fc_interface_get(hba); @@@ -1353,6 -1355,8 +1356,6 @@@ static void bnx2fc_if_destroy(struct fc /* Free existing transmit skbs */ fcoe_clean_pending_queue(lport);
- bnx2fc_interface_put(hba); - /* Free queued packets for the receive thread */ bnx2fc_clean_rx_queue(lport);
@@@ -1371,8 -1375,6 +1374,8 @@@
/* Release Scsi_Host */ scsi_host_put(lport->host); + + bnx2fc_interface_put(hba); }
/** diff --combined drivers/scsi/fcoe/fcoe.c index 5d3700d,04f346b..cc23bd9 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@@ -381,42 -381,6 +381,42 @@@ out }
/** + * fcoe_interface_release() - fcoe_port kref release function + * @kref: Embedded reference count in an fcoe_interface struct + */ +static void fcoe_interface_release(struct kref *kref) +{ + struct fcoe_interface *fcoe; + struct net_device *netdev; + + fcoe = container_of(kref, struct fcoe_interface, kref); + netdev = fcoe->netdev; + /* tear-down the FCoE controller */ + fcoe_ctlr_destroy(&fcoe->ctlr); + kfree(fcoe); + dev_put(netdev); + module_put(THIS_MODULE); +} + +/** + * fcoe_interface_get() - Get a reference to a FCoE interface + * @fcoe: The FCoE interface to be held + */ +static inline void fcoe_interface_get(struct fcoe_interface *fcoe) +{ + kref_get(&fcoe->kref); +} + +/** + * fcoe_interface_put() - Put a reference to a FCoE interface + * @fcoe: The FCoE interface to be released + */ +static inline void fcoe_interface_put(struct fcoe_interface *fcoe) +{ + kref_put(&fcoe->kref, fcoe_interface_release); +} + +/** * fcoe_interface_cleanup() - Clean up a FCoE interface * @fcoe: The FCoE interface to be cleaned up * @@@ -428,21 -392,6 +428,21 @@@ void fcoe_interface_cleanup(struct fcoe struct fcoe_ctlr *fip = &fcoe->ctlr; u8 flogi_maddr[ETH_ALEN]; const struct net_device_ops *ops; + struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + + FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); + + /* Logout of the fabric */ + fc_fabric_logoff(fcoe->ctlr.lp); + + /* Cleanup the fc_lport */ + fc_lport_destroy(fcoe->ctlr.lp); + + /* Stop the transmit retry timer */ + del_timer_sync(&port->timer); + + /* Free existing transmit skbs */ + fcoe_clean_pending_queue(fcoe->ctlr.lp);
/* * Don't listen for Ethernet packets anymore. @@@ -465,9 -414,6 +465,9 @@@ } else dev_mc_del(netdev, FIP_ALL_ENODE_MACS);
+ if (!is_zero_ether_addr(port->data_src_addr)) + dev_uc_del(netdev, port->data_src_addr); + /* Tell the LLD we are done w/ FCoE */ ops = netdev->netdev_ops; if (ops->ndo_fcoe_disable) { @@@ -475,7 -421,42 +475,7 @@@ FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" " specific feature for LLD.\n"); } -} - -/** - * fcoe_interface_release() - fcoe_port kref release function - * @kref: Embedded reference count in an fcoe_interface struct - */ -static void fcoe_interface_release(struct kref *kref) -{ - struct fcoe_interface *fcoe; - struct net_device *netdev; - - fcoe = container_of(kref, struct fcoe_interface, kref); - netdev = fcoe->netdev; - /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(&fcoe->ctlr); - kfree(fcoe); - dev_put(netdev); - module_put(THIS_MODULE); -} - -/** - * fcoe_interface_get() - Get a reference to a FCoE interface - * @fcoe: The FCoE interface to be held - */ -static inline void fcoe_interface_get(struct fcoe_interface *fcoe) -{ - kref_get(&fcoe->kref); -} - -/** - * fcoe_interface_put() - Put a reference to a FCoE interface - * @fcoe: The FCoE interface to be released - */ -static inline void fcoe_interface_put(struct fcoe_interface *fcoe) -{ - kref_put(&fcoe->kref, fcoe_interface_release); + fcoe_interface_put(fcoe); }
/** @@@ -840,9 -821,39 +840,9 @@@ skip_oem * fcoe_if_destroy() - Tear down a SW FCoE instance * @lport: The local port to be destroyed * */ static void fcoe_if_destroy(struct fc_lport *lport) { - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - - FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - - /* Logout of the fabric */ - fc_fabric_logoff(lport); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(netdev, port->data_src_addr); - rtnl_unlock(); - - /* receives may not be stopped until after this */ - fcoe_interface_put(fcoe); - /* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean(lport);
@@@ -1772,8 -1783,23 +1772,8 @@@ static int fcoe_disable(struct net_devi int rc = 0;
mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - }
+ rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock();
@@@ -1783,6 -1809,7 +1783,6 @@@ } else rc = -ENODEV;
-out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@@ -1801,7 -1828,22 +1801,7 @@@ static int fcoe_enable(struct net_devic int rc = 0;
mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); rtnl_unlock();
@@@ -1810,6 -1852,7 +1810,6 @@@ else if (!fcoe_link_ok(fcoe->ctlr.lp)) fcoe_ctlr_link_up(&fcoe->ctlr);
-out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; } @@@ -1825,22 -1868,35 +1825,22 @@@ static int fcoe_destroy(struct net_device *netdev) { struct fcoe_interface *fcoe; + struct fc_lport *lport; int rc = 0;
mutex_lock(&fcoe_config_mutex); -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - + rtnl_lock(); fcoe = fcoe_hostlist_lookup_port(netdev); if (!fcoe) { rtnl_unlock(); rc = -ENODEV; goto out_nodev; } - fcoe_interface_cleanup(fcoe); + lport = fcoe->ctlr.lp; list_del(&fcoe->list); - /* RTNL mutex is dropped by fcoe_if_destroy */ - fcoe_if_destroy(fcoe->ctlr.lp); + fcoe_interface_cleanup(fcoe); + rtnl_unlock(); + fcoe_if_destroy(lport); out_nodev: mutex_unlock(&fcoe_config_mutex); return rc; @@@ -1856,6 -1912,8 +1856,6 @@@ static void fcoe_destroy_work(struct wo
port = container_of(work, struct fcoe_port, destroy_work); mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - /* RTNL mutex is dropped by fcoe_if_destroy */ fcoe_if_destroy(port->lport); mutex_unlock(&fcoe_config_mutex); } @@@ -1890,7 -1948,23 +1890,7 @@@ static int fcoe_create(struct net_devic struct fc_lport *lport;
mutex_lock(&fcoe_config_mutex); - - if (!rtnl_trylock()) { - mutex_unlock(&fcoe_config_mutex); - return -ERESTARTSYS; - } - -#ifdef CONFIG_FCOE_MODULE - /* - * Make sure the module has been initialized, and is not about to be - * removed. Module paramter sysfs files are writable before the - * module_init function is called and after module_exit. - */ - if (THIS_MODULE->state != MODULE_STATE_LIVE) { - rc = -ENODEV; - goto out_nodev; - } -#endif + rtnl_lock();
/* look for existing lport */ if (fcoe_hostlist_lookup(netdev)) { @@@ -1952,7 -2026,7 +1952,7 @@@ out_nodev int fcoe_link_speed_update(struct fc_lport *lport) { struct net_device *netdev = fcoe_netdev(lport); - struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + struct ethtool_cmd ecmd;
if (!dev_ethtool_get_settings(netdev, &ecmd)) { lport->link_supported_speeds &= @@@ -1963,11 -2037,14 +1963,14 @@@ if (ecmd.supported & SUPPORTED_10000baseT_Full) lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - if (ecmd.speed == SPEED_1000) + switch (ethtool_cmd_speed(&ecmd)) { + case SPEED_1000: lport->link_speed = FC_PORTSPEED_1GBIT; - if (ecmd.speed == SPEED_10000) + break; + case SPEED_10000: lport->link_speed = FC_PORTSPEED_10GBIT; - + break; + } return 0; } return -1; diff --combined include/linux/ssb/ssb.h index 045f72a,f017b89..252e4482 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@@ -308,7 -308,7 +308,7 @@@ struct ssb_bus
/* ID information about the Chip. */ u16 chip_id; - u16 chip_rev; + u8 chip_rev; u16 sprom_offset; u16 sprom_size; /* number of words in sprom */ u8 chip_package; @@@ -404,9 -404,7 +404,9 @@@ extern bool ssb_is_sprom_available(stru
/* Set a fallback SPROM. * See kdoc at the function definition for complete documentation. */ -extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom); +extern int ssb_arch_register_fallback_sprom( + int (*sprom_callback)(struct ssb_bus *bus, + struct ssb_sprom *out));
/* Suspend a SSB bus. * Call this from the parent bus suspend routine. */ @@@ -520,6 -518,7 +520,7 @@@ extern int ssb_bus_may_powerdown(struc * Otherwise static always-on powercontrol will be used. */ extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
+ extern void ssb_commit_settings(struct ssb_bus *bus);
/* Various helper functions */ extern u32 ssb_admatch_base(u32 adm); diff --combined include/net/sctp/sctp.h index 01e094c,7e8e34c..b2c2366 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@@ -115,6 -115,7 +115,6 @@@ * sctp/protocol.c */ extern struct sock *sctp_get_ctl_sock(void); -extern void sctp_local_addr_free(struct rcu_head *head); extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, sctp_scope_t, gfp_t gfp, int flags); @@@ -530,7 -531,6 +530,6 @@@ _sctp_walk_params((pos), (chunk), ntohs
#define _sctp_walk_params(pos, chunk, end, member)\ for (pos.v = chunk->member;\ - pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\ pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\ ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\ pos.v += WORD_ROUND(ntohs(pos.p->length))) @@@ -541,7 -541,6 +540,6 @@@ _sctp_walk_errors((err), (chunk_hdr), n #define _sctp_walk_errors(err, chunk_hdr, end)\ for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ sizeof(sctp_chunkhdr_t));\ - (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\ (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\ ntohs(err->length) >= sizeof(sctp_errhdr_t); \ err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length)))) diff --combined net/9p/client.c index a9aa2dd,0ce9592..ceab943 --- a/net/9p/client.c +++ b/net/9p/client.c @@@ -614,7 -614,7 +614,7 @@@ p9_client_rpc(struct p9_client *c, int8
err = c->trans_mod->request(c, req); if (err < 0) { - if (err != -ERESTARTSYS) + if (err != -ERESTARTSYS && err != -EFAULT) c->status = Disconnected; goto reterr; } @@@ -929,15 -929,15 +929,15 @@@ error } EXPORT_SYMBOL(p9_client_attach);
-struct p9_fid *p9_client_walk(struct p9_fid *oldfid, int nwname, char **wnames, - int clone) +struct p9_fid *p9_client_walk(struct p9_fid *oldfid, uint16_t nwname, + char **wnames, int clone) { int err; struct p9_client *clnt; struct p9_fid *fid; struct p9_qid *wqids; struct p9_req_t *req; - int16_t nwqids, count; + uint16_t nwqids, count;
err = 0; wqids = NULL; @@@ -955,7 -955,7 +955,7 @@@ fid = oldfid;
- P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %d wname[0] %s\n", + P9_DPRINTK(P9_DEBUG_9P, ">>> TWALK fids %d,%d nwname %ud wname[0] %s\n", oldfid->fid, fid->fid, nwname, wnames ? wnames[0] : NULL);
req = p9_client_rpc(clnt, P9_TWALK, "ddT", oldfid->fid, fid->fid, @@@ -1220,6 -1220,27 +1220,6 @@@ error } EXPORT_SYMBOL(p9_client_fsync);
-int p9_client_sync_fs(struct p9_fid *fid) -{ - int err = 0; - struct p9_req_t *req; - struct p9_client *clnt; - - P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid); - - clnt = fid->clnt; - req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid); - if (IS_ERR(req)) { - err = PTR_ERR(req); - goto error; - } - P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid); - p9_free_req(clnt, req); -error: - return err; -} -EXPORT_SYMBOL(p9_client_sync_fs); - int p9_client_clunk(struct p9_fid *fid) { int err; @@@ -1281,7 -1302,7 +1281,7 @@@ in p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, u32 count) { - int err, rsize, total; + int err, rsize; struct p9_client *clnt; struct p9_req_t *req; char *dataptr; @@@ -1290,7 -1311,6 +1290,6 @@@ (long long unsigned) offset, count); err = 0; clnt = fid->clnt; - total = 0;
rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) @@@ -1346,7 -1366,7 +1345,7 @@@ in p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, u64 offset, u32 count) { - int err, rsize, total; + int err, rsize; struct p9_client *clnt; struct p9_req_t *req;
@@@ -1354,7 -1374,6 +1353,6 @@@ fid->fid, (long long unsigned) offset, count); err = 0; clnt = fid->clnt; - total = 0;
rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_IOHDRSZ) @@@ -1745,7 -1764,7 +1743,7 @@@ EXPORT_SYMBOL_GPL(p9_client_xattrcreate
int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) { - int err, rsize, total; + int err, rsize; struct p9_client *clnt; struct p9_req_t *req; char *dataptr; @@@ -1755,7 -1774,6 +1753,6 @@@
err = 0; clnt = fid->clnt; - total = 0;
rsize = fid->iounit; if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ) diff --combined net/batman-adv/gateway_client.c index 150b6ce,65f3953..61605a0 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@@ -23,72 -23,96 +23,88 @@@ #include "gateway_client.h" #include "gateway_common.h" #include "hard-interface.h" + #include "originator.h" #include <linux/ip.h> #include <linux/ipv6.h> #include <linux/udp.h> #include <linux/if_vlan.h>
static void gw_node_free_ref(struct gw_node *gw_node) { if (atomic_dec_and_test(&gw_node->refcount)) - call_rcu(&gw_node->rcu, gw_node_free_rcu); + kfree_rcu(gw_node, rcu); }
- void *gw_get_selected(struct bat_priv *bat_priv) + static struct gw_node *gw_get_selected_gw_node(struct bat_priv *bat_priv) { - struct gw_node *curr_gateway_tmp; - struct orig_node *orig_node = NULL; + struct gw_node *gw_node;
rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out; - - orig_node = curr_gateway_tmp->orig_node; - if (!orig_node) + gw_node = rcu_dereference(bat_priv->curr_gw); + if (!gw_node) goto out;
- if (!atomic_inc_not_zero(&orig_node->refcount)) - orig_node = NULL; + if (!atomic_inc_not_zero(&gw_node->refcount)) + gw_node = NULL;
out: rcu_read_unlock(); - return orig_node; + return gw_node; }
- void gw_deselect(struct bat_priv *bat_priv) + struct orig_node *gw_get_selected_orig(struct bat_priv *bat_priv) { struct gw_node *gw_node; + struct orig_node *orig_node = NULL;
- spin_lock_bh(&bat_priv->gw_list_lock); - gw_node = rcu_dereference(bat_priv->curr_gw); - rcu_assign_pointer(bat_priv->curr_gw, NULL); - spin_unlock_bh(&bat_priv->gw_list_lock); + gw_node = gw_get_selected_gw_node(bat_priv); + if (!gw_node) + goto out; + + rcu_read_lock(); + orig_node = gw_node->orig_node; + if (!orig_node) + goto unlock; + + if (!atomic_inc_not_zero(&orig_node->refcount)) + orig_node = NULL;
+ unlock: + rcu_read_unlock(); + out: if (gw_node) gw_node_free_ref(gw_node); + return orig_node; }
static void gw_select(struct bat_priv *bat_priv, struct gw_node *new_gw_node) { struct gw_node *curr_gw_node;
+ spin_lock_bh(&bat_priv->gw_list_lock); + if (new_gw_node && !atomic_inc_not_zero(&new_gw_node->refcount)) new_gw_node = NULL;
- spin_lock_bh(&bat_priv->gw_list_lock); - curr_gw_node = rcu_dereference(bat_priv->curr_gw); + curr_gw_node = bat_priv->curr_gw; rcu_assign_pointer(bat_priv->curr_gw, new_gw_node);
if (curr_gw_node) gw_node_free_ref(curr_gw_node); + + spin_unlock_bh(&bat_priv->gw_list_lock); + } + + void gw_deselect(struct bat_priv *bat_priv) + { + gw_select(bat_priv, NULL); }
void gw_election(struct bat_priv *bat_priv) { struct hlist_node *node; - struct gw_node *gw_node, *curr_gw, *curr_gw_tmp = NULL; + struct gw_node *gw_node, *curr_gw = NULL, *curr_gw_tmp = NULL; + struct neigh_node *router; uint8_t max_tq = 0; uint32_t max_gw_factor = 0, tmp_gw_factor = 0; int down, up; @@@ -102,32 -126,25 +118,25 @@@ if (atomic_read(&bat_priv->gw_mode) != GW_MODE_CLIENT) return;
- rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); - if (curr_gw) { - rcu_read_unlock(); - return; - } + curr_gw = gw_get_selected_gw_node(bat_priv); + if (curr_gw) + goto out;
+ rcu_read_lock(); if (hlist_empty(&bat_priv->gw_list)) { - - if (curr_gw) { - rcu_read_unlock(); - bat_dbg(DBG_BATMAN, bat_priv, - "Removing selected gateway - " - "no gateway in range\n"); - gw_deselect(bat_priv); - } else - rcu_read_unlock(); - - return; + bat_dbg(DBG_BATMAN, bat_priv, + "Removing selected gateway - " + "no gateway in range\n"); + gw_deselect(bat_priv); + goto unlock; }
hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { - if (!gw_node->orig_node->router) + if (gw_node->deleted) continue;
- if (gw_node->deleted) + router = orig_node_get_router(gw_node->orig_node); + if (!router) continue;
switch (atomic_read(&bat_priv->gw_sel_class)) { @@@ -135,15 -152,14 +144,14 @@@ gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
- tmp_gw_factor = (gw_node->orig_node->router->tq_avg * - gw_node->orig_node->router->tq_avg * + tmp_gw_factor = (router->tq_avg * router->tq_avg * down * 100 * 100) / (TQ_LOCAL_WINDOW_SIZE * TQ_LOCAL_WINDOW_SIZE * 64);
if ((tmp_gw_factor > max_gw_factor) || ((tmp_gw_factor == max_gw_factor) && - (gw_node->orig_node->router->tq_avg > max_tq))) + (router->tq_avg > max_tq))) curr_gw_tmp = gw_node; break;
@@@ -155,19 -171,25 +163,25 @@@ * soon as a better gateway appears which has * $routing_class more tq points) **/ - if (gw_node->orig_node->router->tq_avg > max_tq) + if (router->tq_avg > max_tq) curr_gw_tmp = gw_node; break; }
- if (gw_node->orig_node->router->tq_avg > max_tq) - max_tq = gw_node->orig_node->router->tq_avg; + if (router->tq_avg > max_tq) + max_tq = router->tq_avg;
if (tmp_gw_factor > max_gw_factor) max_gw_factor = tmp_gw_factor; + + neigh_node_free_ref(router); }
if (curr_gw != curr_gw_tmp) { + router = orig_node_get_router(curr_gw_tmp->orig_node); + if (!router) + goto unlock; + if ((curr_gw) && (!curr_gw_tmp)) bat_dbg(DBG_BATMAN, bat_priv, "Removing selected gateway - " @@@ -178,48 -200,50 +192,50 @@@ "(gw_flags: %i, tq: %i)\n", curr_gw_tmp->orig_node->orig, curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); + router->tq_avg); else bat_dbg(DBG_BATMAN, bat_priv, "Changing route to gateway %pM " "(gw_flags: %i, tq: %i)\n", curr_gw_tmp->orig_node->orig, curr_gw_tmp->orig_node->gw_flags, - curr_gw_tmp->orig_node->router->tq_avg); + router->tq_avg);
+ neigh_node_free_ref(router); gw_select(bat_priv, curr_gw_tmp); }
+ unlock: rcu_read_unlock(); + out: + if (curr_gw) + gw_node_free_ref(curr_gw); }
void gw_check_election(struct bat_priv *bat_priv, struct orig_node *orig_node) { - struct gw_node *curr_gateway_tmp; + struct orig_node *curr_gw_orig; + struct neigh_node *router_gw = NULL, *router_orig = NULL; uint8_t gw_tq_avg, orig_tq_avg;
- rcu_read_lock(); - curr_gateway_tmp = rcu_dereference(bat_priv->curr_gw); - if (!curr_gateway_tmp) - goto out_rcu; - - if (!curr_gateway_tmp->orig_node) - goto deselect_rcu; + curr_gw_orig = gw_get_selected_orig(bat_priv); + if (!curr_gw_orig) + goto deselect;
- if (!curr_gateway_tmp->orig_node->router) - goto deselect_rcu; + router_gw = orig_node_get_router(curr_gw_orig); + if (!router_gw) + goto deselect;
/* this node already is the gateway */ - if (curr_gateway_tmp->orig_node == orig_node) - goto out_rcu; - - if (!orig_node->router) - goto out_rcu; + if (curr_gw_orig == orig_node) + goto out;
- gw_tq_avg = curr_gateway_tmp->orig_node->router->tq_avg; - rcu_read_unlock(); + router_orig = orig_node_get_router(orig_node); + if (!router_orig) + goto out;
- orig_tq_avg = orig_node->router->tq_avg; + gw_tq_avg = router_gw->tq_avg; + orig_tq_avg = router_orig->tq_avg;
/* the TQ value has to be better */ if (orig_tq_avg < gw_tq_avg) @@@ -237,16 -261,17 +253,17 @@@ "Restarting gateway selection: better gateway found (tq curr: " "%i, tq new: %i)\n", gw_tq_avg, orig_tq_avg); - goto deselect;
deselect: gw_deselect(bat_priv); out: + if (curr_gw_orig) + orig_node_free_ref(curr_gw_orig); + if (router_gw) + neigh_node_free_ref(router_gw); + if (router_orig) + neigh_node_free_ref(router_orig); + return; }
@@@ -283,7 -308,15 +300,15 @@@ void gw_node_update(struct bat_priv *ba struct orig_node *orig_node, uint8_t new_gwflags) { struct hlist_node *node; - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; + + /** + * Note: We don't need a NULL check here, since curr_gw never gets + * dereferenced. If curr_gw is NULL we also should not exit as we may + * have this gateway in our list (duplication check!) even though we + * have no currently selected gateway. + */ + curr_gw = gw_get_selected_gw_node(bat_priv);
rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { @@@ -304,22 -337,26 +329,26 @@@ "Gateway %pM removed from gateway list\n", orig_node->orig);
- if (gw_node == rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); - gw_deselect(bat_priv); - return; - } + if (gw_node == curr_gw) + goto deselect; }
- rcu_read_unlock(); - return; + goto unlock; } - rcu_read_unlock();
if (new_gwflags == 0) - return; + goto unlock;
gw_node_add(bat_priv, orig_node, new_gwflags); + goto unlock; + + deselect: + gw_deselect(bat_priv); + unlock: + rcu_read_unlock(); + + if (curr_gw) + gw_node_free_ref(curr_gw); }
void gw_node_delete(struct bat_priv *bat_priv, struct orig_node *orig_node) @@@ -329,9 -366,12 +358,12 @@@
void gw_node_purge(struct bat_priv *bat_priv) { - struct gw_node *gw_node; + struct gw_node *gw_node, *curr_gw; struct hlist_node *node, *node_tmp; unsigned long timeout = 2 * PURGE_TIMEOUT * HZ; + char do_deselect = 0; + + curr_gw = gw_get_selected_gw_node(bat_priv);
spin_lock_bh(&bat_priv->gw_list_lock);
@@@ -342,41 -382,56 +374,56 @@@ atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) continue;
- if (rcu_dereference(bat_priv->curr_gw) == gw_node) - gw_deselect(bat_priv); + if (curr_gw == gw_node) + do_deselect = 1;
hlist_del_rcu(&gw_node->list); gw_node_free_ref(gw_node); }
- spin_unlock_bh(&bat_priv->gw_list_lock); + + /* gw_deselect() needs to acquire the gw_list_lock */ + if (do_deselect) + gw_deselect(bat_priv); + + if (curr_gw) + gw_node_free_ref(curr_gw); }
+ /** + * fails if orig_node has no router + */ static int _write_buffer_text(struct bat_priv *bat_priv, struct seq_file *seq, struct gw_node *gw_node) { struct gw_node *curr_gw; - int down, up, ret; + struct neigh_node *router; + int down, up, ret = -1;
gw_bandwidth_to_kbit(gw_node->orig_node->gw_flags, &down, &up);
- rcu_read_lock(); - curr_gw = rcu_dereference(bat_priv->curr_gw); + router = orig_node_get_router(gw_node->orig_node); + if (!router) + goto out;
- ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", - (curr_gw == gw_node ? "=>" : " "), - gw_node->orig_node->orig, - gw_node->orig_node->router->tq_avg, - gw_node->orig_node->router->addr, - gw_node->orig_node->router->if_incoming->net_dev->name, - gw_node->orig_node->gw_flags, - (down > 2048 ? down / 1024 : down), - (down > 2048 ? "MBit" : "KBit"), - (up > 2048 ? up / 1024 : up), - (up > 2048 ? "MBit" : "KBit")); + curr_gw = gw_get_selected_gw_node(bat_priv);
- rcu_read_unlock(); + ret = seq_printf(seq, "%s %pM (%3i) %pM [%10s]: %3i - %i%s/%i%s\n", + (curr_gw == gw_node ? "=>" : " "), + gw_node->orig_node->orig, + router->tq_avg, router->addr, + router->if_incoming->net_dev->name, + gw_node->orig_node->gw_flags, + (down > 2048 ? down / 1024 : down), + (down > 2048 ? "MBit" : "KBit"), + (up > 2048 ? up / 1024 : up), + (up > 2048 ? "MBit" : "KBit")); + + neigh_node_free_ref(router); + if (curr_gw) + gw_node_free_ref(curr_gw); + out: return ret; }
@@@ -384,40 -439,42 +431,42 @@@ int gw_client_seq_print_text(struct seq { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); + struct hard_iface *primary_if; struct gw_node *gw_node; struct hlist_node *node; - int gw_count = 0; - - if (!bat_priv->primary_if) { + int gw_count = 0, ret = 0;
- return seq_printf(seq, "BATMAN mesh %s disabled - please " - "specify interfaces to enable it\n", - net_dev->name); + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - please " + "specify interfaces to enable it\n", + net_dev->name); + goto out; }
- if (bat_priv->primary_if->if_status != IF_ACTIVE) { - - return seq_printf(seq, "BATMAN mesh %s disabled - " - "primary interface not active\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, " %-12s (%s/%i) %17s [%10s]: gw_class ... " "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", "Gateway", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + primary_if->net_dev->name, + primary_if->net_dev->dev_addr, net_dev->name);
rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, node, &bat_priv->gw_list, list) { if (gw_node->deleted) continue;
- if (!gw_node->orig_node->router) + /* fails if orig_node has no router */ + if (_write_buffer_text(bat_priv, seq, gw_node) < 0) continue;
- _write_buffer_text(bat_priv, seq, gw_node); gw_count++; } rcu_read_unlock(); @@@ -425,7 -482,10 +474,10 @@@ if (gw_count == 0) seq_printf(seq, "No gateways in range ...\n");
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
int gw_is_target(struct bat_priv *bat_priv, struct sk_buff *skb) @@@ -434,6 -494,7 +486,7 @@@ struct iphdr *iphdr; struct ipv6hdr *ipv6hdr; struct udphdr *udphdr; + struct gw_node *curr_gw; unsigned int header_len = 0;
if (atomic_read(&bat_priv->gw_mode) == GW_MODE_OFF) @@@ -498,12 -559,11 +551,11 @@@ if (atomic_read(&bat_priv->gw_mode) == GW_MODE_SERVER) return -1;
- rcu_read_lock(); - if (!rcu_dereference(bat_priv->curr_gw)) { - rcu_read_unlock(); + curr_gw = gw_get_selected_gw_node(bat_priv); + if (!curr_gw) return 0; - } - rcu_read_unlock();
+ if (curr_gw) + gw_node_free_ref(curr_gw); return 1; } diff --combined net/batman-adv/originator.c index ed23a589,080ec883..40a30bb --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@@ -19,8 -19,6 +19,6 @@@ * */
- /* increase the reference counter for this originator */ - #include "main.h" #include "originator.h" #include "hash.h" @@@ -56,12 -54,35 +54,27 @@@ err return 0; }
void neigh_node_free_ref(struct neigh_node *neigh_node) { if (atomic_dec_and_test(&neigh_node->refcount)) - call_rcu(&neigh_node->rcu, neigh_node_free_rcu); + kfree_rcu(neigh_node, rcu); }
+ /* increases the refcounter of a found router */ + struct neigh_node *orig_node_get_router(struct orig_node *orig_node) + { + struct neigh_node *router; + + rcu_read_lock(); + router = rcu_dereference(orig_node->router); + + if (router && !atomic_inc_not_zero(&router->refcount)) + router = NULL; + + rcu_read_unlock(); + return router; + } + struct neigh_node *create_neighbor(struct orig_node *orig_node, struct orig_node *orig_neigh_node, uint8_t *neigh, @@@ -79,6 -100,7 +92,7 @@@
INIT_HLIST_NODE(&neigh_node->list); INIT_LIST_HEAD(&neigh_node->bonding_list); + spin_lock_init(&neigh_node->tq_lock);
memcpy(neigh_node->addr, neigh, ETH_ALEN); neigh_node->orig_node = orig_neigh_node; @@@ -120,7 -142,7 +134,7 @@@ static void orig_node_free_rcu(struct r spin_unlock_bh(&orig_node->neigh_list_lock);
frag_list_free(&orig_node->frag_list); - hna_global_del_orig(orig_node->bat_priv, orig_node, + tt_global_del_orig(orig_node->bat_priv, orig_node, "originator timed out");
kfree(orig_node->bcast_own); @@@ -198,7 -220,7 +212,7 @@@ struct orig_node *get_orig_node(struct orig_node->bat_priv = bat_priv; memcpy(orig_node->orig, addr, ETH_ALEN); orig_node->router = NULL; - orig_node->hna_buff = NULL; + orig_node->tt_buff = NULL; orig_node->bcast_seqno_reset = jiffies - 1 - msecs_to_jiffies(RESET_PROTECTION_MS); orig_node->batman_seqno_reset = jiffies - 1 @@@ -309,8 -331,8 +323,8 @@@ static bool purge_orig_node(struct bat_ &best_neigh_node)) { update_routes(bat_priv, orig_node, best_neigh_node, - orig_node->hna_buff, - orig_node->hna_buff_len); + orig_node->tt_buff, + orig_node->tt_buff_len); } }
@@@ -381,29 -403,34 +395,34 @@@ int orig_seq_print_text(struct seq_fil struct hashtable_t *hash = bat_priv->orig_hash; struct hlist_node *node, *node_tmp; struct hlist_head *head; + struct hard_iface *primary_if; struct orig_node *orig_node; - struct neigh_node *neigh_node; + struct neigh_node *neigh_node, *neigh_node_tmp; int batman_count = 0; int last_seen_secs; int last_seen_msecs; - int i; + int i, ret = 0; + + primary_if = primary_if_get_selected(bat_priv);
- if ((!bat_priv->primary_if) || - (bat_priv->primary_if->if_status != IF_ACTIVE)) { - if (!bat_priv->primary_if) - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + }
- return seq_printf(seq, "BATMAN mesh %s " - "disabled - primary interface not active\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, "[B.A.T.M.A.N. adv %s%s, MainIF/MAC: %s/%pM (%s)]\n", SOURCE_VERSION, REVISION_VERSION_STR, - bat_priv->primary_if->net_dev->name, - bat_priv->primary_if->net_dev->dev_addr, net_dev->name); + primary_if->net_dev->name, + primary_if->net_dev->dev_addr, net_dev->name); seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", "Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop", "outgoingIF", "Potential nexthops"); @@@ -413,40 -440,47 +432,47 @@@
rcu_read_lock(); hlist_for_each_entry_rcu(orig_node, node, head, hash_entry) { - if (!orig_node->router) + neigh_node = orig_node_get_router(orig_node); + if (!neigh_node) continue;
- if (orig_node->router->tq_avg == 0) - continue; + if (neigh_node->tq_avg == 0) + goto next;
last_seen_secs = jiffies_to_msecs(jiffies - orig_node->last_valid) / 1000; last_seen_msecs = jiffies_to_msecs(jiffies - orig_node->last_valid) % 1000;
- neigh_node = orig_node->router; seq_printf(seq, "%pM %4i.%03is (%3i) %pM [%10s]:", orig_node->orig, last_seen_secs, last_seen_msecs, neigh_node->tq_avg, neigh_node->addr, neigh_node->if_incoming->net_dev->name);
- hlist_for_each_entry_rcu(neigh_node, node_tmp, + hlist_for_each_entry_rcu(neigh_node_tmp, node_tmp, &orig_node->neigh_list, list) { - seq_printf(seq, " %pM (%3i)", neigh_node->addr, - neigh_node->tq_avg); + seq_printf(seq, " %pM (%3i)", + neigh_node_tmp->addr, + neigh_node_tmp->tq_avg); }
seq_printf(seq, "\n"); batman_count++; + + next: + neigh_node_free_ref(neigh_node); } rcu_read_unlock(); }
- if ((batman_count == 0)) + if (batman_count == 0) seq_printf(seq, "No batman nodes in range ...\n");
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; }
static int orig_node_add_if(struct orig_node *orig_node, int max_if_num) diff --combined net/batman-adv/soft-interface.c index 04efe02,c76a33e..d5aa609 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@@ -43,8 -43,6 +43,6 @@@ static void bat_get_drvinfo(struct net_ static u32 bat_get_msglevel(struct net_device *dev); static void bat_set_msglevel(struct net_device *dev, u32 value); static u32 bat_get_link(struct net_device *dev); - static u32 bat_get_rx_csum(struct net_device *dev); - static int bat_set_rx_csum(struct net_device *dev, u32 data);
static const struct ethtool_ops bat_ethtool_ops = { .get_settings = bat_get_settings, @@@ -52,8 -50,6 +50,6 @@@ .get_msglevel = bat_get_msglevel, .set_msglevel = bat_set_msglevel, .get_link = bat_get_link, - .get_rx_csum = bat_get_rx_csum, - .set_rx_csum = bat_set_rx_csum };
int my_skb_head_push(struct sk_buff *skb, unsigned int len) @@@ -76,112 -72,379 +72,371 @@@ return 0; }
static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) { if (atomic_dec_and_test(&softif_neigh->refcount)) - call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + kfree_rcu(softif_neigh, rcu); }
- void softif_neigh_purge(struct bat_priv *bat_priv) + static void softif_neigh_vid_free_rcu(struct rcu_head *rcu) { - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *softif_neigh; struct hlist_node *node, *node_tmp; + struct bat_priv *bat_priv;
- spin_lock_bh(&bat_priv->softif_neigh_lock); + softif_neigh_vid = container_of(rcu, struct softif_neigh_vid, rcu); + bat_priv = softif_neigh_vid->bat_priv;
+ spin_lock_bh(&bat_priv->softif_neigh_lock); hlist_for_each_entry_safe(softif_neigh, node, node_tmp, - &bat_priv->softif_neigh_list, list) { + &softif_neigh_vid->softif_neigh_list, list) { + hlist_del_rcu(&softif_neigh->list); + softif_neigh_free_ref(softif_neigh); + } + spin_unlock_bh(&bat_priv->softif_neigh_lock);
- if ((!time_after(jiffies, softif_neigh->last_seen + - msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && - (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) - continue; + kfree(softif_neigh_vid); + }
- hlist_del_rcu(&softif_neigh->list); + static void softif_neigh_vid_free_ref(struct softif_neigh_vid *softif_neigh_vid) + { + if (atomic_dec_and_test(&softif_neigh_vid->refcount)) + call_rcu(&softif_neigh_vid->rcu, softif_neigh_vid_free_rcu); + }
- if (bat_priv->softif_neigh == softif_neigh) { - bat_dbg(DBG_ROUTES, bat_priv, - "Current mesh exit point '%pM' vanished " - "(vid: %d).\n", - softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = NULL; - softif_neigh_free_ref(softif_neigh_tmp); - } + static struct softif_neigh_vid *softif_neigh_vid_get(struct bat_priv *bat_priv, + short vid) + { + struct softif_neigh_vid *softif_neigh_vid; + struct hlist_node *node;
- softif_neigh_free_ref(softif_neigh); + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh_vid, node, + &bat_priv->softif_neigh_vids, list) { + if (softif_neigh_vid->vid != vid) + continue; + + if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) + continue; + + goto out; }
- spin_unlock_bh(&bat_priv->softif_neigh_lock); + softif_neigh_vid = kzalloc(sizeof(struct softif_neigh_vid), + GFP_ATOMIC); + if (!softif_neigh_vid) + goto out; + + softif_neigh_vid->vid = vid; + softif_neigh_vid->bat_priv = bat_priv; + + /* initialize with 2 - caller decrements counter by one */ + atomic_set(&softif_neigh_vid->refcount, 2); + INIT_HLIST_HEAD(&softif_neigh_vid->softif_neigh_list); + INIT_HLIST_NODE(&softif_neigh_vid->list); + spin_lock_bh(&bat_priv->softif_neigh_vid_lock); + hlist_add_head_rcu(&softif_neigh_vid->list, + &bat_priv->softif_neigh_vids); + spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); + + out: + rcu_read_unlock(); + return softif_neigh_vid; }
static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, uint8_t *addr, short vid) { - struct softif_neigh *softif_neigh; + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *softif_neigh = NULL; struct hlist_node *node;
+ softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); + if (!softif_neigh_vid) + goto out; + rcu_read_lock(); hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) { + &softif_neigh_vid->softif_neigh_list, + list) { if (!compare_eth(softif_neigh->addr, addr)) continue;
- if (softif_neigh->vid != vid) - continue; - if (!atomic_inc_not_zero(&softif_neigh->refcount)) continue;
softif_neigh->last_seen = jiffies; - goto out; + goto unlock; }
softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); if (!softif_neigh) - goto out; + goto unlock;
memcpy(softif_neigh->addr, addr, ETH_ALEN); - softif_neigh->vid = vid; softif_neigh->last_seen = jiffies; /* initialize with 2 - caller decrements counter by one */ atomic_set(&softif_neigh->refcount, 2);
INIT_HLIST_NODE(&softif_neigh->list); spin_lock_bh(&bat_priv->softif_neigh_lock); - hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); + hlist_add_head_rcu(&softif_neigh->list, + &softif_neigh_vid->softif_neigh_list); spin_unlock_bh(&bat_priv->softif_neigh_lock);
+ unlock: + rcu_read_unlock(); out: + if (softif_neigh_vid) + softif_neigh_vid_free_ref(softif_neigh_vid); + return softif_neigh; + } + + static struct softif_neigh *softif_neigh_get_selected( + struct softif_neigh_vid *softif_neigh_vid) + { + struct softif_neigh *softif_neigh; + + rcu_read_lock(); + softif_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); + + if (softif_neigh && !atomic_inc_not_zero(&softif_neigh->refcount)) + softif_neigh = NULL; + rcu_read_unlock(); return softif_neigh; }
+ static struct softif_neigh *softif_neigh_vid_get_selected( + struct bat_priv *bat_priv, + short vid) + { + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *softif_neigh = NULL; + + softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); + if (!softif_neigh_vid) + goto out; + + softif_neigh = softif_neigh_get_selected(softif_neigh_vid); + out: + if (softif_neigh_vid) + softif_neigh_vid_free_ref(softif_neigh_vid); + return softif_neigh; + } + + static void softif_neigh_vid_select(struct bat_priv *bat_priv, + struct softif_neigh *new_neigh, + short vid) + { + struct softif_neigh_vid *softif_neigh_vid; + struct softif_neigh *curr_neigh; + + softif_neigh_vid = softif_neigh_vid_get(bat_priv, vid); + if (!softif_neigh_vid) + goto out; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + + if (new_neigh && !atomic_inc_not_zero(&new_neigh->refcount)) + new_neigh = NULL; + + curr_neigh = softif_neigh_vid->softif_neigh; + rcu_assign_pointer(softif_neigh_vid->softif_neigh, new_neigh); + + if ((curr_neigh) && (!new_neigh)) + bat_dbg(DBG_ROUTES, bat_priv, + "Removing mesh exit point on vid: %d (prev: %pM).\n", + vid, curr_neigh->addr); + else if ((curr_neigh) && (new_neigh)) + bat_dbg(DBG_ROUTES, bat_priv, + "Changing mesh exit point on vid: %d from %pM " + "to %pM.\n", vid, curr_neigh->addr, new_neigh->addr); + else if ((!curr_neigh) && (new_neigh)) + bat_dbg(DBG_ROUTES, bat_priv, + "Setting mesh exit point on vid: %d to %pM.\n", + vid, new_neigh->addr); + + if (curr_neigh) + softif_neigh_free_ref(curr_neigh); + + spin_unlock_bh(&bat_priv->softif_neigh_lock); + + out: + if (softif_neigh_vid) + softif_neigh_vid_free_ref(softif_neigh_vid); + } + + static void softif_neigh_vid_deselect(struct bat_priv *bat_priv, + struct softif_neigh_vid *softif_neigh_vid) + { + struct softif_neigh *curr_neigh; + struct softif_neigh *softif_neigh = NULL, *softif_neigh_tmp; + struct hard_iface *primary_if = NULL; + struct hlist_node *node; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) + goto out; + + /* find new softif_neigh immediately to avoid temporary loops */ + rcu_read_lock(); + curr_neigh = rcu_dereference(softif_neigh_vid->softif_neigh); + + hlist_for_each_entry_rcu(softif_neigh_tmp, node, + &softif_neigh_vid->softif_neigh_list, + list) { + if (softif_neigh_tmp == curr_neigh) + continue; + + /* we got a neighbor but its mac is 'bigger' than ours */ + if (memcmp(primary_if->net_dev->dev_addr, + softif_neigh_tmp->addr, ETH_ALEN) < 0) + continue; + + if (!atomic_inc_not_zero(&softif_neigh_tmp->refcount)) + continue; + + softif_neigh = softif_neigh_tmp; + goto unlock; + } + + unlock: + rcu_read_unlock(); + out: + softif_neigh_vid_select(bat_priv, softif_neigh, softif_neigh_vid->vid); + + if (primary_if) + hardif_free_ref(primary_if); + if (softif_neigh) + softif_neigh_free_ref(softif_neigh); + } + int softif_neigh_seq_print_text(struct seq_file *seq, void *offset) { struct net_device *net_dev = (struct net_device *)seq->private; struct bat_priv *bat_priv = netdev_priv(net_dev); + struct softif_neigh_vid *softif_neigh_vid; struct softif_neigh *softif_neigh; - struct hlist_node *node; + struct hard_iface *primary_if; + struct hlist_node *node, *node_tmp; + struct softif_neigh *curr_softif_neigh; + int ret = 0, last_seen_secs, last_seen_msecs; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) { + ret = seq_printf(seq, "BATMAN mesh %s disabled - " + "please specify interfaces to enable it\n", + net_dev->name); + goto out; + }
- if (!bat_priv->primary_if) { - return seq_printf(seq, "BATMAN mesh %s disabled - " - "please specify interfaces to enable it\n", - net_dev->name); + if (primary_if->if_status != IF_ACTIVE) { + ret = seq_printf(seq, "BATMAN mesh %s " + "disabled - primary interface not active\n", + net_dev->name); + goto out; }
seq_printf(seq, "Softif neighbor list (%s)\n", net_dev->name);
rcu_read_lock(); - hlist_for_each_entry_rcu(softif_neigh, node, - &bat_priv->softif_neigh_list, list) - seq_printf(seq, "%s %pM (vid: %d)\n", - bat_priv->softif_neigh == softif_neigh - ? "=>" : " ", softif_neigh->addr, - softif_neigh->vid); + hlist_for_each_entry_rcu(softif_neigh_vid, node, + &bat_priv->softif_neigh_vids, list) { + seq_printf(seq, " %-15s %s on vid: %d\n", + "Originator", "last-seen", softif_neigh_vid->vid); + + curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); + + hlist_for_each_entry_rcu(softif_neigh, node_tmp, + &softif_neigh_vid->softif_neigh_list, + list) { + last_seen_secs = jiffies_to_msecs(jiffies - + softif_neigh->last_seen) / 1000; + last_seen_msecs = jiffies_to_msecs(jiffies - + softif_neigh->last_seen) % 1000; + seq_printf(seq, "%s %pM %3i.%03is\n", + curr_softif_neigh == softif_neigh + ? "=>" : " ", softif_neigh->addr, + last_seen_secs, last_seen_msecs); + } + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + + seq_printf(seq, "\n"); + } rcu_read_unlock();
- return 0; + out: + if (primary_if) + hardif_free_ref(primary_if); + return ret; + } + + void softif_neigh_purge(struct bat_priv *bat_priv) + { + struct softif_neigh *softif_neigh, *curr_softif_neigh; + struct softif_neigh_vid *softif_neigh_vid; + struct hlist_node *node, *node_tmp, *node_tmp2; + char do_deselect; + + rcu_read_lock(); + hlist_for_each_entry_rcu(softif_neigh_vid, node, + &bat_priv->softif_neigh_vids, list) { + if (!atomic_inc_not_zero(&softif_neigh_vid->refcount)) + continue; + + curr_softif_neigh = softif_neigh_get_selected(softif_neigh_vid); + do_deselect = 0; + + spin_lock_bh(&bat_priv->softif_neigh_lock); + hlist_for_each_entry_safe(softif_neigh, node_tmp, node_tmp2, + &softif_neigh_vid->softif_neigh_list, + list) { + if ((!time_after(jiffies, softif_neigh->last_seen + + msecs_to_jiffies(SOFTIF_NEIGH_TIMEOUT))) && + (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE)) + continue; + + if (curr_softif_neigh == softif_neigh) { + bat_dbg(DBG_ROUTES, bat_priv, + "Current mesh exit point on vid: %d " + "'%pM' vanished.\n", + softif_neigh_vid->vid, + softif_neigh->addr); + do_deselect = 1; + } + + hlist_del_rcu(&softif_neigh->list); + softif_neigh_free_ref(softif_neigh); + } + spin_unlock_bh(&bat_priv->softif_neigh_lock); + + /* soft_neigh_vid_deselect() needs to acquire the + * softif_neigh_lock */ + if (do_deselect) + softif_neigh_vid_deselect(bat_priv, softif_neigh_vid); + + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + + softif_neigh_vid_free_ref(softif_neigh_vid); + } + rcu_read_unlock(); + + spin_lock_bh(&bat_priv->softif_neigh_vid_lock); + hlist_for_each_entry_safe(softif_neigh_vid, node, node_tmp, + &bat_priv->softif_neigh_vids, list) { + if (!hlist_empty(&softif_neigh_vid->softif_neigh_list)) + continue; + + hlist_del_rcu(&softif_neigh_vid->list); + softif_neigh_vid_free_ref(softif_neigh_vid); + } + spin_unlock_bh(&bat_priv->softif_neigh_vid_lock); + }
static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, @@@ -190,7 -453,9 +445,9 @@@ struct bat_priv *bat_priv = netdev_priv(dev); struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batman_packet *batman_packet; - struct softif_neigh *softif_neigh, *softif_neigh_tmp; + struct softif_neigh *softif_neigh = NULL; + struct hard_iface *primary_if = NULL; + struct softif_neigh *curr_softif_neigh = NULL;
if (ntohs(ethhdr->h_proto) == ETH_P_8021Q) batman_packet = (struct batman_packet *) @@@ -199,63 -464,52 +456,52 @@@ batman_packet = (struct batman_packet *)(skb->data + ETH_HLEN);
if (batman_packet->version != COMPAT_VERSION) - goto err; + goto out;
if (batman_packet->packet_type != BAT_PACKET) - goto err; + goto out;
if (!(batman_packet->flags & PRIMARIES_FIRST_HOP)) - goto err; + goto out;
if (is_my_mac(batman_packet->orig)) - goto err; + goto out;
softif_neigh = softif_neigh_get(bat_priv, batman_packet->orig, vid); - if (!softif_neigh) - goto err; + goto out;
- if (bat_priv->softif_neigh == softif_neigh) + curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); + if (curr_softif_neigh == softif_neigh) + goto out; + + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto out;
/* we got a neighbor but its mac is 'bigger' than ours */ - if (memcmp(bat_priv->primary_if->net_dev->dev_addr, + if (memcmp(primary_if->net_dev->dev_addr, softif_neigh->addr, ETH_ALEN) < 0) goto out;
- /* switch to new 'smallest neighbor' */ - if ((bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, bat_priv->softif_neigh->addr, - ETH_ALEN) < 0)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Changing mesh exit point from %pM (vid: %d) " - "to %pM (vid: %d).\n", - bat_priv->softif_neigh->addr, - bat_priv->softif_neigh->vid, - softif_neigh->addr, softif_neigh->vid); - softif_neigh_tmp = bat_priv->softif_neigh; - bat_priv->softif_neigh = softif_neigh; - softif_neigh_free_ref(softif_neigh_tmp); - /* we need to hold the additional reference */ - goto err; - } - /* close own batX device and use softif_neigh as exit node */ - if ((!bat_priv->softif_neigh) && - (memcmp(softif_neigh->addr, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN) < 0)) { - bat_dbg(DBG_ROUTES, bat_priv, - "Setting mesh exit point to %pM (vid: %d).\n", - softif_neigh->addr, softif_neigh->vid); - bat_priv->softif_neigh = softif_neigh; - /* we need to hold the additional reference */ - goto err; + if (!curr_softif_neigh) { + softif_neigh_vid_select(bat_priv, softif_neigh, vid); + goto out; }
+ /* switch to new 'smallest neighbor' */ + if (memcmp(softif_neigh->addr, curr_softif_neigh->addr, ETH_ALEN) < 0) + softif_neigh_vid_select(bat_priv, softif_neigh, vid); + out: - softif_neigh_free_ref(softif_neigh); - err: kfree_skb(skb); + if (softif_neigh) + softif_neigh_free_ref(softif_neigh); + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + if (primary_if) + hardif_free_ref(primary_if); return; }
@@@ -285,11 -539,11 +531,11 @@@ static int interface_set_mac_addr(struc if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
- /* only modify hna-table if it has been initialised before */ + /* only modify transtable if it has been initialised before */ if (atomic_read(&bat_priv->mesh_state) == MESH_ACTIVE) { - hna_local_remove(bat_priv, dev->dev_addr, + tt_local_remove(bat_priv, dev->dev_addr, "mac address changed"); - hna_local_add(dev, addr->sa_data); + tt_local_add(dev, addr->sa_data); }
memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); @@@ -311,8 -565,10 +557,10 @@@ int interface_tx(struct sk_buff *skb, s { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct bat_priv *bat_priv = netdev_priv(soft_iface); + struct hard_iface *primary_if = NULL; struct bcast_packet *bcast_packet; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; int data_len = skb->len, ret; short vid = -1; bool do_bcast = false; @@@ -340,11 -596,12 +588,12 @@@ * if we have a another chosen mesh exit node in range * it will transport the packets to the mesh */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) + curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); + if (curr_softif_neigh) goto dropped;
/* TODO: check this for locks */ - hna_local_add(soft_iface, ethhdr->h_source); + tt_local_add(soft_iface, ethhdr->h_source);
if (is_multicast_ether_addr(ethhdr->h_dest)) { ret = gw_is_target(bat_priv, skb); @@@ -358,7 -615,8 +607,8 @@@
/* ethernet packet should be broadcasted */ if (do_bcast) { - if (!bat_priv->primary_if) + primary_if = primary_if_get_selected(bat_priv); + if (!primary_if) goto dropped;
if (my_skb_head_push(skb, sizeof(struct bcast_packet)) < 0) @@@ -374,7 -632,7 +624,7 @@@ /* hw address of first interface is the orig mac because only * this mac is known throughout the mesh */ memcpy(bcast_packet->orig, - bat_priv->primary_if->net_dev->dev_addr, ETH_ALEN); + primary_if->net_dev->dev_addr, ETH_ALEN);
/* set broadcast sequence number */ bcast_packet->seqno = @@@ -402,6 -660,10 +652,10 @@@ dropped dropped_freed: bat_priv->stats.tx_dropped++; end: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); + if (primary_if) + hardif_free_ref(primary_if); return NETDEV_TX_OK; }
@@@ -413,6 -675,7 +667,7 @@@ void interface_rx(struct net_device *so struct unicast_packet *unicast_packet; struct ethhdr *ethhdr; struct vlan_ethhdr *vhdr; + struct softif_neigh *curr_softif_neigh = NULL; short vid = -1; int ret;
@@@ -442,7 -705,8 +697,8 @@@ * if we have a another chosen mesh exit node in range * it will transport the packets to the non-mesh network */ - if ((bat_priv->softif_neigh) && (bat_priv->softif_neigh->vid == vid)) { + curr_softif_neigh = softif_neigh_vid_get_selected(bat_priv, vid); + if (curr_softif_neigh) { skb_push(skb, hdr_size); unicast_packet = (struct unicast_packet *)skb->data;
@@@ -453,7 -717,7 +709,7 @@@ skb_reset_mac_header(skb);
memcpy(unicast_packet->dest, - bat_priv->softif_neigh->addr, ETH_ALEN); + curr_softif_neigh->addr, ETH_ALEN); ret = route_unicast_packet(skb, recv_if); if (ret == NET_RX_DROP) goto dropped; @@@ -478,11 -742,13 +734,13 @@@ soft_iface->last_rx = jiffies;
netif_rx(skb); - return; + goto out;
dropped: kfree_skb(skb); out: + if (curr_softif_neigh) + softif_neigh_free_ref(curr_softif_neigh); return; }
@@@ -516,14 -782,15 +774,15 @@@ static void interface_setup(struct net_ dev->hard_start_xmit = interface_tx; #endif dev->destructor = free_netdev; + dev->tx_queue_len = 0;
/** * can't call min_mtu, because the needed variables * have not been initialized yet */ dev->mtu = ETH_DATA_LEN; - dev->hard_header_len = BAT_HEADER_LEN; /* reserve more space in the - * skbuff for our header */ + /* reserve more space in the skbuff for our header */ + dev->hard_header_len = BAT_HEADER_LEN;
/* generate random address */ random_ether_addr(dev_addr); @@@ -548,7 -815,7 +807,7 @@@ struct net_device *softif_create(char * goto out; }
- ret = register_netdev(soft_iface); + ret = register_netdevice(soft_iface); if (ret < 0) { pr_err("Unable to register the batman interface '%s': %i\n", name, ret); @@@ -572,11 -839,10 +831,10 @@@
atomic_set(&bat_priv->mesh_state, MESH_INACTIVE); atomic_set(&bat_priv->bcast_seqno, 1); - atomic_set(&bat_priv->hna_local_changed, 0); + atomic_set(&bat_priv->tt_local_changed, 0);
bat_priv->primary_if = NULL; bat_priv->num_ifaces = 0; - bat_priv->softif_neigh = NULL;
ret = sysfs_add_meshif(soft_iface); if (ret < 0) @@@ -632,7 -898,7 +890,7 @@@ static int bat_get_settings(struct net_ { cmd->supported = 0; cmd->advertising = 0; - cmd->speed = SPEED_10; + ethtool_cmd_speed_set(cmd, SPEED_10); cmd->duplex = DUPLEX_FULL; cmd->port = PORT_TP; cmd->phy_address = 0; @@@ -667,12 -933,3 +925,3 @@@ static u32 bat_get_link(struct net_devi return 1; }
- static u32 bat_get_rx_csum(struct net_device *dev) - { - return 0; - } - - static int bat_set_rx_csum(struct net_device *dev, u32 data) - { - return -EOPNOTSUPP; - } diff --combined net/core/dst.c index 0a3920b,da47a29..81a4fa1 --- a/net/core/dst.c +++ b/net/core/dst.c @@@ -19,7 -19,6 +19,7 @@@ #include <linux/types.h> #include <net/net_namespace.h> #include <linux/sched.h> +#include <linux/prefetch.h>
#include <net/dst.h>
@@@ -34,9 -33,6 +34,6 @@@ * 3) This list is guarded by a mutex, * so that the gc_task and dst_dev_event() can be synchronized. */ - #if RT_CACHE_DEBUG >= 2 - static atomic_t dst_total = ATOMIC_INIT(0); - #endif
/* * We want to keep lock & list close together @@@ -70,10 -66,6 +67,6 @@@ static void dst_gc_task(struct work_str unsigned long expires = ~0L; struct dst_entry *dst, *next, head; struct dst_entry *last = &head; - #if RT_CACHE_DEBUG >= 2 - ktime_t time_start = ktime_get(); - struct timespec elapsed; - #endif
mutex_lock(&dst_gc_mutex); next = dst_busy_list; @@@ -147,15 -139,6 +140,6 @@@ loop
spin_unlock_bh(&dst_garbage.lock); mutex_unlock(&dst_gc_mutex); - #if RT_CACHE_DEBUG >= 2 - elapsed = ktime_to_timespec(ktime_sub(ktime_get(), time_start)); - printk(KERN_DEBUG "dst_total: %d delayed: %d work_perf: %d" - " expires: %lu elapsed: %lu us\n", - atomic_read(&dst_total), delayed, work_performed, - expires, - elapsed.tv_sec * USEC_PER_SEC + - elapsed.tv_nsec / NSEC_PER_USEC); - #endif }
int dst_discard(struct sk_buff *skb) @@@ -167,7 -150,8 +151,8 @@@ EXPORT_SYMBOL(dst_discard)
const u32 dst_default_metrics[RTAX_MAX];
- void *dst_alloc(struct dst_ops *ops, int initial_ref) + void *dst_alloc(struct dst_ops *ops, struct net_device *dev, + int initial_ref, int initial_obsolete, int flags) { struct dst_entry *dst;
@@@ -175,18 -159,36 +160,36 @@@ if (ops->gc(ops)) return NULL; } - dst = kmem_cache_zalloc(ops->kmem_cachep, GFP_ATOMIC); + dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); if (!dst) return NULL; - atomic_set(&dst->__refcnt, initial_ref); + dst->child = NULL; + dst->dev = dev; + if (dev) + dev_hold(dev); dst->ops = ops; - dst->lastuse = jiffies; - dst->path = dst; - dst->input = dst->output = dst_discard; dst_init_metrics(dst, dst_default_metrics, true); - #if RT_CACHE_DEBUG >= 2 - atomic_inc(&dst_total); + dst->expires = 0UL; + dst->path = dst; + dst->neighbour = NULL; + dst->hh = NULL; + #ifdef CONFIG_XFRM + dst->xfrm = NULL; + #endif + dst->input = dst_discard; + dst->output = dst_discard; + dst->error = 0; + dst->obsolete = initial_obsolete; + dst->header_len = 0; + dst->trailer_len = 0; + #ifdef CONFIG_IP_ROUTE_CLASSID + dst->tclassid = 0; #endif + atomic_set(&dst->__refcnt, initial_ref); + dst->__use = 0; + dst->lastuse = jiffies; + dst->flags = flags; + dst->next = NULL; dst_entries_add(ops, 1); return dst; } @@@ -246,9 -248,6 +249,6 @@@ again dst->ops->destroy(dst); if (dst->dev) dev_put(dst->dev); - #if RT_CACHE_DEBUG >= 2 - atomic_dec(&dst_total); - #endif kmem_cache_free(dst->ops->kmem_cachep, dst);
dst = child; diff --combined net/core/net-sysfs.c index 80b2aad,1b12217..11b98bc --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@@ -28,6 -28,7 +28,7 @@@ static const char fmt_hex[] = "%#x\n"; static const char fmt_long_hex[] = "%#lx\n"; static const char fmt_dec[] = "%d\n"; + static const char fmt_udec[] = "%u\n"; static const char fmt_ulong[] = "%lu\n"; static const char fmt_u64[] = "%llu\n";
@@@ -145,13 -146,10 +146,10 @@@ static ssize_t show_speed(struct devic if (!rtnl_trylock()) return restart_syscall();
- if (netif_running(netdev) && - netdev->ethtool_ops && - netdev->ethtool_ops->get_settings) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - - if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) - ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); + if (netif_running(netdev)) { + struct ethtool_cmd cmd; + if (!dev_ethtool_get_settings(netdev, &cmd)) + ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd)); } rtnl_unlock(); return ret; @@@ -166,13 -164,11 +164,11 @@@ static ssize_t show_duplex(struct devic if (!rtnl_trylock()) return restart_syscall();
- if (netif_running(netdev) && - netdev->ethtool_ops && - netdev->ethtool_ops->get_settings) { - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - - if (!netdev->ethtool_ops->get_settings(netdev, &cmd)) - ret = sprintf(buf, "%s\n", cmd.duplex ? "full" : "half"); + if (netif_running(netdev)) { + struct ethtool_cmd cmd; + if (!dev_ethtool_get_settings(netdev, &cmd)) + ret = sprintf(buf, "%s\n", + cmd.duplex ? "full" : "half"); } rtnl_unlock(); return ret; @@@ -565,6 -561,13 +561,6 @@@ static ssize_t show_rps_map(struct netd return len; }
-static void rps_map_release(struct rcu_head *rcu) -{ - struct rps_map *map = container_of(rcu, struct rps_map, rcu); - - kfree(map); -} - static ssize_t store_rps_map(struct netdev_rx_queue *queue, struct rx_queue_attribute *attribute, const char *buf, size_t len) @@@ -612,7 -615,7 +608,7 @@@ spin_unlock(&rps_map_lock);
if (old_map) - call_rcu(&old_map->rcu, rps_map_release); + kfree_rcu(old_map, rcu);
free_cpumask_var(mask); return len; @@@ -721,7 -724,7 +717,7 @@@ static void rx_queue_release(struct kob map = rcu_dereference_raw(queue->rps_map); if (map) { RCU_INIT_POINTER(queue->rps_map, NULL); - call_rcu(&map->rcu, rps_map_release); + kfree_rcu(map, rcu); }
flow_table = rcu_dereference_raw(queue->rps_flow_table); @@@ -891,6 -894,21 +887,6 @@@ static ssize_t show_xps_map(struct netd return len; }
-static void xps_map_release(struct rcu_head *rcu) -{ - struct xps_map *map = container_of(rcu, struct xps_map, rcu); - - kfree(map); -} - -static void xps_dev_maps_release(struct rcu_head *rcu) -{ - struct xps_dev_maps *dev_maps = - container_of(rcu, struct xps_dev_maps, rcu); - - kfree(dev_maps); -} - static DEFINE_MUTEX(xps_map_mutex); #define xmap_dereference(P) \ rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex)) @@@ -946,7 -964,7 +942,7 @@@ static ssize_t store_xps_map(struct net } else pos = map_len = alloc_len = 0;
- need_set = cpu_isset(cpu, *mask) && cpu_online(cpu); + need_set = cpumask_test_cpu(cpu, mask) && cpu_online(cpu); #ifdef CONFIG_NUMA if (need_set) { if (numa_node == -2) @@@ -987,7 -1005,7 +983,7 @@@ map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) : NULL; if (map && xmap_dereference(new_dev_maps->cpu_map[cpu]) != map) - call_rcu(&map->rcu, xps_map_release); + kfree_rcu(map, rcu); if (new_dev_maps->cpu_map[cpu]) nonempty = 1; } @@@ -1000,7 -1018,7 +996,7 @@@ }
if (dev_maps) - call_rcu(&dev_maps->rcu, xps_dev_maps_release); + kfree_rcu(dev_maps, rcu);
netdev_queue_numa_node_write(queue, (numa_node >= 0) ? numa_node : NUMA_NO_NODE); @@@ -1062,7 -1080,7 +1058,7 @@@ static void netdev_queue_release(struc else { RCU_INIT_POINTER(dev_maps->cpu_map[i], NULL); - call_rcu(&map->rcu, xps_map_release); + kfree_rcu(map, rcu); map = NULL; } } @@@ -1072,7 -1090,7 +1068,7 @@@
if (!nonempty) { RCU_INIT_POINTER(dev->xps_maps, NULL); - call_rcu(&dev_maps->rcu, xps_dev_maps_release); + kfree_rcu(dev_maps, rcu); } }
diff --combined net/core/net_namespace.c index 297bb92,1abb508..2e2dce6 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@@ -27,6 -27,14 +27,6 @@@ EXPORT_SYMBOL(init_net)
#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */
-static void net_generic_release(struct rcu_head *rcu) -{ - struct net_generic *ng; - - ng = container_of(rcu, struct net_generic, rcu); - kfree(ng); -} - static int net_assign_generic(struct net *net, int id, void *data) { struct net_generic *ng, *old_ng; @@@ -60,7 -68,7 +60,7 @@@ memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*));
rcu_assign_pointer(net->gen, ng); - call_rcu(&old_ng->rcu, net_generic_release); + kfree_rcu(old_ng, rcu); assign: ng->ptr[id - 1] = data; return 0; @@@ -208,11 -216,14 +208,14 @@@ static void net_free(struct net *net kmem_cache_free(net_cachep, net); }
- static struct net *net_create(void) + struct net *copy_net_ns(unsigned long flags, struct net *old_net) { struct net *net; int rv;
+ if (!(flags & CLONE_NEWNET)) + return get_net(old_net); + net = net_alloc(); if (!net) return ERR_PTR(-ENOMEM); @@@ -231,13 -242,6 +234,6 @@@ return net; }
- struct net *copy_net_ns(unsigned long flags, struct net *old_net) - { - if (!(flags & CLONE_NEWNET)) - return get_net(old_net); - return net_create(); - } - static DEFINE_SPINLOCK(cleanup_list_lock); static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */
diff --combined net/core/pktgen.c index 6ed9e27,379270f..67870e9 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@@ -156,7 -156,6 +156,7 @@@ #include <linux/wait.h> #include <linux/etherdevice.h> #include <linux/kthread.h> +#include <linux/prefetch.h> #include <net/net_namespace.h> #include <net/checksum.h> #include <net/ipv6.h> @@@ -450,7 -449,6 +450,6 @@@ static void pktgen_stop(struct pktgen_t static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
static unsigned int scan_ip6(const char *s, char ip[16]); - static unsigned int fmt_ip6(char *s, const char ip[16]);
/* Module parameters, defaults. */ static int pg_count_d __read_mostly = 1000; @@@ -557,21 -555,13 +556,13 @@@ static int pktgen_if_show(struct seq_fi pkt_dev->skb_priority);
if (pkt_dev->flags & F_IPV6) { - char b1[128], b2[128], b3[128]; - fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr); - fmt_ip6(b2, pkt_dev->min_in6_saddr.s6_addr); - fmt_ip6(b3, pkt_dev->max_in6_saddr.s6_addr); seq_printf(seq, - " saddr: %s min_saddr: %s max_saddr: %s\n", b1, - b2, b3); - - fmt_ip6(b1, pkt_dev->in6_daddr.s6_addr); - fmt_ip6(b2, pkt_dev->min_in6_daddr.s6_addr); - fmt_ip6(b3, pkt_dev->max_in6_daddr.s6_addr); - seq_printf(seq, - " daddr: %s min_daddr: %s max_daddr: %s\n", b1, - b2, b3); - + " saddr: %pI6c min_saddr: %pI6c max_saddr: %pI6c\n" + " daddr: %pI6c min_daddr: %pI6c max_daddr: %pI6c\n", + &pkt_dev->in6_saddr, + &pkt_dev->min_in6_saddr, &pkt_dev->max_in6_saddr, + &pkt_dev->in6_daddr, + &pkt_dev->min_in6_daddr, &pkt_dev->max_in6_daddr); } else { seq_printf(seq, " dst_min: %s dst_max: %s\n", @@@ -707,10 -697,9 +698,9 @@@ pkt_dev->cur_src_mac_offset);
if (pkt_dev->flags & F_IPV6) { - char b1[128], b2[128]; - fmt_ip6(b1, pkt_dev->cur_in6_daddr.s6_addr); - fmt_ip6(b2, pkt_dev->cur_in6_saddr.s6_addr); - seq_printf(seq, " cur_saddr: %s cur_daddr: %s\n", b2, b1); + seq_printf(seq, " cur_saddr: %pI6c cur_daddr: %pI6c\n", + &pkt_dev->cur_in6_saddr, + &pkt_dev->cur_in6_daddr); } else seq_printf(seq, " cur_saddr: 0x%x cur_daddr: 0x%x\n", pkt_dev->cur_saddr, pkt_dev->cur_daddr); @@@ -1310,7 -1299,7 +1300,7 @@@ static ssize_t pktgen_if_write(struct f buf[len] = 0;
scan_ip6(buf, pkt_dev->in6_daddr.s6_addr); - fmt_ip6(buf, pkt_dev->in6_daddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_daddr);
ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
@@@ -1333,7 -1322,7 +1323,7 @@@ buf[len] = 0;
scan_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); - fmt_ip6(buf, pkt_dev->min_in6_daddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->min_in6_daddr);
ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->min_in6_daddr); @@@ -1356,7 -1345,7 +1346,7 @@@ buf[len] = 0;
scan_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); - fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->max_in6_daddr);
if (debug) printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf); @@@ -1377,7 -1366,7 +1367,7 @@@ buf[len] = 0;
scan_ip6(buf, pkt_dev->in6_saddr.s6_addr); - fmt_ip6(buf, pkt_dev->in6_saddr.s6_addr); + snprintf(buf, sizeof(buf), "%pI6c", &pkt_dev->in6_saddr);
ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
@@@ -1431,11 -1420,6 +1421,6 @@@ return count; } if (!strcmp(name, "dst_mac")) { - char *v = valstr; - unsigned char old_dmac[ETH_ALEN]; - unsigned char *m = pkt_dev->dst_mac; - memcpy(old_dmac, pkt_dev->dst_mac, ETH_ALEN); - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); if (len < 0) return len; @@@ -1443,35 -1427,16 +1428,16 @@@ memset(valstr, 0, sizeof(valstr)); if (copy_from_user(valstr, &user_buffer[i], len)) return -EFAULT; - i += len; - - for (*m = 0; *v && m < pkt_dev->dst_mac + 6; v++) { - int value; - - value = hex_to_bin(*v); - if (value >= 0) - *m = *m * 16 + value; - - if (*v == ':') { - m++; - *m = 0; - } - }
+ if (!mac_pton(valstr, pkt_dev->dst_mac)) + return -EINVAL; /* Set up Dest MAC */ - if (compare_ether_addr(old_dmac, pkt_dev->dst_mac)) - memcpy(&(pkt_dev->hh[0]), pkt_dev->dst_mac, ETH_ALEN); + memcpy(&pkt_dev->hh[0], pkt_dev->dst_mac, ETH_ALEN);
- sprintf(pg_result, "OK: dstmac"); + sprintf(pg_result, "OK: dstmac %pM", pkt_dev->dst_mac); return count; } if (!strcmp(name, "src_mac")) { - char *v = valstr; - unsigned char old_smac[ETH_ALEN]; - unsigned char *m = pkt_dev->src_mac; - - memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN); - len = strn_len(&user_buffer[i], sizeof(valstr) - 1); if (len < 0) return len; @@@ -1479,26 -1444,13 +1445,13 @@@ memset(valstr, 0, sizeof(valstr)); if (copy_from_user(valstr, &user_buffer[i], len)) return -EFAULT; - i += len; - - for (*m = 0; *v && m < pkt_dev->src_mac + 6; v++) { - int value; - - value = hex_to_bin(*v); - if (value >= 0) - *m = *m * 16 + value; - - if (*v == ':') { - m++; - *m = 0; - } - }
+ if (!mac_pton(valstr, pkt_dev->src_mac)) + return -EINVAL; /* Set up Src MAC */ - if (compare_ether_addr(old_smac, pkt_dev->src_mac)) - memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN); + memcpy(&pkt_dev->hh[6], pkt_dev->src_mac, ETH_ALEN);
- sprintf(pg_result, "OK: srcmac"); + sprintf(pg_result, "OK: srcmac %pM", pkt_dev->src_mac); return count; }
@@@ -2515,7 -2467,6 +2468,6 @@@ static int pktgen_output_ipsec(struct s { struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x; int err = 0; - struct iphdr *iph;
if (!x) return 0; @@@ -2525,7 -2476,6 +2477,6 @@@ return 0;
spin_lock(&x->lock); - iph = ip_hdr(skb);
err = x->outer_mode->output(x, skb); if (err) @@@ -2625,6 -2575,7 +2576,7 @@@ static void pktgen_finalize_skb(struct } else { int frags = pkt_dev->nfrags; int i, len; + int frag_len;
if (frags > MAX_SKB_FRAGS) @@@ -2636,6 -2587,8 +2588,8 @@@ }
i = 0; + frag_len = (datalen/frags) < PAGE_SIZE ? + (datalen/frags) : PAGE_SIZE; while (datalen > 0) { if (unlikely(!pkt_dev->page)) { int node = numa_node_id(); @@@ -2649,38 -2602,18 +2603,18 @@@ skb_shinfo(skb)->frags[i].page = pkt_dev->page; get_page(pkt_dev->page); skb_shinfo(skb)->frags[i].page_offset = 0; - skb_shinfo(skb)->frags[i].size = - (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); + /*last fragment, fill rest of data*/ + if (i == (frags - 1)) + skb_shinfo(skb)->frags[i].size = + (datalen < PAGE_SIZE ? datalen : PAGE_SIZE); + else + skb_shinfo(skb)->frags[i].size = frag_len; datalen -= skb_shinfo(skb)->frags[i].size; skb->len += skb_shinfo(skb)->frags[i].size; skb->data_len += skb_shinfo(skb)->frags[i].size; i++; skb_shinfo(skb)->nr_frags = i; } - - while (i < frags) { - int rem; - - if (i == 0) - break; - - rem = skb_shinfo(skb)->frags[i - 1].size / 2; - if (rem == 0) - break; - - skb_shinfo(skb)->frags[i - 1].size -= rem; - - skb_shinfo(skb)->frags[i] = - skb_shinfo(skb)->frags[i - 1]; - get_page(skb_shinfo(skb)->frags[i].page); - skb_shinfo(skb)->frags[i].page = - skb_shinfo(skb)->frags[i - 1].page; - skb_shinfo(skb)->frags[i].page_offset += - skb_shinfo(skb)->frags[i - 1].size; - skb_shinfo(skb)->frags[i].size = rem; - i++; - skb_shinfo(skb)->nr_frags = i; - } }
/* Stamp the time, and sequence number, @@@ -2918,79 -2851,6 +2852,6 @@@ static unsigned int scan_ip6(const cha return len; }
- static char tohex(char hexdigit) - { - return hexdigit > 9 ? hexdigit + 'a' - 10 : hexdigit + '0'; - } - - static int fmt_xlong(char *s, unsigned int i) - { - char *bak = s; - *s = tohex((i >> 12) & 0xf); - if (s != bak || *s != '0') - ++s; - *s = tohex((i >> 8) & 0xf); - if (s != bak || *s != '0') - ++s; - *s = tohex((i >> 4) & 0xf); - if (s != bak || *s != '0') - ++s; - *s = tohex(i & 0xf); - return s - bak + 1; - } - - static unsigned int fmt_ip6(char *s, const char ip[16]) - { - unsigned int len; - unsigned int i; - unsigned int temp; - unsigned int compressing; - int j; - - len = 0; - compressing = 0; - for (j = 0; j < 16; j += 2) { - - #ifdef V4MAPPEDPREFIX - if (j == 12 && !memcmp(ip, V4mappedprefix, 12)) { - inet_ntoa_r(*(struct in_addr *)(ip + 12), s); - temp = strlen(s); - return len + temp; - } - #endif - temp = ((unsigned long)(unsigned char)ip[j] << 8) + - (unsigned long)(unsigned char)ip[j + 1]; - if (temp == 0) { - if (!compressing) { - compressing = 1; - if (j == 0) { - *s++ = ':'; - ++len; - } - } - } else { - if (compressing) { - compressing = 0; - *s++ = ':'; - ++len; - } - i = fmt_xlong(s, temp); - len += i; - s += i; - if (j < 14) { - *s++ = ':'; - ++len; - } - } - } - if (compressing) { - *s++ = ':'; - ++len; - } - *s = 0; - return len; - } - static struct sk_buff *fill_packet_ipv6(struct net_device *odev, struct pktgen_dev *pkt_dev) { diff --combined net/core/skbuff.c index 960ea89,3e934fe..46cbd28 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@@ -57,7 -57,6 +57,7 @@@ #include <linux/init.h> #include <linux/scatterlist.h> #include <linux/errqueue.h> +#include <linux/prefetch.h>
#include <net/protocol.h> #include <net/dst.h> @@@ -2994,6 -2993,9 +2994,9 @@@ int sock_queue_err_skb(struct sock *sk skb->destructor = sock_rmem_free; atomic_add(skb->truesize, &sk->sk_rmem_alloc);
+ /* before exiting rcu section, make sure dst is refcounted */ + skb_dst_force(skb); + skb_queue_tail(&sk->sk_error_queue, skb); if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk, skb->len); diff --combined net/decnet/dn_dev.c index 4c27615,404fa15..cf26ac7 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@@ -332,9 -332,14 +332,9 @@@ static struct dn_ifaddr *dn_dev_alloc_i return ifa; }
-static void dn_dev_free_ifa_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct dn_ifaddr, rcu)); -} - static void dn_dev_free_ifa(struct dn_ifaddr *ifa) { - call_rcu(&ifa->rcu, dn_dev_free_ifa_rcu); + kfree_rcu(ifa, rcu); }
static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr __rcu **ifap, int destroy) @@@ -747,7 -752,8 +747,8 @@@ static int dn_nl_dump_ifaddr(struct sk_ skip_naddr = cb->args[1];
idx = 0; - for_each_netdev(&init_net, dev) { + rcu_read_lock(); + for_each_netdev_rcu(&init_net, dev) { if (idx < skip_ndevs) goto cont; else if (idx > skip_ndevs) { @@@ -756,11 -762,11 +757,11 @@@ skip_naddr = 0; }
- if ((dn_db = rtnl_dereference(dev->dn_ptr)) == NULL) + if ((dn_db = rcu_dereference(dev->dn_ptr)) == NULL) goto cont;
- for (ifa = rtnl_dereference(dn_db->ifa_list), dn_idx = 0; ifa; - ifa = rtnl_dereference(ifa->ifa_next), dn_idx++) { + for (ifa = rcu_dereference(dn_db->ifa_list), dn_idx = 0; ifa; + ifa = rcu_dereference(ifa->ifa_next), dn_idx++) { if (dn_idx < skip_naddr) continue;
@@@ -773,6 -779,7 +774,7 @@@ cont idx++; } done: + rcu_read_unlock(); cb->args[0] = idx; cb->args[1] = dn_idx;
diff --combined net/ipv4/fib_trie.c index 11d4d28,6375c1c..c779ce9 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@@ -126,7 -126,7 +126,7 @@@ struct tnode struct work_struct work; struct tnode *tnode_free; }; - struct rt_trie_node *child[0]; + struct rt_trie_node __rcu *child[0]; };
#ifdef CONFIG_IP_FIB_TRIE_STATS @@@ -151,7 -151,7 +151,7 @@@ struct trie_stat };
struct trie { - struct rt_trie_node *trie; + struct rt_trie_node __rcu *trie; #ifdef CONFIG_IP_FIB_TRIE_STATS struct trie_use_stats stats; #endif @@@ -177,16 -177,29 +177,29 @@@ static const int sync_pages = 128 static struct kmem_cache *fn_alias_kmem __read_mostly; static struct kmem_cache *trie_leaf_kmem __read_mostly;
- static inline struct tnode *node_parent(struct rt_trie_node *node) + /* + * caller must hold RTNL + */ + static inline struct tnode *node_parent(const struct rt_trie_node *node) { - return (struct tnode *)(node->parent & ~NODE_TYPE_MASK); + unsigned long parent; + + parent = rcu_dereference_index_check(node->parent, lockdep_rtnl_is_held()); + + return (struct tnode *)(parent & ~NODE_TYPE_MASK); }
- static inline struct tnode *node_parent_rcu(struct rt_trie_node *node) + /* + * caller must hold RCU read lock or RTNL + */ + static inline struct tnode *node_parent_rcu(const struct rt_trie_node *node) { - struct tnode *ret = node_parent(node); + unsigned long parent; + + parent = rcu_dereference_index_check(node->parent, rcu_read_lock_held() || + lockdep_rtnl_is_held());
- return rcu_dereference_rtnl(ret); + return (struct tnode *)(parent & ~NODE_TYPE_MASK); }
/* Same as rcu_assign_pointer @@@ -198,18 -211,24 +211,24 @@@ static inline void node_set_parent(stru node->parent = (unsigned long)ptr | NODE_TYPE(node); }
- static inline struct rt_trie_node *tnode_get_child(struct tnode *tn, unsigned int i) + /* + * caller must hold RTNL + */ + static inline struct rt_trie_node *tnode_get_child(const struct tnode *tn, unsigned int i) { BUG_ON(i >= 1U << tn->bits);
- return tn->child[i]; + return rtnl_dereference(tn->child[i]); }
- static inline struct rt_trie_node *tnode_get_child_rcu(struct tnode *tn, unsigned int i) + /* + * caller must hold RCU read lock or RTNL + */ + static inline struct rt_trie_node *tnode_get_child_rcu(const struct tnode *tn, unsigned int i) { - struct rt_trie_node *ret = tnode_get_child(tn, i); + BUG_ON(i >= 1U << tn->bits);
- return rcu_dereference_rtnl(ret); + return rcu_dereference_rtnl(tn->child[i]); }
static inline int tnode_child_length(const struct tnode *tn) @@@ -350,9 -369,14 +369,9 @@@ static inline void free_leaf(struct lea call_rcu_bh(&l->rcu, __leaf_free_rcu); }
-static void __leaf_info_free_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct leaf_info, rcu)); -} - static inline void free_leaf_info(struct leaf_info *leaf) { - call_rcu(&leaf->rcu, __leaf_info_free_rcu); + kfree_rcu(leaf, rcu); }
static struct tnode *tnode_alloc(size_t size) @@@ -482,7 -506,7 +501,7 @@@ static inline void put_child(struct tri static void tnode_put_child_reorg(struct tnode *tn, int i, struct rt_trie_node *n, int wasfull) { - struct rt_trie_node *chi = tn->child[i]; + struct rt_trie_node *chi = rtnl_dereference(tn->child[i]); int isfull;
BUG_ON(i >= 1<<tn->bits); @@@ -660,7 -684,7 +679,7 @@@ one_child for (i = 0; i < tnode_child_length(tn); i++) { struct rt_trie_node *n;
- n = tn->child[i]; + n = rtnl_dereference(tn->child[i]); if (!n) continue;
@@@ -674,6 -698,20 +693,20 @@@ return (struct rt_trie_node *) tn; }
+ + static void tnode_clean_free(struct tnode *tn) + { + int i; + struct tnode *tofree; + + for (i = 0; i < tnode_child_length(tn); i++) { + tofree = (struct tnode *)rtnl_dereference(tn->child[i]); + if (tofree) + tnode_free(tofree); + } + tnode_free(tn); + } + static struct tnode *inflate(struct trie *t, struct tnode *tn) { struct tnode *oldtnode = tn; @@@ -750,8 -788,8 +783,8 @@@ inode = (struct tnode *) node;
if (inode->bits == 1) { - put_child(t, tn, 2*i, inode->child[0]); - put_child(t, tn, 2*i+1, inode->child[1]); + put_child(t, tn, 2*i, rtnl_dereference(inode->child[0])); + put_child(t, tn, 2*i+1, rtnl_dereference(inode->child[1]));
tnode_free_safe(inode); continue; @@@ -792,8 -830,8 +825,8 @@@
size = tnode_child_length(left); for (j = 0; j < size; j++) { - put_child(t, left, j, inode->child[j]); - put_child(t, right, j, inode->child[j + size]); + put_child(t, left, j, rtnl_dereference(inode->child[j])); + put_child(t, right, j, rtnl_dereference(inode->child[j + size])); } put_child(t, tn, 2*i, resize(t, left)); put_child(t, tn, 2*i+1, resize(t, right)); @@@ -803,18 -841,8 +836,8 @@@ tnode_free_safe(oldtnode); return tn; nomem: - { - int size = tnode_child_length(tn); - int j; - - for (j = 0; j < size; j++) - if (tn->child[j]) - tnode_free((struct tnode *)tn->child[j]); - - tnode_free(tn); - - return ERR_PTR(-ENOMEM); - } + tnode_clean_free(tn); + return ERR_PTR(-ENOMEM); }
static struct tnode *halve(struct trie *t, struct tnode *tn) @@@ -885,18 -913,8 +908,8 @@@ tnode_free_safe(oldtnode); return tn; nomem: - { - int size = tnode_child_length(tn); - int j; - - for (j = 0; j < size; j++) - if (tn->child[j]) - tnode_free((struct tnode *)tn->child[j]); - - tnode_free(tn); - - return ERR_PTR(-ENOMEM); - } + tnode_clean_free(tn); + return ERR_PTR(-ENOMEM); }
/* readside must use rcu_read_lock currently dump routines @@@ -1028,7 -1046,7 +1041,7 @@@ static struct list_head *fib_insert_nod t_key cindex;
pos = 0; - n = t->trie; + n = rtnl_dereference(t->trie);
/* If we point to NULL, stop. Either the tree is empty and we should * just put a new leaf in if, or we have reached an empty child slot, @@@ -1314,6 -1332,9 +1327,9 @@@ int fib_table_insert(struct fib_table * } }
+ if (!plen) + tb->tb_num_default++; + list_add_tail_rcu(&new_fa->fa_list, (fa ? &fa->fa_list : fa_head));
@@@ -1679,6 -1700,9 +1695,9 @@@ int fib_table_delete(struct fib_table *
list_del_rcu(&fa->fa_list);
+ if (!plen) + tb->tb_num_default--; + if (list_empty(fa_head)) { hlist_del_rcu(&li->hlist); free_leaf_info(li); @@@ -1751,7 -1775,7 +1770,7 @@@ static struct leaf *leaf_walk_rcu(struc continue;
if (IS_LEAF(c)) { - prefetch(p->child[idx]); + prefetch(rcu_dereference_rtnl(p->child[idx])); return (struct leaf *) c; }
@@@ -1969,6 -1993,7 +1988,7 @@@ struct fib_table *fib_trie_table(u32 id
tb->tb_id = id; tb->tb_default = -1; + tb->tb_num_default = 0;
t = (struct trie *) tb->tb_data; memset(t, 0, sizeof(*t)); @@@ -2264,7 -2289,7 +2284,7 @@@ static void *fib_trie_seq_next(struct s
/* walk rest of this hash chain */ h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); - while ( (tb_node = rcu_dereference(tb->tb_hlist.next)) ) { + while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) { tb = hlist_entry(tb_node, struct fib_table, tb_hlist); n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); if (n) diff --combined net/ipv4/igmp.c index 8f62d66,ec03c2f..672e476 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@@ -149,11 -149,17 +149,11 @@@ static void ip_mc_clear_src(struct ip_m static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, int sfcount, __be32 *psfsrc, int delta);
- -static void ip_mc_list_reclaim(struct rcu_head *head) -{ - kfree(container_of(head, struct ip_mc_list, rcu)); -} - static void ip_ma_put(struct ip_mc_list *im) { if (atomic_dec_and_test(&im->refcnt)) { in_dev_put(im->interface); - call_rcu(&im->rcu, ip_mc_list_reclaim); + kfree_rcu(im, rcu); } }
@@@ -303,6 -309,7 +303,7 @@@ static struct sk_buff *igmpv3_newpack(s struct iphdr *pip; struct igmpv3_report *pig; struct net *net = dev_net(dev); + struct flowi4 fl4;
while (1) { skb = alloc_skb(size + LL_ALLOCATED_SPACE(dev), @@@ -315,18 -322,13 +316,13 @@@ } igmp_skb_size(skb) = size;
- rt = ip_route_output_ports(net, NULL, IGMPV3_ALL_MCR, 0, + rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0, 0, 0, IPPROTO_IGMP, 0, dev->ifindex); if (IS_ERR(rt)) { kfree_skb(skb); return NULL; } - if (rt->rt_src == 0) { - kfree_skb(skb); - ip_rt_put(rt); - return NULL; - }
skb_dst_set(skb, &rt->dst); skb->dev = dev; @@@ -342,8 -344,8 +338,8 @@@ pip->tos = 0xc0; pip->frag_off = htons(IP_DF); pip->ttl = 1; - pip->daddr = rt->rt_dst; - pip->saddr = rt->rt_src; + pip->daddr = fl4.daddr; + pip->saddr = fl4.saddr; pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(pip, &rt->dst, NULL); @@@ -649,6 -651,7 +645,7 @@@ static int igmp_send_report(struct in_d struct net_device *dev = in_dev->dev; struct net *net = dev_net(dev); __be32 group = pmc ? pmc->multiaddr : 0; + struct flowi4 fl4; __be32 dst;
if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) @@@ -658,17 -661,12 +655,12 @@@ else dst = group;
- rt = ip_route_output_ports(net, NULL, dst, 0, + rt = ip_route_output_ports(net, &fl4, NULL, dst, 0, 0, 0, IPPROTO_IGMP, 0, dev->ifindex); if (IS_ERR(rt)) return -1;
- if (rt->rt_src == 0) { - ip_rt_put(rt); - return -1; - } - skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) { ip_rt_put(rt); @@@ -689,7 -687,7 +681,7 @@@ iph->frag_off = htons(IP_DF); iph->ttl = 1; iph->daddr = dst; - iph->saddr = rt->rt_src; + iph->saddr = fl4.saddr; iph->protocol = IPPROTO_IGMP; ip_select_ident(iph, &rt->dst, NULL); ((u8*)&iph[1])[0] = IPOPT_RA; @@@ -1830,6 -1828,12 +1822,6 @@@ done } EXPORT_SYMBOL(ip_mc_join_group);
-static void ip_sf_socklist_reclaim(struct rcu_head *rp) -{ - kfree(container_of(rp, struct ip_sf_socklist, rcu)); - /* sk_omem_alloc should have been decreased by the caller*/ -} - static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, struct in_device *in_dev) { @@@ -1846,10 -1850,18 +1838,10 @@@ rcu_assign_pointer(iml->sflist, NULL); /* decrease mem now to avoid the memleak warning */ atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc); - call_rcu(&psf->rcu, ip_sf_socklist_reclaim); + kfree_rcu(psf, rcu); return err; }
- -static void ip_mc_socklist_reclaim(struct rcu_head *rp) -{ - kfree(container_of(rp, struct ip_mc_socklist, rcu)); - /* sk_omem_alloc should have been decreased by the caller*/ -} - - /* * Ask a socket to leave a group. */ @@@ -1889,7 -1901,7 +1881,7 @@@ int ip_mc_leave_group(struct sock *sk, rtnl_unlock(); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); - call_rcu(&iml->rcu, ip_mc_socklist_reclaim); + kfree_rcu(iml, rcu); return 0; } if (!in_dev) @@@ -2006,7 -2018,7 +1998,7 @@@ int ip_mc_source(int add, int omode, st newpsl->sl_addr[i] = psl->sl_addr[i]; /* decrease mem now to avoid the memleak warning */ atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); - call_rcu(&psl->rcu, ip_sf_socklist_reclaim); + kfree_rcu(psl, rcu); } rcu_assign_pointer(pmc->sflist, newpsl); psl = newpsl; @@@ -2107,7 -2119,7 +2099,7 @@@ int ip_mc_msfilter(struct sock *sk, str psl->sl_count, psl->sl_addr, 0); /* decrease mem now to avoid the memleak warning */ atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); - call_rcu(&psl->rcu, ip_sf_socklist_reclaim); + kfree_rcu(psl, rcu); } else (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, 0, NULL, 0); @@@ -2304,7 -2316,7 +2296,7 @@@ void ip_mc_drop_socket(struct sock *sk ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); /* decrease mem now to avoid the memleak warning */ atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); - call_rcu(&iml->rcu, ip_mc_socklist_reclaim); + kfree_rcu(iml, rcu); } rtnl_unlock(); } diff --combined net/ipv6/addrconf.c index 8f13d88,3cfbbf3..498b927 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@@ -289,19 -289,19 +289,19 @@@ static int snmp6_alloc_dev(struct inet6 sizeof(struct ipstats_mib), __alignof__(struct ipstats_mib)) < 0) goto err_ip; - if (snmp_mib_init((void __percpu **)idev->stats.icmpv6, - sizeof(struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) + idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), + GFP_KERNEL); + if (!idev->stats.icmpv6dev) goto err_icmp; - if (snmp_mib_init((void __percpu **)idev->stats.icmpv6msg, - sizeof(struct icmpv6msg_mib), - __alignof__(struct icmpv6msg_mib)) < 0) + idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), + GFP_KERNEL); + if (!idev->stats.icmpv6msgdev) goto err_icmpmsg;
return 0;
err_icmpmsg: - snmp_mib_free((void __percpu **)idev->stats.icmpv6); + kfree(idev->stats.icmpv6dev); err_icmp: snmp_mib_free((void __percpu **)idev->stats.ipv6); err_ip: @@@ -310,13 -310,19 +310,13 @@@
static void snmp6_free_dev(struct inet6_dev *idev) { - snmp_mib_free((void __percpu **)idev->stats.icmpv6msg); - snmp_mib_free((void __percpu **)idev->stats.icmpv6); + kfree(idev->stats.icmpv6msgdev); + kfree(idev->stats.icmpv6dev); snmp_mib_free((void __percpu **)idev->stats.ipv6); }
/* Nobody refers to this device, we may destroy it. */
-static void in6_dev_finish_destroy_rcu(struct rcu_head *head) -{ - struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); - kfree(idev); -} - void in6_dev_finish_destroy(struct inet6_dev *idev) { struct net_device *dev = idev->dev; @@@ -333,7 -339,7 +333,7 @@@ return; } snmp6_free_dev(idev); - call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); + kfree_rcu(idev, rcu); }
EXPORT_SYMBOL(in6_dev_finish_destroy); @@@ -529,6 -535,12 +529,6 @@@ static int addrconf_fixup_forwarding(st } #endif
-static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head) -{ - struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu); - kfree(ifp); -} - /* Nobody refers to this ifaddr, destroy it */ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) { @@@ -549,7 -561,7 +549,7 @@@ } dst_release(&ifp->rt->dst);
- call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu); + kfree_rcu(ifp, rcu); }
static void @@@ -813,6 -825,8 +813,8 @@@ static void ipv6_del_addr(struct inet6_ dst_release(&rt->dst); }
+ /* clean up prefsrc entries */ + rt6_remove_prefsrc(ifp); out: in6_ifa_put(ifp); } @@@ -1269,7 -1283,7 +1271,7 @@@ static int ipv6_count_addresses(struct return cnt; }
- int ipv6_chk_addr(struct net *net, struct in6_addr *addr, + int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, struct net_device *dev, int strict) { struct inet6_ifaddr *ifp; @@@ -1312,7 -1326,7 +1314,7 @@@ static bool ipv6_chk_same_addr(struct n return false; }
- int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) + int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) { struct inet6_dev *idev; struct inet6_ifaddr *ifa; @@@ -1443,7 -1457,7 +1445,7 @@@ void addrconf_dad_failure(struct inet6_
/* Join to solicited addr multicast group. */
- void addrconf_join_solict(struct net_device *dev, struct in6_addr *addr) + void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr) { struct in6_addr maddr;
@@@ -1454,7 -1468,7 +1456,7 @@@ ipv6_dev_mc_inc(dev, &maddr); }
- void addrconf_leave_solict(struct inet6_dev *idev, struct in6_addr *addr) + void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr) { struct in6_addr maddr;
@@@ -2099,7 -2113,7 +2101,7 @@@ err_exit /* * Manual configuration of address on an interface */ - static int inet6_addr_add(struct net *net, int ifindex, struct in6_addr *pfx, + static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *pfx, unsigned int plen, __u8 ifa_flags, __u32 prefered_lft, __u32 valid_lft) { @@@ -2173,7 -2187,7 +2175,7 @@@ return PTR_ERR(ifp); }
- static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx, + static int inet6_addr_del(struct net *net, int ifindex, const struct in6_addr *pfx, unsigned int plen) { struct inet6_ifaddr *ifp; @@@ -2336,7 -2350,7 +2338,7 @@@ static void init_loopback(struct net_de add_addr(idev, &in6addr_loopback, 128, IFA_HOST); }
- static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr) + static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr) { struct inet6_ifaddr * ifp; u32 addr_flags = IFA_F_PERMANENT; @@@ -3107,7 -3121,7 +3109,7 @@@ void if6_proc_exit(void
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) /* Check if address is a home address configured on any interface. */ - int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr) + int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) { int ret = 0; struct inet6_ifaddr *ifp = NULL; @@@ -3824,7 -3838,7 +3826,7 @@@ static inline size_t inet6_if_nlmsg_siz + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ }
- static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib, + static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, int items, int bytes) { int i; @@@ -3834,7 -3848,7 +3836,7 @@@ /* Use put_unaligned() because stats may not be aligned for u64. */ put_unaligned(items, &stats[0]); for (i = 1; i < items; i++) - put_unaligned(snmp_fold_field(mib, i), &stats[i]); + put_unaligned(atomic_long_read(&mib[i]), &stats[i]);
memset(&stats[items], 0, pad); } @@@ -3863,7 -3877,7 +3865,7 @@@ static void snmp6_fill_stats(u64 *stats IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); break; case IFLA_INET6_ICMP6STATS: - __snmp6_fill_stats(stats, (void __percpu **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes); + __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes); break; } } diff --combined net/ipv6/mcast.c index f2d98ca,ff62e33..3e6ebcd --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@@ -92,16 -92,16 +92,16 @@@ static void mld_gq_timer_expire(unsigne static void mld_ifc_timer_expire(unsigned long data); static void mld_ifc_event(struct inet6_dev *idev); static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc); - static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *addr); + static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr); static void mld_clear_delrec(struct inet6_dev *idev); static int sf_setstate(struct ifmcaddr6 *pmc); static void sf_markstate(struct ifmcaddr6 *pmc); static void ip6_mc_clear_src(struct ifmcaddr6 *pmc); - static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, + static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta); - static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, + static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta); static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, struct inet6_dev *idev); @@@ -201,6 -201,10 +201,6 @@@ int ipv6_sock_mc_join(struct sock *sk, return 0; }
-static void ipv6_mc_socklist_reclaim(struct rcu_head *head) -{ - kfree(container_of(head, struct ipv6_mc_socklist, rcu)); -} /* * socket leave on multicast group */ @@@ -235,7 -239,7 +235,7 @@@ int ipv6_sock_mc_drop(struct sock *sk, (void) ip6_mc_leave_src(sk, mc_lst, NULL); rcu_read_unlock(); atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); - call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim); + kfree_rcu(mc_lst, rcu); return 0; } } @@@ -246,7 -250,7 +246,7 @@@
/* called with rcu_read_lock() */ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, - struct in6_addr *group, + const struct in6_addr *group, int ifindex) { struct net_device *dev = NULL; @@@ -303,7 -307,7 +303,7 @@@ void ipv6_sock_mc_close(struct sock *sk rcu_read_unlock();
atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); - call_rcu(&mc_lst->rcu, ipv6_mc_socklist_reclaim); + kfree_rcu(mc_lst, rcu);
spin_lock(&ipv6_sk_mc_lock); } @@@ -447,7 -451,7 +447,7 @@@ done
int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) { - struct in6_addr *group; + const struct in6_addr *group; struct ipv6_mc_socklist *pmc; struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); @@@ -538,7 -542,7 +538,7 @@@ int ip6_mc_msfget(struct sock *sk, stru struct group_filter __user *optval, int __user *optlen) { int err, i, count, copycount; - struct in6_addr *group; + const struct in6_addr *group; struct ipv6_mc_socklist *pmc; struct inet6_dev *idev; struct ipv6_pinfo *inet6 = inet6_sk(sk); @@@ -748,7 -752,7 +748,7 @@@ static void mld_add_delrec(struct inet6 spin_unlock_bh(&idev->mc_lock); }
- static void mld_del_delrec(struct inet6_dev *idev, struct in6_addr *pmca) + static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) { struct ifmcaddr6 *pmc, *pmc_prev; struct ip6_sf_list *psf, *psf_next; @@@ -1048,7 -1052,7 +1048,7 @@@ static void igmp6_group_queried(struct
/* mark EXCLUDE-mode sources */ static int mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, - struct in6_addr *srcs) + const struct in6_addr *srcs) { struct ip6_sf_list *psf; int i, scount; @@@ -1076,7 -1080,7 +1076,7 @@@ }
static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, - struct in6_addr *srcs) + const struct in6_addr *srcs) { struct ip6_sf_list *psf; int i, scount; @@@ -1111,7 -1115,7 +1111,7 @@@ int igmp6_event_query(struct sk_buff *s { struct mld2_query *mlh2 = NULL; struct ifmcaddr6 *ma; - struct in6_addr *group; + const struct in6_addr *group; unsigned long max_delay; struct inet6_dev *idev; struct mld_msg *mld; @@@ -1817,7 -1821,7 +1817,7 @@@ err_out }
static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, - struct in6_addr *psfsrc) + const struct in6_addr *psfsrc) { struct ip6_sf_list *psf, *psf_prev; int rv = 0; @@@ -1853,8 -1857,8 +1853,8 @@@ return rv; }
- static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, + static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta) { struct ifmcaddr6 *pmc; @@@ -1914,7 -1918,7 +1914,7 @@@ * Add multicast single-source filter to the interface list */ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, - struct in6_addr *psfsrc, int delta) + const struct in6_addr *psfsrc, int delta) { struct ip6_sf_list *psf, *psf_prev;
@@@ -2017,8 -2021,8 +2017,8 @@@ static int sf_setstate(struct ifmcaddr /* * Add multicast source filter list to the interface list */ - static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca, - int sfmode, int sfcount, struct in6_addr *psfsrc, + static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, + int sfmode, int sfcount, const struct in6_addr *psfsrc, int delta) { struct ifmcaddr6 *pmc; diff --combined net/ipv6/sit.c index 5f35d59,a6a32b3..1cca576 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@@ -250,11 -250,6 +250,6 @@@ static struct ip_tunnel *ipip6_tunnel_l
dev_net_set(dev, net);
- if (strchr(name, '%')) { - if (dev_alloc_name(dev, name) < 0) - goto failed_free; - } - nt = netdev_priv(dev);
nt->parms = *parms; @@@ -401,6 -396,11 +396,6 @@@ out return err; }
-static void prl_entry_destroy_rcu(struct rcu_head *head) -{ - kfree(container_of(head, struct ip_tunnel_prl_entry, rcu_head)); -} - static void prl_list_destroy_rcu(struct rcu_head *head) { struct ip_tunnel_prl_entry *p, *n; @@@ -428,7 -428,7 +423,7 @@@ ipip6_tunnel_del_prl(struct ip_tunnel * p = &x->next) { if (x->addr == a->addr) { *p = x->next; - call_rcu(&x->rcu_head, prl_entry_destroy_rcu); + kfree_rcu(x, rcu_head); t->prl_count--; goto out; } @@@ -447,7 -447,7 +442,7 @@@ out }
static int - isatap_chksrc(struct sk_buff *skb, struct iphdr *iph, struct ip_tunnel *t) + isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t) { struct ip_tunnel_prl_entry *p; int ok = 1; @@@ -460,7 -460,8 +455,8 @@@ else skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; } else { - struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; + const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; + if (ipv6_addr_is_isatap(addr6) && (addr6->s6_addr32[3] == iph->saddr) && ipv6_chk_prefix(addr6, t->dev)) @@@ -494,7 -495,7 +490,7 @@@ static int ipip6_err(struct sk_buff *sk 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)skb->data; + const struct iphdr *iph = (const struct iphdr *)skb->data; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; struct ip_tunnel *t; @@@ -552,7 -553,7 +548,7 @@@ out return err; }
- static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) + static inline void ipip6_ecn_decapsulate(const struct iphdr *iph, struct sk_buff *skb) { if (INET_ECN_is_ce(iph->tos)) IP6_ECN_set_ce(ipv6_hdr(skb)); @@@ -560,7 -561,7 +556,7 @@@
static int ipip6_rcv(struct sk_buff *skb) { - struct iphdr *iph; + const struct iphdr *iph; struct ip_tunnel *tunnel;
if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) @@@ -616,7 -617,7 +612,7 @@@ out * comes from 6rd / 6to4 (RFC 3056) addr space. */ static inline - __be32 try_6rd(struct in6_addr *v6dst, struct ip_tunnel *tunnel) + __be32 try_6rd(const struct in6_addr *v6dst, struct ip_tunnel *tunnel) { __be32 dst = 0;
@@@ -659,8 -660,8 +655,8 @@@ static netdev_tx_t ipip6_tunnel_xmit(st { struct ip_tunnel *tunnel = netdev_priv(dev); struct pcpu_tstats *tstats; - struct iphdr *tiph = &tunnel->parms.iph; - struct ipv6hdr *iph6 = ipv6_hdr(skb); + const struct iphdr *tiph = &tunnel->parms.iph; + const struct ipv6hdr *iph6 = ipv6_hdr(skb); u8 tos = tunnel->parms.iph.tos; __be16 df = tiph->frag_off; struct rtable *rt; /* Route to the other host */ @@@ -668,8 -669,9 +664,9 @@@ struct iphdr *iph; /* Our new IP header */ unsigned int max_headroom; /* The extra header space needed */ __be32 dst = tiph->daddr; + struct flowi4 fl4; int mtu; - struct in6_addr *addr6; + const struct in6_addr *addr6; int addr_type;
if (skb->protocol != htons(ETH_P_IPV6)) @@@ -688,7 -690,7 +685,7 @@@ goto tx_error; }
- addr6 = (struct in6_addr*)&neigh->primary_key; + addr6 = (const struct in6_addr*)&neigh->primary_key; addr_type = ipv6_addr_type(addr6);
if ((addr_type & IPV6_ADDR_UNICAST) && @@@ -713,7 -715,7 +710,7 @@@ goto tx_error; }
- addr6 = (struct in6_addr*)&neigh->primary_key; + addr6 = (const struct in6_addr*)&neigh->primary_key; addr_type = ipv6_addr_type(addr6);
if (addr_type == IPV6_ADDR_ANY) { @@@ -727,7 -729,7 +724,7 @@@ dst = addr6->s6_addr32[3]; }
- rt = ip_route_output_ports(dev_net(dev), NULL, + rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, dst, tiph->saddr, 0, 0, IPPROTO_IPV6, RT_TOS(tos), @@@ -821,8 -823,8 +818,8 @@@ iph->frag_off = df; iph->protocol = IPPROTO_IPV6; iph->tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); - iph->daddr = rt->rt_dst; - iph->saddr = rt->rt_src; + iph->daddr = fl4.daddr; + iph->saddr = fl4.saddr;
if ((iph->ttl = tiph->ttl) == 0) iph->ttl = iph6->hop_limit; @@@ -844,13 -846,14 +841,14 @@@ static void ipip6_tunnel_bind_dev(struc { struct net_device *tdev = NULL; struct ip_tunnel *tunnel; - struct iphdr *iph; + const struct iphdr *iph; + struct flowi4 fl4;
tunnel = netdev_priv(dev); iph = &tunnel->parms.iph;
if (iph->daddr) { - struct rtable *rt = ip_route_output_ports(dev_net(dev), NULL, + struct rtable *rt = ip_route_output_ports(dev_net(dev), &fl4, NULL, iph->daddr, iph->saddr, 0, 0, IPPROTO_IPV6, diff --combined net/l2tp/l2tp_ip.c index 5c04f3e,f7fb09e..b6466e7 --- a/net/l2tp/l2tp_ip.c +++ b/net/l2tp/l2tp_ip.c @@@ -296,12 -296,12 +296,12 @@@ out_in_use
static int l2tp_ip_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { - int rc; - struct inet_sock *inet = inet_sk(sk); struct sockaddr_l2tpip *lsa = (struct sockaddr_l2tpip *) uaddr; + struct inet_sock *inet = inet_sk(sk); + struct flowi4 *fl4; struct rtable *rt; __be32 saddr; - int oif; + int oif, rc;
rc = -EINVAL; if (addr_len < sizeof(*lsa)) @@@ -311,6 -311,8 +311,8 @@@ if (lsa->l2tp_family != AF_INET) goto out;
+ lock_sock(sk); + sk_dst_reset(sk);
oif = sk->sk_bound_dev_if; @@@ -320,7 -322,8 +322,8 @@@ if (ipv4_is_multicast(lsa->l2tp_addr.s_addr)) goto out;
- rt = ip_route_connect(lsa->l2tp_addr.s_addr, saddr, + fl4 = &inet->cork.fl.u.ip4; + rt = ip_route_connect(fl4, lsa->l2tp_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, IPPROTO_L2TP, 0, 0, sk, true); @@@ -340,10 -343,10 +343,10 @@@ l2tp_ip_sk(sk)->peer_conn_id = lsa->l2tp_conn_id;
if (!inet->inet_saddr) - inet->inet_saddr = rt->rt_src; + inet->inet_saddr = fl4->saddr; if (!inet->inet_rcv_saddr) - inet->inet_rcv_saddr = rt->rt_src; - inet->inet_daddr = rt->rt_dst; + inet->inet_rcv_saddr = fl4->saddr; + inet->inet_daddr = fl4->daddr; sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies;
@@@ -356,6 -359,7 +359,7 @@@
rc = 0; out: + release_sock(sk); return rc; }
@@@ -416,23 -420,28 +420,28 @@@ static int l2tp_ip_sendmsg(struct kioc int rc; struct l2tp_ip_sock *lsa = l2tp_ip_sk(sk); struct inet_sock *inet = inet_sk(sk); - struct ip_options *opt = inet->opt; struct rtable *rt = NULL; + struct flowi4 *fl4; int connected = 0; __be32 daddr;
+ lock_sock(sk); + + rc = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD)) - return -ENOTCONN; + goto out;
/* Get and verify the address. */ if (msg->msg_name) { struct sockaddr_l2tpip *lip = (struct sockaddr_l2tpip *) msg->msg_name; + rc = -EINVAL; if (msg->msg_namelen < sizeof(*lip)) - return -EINVAL; + goto out;
if (lip->l2tp_family != AF_INET) { + rc = -EAFNOSUPPORT; if (lip->l2tp_family != AF_UNSPEC) - return -EAFNOSUPPORT; + goto out; }
daddr = lip->l2tp_addr.s_addr; @@@ -467,19 -476,27 +476,27 @@@ goto error; }
+ fl4 = &inet->cork.fl.u.ip4; if (connected) rt = (struct rtable *) __sk_dst_check(sk, 0);
if (rt == NULL) { + struct ip_options_rcu *inet_opt; + + rcu_read_lock(); + inet_opt = rcu_dereference(inet->inet_opt); + /* Use correct destination address if we have options. */ - if (opt && opt->srr) - daddr = opt->faddr; + if (inet_opt && inet_opt->opt.srr) + daddr = inet_opt->opt.faddr; + + rcu_read_unlock();
/* If this fails, retransmit mechanism of transport layer will * keep trying until route appears or the connection times * itself out. */ - rt = ip_route_output_ports(sock_net(sk), sk, + rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, inet->inet_dport, inet->inet_sport, sk->sk_protocol, RT_CONN_FLAGS(sk), @@@ -491,7 -508,7 +508,7 @@@ skb_dst_set(skb, dst_clone(&rt->dst));
/* Queue the packet to IP for output */ - rc = ip_queue_xmit(skb); + rc = ip_queue_xmit(skb, &inet->cork.fl);
error: /* Update stats */ @@@ -503,12 -520,15 +520,15 @@@ lsa->tx_errors++; }
+ out: + release_sock(sk); return rc;
no_route: IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); kfree_skb(skb); - return -EHOSTUNREACH; + rc = -EHOSTUNREACH; + goto out; }
static int l2tp_ip_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, @@@ -667,7 -687,7 +687,7 @@@ MODULE_AUTHOR("James Chapman <jchapman@ MODULE_DESCRIPTION("L2TP over IP"); MODULE_VERSION("1.0");
-/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like +/* Use the value of SOCK_DGRAM (2) directory, because __stringify doesn't like * enums */ MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP); diff --combined net/mac80211/agg-tx.c index 53defaf,cd5125f..c8be8ef --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@@ -136,26 -136,45 +136,37 @@@ void ieee80211_send_bar(struct ieee8021 ieee80211_tx_skb(sdata, skb); }
+ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid, + struct tid_ampdu_tx *tid_tx) + { + lockdep_assert_held(&sta->ampdu_mlme.mtx); + lockdep_assert_held(&sta->lock); + rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); + } + -static void kfree_tid_tx(struct rcu_head *rcu_head) -{ - struct tid_ampdu_tx *tid_tx = - container_of(rcu_head, struct tid_ampdu_tx, rcu_head); - - kfree(tid_tx); -} - int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, enum ieee80211_back_parties initiator, bool tx) { struct ieee80211_local *local = sta->local; - struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; + struct tid_ampdu_tx *tid_tx; int ret;
lockdep_assert_held(&sta->ampdu_mlme.mtx);
- if (!tid_tx) - return -ENOENT; - spin_lock_bh(&sta->lock);
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + if (!tid_tx) { + spin_unlock_bh(&sta->lock); + return -ENOENT; + } + if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) { /* not even started yet! */ - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); + ieee80211_assign_tid_tx(sta, tid, NULL); spin_unlock_bh(&sta->lock); - call_rcu(&tid_tx->rcu_head, kfree_tid_tx); + kfree_rcu(tid_tx, rcu_head); return 0; }
@@@ -275,13 -294,13 +286,13 @@@ ieee80211_wake_queue_agg(struct ieee802
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) { - struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid]; + struct tid_ampdu_tx *tid_tx; struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; u16 start_seq_num; int ret;
- lockdep_assert_held(&sta->ampdu_mlme.mtx); + tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
/* * While we're asking the driver about the aggregation, @@@ -310,11 -329,11 +321,11 @@@ " tid %d\n", tid); #endif spin_lock_bh(&sta->lock); - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); + ieee80211_assign_tid_tx(sta, tid, NULL); spin_unlock_bh(&sta->lock);
ieee80211_wake_queue_agg(local, tid); - call_rcu(&tid_tx->rcu_head, kfree_tid_tx); + kfree_rcu(tid_tx, rcu_head); return; }
@@@ -388,9 -407,9 +399,9 @@@ int ieee80211_start_tx_ba_session(struc goto err_unlock_sta; }
- tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* check if the TID is not in aggregation flow already */ - if (tid_tx) { + if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "BA request denied - session is not " "idle on tid %u\n", tid); @@@ -425,8 -444,11 +436,11 @@@ sta->ampdu_mlme.dialog_token_allocator++; tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
- /* finally, assign it to the array */ - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx); + /* + * Finally, assign it to the start array; the work item will + * collect it and move it to the normal array. + */ + sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
@@@ -472,16 -494,19 +486,19 @@@ ieee80211_agg_splice_finish(struct ieee static void ieee80211_agg_tx_operational(struct ieee80211_local *local, struct sta_info *sta, u16 tid) { + struct tid_ampdu_tx *tid_tx; + lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid); + #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid); #endif
drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_OPERATIONAL, - &sta->sta, tid, NULL, - sta->ampdu_mlme.tid_tx[tid]->buf_size); + &sta->sta, tid, NULL, tid_tx->buf_size);
/* * synchronize with TX path, while splicing the TX path @@@ -489,13 -514,13 +506,13 @@@ */ spin_lock_bh(&sta->lock);
- ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid); + ieee80211_agg_splice_packets(local, tid_tx, tid); /* * Now mark as operational. This will be visible * in the TX path, and lets it go lock-free in * the common case. */ - set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state); + set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state); ieee80211_agg_splice_finish(local, tid);
spin_unlock_bh(&sta->lock); @@@ -529,7 -554,7 +546,7 @@@ void ieee80211_start_tx_ba_cb(struct ie }
mutex_lock(&sta->ampdu_mlme.mtx); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (WARN_ON(!tid_tx)) { #ifdef CONFIG_MAC80211_HT_DEBUG @@@ -607,7 -632,7 +624,7 @@@ int ieee80211_stop_tx_ba_session(struc return -EINVAL;
spin_lock_bh(&sta->lock); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx) { ret = -ENOENT; @@@ -663,7 -688,7 +680,7 @@@ void ieee80211_stop_tx_ba_cb(struct iee
mutex_lock(&sta->ampdu_mlme.mtx); spin_lock_bh(&sta->lock); - tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { #ifdef CONFIG_MAC80211_HT_DEBUG @@@ -689,11 -714,11 +706,11 @@@ ieee80211_agg_splice_packets(local, tid_tx, tid);
/* future packets must not find the tid_tx struct any more */ - rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL); + ieee80211_assign_tid_tx(sta, tid, NULL);
ieee80211_agg_splice_finish(local, tid);
- call_rcu(&tid_tx->rcu_head, kfree_tid_tx); + kfree_rcu(tid_tx, rcu_head);
unlock_sta: spin_unlock_bh(&sta->lock); @@@ -744,7 -769,7 +761,7 @@@ void ieee80211_process_addba_resp(struc
mutex_lock(&sta->ampdu_mlme.mtx);
- tid_tx = sta->ampdu_mlme.tid_tx[tid]; + tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (!tid_tx) goto out;
diff --combined net/mac80211/work.c index ac35496,a94b312..d2e7f0e --- a/net/mac80211/work.c +++ b/net/mac80211/work.c @@@ -65,9 -65,17 +65,9 @@@ static void run_again(struct ieee80211_ mod_timer(&local->work_timer, timeout); }
-static void work_free_rcu(struct rcu_head *head) -{ - struct ieee80211_work *wk = - container_of(head, struct ieee80211_work, rcu_head); - - kfree(wk); -} - void free_work(struct ieee80211_work *wk) { - call_rcu(&wk->rcu_head, work_free_rcu); + kfree_rcu(wk, rcu_head); }
static int ieee80211_compatible_rates(const u8 *supp_rates, int supp_rates_len, @@@ -190,9 -198,8 +190,8 @@@ static void ieee80211_send_assoc(struc struct sk_buff *skb; struct ieee80211_mgmt *mgmt; u8 *pos, qos_info; - const u8 *ies; size_t offset = 0, noffset; - int i, len, count, rates_len, supp_rates_len; + int i, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_supported_band *sband; u32 rates = 0; @@@ -277,7 -284,7 +276,7 @@@ }
/* SSID */ - ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len); + pos = skb_put(skb, 2 + wk->assoc.ssid_len); *pos++ = WLAN_EID_SSID; *pos++ = wk->assoc.ssid_len; memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len); @@@ -287,7 -294,6 +286,6 @@@ if (supp_rates_len > 8) supp_rates_len = 8;
- len = sband->n_bitrates; pos = skb_put(skb, supp_rates_len + 2); *pos++ = WLAN_EID_SUPP_RATES; *pos++ = supp_rates_len; diff --combined net/phonet/pn_dev.c index 1566672,47b3452..d2df8f3 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@@ -162,6 -162,14 +162,6 @@@ int phonet_address_add(struct net_devic return err; }
-static void phonet_device_rcu_free(struct rcu_head *head) -{ - struct phonet_device *pnd; - - pnd = container_of(head, struct phonet_device, rcu); - kfree(pnd); -} - int phonet_address_del(struct net_device *dev, u8 addr) { struct phonet_device_list *pndevs = phonet_device_list(dev_net(dev)); @@@ -180,7 -188,7 +180,7 @@@ mutex_unlock(&pndevs->lock);
if (pnd) - call_rcu(&pnd->rcu, phonet_device_rcu_free); + kfree_rcu(pnd, rcu);
return err; } @@@ -418,18 -426,14 +418,14 @@@ int phonet_route_del(struct net_device return 0; }
- struct net_device *phonet_route_get(struct net *net, u8 daddr) + struct net_device *phonet_route_get_rcu(struct net *net, u8 daddr) { struct phonet_net *pnn = phonet_pernet(net); struct phonet_routes *routes = &pnn->routes; struct net_device *dev;
- ASSERT_RTNL(); /* no need to hold the device */ - daddr >>= 2; - rcu_read_lock(); dev = rcu_dereference(routes->table[daddr]); - rcu_read_unlock(); return dev; }
diff --combined net/sctp/bind_addr.c index 3c06c87,6150ac5..6338413 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@@ -140,14 -140,12 +140,12 @@@ void sctp_bind_addr_init(struct sctp_bi /* Dispose of the address list. */ static void sctp_bind_addr_clean(struct sctp_bind_addr *bp) { - struct sctp_sockaddr_entry *addr; - struct list_head *pos, *temp; + struct sctp_sockaddr_entry *addr, *temp;
/* Empty the bind address list. */ - list_for_each_safe(pos, temp, &bp->address_list) { - addr = list_entry(pos, struct sctp_sockaddr_entry, list); - list_del(pos); - kfree(addr); + list_for_each_entry_safe(addr, temp, &bp->address_list, list) { + list_del_rcu(&addr->list); + call_rcu(&addr->rcu, sctp_local_addr_free); SCTP_DBG_OBJCNT_DEC(addr); } } @@@ -219,7 -217,7 +217,7 @@@ int sctp_del_bind_addr(struct sctp_bind }
if (found) { - call_rcu(&addr->rcu, sctp_local_addr_free); + kfree_rcu(addr, rcu); SCTP_DBG_OBJCNT_DEC(addr); return 0; } diff --combined net/sctp/ipv6.c index 185fe05,500875f..0bb0d7c --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@@ -80,6 -80,13 +80,13 @@@
#include <asm/uaccess.h>
+ static inline int sctp_v6_addr_match_len(union sctp_addr *s1, + union sctp_addr *s2); + static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, + __be16 port); + static int sctp_v6_cmp_addr(const union sctp_addr *addr1, + const union sctp_addr *addr2); + /* Event handler for inet6 address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since * multiple notifiers (say IPv4 and IPv6) may be running at the same @@@ -123,7 -130,7 +130,7 @@@ static int sctp_inet6addr_event(struct } spin_unlock_bh(&sctp_local_addr_lock); if (found) - call_rcu(&addr->rcu, sctp_local_addr_free); + kfree_rcu(addr, rcu); break; }
@@@ -240,37 -247,107 +247,107 @@@ static int sctp_v6_xmit(struct sk_buff /* Returns the dst cache entry for the given source and destination ip * addresses. */ - static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr) + static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { - struct dst_entry *dst; - struct flowi6 fl6; + struct sctp_association *asoc = t->asoc; + struct dst_entry *dst = NULL; + struct flowi6 *fl6 = &fl->u.ip6; + struct sctp_bind_addr *bp; + struct sctp_sockaddr_entry *laddr; + union sctp_addr *baddr = NULL; + union sctp_addr *daddr = &t->ipaddr; + union sctp_addr dst_saddr; + __u8 matchlen = 0; + __u8 bmatchlen; + sctp_scope_t scope;
- memset(&fl6, 0, sizeof(fl6)); - ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr); + memset(fl6, 0, sizeof(struct flowi6)); + ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr); + fl6->fl6_dport = daddr->v6.sin6_port; + fl6->flowi6_proto = IPPROTO_SCTP; if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) - fl6.flowi6_oif = daddr->v6.sin6_scope_id; + fl6->flowi6_oif = daddr->v6.sin6_scope_id;
+ SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr);
- SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr); + if (asoc) + fl6->fl6_sport = htons(asoc->base.bind_addr.port);
if (saddr) { - ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr); + ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr); + fl6->fl6_sport = saddr->v6.sin6_port; + SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr); + } + + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); + if (!asoc || saddr) + goto out; + + bp = &asoc->base.bind_addr; + scope = sctp_scope(daddr); + /* ip6_dst_lookup has filled in the fl6->saddr for us. Check + * to see if we can use it. + */ + if (!IS_ERR(dst)) { + /* Walk through the bind address list and look for a bind + * address that matches the source address of the returned dst. + */ + sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port)); + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) + continue; + + /* Do not compare against v4 addrs */ + if ((laddr->a.sa.sa_family == AF_INET6) && + (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) { + rcu_read_unlock(); + goto out; + } + } + rcu_read_unlock(); + /* None of the bound addresses match the source address of the + * dst. So release it. + */ + dst_release(dst); + dst = NULL; }
- dst = ip6_route_output(&init_net, NULL, &fl6); - if (!dst->error) { + /* Walk through the bind address list and try to get the + * best source address for a given destination. + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { + if (!laddr->valid && laddr->state != SCTP_ADDR_SRC) + continue; + if ((laddr->a.sa.sa_family == AF_INET6) && + (scope <= sctp_scope(&laddr->a))) { + bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); + if (!baddr || (matchlen < bmatchlen)) { + baddr = &laddr->a; + matchlen = bmatchlen; + } + } + } + rcu_read_unlock(); + if (baddr) { + ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr); + fl6->fl6_sport = baddr->v6.sin6_port; + dst = ip6_dst_lookup_flow(sk, fl6, NULL, false); + } + + out: + if (!IS_ERR(dst)) { struct rt6_info *rt; rt = (struct rt6_info *)dst; + t->dst = dst; SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", - &rt->rt6i_dst.addr, &rt->rt6i_src.addr); - return dst; + &rt->rt6i_dst.addr, &fl6->saddr); + } else { + t->dst = NULL; + SCTP_DEBUG_PRINTK("NO ROUTE\n"); } - SCTP_DEBUG_PRINTK("NO ROUTE\n"); - dst_release(dst); - return NULL; }
/* Returns the number of consecutive initial bits that match in the 2 ipv6 @@@ -286,64 -363,18 +363,18 @@@ static inline int sctp_v6_addr_match_le * and asoc's bind address list. */ static void sctp_v6_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, - union sctp_addr *daddr, - union sctp_addr *saddr) + struct sctp_transport *t, + struct flowi *fl) { - struct sctp_bind_addr *bp; - struct sctp_sockaddr_entry *laddr; - sctp_scope_t scope; - union sctp_addr *baddr = NULL; - __u8 matchlen = 0; - __u8 bmatchlen; + struct flowi6 *fl6 = &fl->u.ip6; + union sctp_addr *saddr = &t->saddr;
- SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", - __func__, asoc, dst, &daddr->v6.sin6_addr); - - if (!asoc) { - ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), - dst ? ip6_dst_idev(dst)->dev : NULL, - &daddr->v6.sin6_addr, - inet6_sk(&sk->inet.sk)->srcprefs, - &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", - &saddr->v6.sin6_addr); - return; - } - - scope = sctp_scope(daddr); - - bp = &asoc->base.bind_addr; + SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst);
- /* Go through the bind address list and find the best source address - * that matches the scope of the destination address. - */ - rcu_read_lock(); - list_for_each_entry_rcu(laddr, &bp->address_list, list) { - if (!laddr->valid) - continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (laddr->a.sa.sa_family == AF_INET6) && - (scope <= sctp_scope(&laddr->a))) { - bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); - if (!baddr || (matchlen < bmatchlen)) { - baddr = &laddr->a; - matchlen = bmatchlen; - } - } - } - - if (baddr) { - memcpy(saddr, baddr, sizeof(union sctp_addr)); - SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr); - } else { - pr_err("%s: asoc:%p Could not find a valid source " - "address for the dest:%pI6\n", - __func__, asoc, &daddr->v6.sin6_addr); + if (t->dst) { + saddr->v6.sin6_family = AF_INET6; + ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr); } - - rcu_read_unlock(); }
/* Make a copy of all potential local addresses. */ @@@ -465,14 -496,13 +496,13 @@@ static int sctp_v6_to_addr_param(const return length; }
- /* Initialize a sctp_addr from a dst_entry. */ - static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, + /* Initialize a sctp_addr from struct in6_addr. */ + static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr, __be16 port) { - struct rt6_info *rt = (struct rt6_info *)dst; addr->sa.sa_family = AF_INET6; addr->v6.sin6_port = port; - ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); + ipv6_addr_copy(&addr->v6.sin6_addr, saddr); }
/* Compare addresses exactly. @@@ -531,7 -561,7 +561,7 @@@ static int sctp_v6_is_any(const union s static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) { int type; - struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; + const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
type = ipv6_addr_type(in6); if (IPV6_ADDR_ANY == type) @@@ -959,7 -989,6 +989,6 @@@ static struct sctp_af sctp_af_inet6 = .to_sk_daddr = sctp_v6_to_sk_daddr, .from_addr_param = sctp_v6_from_addr_param, .to_addr_param = sctp_v6_to_addr_param, - .dst_saddr = sctp_v6_dst_saddr, .cmp_addr = sctp_v6_cmp_addr, .scope = sctp_v6_scope, .addr_valid = sctp_v6_addr_valid, diff --combined net/sctp/protocol.c index 065d999,4de77cb..67380a2 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@@ -230,6 -230,13 +230,6 @@@ static void sctp_free_local_addr_list(v } }
-void sctp_local_addr_free(struct rcu_head *head) -{ - struct sctp_sockaddr_entry *e = container_of(head, - struct sctp_sockaddr_entry, rcu); - kfree(e); -} - /* Copy the local addresses which are valid for 'scope' into 'bp'. */ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope, gfp_t gfp, int copy_flags) @@@ -332,13 -339,12 +332,12 @@@ static int sctp_v4_to_addr_param(const }
/* Initialize a sctp_addr from a dst_entry. */ - static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst, + static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4, __be16 port) { - struct rtable *rt = (struct rtable *)dst; saddr->v4.sin_family = AF_INET; saddr->v4.sin_port = port; - saddr->v4.sin_addr.s_addr = rt->rt_src; + saddr->v4.sin_addr.s_addr = fl4->saddr; }
/* Compare two addresses exactly. */ @@@ -456,35 -462,36 +455,36 @@@ static sctp_scope_t sctp_v4_scope(unio * addresses. If an association is passed, trys to get a dst entry with a * source address that matches an address in the bind address list. */ - static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, - union sctp_addr *daddr, - union sctp_addr *saddr) + static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, + struct flowi *fl, struct sock *sk) { + struct sctp_association *asoc = t->asoc; struct rtable *rt; - struct flowi4 fl4; + struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; + union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr;
- memset(&fl4, 0x0, sizeof(struct flowi4)); - fl4.daddr = daddr->v4.sin_addr.s_addr; - fl4.fl4_dport = daddr->v4.sin_port; - fl4.flowi4_proto = IPPROTO_SCTP; + memset(fl4, 0x0, sizeof(struct flowi4)); + fl4->daddr = daddr->v4.sin_addr.s_addr; + fl4->fl4_dport = daddr->v4.sin_port; + fl4->flowi4_proto = IPPROTO_SCTP; if (asoc) { - fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); - fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if; - fl4.fl4_sport = htons(asoc->base.bind_addr.port); + fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); + fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; + fl4->fl4_sport = htons(asoc->base.bind_addr.port); } if (saddr) { - fl4.saddr = saddr->v4.sin_addr.s_addr; - fl4.fl4_sport = saddr->v4.sin_port; + fl4->saddr = saddr->v4.sin_addr.s_addr; + fl4->fl4_sport = saddr->v4.sin_port; }
SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", - __func__, &fl4.daddr, &fl4.saddr); + __func__, &fl4->daddr, &fl4->saddr);
- rt = ip_route_output_key(&init_net, &fl4); + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) dst = &rt->dst;
@@@ -500,7 -507,7 +500,7 @@@ /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ - sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port)); + sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) @@@ -526,9 -533,9 +526,9 @@@ continue; if ((laddr->state == SCTP_ADDR_SRC) && (AF_INET == laddr->a.sa.sa_family)) { - fl4.saddr = laddr->a.v4.sin_addr.s_addr; - fl4.fl4_sport = laddr->a.v4.sin_port; - rt = ip_route_output_key(&init_net, &fl4); + fl4->saddr = laddr->a.v4.sin_addr.s_addr; + fl4->fl4_sport = laddr->a.v4.sin_port; + rt = ip_route_output_key(&init_net, fl4); if (!IS_ERR(rt)) { dst = &rt->dst; goto out_unlock; @@@ -539,33 -546,27 +539,27 @@@ out_unlock: rcu_read_unlock(); out: + t->dst = dst; if (dst) SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", - &rt->rt_dst, &rt->rt_src); + &fl4->daddr, &fl4->saddr); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); - - return dst; }
/* For v4, the source address is cached in the route entry(dst). So no need * to cache it separately and hence this is an empty routine. */ static void sctp_v4_get_saddr(struct sctp_sock *sk, - struct sctp_association *asoc, - struct dst_entry *dst, - union sctp_addr *daddr, - union sctp_addr *saddr) + struct sctp_transport *t, + struct flowi *fl) { - struct rtable *rt = (struct rtable *)dst; - - if (!asoc) - return; + union sctp_addr *saddr = &t->saddr; + struct rtable *rt = (struct rtable *)t->dst;
if (rt) { saddr->v4.sin_family = AF_INET; - saddr->v4.sin_port = htons(asoc->base.bind_addr.port); - saddr->v4.sin_addr.s_addr = rt->rt_src; + saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr; } }
@@@ -674,7 -675,7 +668,7 @@@ static int sctp_inetaddr_event(struct n } spin_unlock_bh(&sctp_local_addr_lock); if (found) - call_rcu(&addr->rcu, sctp_local_addr_free); + kfree_rcu(addr, rcu); break; }
@@@ -847,14 -848,14 +841,14 @@@ static inline int sctp_v4_xmit(struct s
SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - &skb_rtable(skb)->rt_src, - &skb_rtable(skb)->rt_dst); + &transport->fl.u.ip4.saddr, + &transport->fl.u.ip4.daddr);
inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); - return ip_queue_xmit(skb); + return ip_queue_xmit(skb, &transport->fl); }
static struct sctp_af sctp_af_inet; @@@ -943,7 -944,6 +937,6 @@@ static struct sctp_af sctp_af_inet = .to_sk_daddr = sctp_v4_to_sk_daddr, .from_addr_param = sctp_v4_from_addr_param, .to_addr_param = sctp_v4_to_addr_param, - .dst_saddr = sctp_v4_dst_saddr, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, .inaddr_any = sctp_v4_inaddr_any, diff --combined net/sctp/ulpevent.c index 61b1f5a,c962c60..e70e5fc --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@@ -554,7 -554,7 +554,7 @@@ struct sctp_ulpevent *sctp_ulpevent_mak memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
/* Per TSVWG discussion with Randy. Allow the application to - * resemble a fragmented message. + * reassemble a fragmented message. */ ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
@@@ -843,7 -843,7 +843,7 @@@ struct sctp_ulpevent *sctp_ulpevent_mak ak = (struct sctp_authkey_event *) skb_put(skb, sizeof(struct sctp_authkey_event));
- ak->auth_type = SCTP_AUTHENTICATION_INDICATION; + ak->auth_type = SCTP_AUTHENTICATION_EVENT; ak->auth_flags = 0; ak->auth_length = sizeof(struct sctp_authkey_event);
@@@ -862,6 -862,34 +862,34 @@@ fail return NULL; }
+ /* + * Socket Extensions for SCTP + * 6.3.10. SCTP_SENDER_DRY_EVENT + */ + struct sctp_ulpevent *sctp_ulpevent_make_sender_dry_event( + const struct sctp_association *asoc, gfp_t gfp) + { + struct sctp_ulpevent *event; + struct sctp_sender_dry_event *sdry; + struct sk_buff *skb; + + event = sctp_ulpevent_new(sizeof(struct sctp_sender_dry_event), + MSG_NOTIFICATION, gfp); + if (!event) + return NULL; + + skb = sctp_event2skb(event); + sdry = (struct sctp_sender_dry_event *) + skb_put(skb, sizeof(struct sctp_sender_dry_event)); + + sdry->sender_dry_type = SCTP_SENDER_DRY_EVENT; + sdry->sender_dry_flags = 0; + sdry->sender_dry_length = sizeof(struct sctp_sender_dry_event); + sctp_ulpevent_set_owner(event, asoc); + sdry->sender_dry_assoc_id = sctp_assoc2id(asoc); + + return event; + }
/* Return the notification type, assuming this is a notification * event. diff --combined net/socket.c index c2ed7c9,2d5382d..02dc82d --- a/net/socket.c +++ b/net/socket.c @@@ -263,6 -263,15 +263,6 @@@ static struct inode *sock_alloc_inode(s return &ei->vfs_inode; }
- - -static void wq_free_rcu(struct rcu_head *head) -{ - struct socket_wq *wq = container_of(head, struct socket_wq, rcu); - - kfree(wq); -} - static void sock_destroy_inode(struct inode *inode) { struct socket_alloc *ei; @@@ -270,7 -279,7 +270,7 @@@
ei = container_of(inode, struct socket_alloc, vfs_inode); wq = rcu_dereference_protected(ei->socket.wq, 1); - call_rcu(&wq->rcu, wq_free_rcu); + kfree_rcu(wq, rcu); kmem_cache_free(sock_inode_cachep, ei); }
@@@ -542,11 -551,10 +542,10 @@@ int sock_tx_timestamp(struct sock *sk, } EXPORT_SYMBOL(sock_tx_timestamp);
- static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t size) + static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size) { struct sock_iocb *si = kiocb_to_siocb(iocb); - int err;
sock_update_classid(sock->sk);
@@@ -555,13 -563,17 +554,17 @@@ si->msg = msg; si->size = size;
return sock->ops->sendmsg(iocb, sock, msg, size); }
+ static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock, + struct msghdr *msg, size_t size) + { + int err = security_socket_sendmsg(sock, msg, size); + + return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size); + } + int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) { struct kiocb iocb; @@@ -577,6 -589,20 +580,20 @@@ } EXPORT_SYMBOL(sock_sendmsg);
+ int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg, size_t size) + { + struct kiocb iocb; + struct sock_iocb siocb; + int ret; + + init_sync_kiocb(&iocb, NULL); + iocb.private = &siocb; + ret = __sock_sendmsg_nosec(&iocb, sock, msg, size); + if (-EIOCBQUEUED == ret) + ret = wait_on_sync_kiocb(&iocb); + return ret; + } + int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, size_t num, size_t size) { @@@ -1854,57 -1880,47 +1871,47 @@@ SYSCALL_DEFINE2(shutdown, int, fd, int #define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) #define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags)
- /* - * BSD sendmsg interface - */ - - SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) + static int __sys_sendmsg(struct socket *sock, struct msghdr __user *msg, + struct msghdr *msg_sys, unsigned flags, int nosec) { struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg; - struct socket *sock; struct sockaddr_storage address; struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20] __attribute__ ((aligned(sizeof(__kernel_size_t)))); /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; - struct msghdr msg_sys; int err, ctl_len, iov_size, total_len;
err = -EFAULT; if (MSG_CMSG_COMPAT & flags) { - if (get_compat_msghdr(&msg_sys, msg_compat)) + if (get_compat_msghdr(msg_sys, msg_compat)) return -EFAULT; - } else if (copy_from_user(&msg_sys, msg, sizeof(struct msghdr))) + } else if (copy_from_user(msg_sys, msg, sizeof(struct msghdr))) return -EFAULT;
- sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - /* do not move before msg_sys is valid */ err = -EMSGSIZE; - if (msg_sys.msg_iovlen > UIO_MAXIOV) - goto out_put; + if (msg_sys->msg_iovlen > UIO_MAXIOV) + goto out;
/* Check whether to allocate the iovec area */ err = -ENOMEM; - iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); - if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov_size = msg_sys->msg_iovlen * sizeof(struct iovec); + if (msg_sys->msg_iovlen > UIO_FASTIOV) { iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); if (!iov) - goto out_put; + goto out; }
/* This will also move the address data into kernel space */ if (MSG_CMSG_COMPAT & flags) { - err = verify_compat_iovec(&msg_sys, iov, + err = verify_compat_iovec(msg_sys, iov, (struct sockaddr *)&address, VERIFY_READ); } else - err = verify_iovec(&msg_sys, iov, + err = verify_iovec(msg_sys, iov, (struct sockaddr *)&address, VERIFY_READ); if (err < 0) @@@ -1913,17 -1929,17 +1920,17 @@@
err = -ENOBUFS;
- if (msg_sys.msg_controllen > INT_MAX) + if (msg_sys->msg_controllen > INT_MAX) goto out_freeiov; - ctl_len = msg_sys.msg_controllen; + ctl_len = msg_sys->msg_controllen; if ((MSG_CMSG_COMPAT & flags) && ctl_len) { err = - cmsghdr_from_user_compat_to_kern(&msg_sys, sock->sk, ctl, + cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, sizeof(ctl)); if (err) goto out_freeiov; - ctl_buf = msg_sys.msg_control; - ctl_len = msg_sys.msg_controllen; + ctl_buf = msg_sys->msg_control; + ctl_len = msg_sys->msg_controllen; } else if (ctl_len) { if (ctl_len > sizeof(ctl)) { ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); @@@ -1932,21 -1948,22 +1939,22 @@@ } err = -EFAULT; /* - * Careful! Before this, msg_sys.msg_control contains a user pointer. + * Careful! Before this, msg_sys->msg_control contains a user pointer. * Afterwards, it will be a kernel pointer. Thus the compiler-assisted * checking falls down on this. */ if (copy_from_user(ctl_buf, - (void __user __force *)msg_sys.msg_control, + (void __user __force *)msg_sys->msg_control, ctl_len)) goto out_freectl; - msg_sys.msg_control = ctl_buf; + msg_sys->msg_control = ctl_buf; } - msg_sys.msg_flags = flags; + msg_sys->msg_flags = flags;
if (sock->file->f_flags & O_NONBLOCK) - msg_sys.msg_flags |= MSG_DONTWAIT; - err = sock_sendmsg(sock, &msg_sys, total_len); + msg_sys->msg_flags |= MSG_DONTWAIT; + err = (nosec ? sock_sendmsg_nosec : sock_sendmsg)(sock, msg_sys, + total_len);
out_freectl: if (ctl_buf != ctl) @@@ -1954,12 -1971,114 +1962,114 @@@ out_freeiov: if (iov != iovstack) sock_kfree_s(sock->sk, iov, iov_size); - out_put: + out: + return err; + } + + /* + * BSD sendmsg interface + */ + + SYSCALL_DEFINE3(sendmsg, int, fd, struct msghdr __user *, msg, unsigned, flags) + { + int fput_needed, err; + struct msghdr msg_sys; + struct socket *sock = sockfd_lookup_light(fd, &err, &fput_needed); + + if (!sock) + goto out; + + err = __sys_sendmsg(sock, msg, &msg_sys, flags, 0); + fput_light(sock->file, fput_needed); out: return err; }
+ /* + * Linux sendmmsg interface + */ + + int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, + unsigned int flags) + { + int fput_needed, err, datagrams; + struct socket *sock; + struct mmsghdr __user *entry; + struct compat_mmsghdr __user *compat_entry; + struct msghdr msg_sys; + + datagrams = 0; + + sock = sockfd_lookup_light(fd, &err, &fput_needed); + if (!sock) + return err; + + err = sock_error(sock->sk); + if (err) + goto out_put; + + entry = mmsg; + compat_entry = (struct compat_mmsghdr __user *)mmsg; + + while (datagrams < vlen) { + /* + * No need to ask LSM for more than the first datagram. + */ + if (MSG_CMSG_COMPAT & flags) { + err = __sys_sendmsg(sock, (struct msghdr __user *)compat_entry, + &msg_sys, flags, datagrams); + if (err < 0) + break; + err = __put_user(err, &compat_entry->msg_len); + ++compat_entry; + } else { + err = __sys_sendmsg(sock, (struct msghdr __user *)entry, + &msg_sys, flags, datagrams); + if (err < 0) + break; + err = put_user(err, &entry->msg_len); + ++entry; + } + + if (err) + break; + ++datagrams; + } + + out_put: + fput_light(sock->file, fput_needed); + + if (err == 0) + return datagrams; + + if (datagrams != 0) { + /* + * We may send less entries than requested (vlen) if the + * sock is non blocking... + */ + if (err != -EAGAIN) { + /* + * ... or if sendmsg returns an error after we + * send some datagrams, where we record the + * error to return on the next call or if the + * app asks about it using getsockopt(SO_ERROR). + */ + sock->sk->sk_err = -err; + } + + return datagrams; + } + + return err; + } + + SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, + unsigned int, vlen, unsigned int, flags) + { + return __sys_sendmmsg(fd, mmsg, vlen, flags); + } + static int __sys_recvmsg(struct socket *sock, struct msghdr __user *msg, struct msghdr *msg_sys, unsigned flags, int nosec) { @@@ -2113,14 -2232,16 +2223,16 @@@ int __sys_recvmmsg(int fd, struct mmsgh */ if (MSG_CMSG_COMPAT & flags) { err = __sys_recvmsg(sock, (struct msghdr __user *)compat_entry, - &msg_sys, flags, datagrams); + &msg_sys, flags & ~MSG_WAITFORONE, + datagrams); if (err < 0) break; err = __put_user(err, &compat_entry->msg_len); ++compat_entry; } else { err = __sys_recvmsg(sock, (struct msghdr __user *)entry, - &msg_sys, flags, datagrams); + &msg_sys, flags & ~MSG_WAITFORONE, + datagrams); if (err < 0) break; err = put_user(err, &entry->msg_len); @@@ -2205,11 -2326,11 +2317,11 @@@ SYSCALL_DEFINE5(recvmmsg, int, fd, stru #ifdef __ARCH_WANT_SYS_SOCKETCALL /* Argument list sizes for sys_socketcall */ #define AL(x) ((x) * sizeof(unsigned long)) - static const unsigned char nargs[20] = { + static const unsigned char nargs[21] = { AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), - AL(4), AL(5) + AL(4), AL(5), AL(4) };
#undef AL @@@ -2229,7 -2350,7 +2341,7 @@@ SYSCALL_DEFINE2(socketcall, int, call, int err; unsigned int len;
- if (call < 1 || call > SYS_RECVMMSG) + if (call < 1 || call > SYS_SENDMMSG) return -EINVAL;
len = nargs[call]; @@@ -2304,6 -2425,9 +2416,9 @@@ case SYS_SENDMSG: err = sys_sendmsg(a0, (struct msghdr __user *)a1, a[2]); break; + case SYS_SENDMMSG: + err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); + break; case SYS_RECVMSG: err = sys_recvmsg(a0, (struct msghdr __user *)a1, a[2]); break; @@@ -2634,13 -2758,13 +2749,13 @@@ static int ethtool_ioctl(struct net *ne return -EFAULT;
if (convert_in) { - /* We expect there to be holes between fs.m_u and + /* We expect there to be holes between fs.m_ext and * fs.ring_cookie and at the end of fs, but nowhere else. */ - BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_u) + - sizeof(compat_rxnfc->fs.m_u) != - offsetof(struct ethtool_rxnfc, fs.m_u) + - sizeof(rxnfc->fs.m_u)); + BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + + sizeof(compat_rxnfc->fs.m_ext) != + offsetof(struct ethtool_rxnfc, fs.m_ext) + + sizeof(rxnfc->fs.m_ext)); BUILD_BUG_ON( offsetof(struct compat_ethtool_rxnfc, fs.location) - offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != @@@ -2648,7 -2772,7 +2763,7 @@@ offsetof(struct ethtool_rxnfc, fs.ring_cookie));
if (copy_in_user(rxnfc, compat_rxnfc, - (void *)(&rxnfc->fs.m_u + 1) - + (void *)(&rxnfc->fs.m_ext + 1) - (void *)rxnfc) || copy_in_user(&rxnfc->fs.ring_cookie, &compat_rxnfc->fs.ring_cookie, @@@ -2665,7 -2789,7 +2780,7 @@@
if (convert_out) { if (copy_in_user(compat_rxnfc, rxnfc, - (const void *)(&rxnfc->fs.m_u + 1) - + (const void *)(&rxnfc->fs.m_ext + 1) - (const void *)rxnfc) || copy_in_user(&compat_rxnfc->fs.ring_cookie, &rxnfc->fs.ring_cookie,