direct-io.hg

changeset 10817:f7b43e5c42b9

merge with xen-unstable.hg
author awilliam@xenbuild.aw
date Tue Jul 25 12:19:05 2006 -0600 (2006-07-25)
parents 2db50529223e d71e72d8532c
children 97cc7ed90061
files buildconfigs/linux-defconfig_xen0_ia64 buildconfigs/linux-defconfig_xen_ia64 patches/linux-2.6.16.13/net-gso.patch tools/examples/vtpm-addtodb tools/ioemu/Changelog tools/ioemu/Makefile tools/ioemu/README tools/ioemu/TODO tools/ioemu/VERSION tools/ioemu/audio/audio.c tools/ioemu/audio/audio.h tools/ioemu/audio/audio_int.h tools/ioemu/audio/mixeng.c tools/ioemu/audio/mixeng.h tools/ioemu/audio/mixeng_template.h tools/ioemu/audio/noaudio.c tools/ioemu/audio/ossaudio.c tools/ioemu/audio/sdlaudio.c tools/ioemu/audio/wavaudio.c tools/ioemu/block-cloop.c tools/ioemu/block-cow.c tools/ioemu/block-qcow.c tools/ioemu/block-vmdk.c tools/ioemu/block.c tools/ioemu/block_int.h tools/ioemu/configure tools/ioemu/console.c tools/ioemu/cpu-all.h tools/ioemu/cpu-defs.h tools/ioemu/cpu.h tools/ioemu/create_keysym_header.sh tools/ioemu/exec-all.h tools/ioemu/exec.c tools/ioemu/hw/acpi.c tools/ioemu/hw/adb.c tools/ioemu/hw/adlib.c tools/ioemu/hw/cirrus_vga.c tools/ioemu/hw/cuda.c tools/ioemu/hw/dma.c tools/ioemu/hw/fdc.c tools/ioemu/hw/i8254.c tools/ioemu/hw/i8259.c tools/ioemu/hw/i8259_stub.c tools/ioemu/hw/ide.c tools/ioemu/hw/iommu.c tools/ioemu/hw/lance.c tools/ioemu/hw/m48t08.c tools/ioemu/hw/m48t08.h tools/ioemu/hw/m48t59.c tools/ioemu/hw/m48t59.h tools/ioemu/hw/magic-load.c tools/ioemu/hw/ne2000.c tools/ioemu/hw/openpic.c tools/ioemu/hw/pc.c tools/ioemu/hw/pci.c tools/ioemu/hw/pckbd.c tools/ioemu/hw/pcnet.c tools/ioemu/hw/pcnet.h tools/ioemu/hw/piix4acpi.c tools/ioemu/hw/port-e9.c tools/ioemu/hw/ppc.c tools/ioemu/hw/ppc_chrp.c tools/ioemu/hw/ppc_prep.c tools/ioemu/hw/sb16.c tools/ioemu/hw/sched.c tools/ioemu/hw/serial.c tools/ioemu/hw/sun4m.c tools/ioemu/hw/tcx.c tools/ioemu/hw/timer.c tools/ioemu/hw/vga.c tools/ioemu/hw/vga_int.h tools/ioemu/ia64_intrinsic.h tools/ioemu/keyboard_rdesktop.c tools/ioemu/keymaps/convert-map tools/ioemu/main.c tools/ioemu/monitor.c tools/ioemu/osdep.c tools/ioemu/osdep.h tools/ioemu/path.c tools/ioemu/qemu-binfmt-conf.sh tools/ioemu/qemu-img.c tools/ioemu/readline.c tools/ioemu/sdl.c tools/ioemu/target-i386-dm/Makefile tools/ioemu/target-i386-dm/helper2.c tools/ioemu/target-i386-dm/qemu-ifup tools/ioemu/thunk.c tools/ioemu/vl.c tools/ioemu/vl.h tools/ioemu/vnc.c tools/ioemu/x86_32.ld tools/libxc/Makefile tools/libxc/xenctrl.h tools/vtpm/tpm_emulator-0.3-x86_64.patch
line diff
     1.1 --- a/.hgignore	Tue Jul 25 09:51:50 2006 -0600
     1.2 +++ b/.hgignore	Tue Jul 25 12:19:05 2006 -0600
     1.3 @@ -54,6 +54,7 @@
     1.4  ^extras/mini-os/h/xen-public$
     1.5  ^extras/mini-os/mini-os\..*$
     1.6  ^install/.*$
     1.7 +^linux-[^/]*-native/.*$
     1.8  ^linux-[^/]*-xen/.*$
     1.9  ^linux-[^/]*-xen0/.*$
    1.10  ^linux-[^/]*-xenU/.*$
    1.11 @@ -73,27 +74,11 @@
    1.12  ^tools/.*/TAGS$
    1.13  ^tools/.*/build/lib.*/.*\.py$
    1.14  ^tools/blktap/Makefile\.smh$
    1.15 -^tools/blktap/blkcow$
    1.16 -^tools/blktap/blkcowgnbd$
    1.17 -^tools/blktap/blkcowimg$
    1.18 -^tools/blktap/blkdump$
    1.19 -^tools/blktap/blkgnbd$
    1.20 -^tools/blktap/blkimg$
    1.21 -^tools/blktap/bstest$
    1.22 -^tools/blktap/parallax/blockstored$
    1.23 -^tools/blktap/parallax/parallax$
    1.24 -^tools/blktap/parallax/vdi_create$
    1.25 -^tools/blktap/parallax/vdi_fill$
    1.26 -^tools/blktap/parallax/vdi_list$
    1.27 -^tools/blktap/parallax/vdi_snap$
    1.28 -^tools/blktap/parallax/vdi_snap_delete$
    1.29 -^tools/blktap/parallax/vdi_snap_list$
    1.30 -^tools/blktap/parallax/vdi_tree$
    1.31 -^tools/blktap/parallax/vdi_validate$
    1.32 -^tools/blktap/ublkback/ublkback$
    1.33 -^tools/blktap/vdi\.dot$
    1.34 -^tools/blktap/vdi\.ps$
    1.35 -^tools/blktap/xen/.*$
    1.36 +^tools/blktap/drivers/blktapctrl$
    1.37 +^tools/blktap/drivers/img2qcow$
    1.38 +^tools/blktap/drivers/qcow-create$
    1.39 +^tools/blktap/drivers/qcow2raw$
    1.40 +^tools/blktap/drivers/tapdisk$
    1.41  ^tools/check/\..*$
    1.42  ^tools/console/xenconsole$
    1.43  ^tools/console/xenconsoled$
    1.44 @@ -122,13 +107,21 @@
    1.45  ^tools/firmware/vmxassist/roms\.h$
    1.46  ^tools/firmware/vmxassist/vmxassist$
    1.47  ^tools/firmware/vmxassist/vmxloader$
    1.48 -^tools/ioemu/config-host\..*$
    1.49 -^tools/ioemu/keysym_adapter_sdl\.h$
    1.50 -^tools/ioemu/keysym_adapter_vnc\.h$
    1.51 -^tools/ioemu/target-.*/Makefile$
    1.52 -^tools/ioemu/target-.*/config\..*$
    1.53 -^tools/ioemu/target-.*/qemu-dm$
    1.54 +^tools/ioemu/\.pc/.*$
    1.55 +^tools/ioemu/config-host\.h$
    1.56 +^tools/ioemu/config-host\.mak$
    1.57 +^tools/ioemu/i386-dm/config\.h$
    1.58 +^tools/ioemu/i386-dm/config\.mak$
    1.59 +^tools/ioemu/i386-dm/qemu-dm$
    1.60 +^tools/ioemu/qemu-doc\.html$
    1.61 +^tools/ioemu/qemu-img\.1$
    1.62 +^tools/ioemu/qemu-img\.pod$
    1.63 +^tools/ioemu/qemu-tech\.html$
    1.64 +^tools/ioemu/qemu\.1$
    1.65 +^tools/ioemu/qemu\.pod$
    1.66  ^tools/libxc/xen/.*$
    1.67 +^tools/libaio/src/.*\.ol$
    1.68 +^tools/libaio/src/.*\.os$
    1.69  ^tools/misc/cpuperf/cpuperf-perfcntr$
    1.70  ^tools/misc/cpuperf/cpuperf-xen$
    1.71  ^tools/misc/lomount/lomount$
    1.72 @@ -203,3 +196,7 @@
    1.73  ^xen/xen$
    1.74  ^xen/xen-syms$
    1.75  ^xen/xen\..*$
    1.76 +^xen/arch/ppc/dom0\.bin$
    1.77 +^xen/arch/ppc/asm-offsets\.s$
    1.78 +^xen/arch/ppc/firmware
    1.79 +^xen/arch/ppc/firmware_image
     2.1 --- a/Config.mk	Tue Jul 25 09:51:50 2006 -0600
     2.2 +++ b/Config.mk	Tue Jul 25 12:19:05 2006 -0600
     2.3 @@ -3,8 +3,8 @@
     2.4  # A debug build of Xen and tools?
     2.5  debug ?= n
     2.6  
     2.7 -# Currently supported architectures: x86_32, x86_64
     2.8 -XEN_COMPILE_ARCH    ?= $(shell uname -m | sed -e s/i.86/x86_32/)
     2.9 +XEN_COMPILE_ARCH    ?= $(shell uname -m | sed -e s/i.86/x86_32/ \
    2.10 +                                              -e s/ppc/powerpc/)
    2.11  XEN_TARGET_ARCH     ?= $(XEN_COMPILE_ARCH)
    2.12  XEN_TARGET_X86_PAE  ?= n
    2.13  
     3.1 --- a/buildconfigs/Rules.mk	Tue Jul 25 09:51:50 2006 -0600
     3.2 +++ b/buildconfigs/Rules.mk	Tue Jul 25 12:19:05 2006 -0600
     3.3 @@ -69,9 +69,6 @@ ref-%/.valid-ref: pristine-%/.valid-pris
     3.4  	touch $@ # update timestamp to avoid rebuild
     3.5  endif
     3.6  
     3.7 -%-prep:
     3.8 -	$(MAKE) -f buildconfigs/mk.$* prep
     3.9 -
    3.10  %-install:
    3.11  	$(MAKE) -f buildconfigs/mk.$* build
    3.12  
    3.13 @@ -83,15 +80,20 @@ endif
    3.14  %-build: %-dist
    3.15  	@: # do nothing
    3.16  
    3.17 +%-prep: DESTDIR=$(DISTDIR)/install
    3.18 +%-prep:
    3.19 +	$(MAKE) -f buildconfigs/mk.$* prep
    3.20 +
    3.21 +%-config: DESTDIR=$(DISTDIR)/install
    3.22 +%-config:
    3.23 +	$(MAKE) -f buildconfigs/mk.$* config
    3.24 +
    3.25  %-delete:
    3.26  	$(MAKE) -f buildconfigs/mk.$* delete
    3.27  
    3.28  %-clean:
    3.29  	$(MAKE) -f buildconfigs/mk.$* clean
    3.30  
    3.31 -%-config:
    3.32 -	$(MAKE) -f buildconfigs/mk.$* config
    3.33 -
    3.34  linux-2.6-xen.patch: ref-linux-$(LINUX_VER)/.valid-ref
    3.35  	rm -rf tmp-$@
    3.36  	cp -al $(<D) tmp-$@
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/buildconfigs/conf.linux-native/00_xen_to_native	Tue Jul 25 12:19:05 2006 -0600
     4.3 @@ -0,0 +1,84 @@
     4.4 +# Linux kernel version: 2.6.16.13-native
     4.5 +# Mon May 15 10:59:54 2006
     4.6 +#
     4.7 +CONFIG_X86_PC=y
     4.8 +# CONFIG_X86_XEN is not set
     4.9 +# CONFIG_HPET_TIMER is not set
    4.10 +# CONFIG_SCHED_SMT is not set
    4.11 +# CONFIG_X86_MCE is not set
    4.12 +# CONFIG_X86_MSR is not set
    4.13 +# CONFIG_SWIOTLB is not set
    4.14 +# CONFIG_EDD is not set
    4.15 +CONFIG_ARCH_FLATMEM_ENABLE=y
    4.16 +CONFIG_ARCH_SPARSEMEM_ENABLE=y
    4.17 +CONFIG_ARCH_SELECT_MEMORY_MODEL=y
    4.18 +CONFIG_SPARSEMEM_STATIC=y
    4.19 +CONFIG_SPLIT_PTLOCK_CPUS=4
    4.20 +# CONFIG_HIGHPTE is not set
    4.21 +# CONFIG_MATH_EMULATION is not set
    4.22 +# CONFIG_EFI is not set
    4.23 +CONFIG_IRQBALANCE=y
    4.24 +# CONFIG_KEXEC is not set
    4.25 +CONFIG_DOUBLEFAULT=y
    4.26 +CONFIG_PM_LEGACY=y
    4.27 +# CONFIG_PM_DEBUG is not set
    4.28 +# CONFIG_SOFTWARE_SUSPEND is not set
    4.29 +CONFIG_SUSPEND_SMP=y
    4.30 +CONFIG_ACPI_SLEEP=y
    4.31 +CONFIG_ACPI_SLEEP_PROC_FS=y
    4.32 +# CONFIG_ACPI_SLEEP_PROC_SLEEP is not set
    4.33 +CONFIG_X86_PM_TIMER=y
    4.34 +# APM (Advanced Power Management) BIOS Support
    4.35 +#
    4.36 +# CONFIG_APM is not set
    4.37 +
    4.38 +#
    4.39 +CONFIG_PCI_BIOS=y
    4.40 +# CONFIG_XEN_PCIDEV_FRONTEND is not set
    4.41 +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
    4.42 +# CONFIG_PCI_MSI is not set
    4.43 +# CONFIG_ISA is not set
    4.44 +# CONFIG_MCA is not set
    4.45 +# CONFIG_HOTPLUG_PCI_COMPAQ is not set
    4.46 +# CONFIG_HOTPLUG_PCI_IBM is not set
    4.47 +# CONFIG_I2O_EXT_ADAPTEC_DMA64 is not set
    4.48 +CONFIG_SERIAL_8250=y
    4.49 +CONFIG_SERIAL_8250_CONSOLE=y
    4.50 +CONFIG_SERIAL_CORE=y
    4.51 +CONFIG_SERIAL_CORE_CONSOLE=y
    4.52 +# CONFIG_TCG_XEN is not set
    4.53 +# CONFIG_HUGETLBFS is not set
    4.54 +# CONFIG_XEN is not set
    4.55 +# CONFIG_XEN_INTERFACE_VERSION is not set
    4.56 +
    4.57 +#
    4.58 +# XEN
    4.59 +#
    4.60 +# CONFIG_XEN_PRIVILEGED_GUEST is not set
    4.61 +# CONFIG_XEN_UNPRIVILEGED_GUEST is not set
    4.62 +# CONFIG_XEN_BACKEND is not set
    4.63 +# CONFIG_XEN_PCIDEV_BACKEND is not set
    4.64 +# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
    4.65 +# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
    4.66 +# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
    4.67 +# CONFIG_XEN_BLKDEV_BACKEND is not set
    4.68 +# CONFIG_XEN_BLKDEV_TAP_BE is not set
    4.69 +# CONFIG_XEN_NETDEV_BACKEND is not set
    4.70 +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
    4.71 +# CONFIG_XEN_NETDEV_LOOPBACK is not set
    4.72 +# CONFIG_XEN_TPMDEV_BACKEND is not set
    4.73 +# CONFIG_XEN_BLKDEV_FRONTEND is not set
    4.74 +# CONFIG_XEN_NETDEV_FRONTEND is not set
    4.75 +# CONFIG_XEN_BLKDEV_TAP is not set
    4.76 +# CONFIG_XEN_SCRUB_PAGES is not set
    4.77 +# CONFIG_XEN_DISABLE_SERIAL is not set
    4.78 +# CONFIG_XEN_SYSFS is not set
    4.79 +# CONFIG_XEN_COMPAT_030002_AND_LATER is not set
    4.80 +# CONFIG_XEN_COMPAT_LATEST_ONLY is not set
    4.81 +# CONFIG_XEN_COMPAT_030002 is not set
    4.82 +# CONFIG_HAVE_ARCH_ALLOC_SKB is not set
    4.83 +# CONFIG_HAVE_ARCH_DEV_ALLOC_SKB is not set
    4.84 +# CONFIG_NO_IDLE_HZ is not set
    4.85 +CONFIG_X86_HT=y
    4.86 +# CONFIG_X86_NO_TSS is not set
    4.87 +# CONFIG_X86_NO_IDT is not set
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/buildconfigs/create_config.sh	Tue Jul 25 12:19:05 2006 -0600
     5.3 @@ -0,0 +1,50 @@
     5.4 +#!/bin/sh
     5.5 +set -e
     5.6 +
     5.7 +
     5.8 +# Parse arguments
     5.9 +#
    5.10 +if [ $# -lt 1 -o $# -gt 4 ]; then
    5.11 +    echo "Usage: $0 config-file EXTRAVERSION XEN_TARGET_ARCH XEN_SYSTYPE"
    5.12 +    exit 1
    5.13 +fi
    5.14 +
    5.15 +config_file=$1
    5.16 +extraversion=$2
    5.17 +target_arch=$3
    5.18 +systype=$4
    5.19 +
    5.20 +
    5.21 +# Start with initial config skeleton file, if any.
    5.22 +# Derive from linux-defconfig_xen_x86_32 otherwise.
    5.23 +#
    5.24 +skeleton=buildconfigs/linux-defconfig_${extraversion}_${target_arch}${systype}
    5.25 +[ -r $skeleton ] || skeleton=buildconfigs/linux-defconfig_xen_x86_32
    5.26 +cp $skeleton $config_file
    5.27 +
    5.28 +
    5.29 +# Update
    5.30 +#
    5.31 +filter_template="s/^#\{0,1\} *\(CONFIG[^= ]*\).*/\/^#\\\{0,1\\\} *\1[= ].*\/d/p"
    5.32 +config_dirs="buildconfigs/conf.linux buildconfigs/conf.linux-${target_arch} buildconfigs/conf.linux-${extraversion} buildconfigs/conf.linux-${target_arch}-${extraversion}"
    5.33 +
    5.34 +for config_dir in $config_dirs
    5.35 +do
    5.36 +    if [ -d $config_dir ]; then
    5.37 +        # processing is done in alphanumeric order
    5.38 +        find $config_dir -type f | sort | while read update
    5.39 +        do
    5.40 +            # create the filter rules in a temp file
    5.41 +            filter_rules=`mktemp -t xenupdateconf.XXXXXXXXXX`
    5.42 +            sed -n "${filter_template}" < $update > $filter_rules
    5.43 +
    5.44 +            # filter the config file in place, removing any options that
    5.45 +            # will be updated.
    5.46 +            sed -f $filter_rules -i $config_file
    5.47 +            cat $update >> $config_file
    5.48 +
    5.49 +            # clean up
    5.50 +            rm -f $filter_rules
    5.51 +        done
    5.52 +    fi
    5.53 +done
     6.1 --- a/buildconfigs/linux-defconfig_xen0_ia64	Tue Jul 25 09:51:50 2006 -0600
     6.2 +++ b/buildconfigs/linux-defconfig_xen0_ia64	Tue Jul 25 12:19:05 2006 -0600
     6.3 @@ -1527,6 +1527,7 @@ CONFIG_XEN_BACKEND=y
     6.4  # CONFIG_XEN_PCIDEV_BACKEND is not set
     6.5  CONFIG_XEN_BLKDEV_BACKEND=y
     6.6  CONFIG_XEN_XENBUS_DEV=y
     6.7 +# CONFIG_XEN_BLKDEV_TAP is not set
     6.8  # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
     6.9  CONFIG_XEN_NETDEV_LOOPBACK=y
    6.10  # CONFIG_XEN_TPMDEV_BACKEND is not set
     7.1 --- a/buildconfigs/linux-defconfig_xen0_x86_32	Tue Jul 25 09:51:50 2006 -0600
     7.2 +++ b/buildconfigs/linux-defconfig_xen0_x86_32	Tue Jul 25 12:19:05 2006 -0600
     7.3 @@ -1322,6 +1322,7 @@ CONFIG_XEN_PCIDEV_BACKEND=y
     7.4  CONFIG_XEN_PCIDEV_BACKEND_PASS=y
     7.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     7.6  CONFIG_XEN_BLKDEV_BACKEND=y
     7.7 +CONFIG_XEN_BLKDEV_TAP=y
     7.8  CONFIG_XEN_NETDEV_BACKEND=y
     7.9  # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
    7.10  CONFIG_XEN_NETDEV_LOOPBACK=y
     8.1 --- a/buildconfigs/linux-defconfig_xen0_x86_64	Tue Jul 25 09:51:50 2006 -0600
     8.2 +++ b/buildconfigs/linux-defconfig_xen0_x86_64	Tue Jul 25 12:19:05 2006 -0600
     8.3 @@ -1263,6 +1263,7 @@ CONFIG_XEN_PCIDEV_BACKEND=y
     8.4  CONFIG_XEN_PCIDEV_BACKEND_PASS=y
     8.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
     8.6  CONFIG_XEN_BLKDEV_BACKEND=y
     8.7 +CONFIG_XEN_BLKDEV_TAP=y
     8.8  CONFIG_XEN_NETDEV_BACKEND=y
     8.9  # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
    8.10  CONFIG_XEN_NETDEV_LOOPBACK=y
     9.1 --- a/buildconfigs/linux-defconfig_xen_ia64	Tue Jul 25 09:51:50 2006 -0600
     9.2 +++ b/buildconfigs/linux-defconfig_xen_ia64	Tue Jul 25 12:19:05 2006 -0600
     9.3 @@ -1533,6 +1533,7 @@ CONFIG_XEN_BACKEND=y
     9.4  # CONFIG_XEN_PCIDEV_BACKEND is not set
     9.5  CONFIG_XEN_BLKDEV_BACKEND=y
     9.6  CONFIG_XEN_XENBUS_DEV=y
     9.7 +# CONFIG_XEN_BLKDEV_TAP is not set
     9.8  # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
     9.9  CONFIG_XEN_NETDEV_LOOPBACK=y
    9.10  # CONFIG_XEN_TPMDEV_BACKEND is not set
    10.1 --- a/buildconfigs/linux-defconfig_xen_x86_32	Tue Jul 25 09:51:50 2006 -0600
    10.2 +++ b/buildconfigs/linux-defconfig_xen_x86_32	Tue Jul 25 12:19:05 2006 -0600
    10.3 @@ -3023,6 +3023,7 @@ CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
    10.4  # CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
    10.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
    10.6  CONFIG_XEN_BLKDEV_BACKEND=y
    10.7 +CONFIG_XEN_BLKDEV_TAP=y
    10.8  CONFIG_XEN_NETDEV_BACKEND=y
    10.9  # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
   10.10  CONFIG_XEN_NETDEV_LOOPBACK=y
    11.1 --- a/buildconfigs/linux-defconfig_xen_x86_64	Tue Jul 25 09:51:50 2006 -0600
    11.2 +++ b/buildconfigs/linux-defconfig_xen_x86_64	Tue Jul 25 12:19:05 2006 -0600
    11.3 @@ -2855,6 +2855,7 @@ CONFIG_XEN_PCIDEV_BACKEND=m
    11.4  CONFIG_XEN_PCIDEV_BACKEND_PASS=y
    11.5  # CONFIG_XEN_PCIDEV_BE_DEBUG is not set
    11.6  CONFIG_XEN_BLKDEV_BACKEND=y
    11.7 +CONFIG_XEN_BLKDEV_TAP=y
    11.8  CONFIG_XEN_NETDEV_BACKEND=y
    11.9  # CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
   11.10  CONFIG_XEN_NETDEV_LOOPBACK=y
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/buildconfigs/mk.linux-2.6-native	Tue Jul 25 12:19:05 2006 -0600
    12.3 @@ -0,0 +1,4 @@
    12.4 +EXTRAVERSION = native
    12.5 +IMAGE_TARGET = bzImage
    12.6 +INSTALL_BOOT_PATH = $(DESTDIR)/boot
    12.7 +include buildconfigs/mk.linux-2.6-xen
    13.1 --- a/buildconfigs/mk.linux-2.6-xen	Tue Jul 25 09:51:50 2006 -0600
    13.2 +++ b/buildconfigs/mk.linux-2.6-xen	Tue Jul 25 12:19:05 2006 -0600
    13.3 @@ -5,6 +5,11 @@ EXTRAVERSION ?= xen
    13.4  
    13.5  LINUX_DIR    = linux-$(LINUX_VER)-$(EXTRAVERSION)
    13.6  
    13.7 +IMAGE_TARGET ?= vmlinuz
    13.8 +INSTALL_BOOT_PATH ?= $(DESTDIR)
    13.9 +
   13.10 +LINUX_VER3  := $(LINUX_SERIES).$(word 3, $(subst ., ,$(LINUX_VER)))
   13.11 +
   13.12  include buildconfigs/Rules.mk
   13.13  
   13.14  # The real action starts here!
   13.15 @@ -14,8 +19,9 @@ build: $(LINUX_DIR)/include/linux/autoco
   13.16  	    $(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) modules ; \
   13.17  	    $(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) INSTALL_MOD_PATH=$(DESTDIR) modules_install ; \
   13.18  	fi
   13.19 -	$(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) INSTALL_PATH=$(DESTDIR) vmlinuz
   13.20 -	$(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) INSTALL_PATH=$(DESTDIR) install
   13.21 +	$(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) INSTALL_PATH=$(DESTDIR) $(IMAGE_TARGET)
   13.22 +	mkdir -p $(INSTALL_BOOT_PATH)
   13.23 +	$(MAKE) -C $(LINUX_DIR) ARCH=$(LINUX_ARCH) INSTALL_PATH=$(INSTALL_BOOT_PATH) install
   13.24  
   13.25  $(LINUX_DIR)/include/linux/autoconf.h: ref-linux-$(LINUX_VER)/.valid-ref
   13.26  	rm -rf $(LINUX_DIR)
   13.27 @@ -25,10 +31,9 @@ build: $(LINUX_DIR)/include/linux/autoco
   13.28            LINUX_ARCH=$(LINUX_ARCH) bash ./mkbuildtree ../$(LINUX_DIR) )
   13.29  	# Re-use config from install dir if one exits else use default config
   13.30  	CONFIG_VERSION=$$(sed -ne 's/^EXTRAVERSION = //p' $(LINUX_DIR)/Makefile); \
   13.31 -	[ -r $(DESTDIR)/boot/config-$(LINUX_VER)$$CONFIG_VERSION-$(EXTRAVERSION) ] && \
   13.32 -	  cp $(DESTDIR)/boot/config-$(LINUX_VER)$$CONFIG_VERSION-$(EXTRAVERSION) $(LINUX_DIR)/.config \
   13.33 -	  || cp buildconfigs/linux-defconfig_$(EXTRAVERSION)_$(XEN_TARGET_ARCH)$(XEN_SYSTYPE) \
   13.34 -		$(LINUX_DIR)/.config
   13.35 +	[ -r $(DESTDIR)/boot/config-$(LINUX_VER3)$$CONFIG_VERSION-$(EXTRAVERSION) ] && \
   13.36 +	  cp $(DESTDIR)/boot/config-$(LINUX_VER3)$$CONFIG_VERSION-$(EXTRAVERSION) $(LINUX_DIR)/.config \
   13.37 +	  || sh buildconfigs/create_config.sh $(LINUX_DIR)/.config $(EXTRAVERSION) $(XEN_TARGET_ARCH) $(XEN_SYSTYPE)
   13.38  	# See if we need to munge config to enable PAE
   13.39  	$(MAKE) CONFIG_FILE=$(LINUX_DIR)/.config -f buildconfigs/Rules.mk config-update-pae
   13.40  	# Patch kernel Makefile to set EXTRAVERSION
    14.1 --- a/config/ia64.mk	Tue Jul 25 09:51:50 2006 -0600
    14.2 +++ b/config/ia64.mk	Tue Jul 25 12:19:05 2006 -0600
    14.3 @@ -1,4 +1,5 @@
    14.4  CONFIG_IA64 := y
    14.5  CONFIG_IOEMU := y
    14.6 +CONFIG_XCUTILS := y
    14.7  
    14.8  LIBDIR := lib
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/config/powerpc64.mk	Tue Jul 25 12:19:05 2006 -0600
    15.3 @@ -0,0 +1,4 @@
    15.4 +CONFIG_POWERPC := y
    15.5 +
    15.6 +CFLAGS += -DELFSIZE=64
    15.7 +LIBDIR := lib
    16.1 --- a/config/x86_32.mk	Tue Jul 25 09:51:50 2006 -0600
    16.2 +++ b/config/x86_32.mk	Tue Jul 25 12:19:05 2006 -0600
    16.3 @@ -1,7 +1,7 @@
    16.4  CONFIG_X86 := y
    16.5 -CONFIG_PLAN9 := y
    16.6  CONFIG_HVM := y
    16.7  CONFIG_MIGRATE := y
    16.8 +CONFIG_XCUTILS := y
    16.9  CONFIG_IOEMU := y
   16.10  CONFIG_MBOOTPACK := y
   16.11  
    17.1 --- a/config/x86_64.mk	Tue Jul 25 09:51:50 2006 -0600
    17.2 +++ b/config/x86_64.mk	Tue Jul 25 12:19:05 2006 -0600
    17.3 @@ -1,7 +1,7 @@
    17.4  CONFIG_X86 := y
    17.5 -CONFIG_PLAN9 := y
    17.6  CONFIG_HVM := y
    17.7  CONFIG_MIGRATE := y
    17.8 +CONFIG_XCUTILS := y
    17.9  CONFIG_IOEMU := y
   17.10  CONFIG_MBOOTPACK := y
   17.11  
    18.1 --- a/extras/mini-os/mm.c	Tue Jul 25 09:51:50 2006 -0600
    18.2 +++ b/extras/mini-os/mm.c	Tue Jul 25 12:19:05 2006 -0600
    18.3 @@ -687,7 +687,7 @@ void *map_frames(unsigned long *f, unsig
    18.4      /* Find a run of n contiguous frames */
    18.5      for (x = 0; x <= 1024 - n; x += y + 1) {
    18.6          for (y = 0; y < n; y++)
    18.7 -            if (demand_map_pgt[y] & _PAGE_PRESENT)
    18.8 +            if (demand_map_pgt[x+y] & _PAGE_PRESENT)
    18.9                  break;
   18.10          if (y == n)
   18.11              break;
    19.1 --- a/linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c	Tue Jul 25 09:51:50 2006 -0600
    19.2 +++ b/linux-2.6-xen-sparse/arch/i386/oprofile/xenoprof.c	Tue Jul 25 12:19:05 2006 -0600
    19.3 @@ -29,6 +29,7 @@
    19.4  #include <xen/interface/xen.h>
    19.5  #include <xen/interface/xenoprof.h>
    19.6  #include <../../../drivers/oprofile/cpu_buffer.h>
    19.7 +#include <../../../drivers/oprofile/event_buffer.h>
    19.8  
    19.9  static int xenoprof_start(void);
   19.10  static void xenoprof_stop(void);
   19.11 @@ -151,16 +152,27 @@ static void xenoprof_add_pc(xenoprof_buf
   19.12  static void xenoprof_handle_passive(void)
   19.13  {
   19.14  	int i, j;
   19.15 -
   19.16 -	for (i = 0; i < pdomains; i++)
   19.17 +	int flag_domain, flag_switch = 0;
   19.18 +	
   19.19 +	for (i = 0; i < pdomains; i++) {
   19.20 +		flag_domain = 0;
   19.21  		for (j = 0; j < passive_domains[i].nbuf; j++) {
   19.22  			xenoprof_buf_t *buf = p_xenoprof_buf[i][j];
   19.23  			if (buf->event_head == buf->event_tail)
   19.24  				continue;
   19.25 -                        oprofile_add_pc(IGNORED_PC, CPU_MODE_PASSIVE_START, passive_domains[i].domain_id);
   19.26 +			if (!flag_domain) {
   19.27 +				if (!oprofile_add_domain_switch(passive_domains[i].
   19.28 +								domain_id))
   19.29 +					goto done;
   19.30 +				flag_domain = 1;
   19.31 +			}
   19.32  			xenoprof_add_pc(buf, 1);
   19.33 -                        oprofile_add_pc(IGNORED_PC, CPU_MODE_PASSIVE_STOP, passive_domains[i].domain_id);
   19.34 -		}			
   19.35 +			flag_switch = 1;
   19.36 +		}
   19.37 +	}
   19.38 +done:
   19.39 +	if (flag_switch)
   19.40 +		oprofile_add_domain_switch(COORDINATOR_DOMAIN);
   19.41  }
   19.42  
   19.43  static irqreturn_t 
   19.44 @@ -177,6 +189,7 @@ xenoprof_ovf_interrupt(int irq, void * d
   19.45  
   19.46  	if (is_primary && !test_and_set_bit(0, &flag)) {
   19.47  		xenoprof_handle_passive();
   19.48 +		smp_mb__before_clear_bit();
   19.49  		clear_bit(0, &flag);
   19.50  	}
   19.51  
    20.1 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Jul 25 09:51:50 2006 -0600
    20.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Tue Jul 25 12:19:05 2006 -0600
    20.3 @@ -33,6 +33,11 @@ config XEN_PRIVCMD
    20.4  	depends on PROC_FS
    20.5  	default y
    20.6  
    20.7 +config XEN_XENBUS_DEV
    20.8 +	bool
    20.9 +	depends on PROC_FS
   20.10 +	default y
   20.11 +
   20.12  config XEN_BACKEND
   20.13          tristate "Backend driver support"
   20.14          default y
   20.15 @@ -40,8 +45,59 @@ config XEN_BACKEND
   20.16            Support for backend device drivers that provide I/O services
   20.17            to other virtual machines.
   20.18  
   20.19 +config XEN_BLKDEV_BACKEND
   20.20 +	tristate "Block-device backend driver"
   20.21 +        depends on XEN_BACKEND
   20.22 +	default y
   20.23 +	help
   20.24 +	  The block-device backend driver allows the kernel to export its
   20.25 +	  block devices to other guests via a high-performance shared-memory
   20.26 +	  interface.
   20.27 +
   20.28 +config XEN_BLKDEV_TAP
   20.29 +	tristate "Block-device tap backend driver"
   20.30 +	depends on XEN_BACKEND
   20.31 +	default XEN_PRIVILEGED_GUEST
   20.32 +	help
   20.33 +	  The block tap driver is an alternative to the block back driver 
   20.34 +          and allows VM block requests to be redirected to userspace through
   20.35 +          a device interface.  The tap allows user-space development of 
   20.36 +          high-performance block backends, where disk images may be implemented
   20.37 +          as files, in memory, or on other hosts across the network.  This 
   20.38 +	  driver can safely coexist with the existing blockback driver.
   20.39 +
   20.40 +config XEN_NETDEV_BACKEND
   20.41 +	tristate "Network-device backend driver"
   20.42 +        depends on XEN_BACKEND && NET
   20.43 +	default y
   20.44 +	help
   20.45 +	  The network-device backend driver allows the kernel to export its
   20.46 +	  network devices to other guests via a high-performance shared-memory
   20.47 +	  interface.
   20.48 +
   20.49 +config XEN_NETDEV_PIPELINED_TRANSMITTER
   20.50 +	bool "Pipelined transmitter (DANGEROUS)"
   20.51 +	depends on XEN_NETDEV_BACKEND
   20.52 +	default n
   20.53 +	help
   20.54 +	  If the net backend is a dumb domain, such as a transparent Ethernet
   20.55 +	  bridge with no local IP interface, it is safe to say Y here to get
   20.56 +	  slightly lower network overhead.
   20.57 +	  If the backend has a local IP interface; or may be doing smart things
   20.58 +	  like reassembling packets to perform firewall filtering; or if you
   20.59 +	  are unsure; or if you experience network hangs when this option is
   20.60 +	  enabled; then you must say N here.
   20.61 +
   20.62 +config XEN_NETDEV_LOOPBACK
   20.63 +	tristate "Network-device loopback driver"
   20.64 +	depends on XEN_NETDEV_BACKEND
   20.65 +	default y
   20.66 +	help
   20.67 +	  A two-interface loopback device to emulate a local netfront-netback
   20.68 +	  connection.
   20.69 +
   20.70  config XEN_PCIDEV_BACKEND
   20.71 -	tristate "PCI device backend driver"
   20.72 +	tristate "PCI-device backend driver"
   20.73  	depends on PCI && XEN_BACKEND
   20.74  	default XEN_PRIVILEGED_GUEST
   20.75  	help
   20.76 @@ -80,50 +136,6 @@ config XEN_PCIDEV_BE_DEBUG
   20.77  	depends on XEN_PCIDEV_BACKEND
   20.78  	default n
   20.79  
   20.80 -config XEN_BLKDEV_BACKEND
   20.81 -	tristate "Block-device backend driver"
   20.82 -        depends on XEN_BACKEND
   20.83 -	default y
   20.84 -	help
   20.85 -	  The block-device backend driver allows the kernel to export its
   20.86 -	  block devices to other guests via a high-performance shared-memory
   20.87 -	  interface.
   20.88 -
   20.89 -config XEN_XENBUS_DEV
   20.90 -	bool
   20.91 -	depends on PROC_FS
   20.92 -	default y
   20.93 -
   20.94 -config XEN_NETDEV_BACKEND
   20.95 -	tristate "Network-device backend driver"
   20.96 -        depends on XEN_BACKEND && NET
   20.97 -	default y
   20.98 -	help
   20.99 -	  The network-device backend driver allows the kernel to export its
  20.100 -	  network devices to other guests via a high-performance shared-memory
  20.101 -	  interface.
  20.102 -
  20.103 -config XEN_NETDEV_PIPELINED_TRANSMITTER
  20.104 -	bool "Pipelined transmitter (DANGEROUS)"
  20.105 -	depends on XEN_NETDEV_BACKEND
  20.106 -	default n
  20.107 -	help
  20.108 -	  If the net backend is a dumb domain, such as a transparent Ethernet
  20.109 -	  bridge with no local IP interface, it is safe to say Y here to get
  20.110 -	  slightly lower network overhead.
  20.111 -	  If the backend has a local IP interface; or may be doing smart things
  20.112 -	  like reassembling packets to perform firewall filtering; or if you
  20.113 -	  are unsure; or if you experience network hangs when this option is
  20.114 -	  enabled; then you must say N here.
  20.115 -
  20.116 -config XEN_NETDEV_LOOPBACK
  20.117 -	tristate "Network-device loopback driver"
  20.118 -	depends on XEN_NETDEV_BACKEND
  20.119 -	default y
  20.120 -	help
  20.121 -	  A two-interface loopback device to emulate a local netfront-netback
  20.122 -	  connection.
  20.123 -
  20.124  config XEN_TPMDEV_BACKEND
  20.125  	tristate "TPM-device backend driver"
  20.126          depends on XEN_BACKEND
  20.127 @@ -183,7 +195,7 @@ config XEN_SYSFS
  20.128  	depends on SYSFS
  20.129  	default y
  20.130  	help
  20.131 -		Xen hypervisor attributes will show up under /sys/hypervisor/.
  20.132 +	  Xen hypervisor attributes will show up under /sys/hypervisor/.
  20.133  
  20.134  choice
  20.135  	prompt "Xen version compatibility"
    21.1 --- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Jul 25 09:51:50 2006 -0600
    21.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Tue Jul 25 12:19:05 2006 -0600
    21.3 @@ -8,6 +8,7 @@ obj-$(CONFIG_XEN_UTIL)			+= util.o
    21.4  obj-$(CONFIG_XEN_BALLOON)		+= balloon/
    21.5  obj-$(CONFIG_XEN_DEVMEM)		+= char/
    21.6  obj-$(CONFIG_XEN_BLKDEV_BACKEND)	+= blkback/
    21.7 +obj-$(CONFIG_XEN_BLKDEV_TAP)		+= blktap/
    21.8  obj-$(CONFIG_XEN_NETDEV_BACKEND)	+= netback/
    21.9  obj-$(CONFIG_XEN_TPMDEV_BACKEND)	+= tpmback/
   21.10  obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= blkfront/
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/Makefile	Tue Jul 25 12:19:05 2006 -0600
    22.3 @@ -0,0 +1,3 @@
    22.4 +LINUXINCLUDE += -I../xen/include/public/io
    22.5 +obj-y	:= xenbus.o interface.o blktap.o 
    22.6 +
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/blktap.c	Tue Jul 25 12:19:05 2006 -0600
    23.3 @@ -0,0 +1,1439 @@
    23.4 +/******************************************************************************
    23.5 + * drivers/xen/blktap/blktap.c
    23.6 + * 
    23.7 + * Back-end driver for user level virtual block devices. This portion of the
    23.8 + * driver exports a 'unified' block-device interface that can be accessed
    23.9 + * by any operating system that implements a compatible front end. Requests
   23.10 + * are remapped to a user-space memory region.
   23.11 + *
   23.12 + * Based on the blkback driver code.
   23.13 + * 
   23.14 + * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
   23.15 + *
   23.16 + * This program is free software; you can redistribute it and/or
   23.17 + * modify it under the terms of the GNU General Public License version 2
   23.18 + * as published by the Free Software Foundation; or, when distributed
   23.19 + * separately from the Linux kernel or incorporated into other
   23.20 + * software packages, subject to the following license:
   23.21 + * 
   23.22 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   23.23 + * of this source file (the "Software"), to deal in the Software without
   23.24 + * restriction, including without limitation the rights to use, copy, modify,
   23.25 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   23.26 + * and to permit persons to whom the Software is furnished to do so, subject to
   23.27 + * the following conditions:
   23.28 + * 
   23.29 + * The above copyright notice and this permission notice shall be included in
   23.30 + * all copies or substantial portions of the Software.
   23.31 + * 
   23.32 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   23.33 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   23.34 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   23.35 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   23.36 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   23.37 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   23.38 + * IN THE SOFTWARE.
   23.39 + */
   23.40 +
   23.41 +#include <linux/spinlock.h>
   23.42 +#include <linux/kthread.h>
   23.43 +#include <linux/list.h>
   23.44 +#include <asm/hypervisor.h>
   23.45 +#include "common.h"
   23.46 +#include <xen/balloon.h>
   23.47 +#include <linux/kernel.h>
   23.48 +#include <linux/fs.h>
   23.49 +#include <linux/mm.h>
   23.50 +#include <linux/miscdevice.h>
   23.51 +#include <linux/errno.h>
   23.52 +#include <linux/major.h>
   23.53 +#include <linux/gfp.h>
   23.54 +#include <linux/poll.h>
   23.55 +#include <asm/tlbflush.h>
   23.56 +#include <linux/devfs_fs_kernel.h>
   23.57 +
   23.58 +#define MAX_TAP_DEV 100     /*the maximum number of tapdisk ring devices    */
   23.59 +#define MAX_DEV_NAME 100    /*the max tapdisk ring device name e.g. blktap0 */
   23.60 +
   23.61 +/*
   23.62 + * The maximum number of requests that can be outstanding at any time
   23.63 + * is determined by 
   23.64 + *
   23.65 + *   [mmap_alloc * MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST] 
   23.66 + *
   23.67 + * where mmap_alloc < MAX_DYNAMIC_MEM.
   23.68 + *
   23.69 + * TODO:
   23.70 + * mmap_alloc is initialised to 2 and should be adjustable on the fly via
   23.71 + * sysfs.
   23.72 + */
   23.73 +#define MAX_DYNAMIC_MEM 64
   23.74 +#define MAX_PENDING_REQS 64   
   23.75 +#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
   23.76 +#define MMAP_VADDR(_start, _req,_seg)                                   \
   23.77 +        (_start +                                                       \
   23.78 +         ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) +        \
   23.79 +         ((_seg) * PAGE_SIZE))
   23.80 +static int blkif_reqs = MAX_PENDING_REQS;
   23.81 +static int mmap_pages = MMAP_PAGES;
   23.82 +
   23.83 +#define RING_PAGES 1 /* BLKTAP - immediately before the mmap area, we
   23.84 +		      * have a bunch of pages reserved for shared
   23.85 +		      * memory rings.
   23.86 +		      */
   23.87 +
   23.88 +/*Data struct associated with each of the tapdisk devices*/
   23.89 +typedef struct tap_blkif {
   23.90 +	struct vm_area_struct *vma;   /*Shared memory area                   */
   23.91 +	unsigned long rings_vstart;   /*Kernel memory mapping                */
   23.92 +	unsigned long user_vstart;    /*User memory mapping                  */
   23.93 +	unsigned long dev_inuse;      /*One process opens device at a time.  */
   23.94 +	unsigned long dev_pending;    /*In process of being opened           */
   23.95 +	unsigned long ring_ok;        /*make this ring->state                */
   23.96 +	blkif_front_ring_t ufe_ring;  /*Rings up to user space.              */
   23.97 +	wait_queue_head_t wait;       /*for poll                             */
   23.98 +	unsigned long mode;           /*current switching mode               */
   23.99 +	int minor;                    /*Minor number for tapdisk device      */
  23.100 +	pid_t pid;                    /*tapdisk process id                   */
  23.101 +	enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace 
  23.102 +						  shutdown                   */
  23.103 +	unsigned long *idx_map;       /*Record the user ring id to kern 
  23.104 +					[req id, idx] tuple                  */
  23.105 +	blkif_t *blkif;               /*Associate blkif with tapdev          */
  23.106 +} tap_blkif_t;
  23.107 +
  23.108 +/*Private data struct associated with the inode*/
  23.109 +typedef struct private_info {
  23.110 +	int idx;
  23.111 +} private_info_t;
  23.112 +
  23.113 +/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
  23.114 +typedef struct domid_translate {
  23.115 +	unsigned short domid;
  23.116 +	unsigned short busid;
  23.117 +} domid_translate_t ;
  23.118 +
  23.119 +
  23.120 +domid_translate_t  translate_domid[MAX_TAP_DEV];
  23.121 +tap_blkif_t *tapfds[MAX_TAP_DEV];
  23.122 +
  23.123 +static int __init set_blkif_reqs(char *str)
  23.124 +{
  23.125 +	get_option(&str, &blkif_reqs);
  23.126 +	return 1;
  23.127 +}
  23.128 +__setup("blkif_reqs=", set_blkif_reqs);
  23.129 +
  23.130 +/* Run-time switchable: /sys/module/blktap/parameters/ */
  23.131 +static unsigned int log_stats = 0;
  23.132 +static unsigned int debug_lvl = 0;
  23.133 +module_param(log_stats, int, 0644);
  23.134 +module_param(debug_lvl, int, 0644);
  23.135 +
  23.136 +/*
  23.137 + * Each outstanding request that we've passed to the lower device layers has a 
  23.138 + * 'pending_req' allocated to it. Each buffer_head that completes decrements 
  23.139 + * the pendcnt towards zero. When it hits zero, the specified domain has a 
  23.140 + * response queued for it, with the saved 'id' passed back.
  23.141 + */
  23.142 +typedef struct {
  23.143 +	blkif_t       *blkif;
  23.144 +	unsigned long  id;
  23.145 +	unsigned short mem_idx;
  23.146 +	int            nr_pages;
  23.147 +	atomic_t       pendcnt;
  23.148 +	unsigned short operation;
  23.149 +	int            status;
  23.150 +	struct list_head free_list;
  23.151 +	int            inuse;
  23.152 +} pending_req_t;
  23.153 +
  23.154 +static pending_req_t *pending_reqs[MAX_PENDING_REQS];
  23.155 +static struct list_head pending_free;
  23.156 +static DEFINE_SPINLOCK(pending_free_lock);
  23.157 +static DECLARE_WAIT_QUEUE_HEAD (pending_free_wq);
  23.158 +static int alloc_pending_reqs;
  23.159 +
  23.160 +typedef unsigned int PEND_RING_IDX;
  23.161 +
  23.162 +static inline int MASK_PEND_IDX(int i) { 
  23.163 +	return (i & (MAX_PENDING_REQS-1)); 
  23.164 +}
  23.165 +
  23.166 +static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) {
  23.167 +	return (req - pending_reqs[idx]);
  23.168 +}
  23.169 +
  23.170 +#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
  23.171 +
  23.172 +#define BLKBACK_INVALID_HANDLE (~0)
  23.173 +
  23.174 +typedef struct mmap_page {
  23.175 +	unsigned long start;
  23.176 +	struct page *mpage;
  23.177 +} mmap_page_t;
  23.178 +
  23.179 +static mmap_page_t mmap_start[MAX_DYNAMIC_MEM];
  23.180 +static unsigned short mmap_alloc = 0;
  23.181 +static unsigned short mmap_lock = 0;
  23.182 +static unsigned short mmap_inuse = 0;
  23.183 +static unsigned long *pending_addrs[MAX_DYNAMIC_MEM];
  23.184 +
  23.185 +/******************************************************************
  23.186 + * GRANT HANDLES
  23.187 + */
  23.188 +
  23.189 +/* When using grant tables to map a frame for device access then the
  23.190 + * handle returned must be used to unmap the frame. This is needed to
  23.191 + * drop the ref count on the frame.
  23.192 + */
  23.193 +struct grant_handle_pair
  23.194 +{
  23.195 +        grant_handle_t kernel;
  23.196 +        grant_handle_t user;
  23.197 +};
  23.198 +
  23.199 +static struct grant_handle_pair 
  23.200 +    pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES];
  23.201 +#define pending_handle(_id, _idx, _i) \
  23.202 +    (pending_grant_handles[_id][((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) \
  23.203 +    + (_i)])
  23.204 +
  23.205 +
  23.206 +static int blktap_read_ufe_ring(int idx); /*local prototypes*/
  23.207 +
  23.208 +#define BLKTAP_MINOR 0  /*/dev/xen/blktap resides at device number
  23.209 +			  major=254, minor numbers begin at 0            */ 
  23.210 +#define BLKTAP_DEV_MAJOR 254         /* TODO: Make major number dynamic  *
  23.211 +                                      * and create devices in the kernel *
  23.212 +				      */
  23.213 +#define BLKTAP_DEV_DIR  "/dev/xen"
  23.214 +
  23.215 +/* blktap IOCTLs: */
  23.216 +#define BLKTAP_IOCTL_KICK_FE         1
  23.217 +#define BLKTAP_IOCTL_KICK_BE         2 /* currently unused */
  23.218 +#define BLKTAP_IOCTL_SETMODE         3
  23.219 +#define BLKTAP_IOCTL_SENDPID	     4
  23.220 +#define BLKTAP_IOCTL_NEWINTF	     5
  23.221 +#define BLKTAP_IOCTL_MINOR	     6
  23.222 +#define BLKTAP_IOCTL_MAJOR	     7
  23.223 +#define BLKTAP_QUERY_ALLOC_REQS      8
  23.224 +#define BLKTAP_IOCTL_FREEINTF        9
  23.225 +#define BLKTAP_IOCTL_PRINT_IDXS      100  
  23.226 +
  23.227 +/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE)             */
  23.228 +#define BLKTAP_MODE_PASSTHROUGH      0x00000000  /* default            */
  23.229 +#define BLKTAP_MODE_INTERCEPT_FE     0x00000001
  23.230 +#define BLKTAP_MODE_INTERCEPT_BE     0x00000002  /* unimp.             */
  23.231 +
  23.232 +#define BLKTAP_MODE_INTERPOSE \
  23.233 +           (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
  23.234 +
  23.235 +
  23.236 +static inline int BLKTAP_MODE_VALID(unsigned long arg)
  23.237 +{
  23.238 +	return ((arg == BLKTAP_MODE_PASSTHROUGH ) ||
  23.239 +		(arg == BLKTAP_MODE_INTERCEPT_FE) ||
  23.240 +                (arg == BLKTAP_MODE_INTERPOSE   ));
  23.241 +}
  23.242 +
  23.243 +/* Requests passing through the tap to userspace are re-assigned an ID.
  23.244 + * We must record a mapping between the BE [IDX,ID] tuple and the userspace
  23.245 + * ring ID. 
  23.246 + */
  23.247 +
  23.248 +static inline unsigned long MAKE_ID(domid_t fe_dom, PEND_RING_IDX idx)
  23.249 +{
  23.250 +        return ((fe_dom << 16) | MASK_PEND_IDX(idx));
  23.251 +}
  23.252 +
  23.253 +extern inline PEND_RING_IDX ID_TO_IDX(unsigned long id)
  23.254 +{
  23.255 +        return (PEND_RING_IDX)(id & 0x0000ffff);
  23.256 +}
  23.257 +
  23.258 +extern inline int ID_TO_MIDX(unsigned long id)
  23.259 +{
  23.260 +        return (int)(id >> 16);
  23.261 +}
  23.262 +
  23.263 +#define INVALID_REQ 0xdead0000
  23.264 +
  23.265 +/*TODO: Convert to a free list*/
  23.266 +static inline int GET_NEXT_REQ(unsigned long *idx_map)
  23.267 +{
  23.268 +	int i;
  23.269 +	for (i = 0; i < MAX_PENDING_REQS; i++)
  23.270 +		if (idx_map[i] == INVALID_REQ) return i;
  23.271 +
  23.272 +	return INVALID_REQ;
  23.273 +}
  23.274 +
  23.275 +
  23.276 +#define BLKTAP_INVALID_HANDLE(_g) \
  23.277 +    (((_g->kernel) == 0xFFFF) && ((_g->user) == 0xFFFF))
  23.278 +
  23.279 +#define BLKTAP_INVALIDATE_HANDLE(_g) do {       \
  23.280 +    (_g)->kernel = 0xFFFF; (_g)->user = 0xFFFF; \
  23.281 +    } while(0)
  23.282 +
  23.283 +
  23.284 +/******************************************************************
  23.285 + * BLKTAP VM OPS
  23.286 + */
  23.287 +
  23.288 +static struct page *blktap_nopage(struct vm_area_struct *vma,
  23.289 +				  unsigned long address,
  23.290 +				  int *type)
  23.291 +{
  23.292 +	/*
  23.293 +	 * if the page has not been mapped in by the driver then return
  23.294 +	 * NOPAGE_SIGBUS to the domain.
  23.295 +	 */
  23.296 +
  23.297 +	return NOPAGE_SIGBUS;
  23.298 +}
  23.299 +
  23.300 +struct vm_operations_struct blktap_vm_ops = {
  23.301 +	nopage:   blktap_nopage,
  23.302 +};
  23.303 +
  23.304 +/******************************************************************
  23.305 + * BLKTAP FILE OPS
  23.306 + */
  23.307 + 
  23.308 +/*Function Declarations*/
  23.309 +static int get_next_free_dev(void);
  23.310 +static int blktap_open(struct inode *inode, struct file *filp);
  23.311 +static int blktap_release(struct inode *inode, struct file *filp);
  23.312 +static int blktap_mmap(struct file *filp, struct vm_area_struct *vma);
  23.313 +static int blktap_ioctl(struct inode *inode, struct file *filp,
  23.314 +                        unsigned int cmd, unsigned long arg);
  23.315 +static unsigned int blktap_poll(struct file *file, poll_table *wait);
  23.316 +
  23.317 +struct miscdevice *set_misc(int minor, char *name, int dev);
  23.318 +
  23.319 +static struct file_operations blktap_fops = {
  23.320 +	.owner   = THIS_MODULE,
  23.321 +	.poll    = blktap_poll,
  23.322 +	.ioctl   = blktap_ioctl,
  23.323 +	.open    = blktap_open,
  23.324 +	.release = blktap_release,
  23.325 +	.mmap    = blktap_mmap,
  23.326 +};
  23.327 +
  23.328 +
  23.329 +static int get_next_free_dev(void)
  23.330 +{
  23.331 +	tap_blkif_t *info;
  23.332 +	int i = 0, ret = -1;
  23.333 +	unsigned long flags;
  23.334 +
  23.335 +	spin_lock_irqsave(&pending_free_lock, flags);
  23.336 +	
  23.337 +	while (i < MAX_TAP_DEV) {
  23.338 +		info = tapfds[i];
  23.339 +		if ( (tapfds[i] != NULL) && (info->dev_inuse == 0)
  23.340 +			&& (info->dev_pending == 0) ) {
  23.341 +			info->dev_pending = 1;
  23.342 +			ret = i;
  23.343 +			goto done;
  23.344 +		}
  23.345 +		i++;
  23.346 +	}
  23.347 +	
  23.348 +done:
  23.349 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  23.350 +	return ret;
  23.351 +}
  23.352 +
  23.353 +int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif) 
  23.354 +{
  23.355 +	int i;
  23.356 +		
  23.357 +	for (i = 0; i < MAX_TAP_DEV; i++)
  23.358 +		if ( (translate_domid[i].domid == domid)
  23.359 +		    && (translate_domid[i].busid == xenbus_id) ) {
  23.360 +			tapfds[i]->blkif = blkif;
  23.361 +			tapfds[i]->status = RUNNING;
  23.362 +			return i;
  23.363 +		}
  23.364 +	return -1;
  23.365 +}
  23.366 +
  23.367 +void signal_tapdisk(int idx) 
  23.368 +{
  23.369 +	tap_blkif_t *info;
  23.370 +	struct task_struct *ptask;
  23.371 +
  23.372 +	info = tapfds[idx];
  23.373 +	if ( (idx > 0) && (idx < MAX_TAP_DEV) && (info->pid > 0) ) {
  23.374 +		ptask = find_task_by_pid(info->pid);
  23.375 +		if (ptask) { 
  23.376 +			info->status = CLEANSHUTDOWN;
  23.377 + 		}
  23.378 +	}
  23.379 +	info->blkif = NULL;
  23.380 +	return;
  23.381 +}
  23.382 +
  23.383 +static int blktap_open(struct inode *inode, struct file *filp)
  23.384 +{
  23.385 +	blkif_sring_t *sring;
  23.386 +	int idx = iminor(inode) - BLKTAP_MINOR;
  23.387 +	tap_blkif_t *info;
  23.388 +	private_info_t *prv;
  23.389 +	int i;
  23.390 +	
  23.391 +	if (tapfds[idx] == NULL) {
  23.392 +		WPRINTK("Unable to open device /dev/xen/blktap%d\n",
  23.393 +		       idx);
  23.394 +		return -ENOMEM;
  23.395 +	}
  23.396 +	DPRINTK("Opening device /dev/xen/blktap%d\n",idx);
  23.397 +	
  23.398 +	info = tapfds[idx];
  23.399 +	
  23.400 +	/*Only one process can access device at a time*/
  23.401 +	if (test_and_set_bit(0, &info->dev_inuse))
  23.402 +		return -EBUSY;
  23.403 +
  23.404 +	info->dev_pending = 0;
  23.405 +	    
  23.406 +	/* Allocate the fe ring. */
  23.407 +	sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
  23.408 +	if (sring == NULL)
  23.409 +		goto fail_nomem;
  23.410 +
  23.411 +	SetPageReserved(virt_to_page(sring));
  23.412 +    
  23.413 +	SHARED_RING_INIT(sring);
  23.414 +	FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE);
  23.415 +	
  23.416 +	prv = kzalloc(sizeof(private_info_t),GFP_KERNEL);
  23.417 +	prv->idx = idx;
  23.418 +	filp->private_data = prv;
  23.419 +	info->vma = NULL;
  23.420 +
  23.421 +	info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS, 
  23.422 +				GFP_KERNEL);
  23.423 +	
  23.424 +	if (idx > 0) {
  23.425 +		init_waitqueue_head(&info->wait);
  23.426 +		for (i = 0; i < MAX_PENDING_REQS; i++) 
  23.427 +			info->idx_map[i] = INVALID_REQ;
  23.428 +	}
  23.429 +
  23.430 +	DPRINTK("Tap open: device /dev/xen/blktap%d\n",idx);
  23.431 +	return 0;
  23.432 +
  23.433 + fail_nomem:
  23.434 +	return -ENOMEM;
  23.435 +}
  23.436 +
  23.437 +static int blktap_release(struct inode *inode, struct file *filp)
  23.438 +{
  23.439 +	int idx = iminor(inode) - BLKTAP_MINOR;
  23.440 +	tap_blkif_t *info;
  23.441 +	
  23.442 +	if (tapfds[idx] == NULL) {
  23.443 +		WPRINTK("Trying to free device that doesn't exist "
  23.444 +		       "[/dev/xen/blktap%d]\n",idx);
  23.445 +		return -1;
  23.446 +	}
  23.447 +	info = tapfds[idx];
  23.448 +	info->dev_inuse = 0;
  23.449 +	DPRINTK("Freeing device [/dev/xen/blktap%d]\n",idx);
  23.450 +
  23.451 +	/* Free the ring page. */
  23.452 +	ClearPageReserved(virt_to_page(info->ufe_ring.sring));
  23.453 +	free_page((unsigned long) info->ufe_ring.sring);
  23.454 +
  23.455 +	/* Clear any active mappings and free foreign map table */
  23.456 +	if (info->vma) {
  23.457 +		zap_page_range(
  23.458 +			info->vma, info->vma->vm_start, 
  23.459 +			info->vma->vm_end - info->vma->vm_start, NULL);
  23.460 +		info->vma = NULL;
  23.461 +	}
  23.462 +	
  23.463 +	if (filp->private_data) kfree(filp->private_data);
  23.464 +
  23.465 +	if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
  23.466 +		kthread_stop(info->blkif->xenblkd);
  23.467 +		info->blkif->xenblkd = NULL;
  23.468 +		info->status = CLEANSHUTDOWN;
  23.469 +	}	
  23.470 +	return 0;
  23.471 +}
  23.472 +
  23.473 +
  23.474 +/* Note on mmap:
  23.475 + * We need to map pages to user space in a way that will allow the block
  23.476 + * subsystem set up direct IO to them.  This couldn't be done before, because
  23.477 + * there isn't really a sane way to translate a user virtual address down to a 
  23.478 + * physical address when the page belongs to another domain.
  23.479 + *
  23.480 + * My first approach was to map the page in to kernel memory, add an entry
  23.481 + * for it in the physical frame list (using alloc_lomem_region as in blkback)
  23.482 + * and then attempt to map that page up to user space.  This is disallowed
  23.483 + * by xen though, which realizes that we don't really own the machine frame
  23.484 + * underlying the physical page.
  23.485 + *
  23.486 + * The new approach is to provide explicit support for this in xen linux.
  23.487 + * The VMA now has a flag, VM_FOREIGN, to indicate that it contains pages
  23.488 + * mapped from other vms.  vma->vm_private_data is set up as a mapping 
  23.489 + * from pages to actual page structs.  There is a new clause in get_user_pages
  23.490 + * that does the right thing for this sort of mapping.
  23.491 + */
  23.492 +static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
  23.493 +{
  23.494 +	int size;
  23.495 +	struct page **map;
  23.496 +	int i;
  23.497 +	private_info_t *prv;
  23.498 +	tap_blkif_t *info;
  23.499 +
  23.500 +	/*Retrieve the dev info*/
  23.501 +	prv = (private_info_t *)filp->private_data;
  23.502 +	if (prv == NULL) {
  23.503 +		WPRINTK("blktap: mmap, retrieving idx failed\n");
  23.504 +		return -ENOMEM;
  23.505 +	}
  23.506 +	info = tapfds[prv->idx];
  23.507 +	
  23.508 +	vma->vm_flags |= VM_RESERVED;
  23.509 +	vma->vm_ops = &blktap_vm_ops;
  23.510 +
  23.511 +	size = vma->vm_end - vma->vm_start;
  23.512 +	if (size != ((mmap_pages + RING_PAGES) << PAGE_SHIFT)) {
  23.513 +		WPRINTK("you _must_ map exactly %d pages!\n",
  23.514 +		       mmap_pages + RING_PAGES);
  23.515 +		return -EAGAIN;
  23.516 +	}
  23.517 +
  23.518 +	size >>= PAGE_SHIFT;
  23.519 +	info->rings_vstart = vma->vm_start;
  23.520 +	info->user_vstart  = info->rings_vstart + (RING_PAGES << PAGE_SHIFT);
  23.521 +    
  23.522 +	/* Map the ring pages to the start of the region and reserve it. */
  23.523 +	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
  23.524 +
  23.525 +	if (remap_pfn_range(vma, vma->vm_start, 
  23.526 +			    __pa(info->ufe_ring.sring) >> PAGE_SHIFT, 
  23.527 +			    PAGE_SIZE, vma->vm_page_prot)) {
  23.528 +		WPRINTK("Mapping user ring failed!\n");
  23.529 +		goto fail;
  23.530 +	}
  23.531 +
  23.532 +	/* Mark this VM as containing foreign pages, and set up mappings. */
  23.533 +	map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT)
  23.534 +		      * sizeof(struct page_struct*),
  23.535 +		      GFP_KERNEL);
  23.536 +	if (map == NULL) {
  23.537 +		WPRINTK("Couldn't alloc VM_FOREIGN map.\n");
  23.538 +		goto fail;
  23.539 +	}
  23.540 +
  23.541 +	for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++)
  23.542 +		map[i] = NULL;
  23.543 +    
  23.544 +	vma->vm_private_data = map;
  23.545 +	vma->vm_flags |= VM_FOREIGN;
  23.546 +
  23.547 +	info->vma = vma;
  23.548 +	info->ring_ok = 1;
  23.549 +	return 0;
  23.550 + fail:
  23.551 +	/* Clear any active mappings. */
  23.552 +	zap_page_range(vma, vma->vm_start, 
  23.553 +		       vma->vm_end - vma->vm_start, NULL);
  23.554 +
  23.555 +	return -ENOMEM;
  23.556 +}
  23.557 +
  23.558 +
  23.559 +static int blktap_ioctl(struct inode *inode, struct file *filp,
  23.560 +                        unsigned int cmd, unsigned long arg)
  23.561 +{
  23.562 +	int idx = iminor(inode) - BLKTAP_MINOR;
  23.563 +	switch(cmd) {
  23.564 +	case BLKTAP_IOCTL_KICK_FE: 
  23.565 +	{
  23.566 +		/* There are fe messages to process. */
  23.567 +		return blktap_read_ufe_ring(idx);
  23.568 +	}
  23.569 +	case BLKTAP_IOCTL_SETMODE:
  23.570 +	{
  23.571 +		tap_blkif_t *info = tapfds[idx];
  23.572 +		
  23.573 +		if ( (idx > 0) && (idx < MAX_TAP_DEV) 
  23.574 +		     && (tapfds[idx] != NULL) ) 
  23.575 +		{
  23.576 +			if (BLKTAP_MODE_VALID(arg)) {
  23.577 +				info->mode = arg;
  23.578 +				/* XXX: may need to flush rings here. */
  23.579 +				DPRINTK("blktap: set mode to %lx\n", 
  23.580 +				       arg);
  23.581 +				return 0;
  23.582 +			}
  23.583 +		}
  23.584 +		return 0;
  23.585 +	}
  23.586 +	case BLKTAP_IOCTL_PRINT_IDXS:
  23.587 +        {
  23.588 +		tap_blkif_t *info = tapfds[idx];
  23.589 +		
  23.590 +		if ( (idx > 0) && (idx < MAX_TAP_DEV) 
  23.591 +		     && (tapfds[idx] != NULL) ) 
  23.592 +		{
  23.593 +			printk("User Rings: \n-----------\n");
  23.594 +			printk("UF: rsp_cons: %2d, req_prod_prv: %2d "
  23.595 +				"| req_prod: %2d, rsp_prod: %2d\n",
  23.596 +				info->ufe_ring.rsp_cons,
  23.597 +				info->ufe_ring.req_prod_pvt,
  23.598 +				info->ufe_ring.sring->req_prod,
  23.599 +				info->ufe_ring.sring->rsp_prod);
  23.600 +		}
  23.601 +            	return 0;
  23.602 +        }
  23.603 +	case BLKTAP_IOCTL_SENDPID:
  23.604 +	{
  23.605 +		tap_blkif_t *info = tapfds[idx];
  23.606 +		
  23.607 +		if ( (idx > 0) && (idx < MAX_TAP_DEV) 
  23.608 +		     && (tapfds[idx] != NULL) ) 
  23.609 +		{
  23.610 +			info->pid = (pid_t)arg;
  23.611 +			DPRINTK("blktap: pid received %d\n", 
  23.612 +			       info->pid);
  23.613 +		}
  23.614 +		return 0;
  23.615 +	}
  23.616 +	case BLKTAP_IOCTL_NEWINTF:
  23.617 +	{		
  23.618 +		uint64_t val = (uint64_t)arg;
  23.619 +		domid_translate_t *tr = (domid_translate_t *)&val;
  23.620 +		int newdev;
  23.621 +
  23.622 +		DPRINTK("NEWINTF Req for domid %d and bus id %d\n", 
  23.623 +		       tr->domid, tr->busid);
  23.624 +		newdev = get_next_free_dev();
  23.625 +		if (newdev < 1) {
  23.626 +			WPRINTK("Error initialising /dev/xen/blktap - "
  23.627 +				"No more devices\n");
  23.628 +			return -1;
  23.629 +		}
  23.630 +		translate_domid[newdev].domid = tr->domid;
  23.631 +		translate_domid[newdev].busid = tr->busid;
  23.632 +		return newdev;
  23.633 +	}
  23.634 +	case BLKTAP_IOCTL_FREEINTF:
  23.635 +	{
  23.636 +		unsigned long dev = arg;
  23.637 +		tap_blkif_t *info = NULL;
  23.638 +
  23.639 +		if ( (dev > 0) && (dev < MAX_TAP_DEV) ) info = tapfds[dev];
  23.640 +
  23.641 +		if ( (info != NULL) && (info->dev_pending) )
  23.642 +			info->dev_pending = 0;
  23.643 +		return 0;
  23.644 +	}
  23.645 +	case BLKTAP_IOCTL_MINOR:
  23.646 +	{
  23.647 +		unsigned long dev = arg;
  23.648 +		tap_blkif_t *info = NULL;
  23.649 +		
  23.650 +		if ( (dev > 0) && (dev < MAX_TAP_DEV) ) info = tapfds[dev];
  23.651 +		
  23.652 +		if (info != NULL) return info->minor;
  23.653 +		else return -1;
  23.654 +	}
  23.655 +	case BLKTAP_IOCTL_MAJOR:
  23.656 +		return BLKTAP_DEV_MAJOR;
  23.657 +
  23.658 +	case BLKTAP_QUERY_ALLOC_REQS:
  23.659 +	{
  23.660 +		WPRINTK("BLKTAP_QUERY_ALLOC_REQS ioctl: %d/%d\n",
  23.661 +		       alloc_pending_reqs, blkif_reqs);
  23.662 +		return (alloc_pending_reqs/blkif_reqs) * 100;
  23.663 +	}
  23.664 +	}
  23.665 +	return -ENOIOCTLCMD;
  23.666 +}
  23.667 +
  23.668 +static unsigned int blktap_poll(struct file *file, poll_table *wait)
  23.669 +{
  23.670 +	private_info_t *prv;
  23.671 +	tap_blkif_t *info;
  23.672 +	
  23.673 +	/*Retrieve the dev info*/
  23.674 +	prv = (private_info_t *)file->private_data;
  23.675 +	if (prv == NULL) {
  23.676 +		WPRINTK(" poll, retrieving idx failed\n");
  23.677 +		return 0;
  23.678 +	}
  23.679 +	
  23.680 +	if (prv->idx == 0) return 0;
  23.681 +	
  23.682 +	info = tapfds[prv->idx];
  23.683 +	
  23.684 +	poll_wait(file, &info->wait, wait);
  23.685 +	if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) {
  23.686 +		flush_tlb_all();
  23.687 +		RING_PUSH_REQUESTS(&info->ufe_ring);
  23.688 +		return POLLIN | POLLRDNORM;
  23.689 +	}
  23.690 +	return 0;
  23.691 +}
  23.692 +
  23.693 +void blktap_kick_user(int idx)
  23.694 +{
  23.695 +	tap_blkif_t *info;
  23.696 +
  23.697 +	if (idx == 0) return;
  23.698 +	
  23.699 +	info = tapfds[idx];
  23.700 +	
  23.701 +	if (info != NULL) wake_up_interruptible(&info->wait);
  23.702 +	return;
  23.703 +}
  23.704 +
  23.705 +static int do_block_io_op(blkif_t *blkif);
  23.706 +static void dispatch_rw_block_io(blkif_t *blkif,
  23.707 +				 blkif_request_t *req,
  23.708 +				 pending_req_t *pending_req);
  23.709 +static void make_response(blkif_t *blkif, unsigned long id, 
  23.710 +                          unsigned short op, int st);
  23.711 +
  23.712 +/******************************************************************
  23.713 + * misc small helpers
  23.714 + */
  23.715 +/* FIXME: Return ENOMEM properly on failure to allocate additional reqs. */
  23.716 +static void req_increase(void)
  23.717 +{
  23.718 +	int i, j;
  23.719 +	struct page *page;
  23.720 +	unsigned long flags;
  23.721 +
  23.722 +	spin_lock_irqsave(&pending_free_lock, flags);
  23.723 +
  23.724 +	if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock) 
  23.725 +		goto done;
  23.726 +
  23.727 +	pending_reqs[mmap_alloc]  = kzalloc(sizeof(pending_req_t) *
  23.728 +					blkif_reqs, GFP_KERNEL);
  23.729 +	pending_addrs[mmap_alloc] = kzalloc(sizeof(unsigned long) *
  23.730 +					mmap_pages, GFP_KERNEL);
  23.731 +
  23.732 +	if (!pending_reqs[mmap_alloc] || !pending_addrs[mmap_alloc]) {
  23.733 +		kfree(pending_reqs[mmap_alloc]);
  23.734 +		kfree(pending_addrs[mmap_alloc]);
  23.735 +		WPRINTK("%s: out of memory\n", __FUNCTION__); 
  23.736 +		goto done;
  23.737 +	}
  23.738 +
  23.739 +#ifdef __ia64__
  23.740 +	extern unsigned long alloc_empty_foreign_map_page_range(
  23.741 +		unsigned long pages);
  23.742 +	mmap_start[mmap_alloc].start = (unsigned long)
  23.743 +		alloc_empty_foreign_map_page_range(mmap_pages);
  23.744 +#else /* ! ia64 */
  23.745 +	page = balloon_alloc_empty_page_range(mmap_pages);
  23.746 +	BUG_ON(page == NULL);
  23.747 +
  23.748 +	/* Pin all of the pages. */
  23.749 +	for (i=0; i<mmap_pages; i++)
  23.750 +		get_page(&page[i]);
  23.751 +
  23.752 +	mmap_start[mmap_alloc].start = 
  23.753 +		(unsigned long)pfn_to_kaddr(page_to_pfn(page));
  23.754 +	mmap_start[mmap_alloc].mpage = page;
  23.755 +
  23.756 +#endif
  23.757 +	DPRINTK("%s: reqs=%d, pages=%d, mmap_vstart=0x%lx\n",
  23.758 +	        __FUNCTION__, blkif_reqs, mmap_pages, 
  23.759 +	       mmap_start[mmap_alloc].start);
  23.760 +
  23.761 +	BUG_ON(mmap_start[mmap_alloc].start == 0);
  23.762 +
  23.763 +	for (i = 0; i < mmap_pages; i++) 
  23.764 +		pending_addrs[mmap_alloc][i] = 
  23.765 +			mmap_start[mmap_alloc].start + (i << PAGE_SHIFT);
  23.766 +
  23.767 +	for (i = 0; i < MAX_PENDING_REQS ; i++) {
  23.768 +		list_add_tail(&pending_reqs[mmap_alloc][i].free_list, 
  23.769 +			      &pending_free);
  23.770 +		pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc;
  23.771 +		for (j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++)
  23.772 +			BLKTAP_INVALIDATE_HANDLE(&pending_handle(mmap_alloc, 
  23.773 +								 i, j));
  23.774 +	}
  23.775 +
  23.776 +	mmap_alloc++;
  23.777 +	DPRINTK("# MMAPs increased to %d\n",mmap_alloc);
  23.778 + done:
  23.779 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  23.780 +
  23.781 +}
  23.782 +
  23.783 +static void mmap_req_del(int mmap)
  23.784 +{
  23.785 +	int i;
  23.786 +	struct page *page;
  23.787 +
  23.788 +	/*Spinlock already acquired*/
  23.789 +	kfree(pending_reqs[mmap]);
  23.790 +	kfree(pending_addrs[mmap]);
  23.791 +
  23.792 +#ifdef __ia64__
  23.793 +	/*Not sure what goes here yet!*/
  23.794 +#else
  23.795 +
  23.796 +	/* Unpin all of the pages. */
  23.797 +	page = mmap_start[mmap].mpage;
  23.798 +	for (i=0; i<mmap_pages; i++)
  23.799 +		put_page(&page[i]);
  23.800 +
  23.801 +	balloon_dealloc_empty_page_range(mmap_start[mmap].mpage, mmap_pages);
  23.802 +#endif
  23.803 +
  23.804 +	mmap_lock = 0;
  23.805 +	DPRINTK("# MMAPs decreased to %d\n",mmap_alloc);
  23.806 +	mmap_alloc--;
  23.807 +}
  23.808 +
  23.809 +/*N.B. Currently unused - will be accessed via sysfs*/
  23.810 +static void req_decrease(void)
  23.811 +{
  23.812 +	pending_req_t *req;
  23.813 +	int i;
  23.814 +	unsigned long flags;
  23.815 +
  23.816 +	spin_lock_irqsave(&pending_free_lock, flags);
  23.817 +
  23.818 +	DPRINTK("Req decrease called.\n");
  23.819 +	if (mmap_lock || mmap_alloc == 1) 
  23.820 +		goto done;
  23.821 +
  23.822 +	mmap_lock = 1;
  23.823 +	mmap_inuse = MAX_PENDING_REQS;
  23.824 +	
  23.825 +        /*Go through reqs and remove any that aren't in use*/
  23.826 +	for (i = 0; i < MAX_PENDING_REQS ; i++) {
  23.827 +		req = &pending_reqs[mmap_alloc-1][i];
  23.828 +		if (req->inuse == 0) {
  23.829 +			list_del(&req->free_list);
  23.830 +			mmap_inuse--;
  23.831 +		}
  23.832 +	}
  23.833 +	if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
  23.834 + done:
  23.835 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  23.836 +	return;
  23.837 +}
  23.838 +
  23.839 +static pending_req_t* alloc_req(void)
  23.840 +{
  23.841 +	pending_req_t *req = NULL;
  23.842 +	unsigned long flags;
  23.843 +
  23.844 +	spin_lock_irqsave(&pending_free_lock, flags);
  23.845 +
  23.846 +	if (!list_empty(&pending_free)) {
  23.847 +		req = list_entry(pending_free.next, pending_req_t, free_list);
  23.848 +		list_del(&req->free_list);
  23.849 +	}
  23.850 +
  23.851 +	if (req) {
  23.852 +		req->inuse = 1;
  23.853 +		alloc_pending_reqs++;
  23.854 +	}
  23.855 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  23.856 +
  23.857 +	return req;
  23.858 +}
  23.859 +
  23.860 +static void free_req(pending_req_t *req)
  23.861 +{
  23.862 +	unsigned long flags;
  23.863 +	int was_empty;
  23.864 +
  23.865 +	spin_lock_irqsave(&pending_free_lock, flags);
  23.866 +
  23.867 +	alloc_pending_reqs--;
  23.868 +	req->inuse = 0;
  23.869 +	if (mmap_lock && (req->mem_idx == mmap_alloc-1)) {
  23.870 +		mmap_inuse--;
  23.871 +		if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
  23.872 +		spin_unlock_irqrestore(&pending_free_lock, flags);
  23.873 +		return;
  23.874 +	}
  23.875 +	was_empty = list_empty(&pending_free);
  23.876 +	list_add(&req->free_list, &pending_free);
  23.877 +
  23.878 +	spin_unlock_irqrestore(&pending_free_lock, flags);
  23.879 +
  23.880 +	if (was_empty)
  23.881 +		wake_up(&pending_free_wq);
  23.882 +}
  23.883 +
  23.884 +static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx, int 
  23.885 +			    tapidx)
  23.886 +{
  23.887 +	struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
  23.888 +	unsigned int i, invcount = 0;
  23.889 +	struct grant_handle_pair *khandle;
  23.890 +	uint64_t ptep;
  23.891 +	int ret, mmap_idx;
  23.892 +	unsigned long kvaddr, uvaddr;
  23.893 +
  23.894 +	tap_blkif_t *info = tapfds[tapidx];
  23.895 +	
  23.896 +	if (info == NULL) {
  23.897 +		WPRINTK("fast_flush: Couldn't get info!\n");
  23.898 +		return;
  23.899 +	}
  23.900 +	mmap_idx = req->mem_idx;
  23.901 +
  23.902 +	for (i = 0; i < req->nr_pages; i++) {
  23.903 +		kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, k_idx, i);
  23.904 +		uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
  23.905 +
  23.906 +		khandle = &pending_handle(mmap_idx, k_idx, i);
  23.907 +		if (BLKTAP_INVALID_HANDLE(khandle)) {
  23.908 +			WPRINTK("BLKTAP_INVALID_HANDLE\n");
  23.909 +			continue;
  23.910 +		}
  23.911 +		gnttab_set_unmap_op(&unmap[invcount], 
  23.912 +			MMAP_VADDR(mmap_start[mmap_idx].start, k_idx, i), 
  23.913 +				    GNTMAP_host_map, khandle->kernel);
  23.914 +		invcount++;
  23.915 +
  23.916 +		if (create_lookup_pte_addr(
  23.917 +		    info->vma->vm_mm,
  23.918 +		    MMAP_VADDR(info->user_vstart, u_idx, i), 
  23.919 +		    &ptep) !=0) {
  23.920 +			WPRINTK("Couldn't get a pte addr!\n");
  23.921 +			return;
  23.922 +		}
  23.923 +
  23.924 +		gnttab_set_unmap_op(&unmap[invcount], 
  23.925 +			ptep, GNTMAP_host_map,
  23.926 +			khandle->user);
  23.927 +		invcount++;
  23.928 +            
  23.929 +		BLKTAP_INVALIDATE_HANDLE(khandle);
  23.930 +	}
  23.931 +	ret = HYPERVISOR_grant_table_op(
  23.932 +		GNTTABOP_unmap_grant_ref, unmap, invcount);
  23.933 +	BUG_ON(ret);
  23.934 +	
  23.935 +	if (info->vma != NULL)
  23.936 +		zap_page_range(info->vma, 
  23.937 +			       MMAP_VADDR(info->user_vstart, u_idx, 0), 
  23.938 +			       req->nr_pages << PAGE_SHIFT, NULL);
  23.939 +}
  23.940 +
  23.941 +/******************************************************************
  23.942 + * SCHEDULER FUNCTIONS
  23.943 + */
  23.944 +
  23.945 +static void print_stats(blkif_t *blkif)
  23.946 +{
  23.947 +	printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d\n",
  23.948 +	       current->comm, blkif->st_oo_req,
  23.949 +	       blkif->st_rd_req, blkif->st_wr_req);
  23.950 +	blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
  23.951 +	blkif->st_rd_req = 0;
  23.952 +	blkif->st_wr_req = 0;
  23.953 +	blkif->st_oo_req = 0;
  23.954 +}
  23.955 +
  23.956 +int tap_blkif_schedule(void *arg)
  23.957 +{
  23.958 +	blkif_t *blkif = arg;
  23.959 +
  23.960 +	blkif_get(blkif);
  23.961 +
  23.962 +	if (debug_lvl)
  23.963 +		printk(KERN_DEBUG "%s: started\n", current->comm);
  23.964 +
  23.965 +	while (!kthread_should_stop()) {
  23.966 +		wait_event_interruptible(
  23.967 +			blkif->wq,
  23.968 +			blkif->waiting_reqs || kthread_should_stop());
  23.969 +		wait_event_interruptible(
  23.970 +			pending_free_wq,
  23.971 +			!list_empty(&pending_free) || kthread_should_stop());
  23.972 +
  23.973 +		blkif->waiting_reqs = 0;
  23.974 +		smp_mb(); /* clear flag *before* checking for work */
  23.975 +
  23.976 +		if (do_block_io_op(blkif))
  23.977 +			blkif->waiting_reqs = 1;
  23.978 +
  23.979 +		if (log_stats && time_after(jiffies, blkif->st_print))
  23.980 +			print_stats(blkif);
  23.981 +	}
  23.982 +
  23.983 +	if (log_stats)
  23.984 +		print_stats(blkif);
  23.985 +	if (debug_lvl)
  23.986 +		printk(KERN_DEBUG "%s: exiting\n", current->comm);
  23.987 +
  23.988 +	blkif->xenblkd = NULL;
  23.989 +	blkif_put(blkif);
  23.990 +
  23.991 +	return 0;
  23.992 +}
  23.993 +
  23.994 +/******************************************************************
  23.995 + * COMPLETION CALLBACK -- Called by user level ioctl()
  23.996 + */
  23.997 +
  23.998 +static int blktap_read_ufe_ring(int idx)
  23.999 +{
 23.1000 +	/* This is called to read responses from the UFE ring. */
 23.1001 +	RING_IDX i, j, rp;
 23.1002 +	blkif_response_t *resp;
 23.1003 +	blkif_t *blkif=NULL;
 23.1004 +	int pending_idx, usr_idx, mmap_idx;
 23.1005 +	pending_req_t *pending_req;
 23.1006 +	tap_blkif_t *info;
 23.1007 +	
 23.1008 +	info = tapfds[idx];
 23.1009 +	if (info == NULL) {
 23.1010 +		return 0;
 23.1011 +	}
 23.1012 +
 23.1013 +	/* We currently only forward packets in INTERCEPT_FE mode. */
 23.1014 +	if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE))
 23.1015 +		return 0;
 23.1016 +
 23.1017 +	/* for each outstanding message on the UFEring  */
 23.1018 +	rp = info->ufe_ring.sring->rsp_prod;
 23.1019 +	rmb();
 23.1020 +        
 23.1021 +	for (i = info->ufe_ring.rsp_cons; i != rp; i++) {
 23.1022 +		resp = RING_GET_RESPONSE(&info->ufe_ring, i);
 23.1023 +		++info->ufe_ring.rsp_cons;
 23.1024 +
 23.1025 +		/*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/
 23.1026 +		usr_idx = (int)resp->id;
 23.1027 +		pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
 23.1028 +		mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
 23.1029 +
 23.1030 +		if ( (mmap_idx >= mmap_alloc) || 
 23.1031 +		   (ID_TO_IDX(info->idx_map[usr_idx]) >= MAX_PENDING_REQS) )
 23.1032 +			WPRINTK("Incorrect req map"
 23.1033 +			       "[%d], internal map [%d,%d (%d)]\n", 
 23.1034 +			       usr_idx, mmap_idx, 
 23.1035 +			       ID_TO_IDX(info->idx_map[usr_idx]),
 23.1036 +			       MASK_PEND_IDX(
 23.1037 +				       ID_TO_IDX(info->idx_map[usr_idx])));
 23.1038 +
 23.1039 +		pending_req = &pending_reqs[mmap_idx][pending_idx];
 23.1040 +		blkif = pending_req->blkif;
 23.1041 +
 23.1042 +		for (j = 0; j < pending_req->nr_pages; j++) {
 23.1043 +
 23.1044 +			unsigned long kvaddr, uvaddr;
 23.1045 +			struct page **map = info->vma->vm_private_data;
 23.1046 +			struct page *pg;
 23.1047 +			int offset; 
 23.1048 +
 23.1049 +			uvaddr  = MMAP_VADDR(info->user_vstart, usr_idx, j);
 23.1050 +			kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
 23.1051 +					    pending_idx, j);
 23.1052 +
 23.1053 +			pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
 23.1054 +			ClearPageReserved(pg);
 23.1055 +			offset = (uvaddr - info->vma->vm_start) 
 23.1056 +				>> PAGE_SHIFT;
 23.1057 +			map[offset] = NULL;
 23.1058 +		}
 23.1059 +		fast_flush_area(pending_req, pending_idx, usr_idx, idx); 
 23.1060 +		make_response(blkif, pending_req->id, resp->operation,
 23.1061 +			      resp->status);
 23.1062 +		info->idx_map[usr_idx] = INVALID_REQ;
 23.1063 +		blkif_put(pending_req->blkif);
 23.1064 +		free_req(pending_req);
 23.1065 +	}
 23.1066 +		
 23.1067 +	return 0;
 23.1068 +}
 23.1069 +
 23.1070 +
 23.1071 +/******************************************************************************
 23.1072 + * NOTIFICATION FROM GUEST OS.
 23.1073 + */
 23.1074 +
 23.1075 +static void blkif_notify_work(blkif_t *blkif)
 23.1076 +{
 23.1077 +	blkif->waiting_reqs = 1;
 23.1078 +	wake_up(&blkif->wq);
 23.1079 +}
 23.1080 +
 23.1081 +irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
 23.1082 +{
 23.1083 +	blkif_notify_work(dev_id);
 23.1084 +	return IRQ_HANDLED;
 23.1085 +}
 23.1086 +
 23.1087 +
 23.1088 +
 23.1089 +/******************************************************************
 23.1090 + * DOWNWARD CALLS -- These interface with the block-device layer proper.
 23.1091 + */
 23.1092 +static int print_dbug = 1;
 23.1093 +static int do_block_io_op(blkif_t *blkif)
 23.1094 +{
 23.1095 +	blkif_back_ring_t *blk_ring = &blkif->blk_ring;
 23.1096 +	blkif_request_t *req;
 23.1097 +	pending_req_t *pending_req;
 23.1098 +	RING_IDX rc, rp;
 23.1099 +	int more_to_do = 0;
 23.1100 +	tap_blkif_t *info;
 23.1101 +
 23.1102 +	rc = blk_ring->req_cons;
 23.1103 +	rp = blk_ring->sring->req_prod;
 23.1104 +	rmb(); /* Ensure we see queued requests up to 'rp'. */
 23.1105 +
 23.1106 +	/*Check blkif has corresponding UE ring*/
 23.1107 +	if (blkif->dev_num == -1) {
 23.1108 +		/*oops*/
 23.1109 +		if (print_dbug) {
 23.1110 +			WPRINTK("Corresponding UE " 
 23.1111 +			       "ring does not exist!\n");
 23.1112 +			print_dbug = 0; /*We only print this message once*/
 23.1113 +		}
 23.1114 +		return 1; 
 23.1115 +	}
 23.1116 +
 23.1117 +	info = tapfds[blkif->dev_num];
 23.1118 +	if (info == NULL || !info->dev_inuse) {
 23.1119 +		if (print_dbug) {
 23.1120 +			WPRINTK("Can't get UE info!\n");
 23.1121 +			print_dbug = 0;
 23.1122 +		}
 23.1123 +		return 1;
 23.1124 +	}
 23.1125 +
 23.1126 +	while (rc != rp) {
 23.1127 +		
 23.1128 +		if (RING_FULL(&info->ufe_ring)) {
 23.1129 +			WPRINTK("RING_FULL! More to do\n");
 23.1130 +			more_to_do = 1;
 23.1131 +			break;
 23.1132 +		}
 23.1133 +		
 23.1134 +		if (RING_REQUEST_CONS_OVERFLOW(blk_ring, rc)) {
 23.1135 +			WPRINTK("RING_REQUEST_CONS_OVERFLOW!"
 23.1136 +			       " More to do\n");
 23.1137 +			more_to_do = 1;
 23.1138 +			break;		
 23.1139 +		}
 23.1140 +
 23.1141 +		pending_req = alloc_req();
 23.1142 +		if (NULL == pending_req) {
 23.1143 +			blkif->st_oo_req++;
 23.1144 +			more_to_do = 1;
 23.1145 +			break;
 23.1146 +		}
 23.1147 +
 23.1148 +		req = RING_GET_REQUEST(blk_ring, rc);
 23.1149 +		blk_ring->req_cons = ++rc; /* before make_response() */	
 23.1150 +
 23.1151 +		switch (req->operation) {
 23.1152 +		case BLKIF_OP_READ:
 23.1153 +			blkif->st_rd_req++;
 23.1154 +			dispatch_rw_block_io(blkif, req, pending_req);
 23.1155 +			break;
 23.1156 +
 23.1157 +		case BLKIF_OP_WRITE:
 23.1158 +			blkif->st_wr_req++;
 23.1159 +			dispatch_rw_block_io(blkif, req, pending_req);
 23.1160 +			break;
 23.1161 +
 23.1162 +		default:
 23.1163 +			WPRINTK("unknown operation [%d]\n",
 23.1164 +				req->operation);
 23.1165 +			make_response(blkif, req->id, req->operation,
 23.1166 +				      BLKIF_RSP_ERROR);
 23.1167 +			free_req(pending_req);
 23.1168 +			break;
 23.1169 +		}
 23.1170 +	}
 23.1171 +		
 23.1172 +	blktap_kick_user(blkif->dev_num);
 23.1173 +
 23.1174 +	return more_to_do;
 23.1175 +}
 23.1176 +
 23.1177 +static void dispatch_rw_block_io(blkif_t *blkif,
 23.1178 +				 blkif_request_t *req,
 23.1179 +				 pending_req_t *pending_req)
 23.1180 +{
 23.1181 +	extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]); 
 23.1182 +	int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
 23.1183 +	struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
 23.1184 +	unsigned int nseg;
 23.1185 +	int ret, i;
 23.1186 +	tap_blkif_t *info = tapfds[blkif->dev_num];
 23.1187 +	uint64_t sector;
 23.1188 +	
 23.1189 +	blkif_request_t *target;
 23.1190 +	int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx);
 23.1191 +	int usr_idx = GET_NEXT_REQ(info->idx_map);
 23.1192 +	uint16_t mmap_idx = pending_req->mem_idx;
 23.1193 +
 23.1194 +	/*Check we have space on user ring - should never fail*/
 23.1195 +	if(usr_idx == INVALID_REQ) goto fail_flush;
 23.1196 +	
 23.1197 +	/* Check that number of segments is sane. */
 23.1198 +	nseg = req->nr_segments;
 23.1199 +	if ( unlikely(nseg == 0) || 
 23.1200 +	    unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) {
 23.1201 +		WPRINTK("Bad number of segments in request (%d)\n", nseg);
 23.1202 +		goto fail_response;
 23.1203 +	}
 23.1204 +	
 23.1205 +	/* Make sure userspace is ready. */
 23.1206 +	if (!info->ring_ok) {
 23.1207 +		WPRINTK("blktap: ring not ready for requests!\n");
 23.1208 +		goto fail_response;
 23.1209 +	}
 23.1210 +
 23.1211 +	if (RING_FULL(&info->ufe_ring)) {
 23.1212 +		WPRINTK("blktap: fe_ring is full, can't add "
 23.1213 +			"IO Request will be dropped. %d %d\n",
 23.1214 +			RING_SIZE(&info->ufe_ring),
 23.1215 +			RING_SIZE(&blkif->blk_ring));
 23.1216 +		goto fail_response;
 23.1217 +	}
 23.1218 +
 23.1219 +	pending_req->blkif     = blkif;
 23.1220 +	pending_req->id        = req->id;
 23.1221 +	pending_req->operation = operation;
 23.1222 +	pending_req->status    = BLKIF_RSP_OKAY;
 23.1223 +	pending_req->nr_pages  = nseg;
 23.1224 +	op = 0;
 23.1225 +	for (i = 0; i < nseg; i++) {
 23.1226 +		unsigned long uvaddr;
 23.1227 +		unsigned long kvaddr;
 23.1228 +		uint64_t ptep;
 23.1229 +		struct page *page;
 23.1230 +		uint32_t flags;
 23.1231 +
 23.1232 +		uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
 23.1233 +		kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
 23.1234 +				    pending_idx, i);
 23.1235 +		page = virt_to_page(kvaddr);
 23.1236 +
 23.1237 +		sector = req->sector_number + (8*i);
 23.1238 +		if( (blkif->sectors > 0) && (sector >= blkif->sectors) ) {
 23.1239 +			WPRINTK("BLKTAP: Sector request greater" 
 23.1240 +			       "than size\n");
 23.1241 +			WPRINTK("BLKTAP: %s request sector" 
 23.1242 +			       "[%llu,%llu], Total [%llu]\n",
 23.1243 +			       (req->operation == 
 23.1244 +				BLKIF_OP_WRITE ? "WRITE" : "READ"),
 23.1245 +				(long long unsigned) sector,
 23.1246 +				(long long unsigned) sector>>9,
 23.1247 +				blkif->sectors);
 23.1248 +		}
 23.1249 +
 23.1250 +		flags = GNTMAP_host_map;
 23.1251 +		if (operation == WRITE)
 23.1252 +			flags |= GNTMAP_readonly;
 23.1253 +		gnttab_set_map_op(&map[op], kvaddr, flags,
 23.1254 +				  req->seg[i].gref, blkif->domid);
 23.1255 +		op++;
 23.1256 +
 23.1257 +		/* Now map it to user. */
 23.1258 +		ret = create_lookup_pte_addr(info->vma->vm_mm, 
 23.1259 +					     uvaddr, &ptep);
 23.1260 +		if (ret) {
 23.1261 +			WPRINTK("Couldn't get a pte addr!\n");
 23.1262 +			fast_flush_area(pending_req, pending_idx, usr_idx, 
 23.1263 +					blkif->dev_num);
 23.1264 +			goto fail_flush;
 23.1265 +		}
 23.1266 +
 23.1267 +		flags = GNTMAP_host_map | GNTMAP_application_map
 23.1268 +			| GNTMAP_contains_pte;
 23.1269 +		if (operation == WRITE)
 23.1270 +			flags |= GNTMAP_readonly;
 23.1271 +		gnttab_set_map_op(&map[op], ptep, flags,
 23.1272 +				  req->seg[i].gref, blkif->domid);
 23.1273 +		op++;
 23.1274 +	}
 23.1275 +
 23.1276 +	ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
 23.1277 +	BUG_ON(ret);
 23.1278 +
 23.1279 +	for (i = 0; i < (nseg*2); i+=2) {
 23.1280 +		unsigned long uvaddr;
 23.1281 +		unsigned long kvaddr;
 23.1282 +		unsigned long offset;
 23.1283 +		struct page *pg;
 23.1284 +
 23.1285 +		uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
 23.1286 +		kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
 23.1287 +				    pending_idx, i/2);
 23.1288 +
 23.1289 +		if (unlikely(map[i].status != 0)) {
 23.1290 +			WPRINTK("invalid kernel buffer -- "
 23.1291 +				"could not remap it\n");
 23.1292 +			goto fail_flush;
 23.1293 +		}
 23.1294 +
 23.1295 +		if (unlikely(map[i+1].status != 0)) {
 23.1296 +			WPRINTK("invalid user buffer -- "
 23.1297 +				"could not remap it\n");
 23.1298 +			goto fail_flush;
 23.1299 +		}
 23.1300 +
 23.1301 +		pending_handle(mmap_idx, pending_idx, i/2).kernel 
 23.1302 +			= map[i].handle;
 23.1303 +		pending_handle(mmap_idx, pending_idx, i/2).user   
 23.1304 +			= map[i+1].handle;
 23.1305 +#ifdef CONFIG_XEN_IA64_DOM0_NON_VP
 23.1306 +		pending_addrs[mmap_idx][vaddr_pagenr(pending_req, i)] =
 23.1307 +			(unsigned long)gnttab_map_vaddr(map[i]);
 23.1308 +#else
 23.1309 +		set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
 23.1310 +			FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
 23.1311 +#endif
 23.1312 +		offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
 23.1313 +		pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
 23.1314 +		((struct page **)info->vma->vm_private_data)[offset] =
 23.1315 +			pg;
 23.1316 +	}
 23.1317 +	/* Mark mapped pages as reserved: */
 23.1318 +	for (i = 0; i < req->nr_segments; i++) {
 23.1319 +		unsigned long kvaddr;
 23.1320 +		struct page *pg;
 23.1321 +
 23.1322 +		kvaddr = MMAP_VADDR(mmap_start[mmap_idx].start, 
 23.1323 +				    pending_idx, i);
 23.1324 +		pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
 23.1325 +		SetPageReserved(pg);
 23.1326 +	}
 23.1327 +	
 23.1328 +	/*record [mmap_idx,pending_idx] to [usr_idx] mapping*/
 23.1329 +	info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx);
 23.1330 +
 23.1331 +	blkif_get(blkif);
 23.1332 +	/* Finally, write the request message to the user ring. */
 23.1333 +	target = RING_GET_REQUEST(&info->ufe_ring,
 23.1334 +				  info->ufe_ring.req_prod_pvt);
 23.1335 +	memcpy(target, req, sizeof(*req));
 23.1336 +	target->id = usr_idx;
 23.1337 +	info->ufe_ring.req_prod_pvt++;
 23.1338 +	return;
 23.1339 +
 23.1340 + fail_flush:
 23.1341 +	WPRINTK("Reached Fail_flush\n");
 23.1342 +	fast_flush_area(pending_req, pending_idx, usr_idx, blkif->dev_num);
 23.1343 + fail_response:
 23.1344 +	make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
 23.1345 +	free_req(pending_req);
 23.1346 +} 
 23.1347 +
 23.1348 +
 23.1349 +
 23.1350 +/******************************************************************
 23.1351 + * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
 23.1352 + */
 23.1353 +
 23.1354 +
 23.1355 +static void make_response(blkif_t *blkif, unsigned long id, 
 23.1356 +                          unsigned short op, int st)
 23.1357 +{
 23.1358 +	blkif_response_t *resp;
 23.1359 +	unsigned long     flags;
 23.1360 +	blkif_back_ring_t *blk_ring = &blkif->blk_ring;
 23.1361 +	int more_to_do = 0;
 23.1362 +	int notify;
 23.1363 +
 23.1364 +	spin_lock_irqsave(&blkif->blk_ring_lock, flags);
 23.1365 +	/* Place on the response ring for the relevant domain. */ 
 23.1366 +	resp = RING_GET_RESPONSE(blk_ring, blk_ring->rsp_prod_pvt);
 23.1367 +	resp->id        = id;
 23.1368 +	resp->operation = op;
 23.1369 +	resp->status    = st;
 23.1370 +	blk_ring->rsp_prod_pvt++;
 23.1371 +	RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(blk_ring, notify);
 23.1372 +
 23.1373 +	if (blk_ring->rsp_prod_pvt == blk_ring->req_cons) {
 23.1374 +		/*
 23.1375 +		 * Tail check for pending requests. Allows frontend to avoid
 23.1376 +		 * notifications if requests are already in flight (lower
 23.1377 +		 * overheads and promotes batching).
 23.1378 +		 */
 23.1379 +		RING_FINAL_CHECK_FOR_REQUESTS(blk_ring, more_to_do);
 23.1380 +	} else if (RING_HAS_UNCONSUMED_REQUESTS(blk_ring)) {
 23.1381 +		more_to_do = 1;
 23.1382 +
 23.1383 +	}	
 23.1384 +	spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
 23.1385 +	if (more_to_do)
 23.1386 +		blkif_notify_work(blkif);
 23.1387 +	if (notify)
 23.1388 +		notify_remote_via_irq(blkif->irq);
 23.1389 +}
 23.1390 +
 23.1391 +static int __init blkif_init(void)
 23.1392 +{
 23.1393 +	int i,ret,blktap_dir;
 23.1394 +	tap_blkif_t *info;
 23.1395 +
 23.1396 +	if (!is_running_on_xen())
 23.1397 +		return -ENODEV;
 23.1398 +
 23.1399 +	INIT_LIST_HEAD(&pending_free);
 23.1400 +        for(i = 0; i < 2; i++) req_increase();
 23.1401 +
 23.1402 +	tap_blkif_interface_init();
 23.1403 +
 23.1404 +	alloc_pending_reqs = 0;
 23.1405 +
 23.1406 +	tap_blkif_xenbus_init();
 23.1407 +
 23.1408 +	/*Create the blktap devices, but do not map memory or waitqueue*/
 23.1409 +	for(i = 0; i < MAX_TAP_DEV; i++) translate_domid[i].domid = 0xFFFF;
 23.1410 +
 23.1411 +	ret = register_chrdev(BLKTAP_DEV_MAJOR,"blktap",&blktap_fops);
 23.1412 +	blktap_dir = devfs_mk_dir(NULL, "xen", 0, NULL);
 23.1413 +
 23.1414 +	if ( (ret < 0)||(blktap_dir < 0) ) {
 23.1415 +		WPRINTK("Couldn't register /dev/xen/blktap\n");
 23.1416 +		return -ENOMEM;
 23.1417 +	}	
 23.1418 +	
 23.1419 +	for(i = 0; i < MAX_TAP_DEV; i++ ) {
 23.1420 +		info = tapfds[i] = kzalloc(sizeof(tap_blkif_t),GFP_KERNEL);
 23.1421 +		if(tapfds[i] == NULL) return -ENOMEM;
 23.1422 +		info->minor = i;
 23.1423 +		info->pid = 0;
 23.1424 +		info->blkif = NULL;
 23.1425 +
 23.1426 +		ret = devfs_mk_cdev(MKDEV(BLKTAP_DEV_MAJOR, i),
 23.1427 +			S_IFCHR|S_IRUGO|S_IWUSR, "xen/blktap%d", i);
 23.1428 +
 23.1429 +		if(ret != 0) return -ENOMEM;
 23.1430 +		info->dev_pending = info->dev_inuse = 0;
 23.1431 +
 23.1432 +		DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
 23.1433 +	}
 23.1434 +	
 23.1435 +	DPRINTK("Blktap device successfully created\n");
 23.1436 +
 23.1437 +	return 0;
 23.1438 +}
 23.1439 +
 23.1440 +module_init(blkif_init);
 23.1441 +
 23.1442 +MODULE_LICENSE("Dual BSD/GPL");
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/common.h	Tue Jul 25 12:19:05 2006 -0600
    24.3 @@ -0,0 +1,120 @@
    24.4 +/* 
    24.5 + * This program is free software; you can redistribute it and/or
    24.6 + * modify it under the terms of the GNU General Public License version 2
    24.7 + * as published by the Free Software Foundation; or, when distributed
    24.8 + * separately from the Linux kernel or incorporated into other
    24.9 + * software packages, subject to the following license:
   24.10 + * 
   24.11 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   24.12 + * of this source file (the "Software"), to deal in the Software without
   24.13 + * restriction, including without limitation the rights to use, copy, modify,
   24.14 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   24.15 + * and to permit persons to whom the Software is furnished to do so, subject to
   24.16 + * the following conditions:
   24.17 + * 
   24.18 + * The above copyright notice and this permission notice shall be included in
   24.19 + * all copies or substantial portions of the Software.
   24.20 + * 
   24.21 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   24.22 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   24.23 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   24.24 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   24.25 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   24.26 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   24.27 + * IN THE SOFTWARE.
   24.28 + */
   24.29 +
   24.30 +#ifndef __BLKIF__BACKEND__COMMON_H__
   24.31 +#define __BLKIF__BACKEND__COMMON_H__
   24.32 +
   24.33 +#include <linux/config.h>
   24.34 +#include <linux/version.h>
   24.35 +#include <linux/module.h>
   24.36 +#include <linux/interrupt.h>
   24.37 +#include <linux/slab.h>
   24.38 +#include <linux/blkdev.h>
   24.39 +#include <linux/vmalloc.h>
   24.40 +#include <asm/io.h>
   24.41 +#include <asm/setup.h>
   24.42 +#include <asm/pgalloc.h>
   24.43 +#include <xen/evtchn.h>
   24.44 +#include <asm/hypervisor.h>
   24.45 +#include <xen/interface/io/blkif.h>
   24.46 +#include <xen/interface/io/ring.h>
   24.47 +#include <xen/gnttab.h>
   24.48 +#include <xen/driver_util.h>
   24.49 +
   24.50 +#define DPRINTK(_f, _a...) pr_debug("(file=%s, line=%d) " _f, \
   24.51 +                                    __FILE__ , __LINE__ , ## _a )
   24.52 +
   24.53 +#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
   24.54 +
   24.55 +struct backend_info; 
   24.56 +
   24.57 +typedef struct blkif_st {
   24.58 +	/* Unique identifier for this interface. */
   24.59 +	domid_t           domid;
   24.60 +	unsigned int      handle;
   24.61 +	/* Physical parameters of the comms window. */
   24.62 +	unsigned int      evtchn;
   24.63 +	unsigned int      irq;
   24.64 +	/* Comms information. */
   24.65 +	blkif_back_ring_t blk_ring;
   24.66 +	struct vm_struct *blk_ring_area;
   24.67 +	/* Back pointer to the backend_info. */
   24.68 +	struct backend_info *be; 
   24.69 +	/* Private fields. */
   24.70 +	spinlock_t       blk_ring_lock;
   24.71 +	atomic_t         refcnt;
   24.72 +
   24.73 +	wait_queue_head_t   wq;
   24.74 +	struct task_struct  *xenblkd;
   24.75 +	unsigned int        waiting_reqs;
   24.76 +	request_queue_t     *plug;
   24.77 +
   24.78 +	/* statistics */
   24.79 +	unsigned long       st_print;
   24.80 +	int                 st_rd_req;
   24.81 +	int                 st_wr_req;
   24.82 +	int                 st_oo_req;
   24.83 +
   24.84 +	wait_queue_head_t waiting_to_free;
   24.85 +
   24.86 +	grant_handle_t shmem_handle;
   24.87 +	grant_ref_t    shmem_ref;
   24.88 +	
   24.89 +	int		dev_num;
   24.90 +	uint64_t        sectors;
   24.91 +} blkif_t;
   24.92 +
   24.93 +blkif_t *tap_alloc_blkif(domid_t domid);
   24.94 +void tap_blkif_free(blkif_t *blkif);
   24.95 +int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
   24.96 +		  unsigned int evtchn);
   24.97 +
   24.98 +#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
   24.99 +#define blkif_put(_b)					\
  24.100 +	do {						\
  24.101 +		if (atomic_dec_and_test(&(_b)->refcnt))	\
  24.102 +			wake_up(&(_b)->waiting_to_free);\
  24.103 +	} while (0)
  24.104 +
  24.105 +
  24.106 +struct phys_req {
  24.107 +	unsigned short       dev;
  24.108 +	unsigned short       nr_sects;
  24.109 +	struct block_device *bdev;
  24.110 +	blkif_sector_t       sector_number;
  24.111 +};
  24.112 +
  24.113 +void tap_blkif_interface_init(void);
  24.114 +
  24.115 +void tap_blkif_xenbus_init(void);
  24.116 +
  24.117 +irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
  24.118 +int tap_blkif_schedule(void *arg);
  24.119 +
  24.120 +int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif);
  24.121 +void signal_tapdisk(int idx);
  24.122 +
  24.123 +#endif /* __BLKIF__BACKEND__COMMON_H__ */
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/interface.c	Tue Jul 25 12:19:05 2006 -0600
    25.3 @@ -0,0 +1,165 @@
    25.4 +/******************************************************************************
    25.5 + * drivers/xen/blktap/interface.c
    25.6 + * 
    25.7 + * Block-device interface management.
    25.8 + * 
    25.9 + * Copyright (c) 2004, Keir Fraser
   25.10 + *
   25.11 + * This program is free software; you can redistribute it and/or
   25.12 + * modify it under the terms of the GNU General Public License version 2
   25.13 + * as published by the Free Software Foundation; or, when distributed
   25.14 + * separately from the Linux kernel or incorporated into other
   25.15 + * software packages, subject to the following license:
   25.16 + *
   25.17 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   25.18 + * of this source file (the "Software"), to deal in the Software without
   25.19 + * restriction, including without limitation the rights to use, copy, modify,
   25.20 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   25.21 + * and to permit persons to whom the Software is furnished to do so, subject to
   25.22 + * the following conditions:
   25.23 + *
   25.24 + * The above copyright notice and this permission notice shall be included in
   25.25 + * all copies or substantial portions of the Software.
   25.26 + *
   25.27 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   25.28 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   25.29 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   25.30 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   25.31 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   25.32 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   25.33 + * IN THE SOFTWARE.
   25.34 +
   25.35 + */
   25.36 +
   25.37 +#include "common.h"
   25.38 +#include <xen/evtchn.h>
   25.39 +
   25.40 +static kmem_cache_t *blkif_cachep;
   25.41 +
   25.42 +blkif_t *tap_alloc_blkif(domid_t domid)
   25.43 +{
   25.44 +	blkif_t *blkif;
   25.45 +
   25.46 +	blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
   25.47 +	if (!blkif)
   25.48 +		return ERR_PTR(-ENOMEM);
   25.49 +
   25.50 +	memset(blkif, 0, sizeof(*blkif));
   25.51 +	blkif->domid = domid;
   25.52 +	spin_lock_init(&blkif->blk_ring_lock);
   25.53 +	atomic_set(&blkif->refcnt, 1);
   25.54 +	init_waitqueue_head(&blkif->wq);
   25.55 +	blkif->st_print = jiffies;
   25.56 +	init_waitqueue_head(&blkif->waiting_to_free);
   25.57 +
   25.58 +	return blkif;
   25.59 +}
   25.60 +
   25.61 +static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
   25.62 +{
   25.63 +	struct gnttab_map_grant_ref op;
   25.64 +	int ret;
   25.65 +
   25.66 +	gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
   25.67 +			  GNTMAP_host_map, shared_page, blkif->domid);
   25.68 +
   25.69 +	lock_vm_area(blkif->blk_ring_area);
   25.70 +	ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1);
   25.71 +	unlock_vm_area(blkif->blk_ring_area);
   25.72 +	BUG_ON(ret);
   25.73 +
   25.74 +	if (op.status) {
   25.75 +		DPRINTK(" Grant table operation failure !\n");
   25.76 +		return op.status;
   25.77 +	}
   25.78 +
   25.79 +	blkif->shmem_ref = shared_page;
   25.80 +	blkif->shmem_handle = op.handle;
   25.81 +
   25.82 +#ifdef CONFIG_XEN_IA64_DOM0_NON_VP
   25.83 +	/* on some arch's, map_grant_ref behaves like mmap, in that the
   25.84 +	 * passed address is a hint and a different address may be returned */
   25.85 +	blkif->blk_ring_area->addr = gnttab_map_vaddr(op);
   25.86 +#endif
   25.87 +
   25.88 +	return 0;
   25.89 +}
   25.90 +
   25.91 +static void unmap_frontend_page(blkif_t *blkif)
   25.92 +{
   25.93 +	struct gnttab_unmap_grant_ref op;
   25.94 +	int ret;
   25.95 +
   25.96 +	gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
   25.97 +			    GNTMAP_host_map, blkif->shmem_handle);
   25.98 +
   25.99 +	lock_vm_area(blkif->blk_ring_area);
  25.100 +	ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1);
  25.101 +	unlock_vm_area(blkif->blk_ring_area);
  25.102 +	BUG_ON(ret);
  25.103 +}
  25.104 +
  25.105 +int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
  25.106 +		  unsigned int evtchn)
  25.107 +{
  25.108 +	blkif_sring_t *sring;
  25.109 +	int err;
  25.110 +	struct evtchn_bind_interdomain bind_interdomain;
  25.111 +
  25.112 +	/* Already connected through? */
  25.113 +	if (blkif->irq)
  25.114 +		return 0;
  25.115 +
  25.116 +	if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
  25.117 +		return -ENOMEM;
  25.118 +
  25.119 +	err = map_frontend_page(blkif, shared_page);
  25.120 +	if (err) {
  25.121 +		free_vm_area(blkif->blk_ring_area);
  25.122 +		return err;
  25.123 +	}
  25.124 +
  25.125 +	bind_interdomain.remote_dom  = blkif->domid;
  25.126 +	bind_interdomain.remote_port = evtchn;
  25.127 +
  25.128 +	err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
  25.129 +					  &bind_interdomain);
  25.130 +	if (err) {
  25.131 +		unmap_frontend_page(blkif);
  25.132 +		free_vm_area(blkif->blk_ring_area);
  25.133 +		return err;
  25.134 +	}
  25.135 +
  25.136 +	blkif->evtchn = bind_interdomain.local_port;
  25.137 +
  25.138 +	sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
  25.139 +	BACK_RING_INIT(&blkif->blk_ring, sring, PAGE_SIZE);
  25.140 +
  25.141 +	blkif->irq = bind_evtchn_to_irqhandler(
  25.142 +		blkif->evtchn, tap_blkif_be_int, 0, "blkif-backend", blkif);
  25.143 +
  25.144 +	return 0;
  25.145 +}
  25.146 +
  25.147 +void tap_blkif_free(blkif_t *blkif)
  25.148 +{
  25.149 +	atomic_dec(&blkif->refcnt);
  25.150 +	wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
  25.151 +
  25.152 +	/* Already disconnected? */
  25.153 +	if (blkif->irq)
  25.154 +		unbind_from_irqhandler(blkif->irq, blkif);
  25.155 +
  25.156 +	if (blkif->blk_ring.sring) {
  25.157 +		unmap_frontend_page(blkif);
  25.158 +		free_vm_area(blkif->blk_ring_area);
  25.159 +	}
  25.160 +
  25.161 +	kmem_cache_free(blkif_cachep, blkif);
  25.162 +}
  25.163 +
  25.164 +void __init tap_blkif_interface_init(void)
  25.165 +{
  25.166 +	blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t), 
  25.167 +					 0, 0, NULL, NULL);
  25.168 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/linux-2.6-xen-sparse/drivers/xen/blktap/xenbus.c	Tue Jul 25 12:19:05 2006 -0600
    26.3 @@ -0,0 +1,354 @@
    26.4 +/* drivers/xen/blktap/xenbus.c
    26.5 + *
    26.6 + * Xenbus code for blktap
    26.7 + *
    26.8 + * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
    26.9 + *
   26.10 + * Based on the blkback xenbus code:
   26.11 + *
   26.12 + * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
   26.13 + * Copyright (C) 2005 XenSource Ltd
   26.14 + *
   26.15 + * This program is free software; you can redistribute it and/or
   26.16 + * modify it under the terms of the GNU General Public License version 2
   26.17 + * as published by the Free Software Foundation; or, when distributed
   26.18 + * separately from the Linux kernel or incorporated into other
   26.19 + * software packages, subject to the following license:
   26.20 + *
   26.21 + * Permission is hereby granted, free of charge, to any person obtaining a copy
   26.22 + * of this source file (the "Software"), to deal in the Software without
   26.23 + * restriction, including without limitation the rights to use, copy, modify,
   26.24 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
   26.25 + * and to permit persons to whom the Software is furnished to do so, subject to
   26.26 + * the following conditions:
   26.27 + *
   26.28 + * The above copyright notice and this permission notice shall be included in
   26.29 + * all copies or substantial portions of the Software.
   26.30 + *
   26.31 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   26.32 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   26.33 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   26.34 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   26.35 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   26.36 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   26.37 + * IN THE SOFTWARE.
   26.38 + */
   26.39 +
   26.40 +#include <stdarg.h>
   26.41 +#include <linux/module.h>
   26.42 +#include <linux/kthread.h>
   26.43 +#include <xen/xenbus.h>
   26.44 +#include "common.h"
   26.45 +
   26.46 +
   26.47 +struct backend_info
   26.48 +{
   26.49 +	struct xenbus_device *dev;
   26.50 +	blkif_t *blkif;
   26.51 +	struct xenbus_watch backend_watch;
   26.52 +	int xenbus_id;
   26.53 +};
   26.54 +
   26.55 +
   26.56 +static void connect(struct backend_info *);
   26.57 +static int connect_ring(struct backend_info *);
   26.58 +static int blktap_remove(struct xenbus_device *dev);
   26.59 +static int blktap_probe(struct xenbus_device *dev,
   26.60 +			 const struct xenbus_device_id *id);
   26.61 +static void tap_backend_changed(struct xenbus_watch *, const char **,
   26.62 +			    unsigned int);
   26.63 +static void tap_frontend_changed(struct xenbus_device *dev,
   26.64 +			     enum xenbus_state frontend_state);
   26.65 +
   26.66 +static int strsep_len(const char *str, char c, unsigned int len)
   26.67 +{
   26.68 +        unsigned int i;
   26.69 +
   26.70 +        for (i = 0; str[i]; i++)
   26.71 +                if (str[i] == c) {
   26.72 +                        if (len == 0)
   26.73 +                                return i;
   26.74 +                        len--;
   26.75 +                }
   26.76 +        return (len == 0) ? i : -ERANGE;
   26.77 +}
   26.78 +
   26.79 +static long get_id(const char *str)
   26.80 +{
   26.81 +        int len,end;
   26.82 +        const char *ptr;
   26.83 +        char *tptr, num[10];
   26.84 +	
   26.85 +        len = strsep_len(str, '/', 2);
   26.86 +        end = strlen(str);
   26.87 +        if ( (len < 0) || (end < 0) ) return -1;
   26.88 +	
   26.89 +        ptr = str + len + 1;
   26.90 +        strncpy(num,ptr,end - len);
   26.91 +        tptr = num + (end - (len + 1));
   26.92 +        *tptr = '\0';
   26.93 +	DPRINTK("Get_id called for %s (%s)\n",str,num);
   26.94 +	
   26.95 +        return simple_strtol(num, NULL, 10);
   26.96 +}				
   26.97 +
   26.98 +static void tap_update_blkif_status(blkif_t *blkif)
   26.99 +{ 
  26.100 +	int err;
  26.101 +
  26.102 +	/* Not ready to connect? */
  26.103 +	if(!blkif->irq || !blkif->sectors) {
  26.104 +		return;
  26.105 +	} 
  26.106 +
  26.107 +	/* Already connected? */
  26.108 +	if (blkif->be->dev->state == XenbusStateConnected)
  26.109 +		return;
  26.110 +
  26.111 +	/* Attempt to connect: exit if we fail to. */
  26.112 +	connect(blkif->be);
  26.113 +	if (blkif->be->dev->state != XenbusStateConnected)
  26.114 +		return;
  26.115 +
  26.116 +	blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif,
  26.117 +				     "xvd %d",
  26.118 +				     blkif->domid);
  26.119 +
  26.120 +	if (IS_ERR(blkif->xenblkd)) {
  26.121 +		err = PTR_ERR(blkif->xenblkd);
  26.122 +		blkif->xenblkd = NULL;
  26.123 +		xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
  26.124 +		WPRINTK("Error starting thread\n");
  26.125 +	}
  26.126 +}
  26.127 +
  26.128 +static int blktap_remove(struct xenbus_device *dev)
  26.129 +{
  26.130 +	struct backend_info *be = dev->dev.driver_data;
  26.131 +
  26.132 +	if (be->backend_watch.node) {
  26.133 +		unregister_xenbus_watch(&be->backend_watch);
  26.134 +		kfree(be->backend_watch.node);
  26.135 +		be->backend_watch.node = NULL;
  26.136 +	}
  26.137 +	if (be->blkif) {
  26.138 +		if (be->blkif->xenblkd)
  26.139 +			kthread_stop(be->blkif->xenblkd);
  26.140 +		signal_tapdisk(be->blkif->dev_num);
  26.141 +		tap_blkif_free(be->blkif);
  26.142 +		be->blkif = NULL;
  26.143 +	}
  26.144 +	kfree(be);
  26.145 +	dev->dev.driver_data = NULL;
  26.146 +	return 0;
  26.147 +}
  26.148 +
  26.149 +/**
  26.150 + * Entry point to this code when a new device is created.  Allocate
  26.151 + * the basic structures, and watch the store waiting for the
  26.152 + * user-space program to tell us the physical device info.  Switch to
  26.153 + * InitWait.
  26.154 + */
  26.155 +static int blktap_probe(struct xenbus_device *dev,
  26.156 +			 const struct xenbus_device_id *id)
  26.157 +{
  26.158 +	int err;
  26.159 +	struct backend_info *be = kzalloc(sizeof(struct backend_info),
  26.160 +					  GFP_KERNEL);
  26.161 +	if (!be) {
  26.162 +		xenbus_dev_fatal(dev, -ENOMEM,
  26.163 +				 "allocating backend structure");
  26.164 +		return -ENOMEM;
  26.165 +	}
  26.166 +
  26.167 +	be->dev = dev;
  26.168 +	dev->dev.driver_data = be;
  26.169 +	be->xenbus_id = get_id(dev->nodename);
  26.170 +
  26.171 +	be->blkif = tap_alloc_blkif(dev->otherend_id);
  26.172 +	if (IS_ERR(be->blkif)) {
  26.173 +		err = PTR_ERR(be->blkif);
  26.174 +		be->blkif = NULL;
  26.175 +		xenbus_dev_fatal(dev, err, "creating block interface");
  26.176 +		goto fail;
  26.177 +	}
  26.178 +
  26.179 +	/* setup back pointer */
  26.180 +	be->blkif->be = be; 
  26.181 +	be->blkif->sectors = 0;
  26.182 +
  26.183 +	/* set a watch on disk info, waiting for userspace to update details*/
  26.184 +	err = xenbus_watch_path2(dev, dev->nodename, "info",
  26.185 +				 &be->backend_watch, tap_backend_changed);
  26.186 +	if (err)
  26.187 +		goto fail;
  26.188 +	
  26.189 +	err = xenbus_switch_state(dev, XenbusStateInitWait);
  26.190 +	if (err)
  26.191 +		goto fail;
  26.192 +	return 0;
  26.193 +
  26.194 +fail:
  26.195 +	DPRINTK("blktap probe failed");
  26.196 +	blktap_remove(dev);
  26.197 +	return err;
  26.198 +}
  26.199 +
  26.200 +
  26.201 +/**
  26.202 + * Callback received when the user space code has placed the device
  26.203 + * information in xenstore. 
  26.204 + */
  26.205 +static void tap_backend_changed(struct xenbus_watch *watch,
  26.206 +			    const char **vec, unsigned int len)
  26.207 +{
  26.208 +	int err;
  26.209 +	unsigned long info;
  26.210 +	struct backend_info *be
  26.211 +		= container_of(watch, struct backend_info, backend_watch);
  26.212 +	struct xenbus_device *dev = be->dev;
  26.213 +	
  26.214 +	/** 
  26.215 +	 * Check to see whether userspace code has opened the image 
  26.216 +	 * and written sector
  26.217 +	 * and disk info to xenstore
  26.218 +	 */
  26.219 +	err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, 
  26.220 +			    NULL);	
  26.221 +	if (err) {
  26.222 +		xenbus_dev_error(dev, err, "getting info");
  26.223 +		return;
  26.224 +	}
  26.225 +
  26.226 +	DPRINTK("Userspace update on disk info, %lu\n",info);
  26.227 +
  26.228 +	err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu", 
  26.229 +			    &be->blkif->sectors, NULL);
  26.230 +
  26.231 +	/* Associate tap dev with domid*/
  26.232 +	be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id, 
  26.233 +					  be->blkif);
  26.234 +	DPRINTK("Thread started for domid [%d], connecting disk\n", 
  26.235 +		be->blkif->dev_num);
  26.236 +
  26.237 +	tap_update_blkif_status(be->blkif);
  26.238 +}
  26.239 +
  26.240 +/**
  26.241 + * Callback received when the frontend's state changes.
  26.242 + */
  26.243 +static void tap_frontend_changed(struct xenbus_device *dev,
  26.244 +			     enum xenbus_state frontend_state)
  26.245 +{
  26.246 +	struct backend_info *be = dev->dev.driver_data;
  26.247 +	int err;
  26.248 +
  26.249 +	DPRINTK("");
  26.250 +
  26.251 +	switch (frontend_state) {
  26.252 +	case XenbusStateInitialising:
  26.253 +		break;
  26.254 +
  26.255 +	case XenbusStateInitialised:
  26.256 +	case XenbusStateConnected:
  26.257 +		/* Ensure we connect even when two watches fire in 
  26.258 +		   close successsion and we miss the intermediate value 
  26.259 +		   of frontend_state. */
  26.260 +		if (dev->state == XenbusStateConnected)
  26.261 +			break;
  26.262 +
  26.263 +		err = connect_ring(be);
  26.264 +		if (err)
  26.265 +			break;
  26.266 +		tap_update_blkif_status(be->blkif);
  26.267 +		break;
  26.268 +
  26.269 +	case XenbusStateClosing:
  26.270 +		xenbus_switch_state(dev, XenbusStateClosing);
  26.271 +		break;
  26.272 +
  26.273 +	case XenbusStateClosed:
  26.274 +		device_unregister(&dev->dev);
  26.275 +		break;
  26.276 +
  26.277 +	case XenbusStateUnknown:
  26.278 +	case XenbusStateInitWait:
  26.279 +	default:
  26.280 +		xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
  26.281 +				 frontend_state);
  26.282 +		break;
  26.283 +	}
  26.284 +}
  26.285 +
  26.286 +
  26.287 +/**
  26.288 + * Switch to Connected state.
  26.289 + */
  26.290 +static void connect(struct backend_info *be)
  26.291 +{
  26.292 +	int err;
  26.293 +
  26.294 +	struct xenbus_device *dev = be->dev;
  26.295 +
  26.296 +	err = xenbus_switch_state(dev, XenbusStateConnected);
  26.297 +	if (err)
  26.298 +		xenbus_dev_fatal(dev, err, "switching to Connected state",
  26.299 +				 dev->nodename);
  26.300 +
  26.301 +	return;
  26.302 +}
  26.303 +
  26.304 +
  26.305 +static int connect_ring(struct backend_info *be)
  26.306 +{
  26.307 +	struct xenbus_device *dev = be->dev;
  26.308 +	unsigned long ring_ref;
  26.309 +	unsigned int evtchn;
  26.310 +	int err;
  26.311 +
  26.312 +	DPRINTK("%s", dev->otherend);
  26.313 +
  26.314 +	err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", 
  26.315 +			    &ring_ref, "event-channel", "%u", &evtchn, NULL);
  26.316 +	if (err) {
  26.317 +		xenbus_dev_fatal(dev, err,
  26.318 +				 "reading %s/ring-ref and event-channel",
  26.319 +				 dev->otherend);
  26.320 +		return err;
  26.321 +	}
  26.322 +
  26.323 +	/* Map the shared frame, irq etc. */
  26.324 +	err = tap_blkif_map(be->blkif, ring_ref, evtchn);
  26.325 +	if (err) {
  26.326 +		xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
  26.327 +				 ring_ref, evtchn);
  26.328 +		return err;
  26.329 +	} 
  26.330 +
  26.331 +	return 0;
  26.332 +}
  26.333 +
  26.334 +
  26.335 +/* ** Driver Registration ** */
  26.336 +
  26.337 +
  26.338 +static struct xenbus_device_id blktap_ids[] = {
  26.339 +	{ "tap" },
  26.340 +	{ "" }
  26.341 +};
  26.342 +
  26.343 +
  26.344 +static struct xenbus_driver blktap = {
  26.345 +	.name = "tap",
  26.346 +	.owner = THIS_MODULE,
  26.347 +	.ids = blktap_ids,
  26.348 +	.probe = blktap_probe,
  26.349 +	.remove = blktap_remove,
  26.350 +	.otherend_changed = tap_frontend_changed
  26.351 +};
  26.352 +
  26.353 +
  26.354 +void tap_blkif_xenbus_init(void)
  26.355 +{
  26.356 +	xenbus_register_backend(&blktap);
  26.357 +}
    27.1 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c	Tue Jul 25 09:51:50 2006 -0600
    27.2 +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c	Tue Jul 25 12:19:05 2006 -0600
    27.3 @@ -536,18 +536,27 @@ static void xencons_close(struct tty_str
    27.4  	if (DUMMY_TTY(tty))
    27.5  		return;
    27.6  
    27.7 -	if (tty->count == 1) {
    27.8 -		tty->closing = 1;
    27.9 -		tty_wait_until_sent(tty, 0);
   27.10 -		if (DRV(tty->driver)->flush_buffer != NULL)
   27.11 -			DRV(tty->driver)->flush_buffer(tty);
   27.12 -		if (tty->ldisc.flush_buffer != NULL)
   27.13 -			tty->ldisc.flush_buffer(tty);
   27.14 -		tty->closing = 0;
   27.15 -		spin_lock_irqsave(&xencons_lock, flags);
   27.16 -		xencons_tty = NULL;
   27.17 -		spin_unlock_irqrestore(&xencons_lock, flags);
   27.18 +	down(&tty_sem);
   27.19 +
   27.20 +	if (tty->count != 1) {
   27.21 +		up(&tty_sem);
   27.22 +		return;
   27.23  	}
   27.24 +
   27.25 +	/* Prevent other threads from re-opening this tty. */
   27.26 +	set_bit(TTY_CLOSING, &tty->flags);
   27.27 +	up(&tty_sem);
   27.28 +
   27.29 +	tty->closing = 1;
   27.30 +	tty_wait_until_sent(tty, 0);
   27.31 +	if (DRV(tty->driver)->flush_buffer != NULL)
   27.32 +		DRV(tty->driver)->flush_buffer(tty);
   27.33 +	if (tty->ldisc.flush_buffer != NULL)
   27.34 +		tty->ldisc.flush_buffer(tty);
   27.35 +	tty->closing = 0;
   27.36 +	spin_lock_irqsave(&xencons_lock, flags);
   27.37 +	xencons_tty = NULL;
   27.38 +	spin_unlock_irqrestore(&xencons_lock, flags);
   27.39  }
   27.40  
   27.41  static struct tty_operations xencons_ops = {
    28.1 --- a/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c	Tue Jul 25 09:51:50 2006 -0600
    28.2 +++ b/linux-2.6-xen-sparse/drivers/xen/tpmback/tpmback.c	Tue Jul 25 12:19:05 2006 -0600
    28.3 @@ -852,11 +852,11 @@ static void processing_timeout(unsigned 
    28.4  	 */
    28.5  	if (pak == packet_find_packet(&dataex.pending_pak, pak) ||
    28.6  	    pak == packet_find_packet(&dataex.current_pak, pak)) {
    28.7 -		list_del(&pak->next);
    28.8  		if ((pak->flags & PACKET_FLAG_DISCARD_RESPONSE) == 0) {
    28.9  			tpm_send_fail_message(pak, pak->req_tag);
   28.10  		}
   28.11 -		packet_free(pak);
   28.12 +		/* discard future responses */
   28.13 +		pak->flags |= PACKET_FLAG_DISCARD_RESPONSE;
   28.14  	}
   28.15  
   28.16  	write_unlock_irqrestore(&dataex.pak_lock, flags);
    29.1 --- a/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/dma-mapping.h	Tue Jul 25 09:51:50 2006 -0600
    29.2 +++ b/linux-2.6-xen-sparse/include/asm-i386/mach-xen/asm/dma-mapping.h	Tue Jul 25 12:19:05 2006 -0600
    29.3 @@ -120,7 +120,6 @@ dma_set_mask(struct device *dev, u64 mas
    29.4  	return 0;
    29.5  }
    29.6  
    29.7 -#ifdef __i386__
    29.8  static inline int
    29.9  dma_get_cache_alignment(void)
   29.10  {
   29.11 @@ -128,7 +127,6 @@ dma_get_cache_alignment(void)
   29.12  	 * maximum possible, to be safe */
   29.13  	return (1 << INTERNODE_CACHE_SHIFT);
   29.14  }
   29.15 -#endif
   29.16  
   29.17  #define dma_is_consistent(d)	(1)
   29.18  
    30.1 --- a/linux-2.6-xen-sparse/include/linux/skbuff.h	Tue Jul 25 09:51:50 2006 -0600
    30.2 +++ b/linux-2.6-xen-sparse/include/linux/skbuff.h	Tue Jul 25 12:19:05 2006 -0600
    30.3 @@ -1412,5 +1412,10 @@ static inline void nf_bridge_get(struct 
    30.4  static inline void nf_reset(struct sk_buff *skb) {}
    30.5  #endif /* CONFIG_NETFILTER */
    30.6  
    30.7 +static inline int skb_is_gso(const struct sk_buff *skb)
    30.8 +{
    30.9 +	return skb_shinfo(skb)->gso_size;
   30.10 +}
   30.11 +
   30.12  #endif	/* __KERNEL__ */
   30.13  #endif	/* _LINUX_SKBUFF_H */
    31.1 --- a/linux-2.6-xen-sparse/net/core/dev.c	Tue Jul 25 09:51:50 2006 -0600
    31.2 +++ b/linux-2.6-xen-sparse/net/core/dev.c	Tue Jul 25 12:19:05 2006 -0600
    31.3 @@ -1089,9 +1089,17 @@ int skb_checksum_help(struct sk_buff *sk
    31.4  	unsigned int csum;
    31.5  	int ret = 0, offset = skb->h.raw - skb->data;
    31.6  
    31.7 -	if (inward) {
    31.8 -		skb->ip_summed = CHECKSUM_NONE;
    31.9 -		goto out;
   31.10 +	if (inward)
   31.11 +		goto out_set_summed;
   31.12 +
   31.13 +	if (unlikely(skb_shinfo(skb)->gso_size)) {
   31.14 +		static int warned;
   31.15 +
   31.16 +		WARN_ON(!warned);
   31.17 +		warned = 1;
   31.18 +
   31.19 +		/* Let GSO fix up the checksum. */
   31.20 +		goto out_set_summed;
   31.21  	}
   31.22  
   31.23  	if (skb_cloned(skb)) {
   31.24 @@ -1108,6 +1116,8 @@ int skb_checksum_help(struct sk_buff *sk
   31.25  	BUG_ON(skb->csum + 2 > offset);
   31.26  
   31.27  	*(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
   31.28 +
   31.29 +out_set_summed:
   31.30  	skb->ip_summed = CHECKSUM_NONE;
   31.31  out:	
   31.32  	return ret;
   31.33 @@ -1128,17 +1138,35 @@ struct sk_buff *skb_gso_segment(struct s
   31.34  	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
   31.35  	struct packet_type *ptype;
   31.36  	int type = skb->protocol;
   31.37 +	int err;
   31.38  
   31.39  	BUG_ON(skb_shinfo(skb)->frag_list);
   31.40 -	BUG_ON(skb->ip_summed != CHECKSUM_HW);
   31.41  
   31.42  	skb->mac.raw = skb->data;
   31.43  	skb->mac_len = skb->nh.raw - skb->data;
   31.44  	__skb_pull(skb, skb->mac_len);
   31.45  
   31.46 +	if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
   31.47 +		static int warned;
   31.48 +
   31.49 +		WARN_ON(!warned);
   31.50 +		warned = 1;
   31.51 +
   31.52 +		if (skb_header_cloned(skb) &&
   31.53 +		    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
   31.54 +			return ERR_PTR(err);
   31.55 +	}
   31.56 +
   31.57  	rcu_read_lock();
   31.58  	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
   31.59  		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
   31.60 +			if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
   31.61 +				err = ptype->gso_send_check(skb);
   31.62 +				segs = ERR_PTR(err);
   31.63 +				if (err || skb_gso_ok(skb, features))
   31.64 +					break;
   31.65 +				__skb_push(skb, skb->data - skb->nh.raw);
   31.66 +			}
   31.67  			segs = ptype->gso_segment(skb, features);
   31.68  			break;
   31.69  		}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/patches/linux-2.6.16.13/blktap-aio-16_03_06.patch	Tue Jul 25 12:19:05 2006 -0600
    32.3 @@ -0,0 +1,297 @@
    32.4 +diff -pruN ../pristine-linux-2.6.16-rc5/fs/aio.c ./fs/aio.c
    32.5 +--- ../pristine-linux-2.6.16-rc5/fs/aio.c	2006-03-14 14:10:10.827401387 +0000
    32.6 ++++ ./fs/aio.c	2006-03-16 09:57:53.898316582 +0000
    32.7 +@@ -34,6 +34,11 @@
    32.8 + #include <asm/uaccess.h>
    32.9 + #include <asm/mmu_context.h>
   32.10 + 
   32.11 ++#ifdef CONFIG_EPOLL
   32.12 ++#include <linux/poll.h>
   32.13 ++#include <linux/eventpoll.h>
   32.14 ++#endif
   32.15 ++
   32.16 + #if DEBUG > 1
   32.17 + #define dprintk		printk
   32.18 + #else
   32.19 +@@ -1016,6 +1021,10 @@ put_rq:
   32.20 + 	if (waitqueue_active(&ctx->wait))
   32.21 + 		wake_up(&ctx->wait);
   32.22 + 
   32.23 ++#ifdef CONFIG_EPOLL
   32.24 ++	if (ctx->file && waitqueue_active(&ctx->poll_wait))
   32.25 ++		wake_up(&ctx->poll_wait);
   32.26 ++#endif
   32.27 + 	if (ret)
   32.28 + 		put_ioctx(ctx);
   32.29 + 
   32.30 +@@ -1025,6 +1034,8 @@ put_rq:
   32.31 + /* aio_read_evt
   32.32 +  *	Pull an event off of the ioctx's event ring.  Returns the number of 
   32.33 +  *	events fetched (0 or 1 ;-)
   32.34 ++ *	If ent parameter is 0, just returns the number of events that would
   32.35 ++ *	be fetched.
   32.36 +  *	FIXME: make this use cmpxchg.
   32.37 +  *	TODO: make the ringbuffer user mmap()able (requires FIXME).
   32.38 +  */
   32.39 +@@ -1047,13 +1058,18 @@ static int aio_read_evt(struct kioctx *i
   32.40 + 
   32.41 + 	head = ring->head % info->nr;
   32.42 + 	if (head != ring->tail) {
   32.43 +-		struct io_event *evp = aio_ring_event(info, head, KM_USER1);
   32.44 +-		*ent = *evp;
   32.45 +-		head = (head + 1) % info->nr;
   32.46 +-		smp_mb(); /* finish reading the event before updatng the head */
   32.47 +-		ring->head = head;
   32.48 +-		ret = 1;
   32.49 +-		put_aio_ring_event(evp, KM_USER1);
   32.50 ++		if (ent) { /* event requested */
   32.51 ++			struct io_event *evp =
   32.52 ++				aio_ring_event(info, head, KM_USER1);
   32.53 ++			*ent = *evp;
   32.54 ++			head = (head + 1) % info->nr;
   32.55 ++			/* finish reading the event before updatng the head */
   32.56 ++			smp_mb();
   32.57 ++			ring->head = head;
   32.58 ++			ret = 1;
   32.59 ++			put_aio_ring_event(evp, KM_USER1);
   32.60 ++		} else /* only need to know availability */
   32.61 ++			ret = 1;
   32.62 + 	}
   32.63 + 	spin_unlock(&info->ring_lock);
   32.64 + 
   32.65 +@@ -1236,9 +1252,78 @@ static void io_destroy(struct kioctx *io
   32.66 + 
   32.67 + 	aio_cancel_all(ioctx);
   32.68 + 	wait_for_all_aios(ioctx);
   32.69 ++#ifdef CONFIG_EPOLL
   32.70 ++	/* forget the poll file, but it's up to the user to close it */
   32.71 ++	if (ioctx->file) {
   32.72 ++		ioctx->file->private_data = 0;
   32.73 ++		ioctx->file = 0;
   32.74 ++	}
   32.75 ++#endif
   32.76 + 	put_ioctx(ioctx);	/* once for the lookup */
   32.77 + }
   32.78 + 
   32.79 ++#ifdef CONFIG_EPOLL
   32.80 ++
   32.81 ++static int aio_queue_fd_close(struct inode *inode, struct file *file)
   32.82 ++{
   32.83 ++	struct kioctx *ioctx = file->private_data;
   32.84 ++	if (ioctx) {
   32.85 ++		file->private_data = 0;
   32.86 ++		spin_lock_irq(&ioctx->ctx_lock);
   32.87 ++		ioctx->file = 0;
   32.88 ++		spin_unlock_irq(&ioctx->ctx_lock);
   32.89 ++	}
   32.90 ++	return 0;
   32.91 ++}
   32.92 ++
   32.93 ++static unsigned int aio_queue_fd_poll(struct file *file, poll_table *wait)
   32.94 ++{	unsigned int pollflags = 0;
   32.95 ++	struct kioctx *ioctx = file->private_data;
   32.96 ++
   32.97 ++	if (ioctx) {
   32.98 ++
   32.99 ++		spin_lock_irq(&ioctx->ctx_lock);
  32.100 ++		/* Insert inside our poll wait queue */
  32.101 ++		poll_wait(file, &ioctx->poll_wait, wait);
  32.102 ++
  32.103 ++		/* Check our condition */
  32.104 ++		if (aio_read_evt(ioctx, 0))
  32.105 ++			pollflags = POLLIN | POLLRDNORM;
  32.106 ++		spin_unlock_irq(&ioctx->ctx_lock);
  32.107 ++	}
  32.108 ++
  32.109 ++	return pollflags;
  32.110 ++}
  32.111 ++
  32.112 ++static struct file_operations aioq_fops = {
  32.113 ++	.release	= aio_queue_fd_close,
  32.114 ++	.poll		= aio_queue_fd_poll
  32.115 ++};
  32.116 ++
  32.117 ++/* make_aio_fd:
  32.118 ++ *  Create a file descriptor that can be used to poll the event queue.
  32.119 ++ *  Based and piggybacked on the excellent epoll code.
  32.120 ++ */
  32.121 ++
  32.122 ++static int make_aio_fd(struct kioctx *ioctx)
  32.123 ++{
  32.124 ++	int error, fd;
  32.125 ++	struct inode *inode;
  32.126 ++	struct file *file;
  32.127 ++
  32.128 ++	error = ep_getfd(&fd, &inode, &file, NULL, &aioq_fops);
  32.129 ++	if (error)
  32.130 ++		return error;
  32.131 ++
  32.132 ++	/* associate the file with the IO context */
  32.133 ++	file->private_data = ioctx;
  32.134 ++	ioctx->file = file;
  32.135 ++	init_waitqueue_head(&ioctx->poll_wait);
  32.136 ++	return fd;
  32.137 ++}
  32.138 ++#endif
  32.139 ++
  32.140 ++
  32.141 + /* sys_io_setup:
  32.142 +  *	Create an aio_context capable of receiving at least nr_events.
  32.143 +  *	ctxp must not point to an aio_context that already exists, and
  32.144 +@@ -1251,18 +1336,30 @@ static void io_destroy(struct kioctx *io
  32.145 +  *	resources are available.  May fail with -EFAULT if an invalid
  32.146 +  *	pointer is passed for ctxp.  Will fail with -ENOSYS if not
  32.147 +  *	implemented.
  32.148 ++ *
  32.149 ++ *	To request a selectable fd, the user context has to be initialized
  32.150 ++ *	to 1, instead of 0, and the return value is the fd.
  32.151 ++ *	This keeps the system call compatible, since a non-zero value
  32.152 ++ *	was not allowed so far.
  32.153 +  */
  32.154 + asmlinkage long sys_io_setup(unsigned nr_events, aio_context_t __user *ctxp)
  32.155 + {
  32.156 + 	struct kioctx *ioctx = NULL;
  32.157 + 	unsigned long ctx;
  32.158 + 	long ret;
  32.159 ++	int make_fd = 0;
  32.160 + 
  32.161 + 	ret = get_user(ctx, ctxp);
  32.162 + 	if (unlikely(ret))
  32.163 + 		goto out;
  32.164 + 
  32.165 + 	ret = -EINVAL;
  32.166 ++#ifdef CONFIG_EPOLL
  32.167 ++	if (ctx == 1) {
  32.168 ++		make_fd = 1;
  32.169 ++		ctx = 0;
  32.170 ++	}
  32.171 ++#endif
  32.172 + 	if (unlikely(ctx || nr_events == 0)) {
  32.173 + 		pr_debug("EINVAL: io_setup: ctx %lu nr_events %u\n",
  32.174 + 		         ctx, nr_events);
  32.175 +@@ -1273,8 +1370,12 @@ asmlinkage long sys_io_setup(unsigned nr
  32.176 + 	ret = PTR_ERR(ioctx);
  32.177 + 	if (!IS_ERR(ioctx)) {
  32.178 + 		ret = put_user(ioctx->user_id, ctxp);
  32.179 +-		if (!ret)
  32.180 +-			return 0;
  32.181 ++#ifdef CONFIG_EPOLL
  32.182 ++		if (make_fd && ret >= 0)
  32.183 ++			ret = make_aio_fd(ioctx);
  32.184 ++#endif
  32.185 ++		if (ret >= 0)
  32.186 ++			return ret;
  32.187 + 
  32.188 + 		get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
  32.189 + 		io_destroy(ioctx);
  32.190 +
  32.191 +diff -pruN ../pristine-linux-2.6.16-rc5/fs/eventpoll.c ./fs/eventpoll.c
  32.192 +--- ../pristine-linux-2.6.16-rc5/fs/eventpoll.c	2006-01-03 03:21:10.000000000 +0000
  32.193 ++++ ./fs/eventpoll.c	2006-03-16 10:04:35.469956167 +0000
  32.194 +@@ -235,8 +235,6 @@ struct ep_pqueue {
  32.195 + 
  32.196 + static void ep_poll_safewake_init(struct poll_safewake *psw);
  32.197 + static void ep_poll_safewake(struct poll_safewake *psw, wait_queue_head_t *wq);
  32.198 +-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
  32.199 +-		    struct eventpoll *ep);
  32.200 + static int ep_alloc(struct eventpoll **pep);
  32.201 + static void ep_free(struct eventpoll *ep);
  32.202 + static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd);
  32.203 +@@ -266,7 +264,7 @@ static int ep_events_transfer(struct eve
  32.204 + static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events,
  32.205 + 		   int maxevents, long timeout);
  32.206 + static int eventpollfs_delete_dentry(struct dentry *dentry);
  32.207 +-static struct inode *ep_eventpoll_inode(void);
  32.208 ++static struct inode *ep_eventpoll_inode(struct file_operations *fops);
  32.209 + static struct super_block *eventpollfs_get_sb(struct file_system_type *fs_type,
  32.210 + 					      int flags, const char *dev_name,
  32.211 + 					      void *data);
  32.212 +@@ -525,7 +523,7 @@ asmlinkage long sys_epoll_create(int siz
  32.213 + 	 * Creates all the items needed to setup an eventpoll file. That is,
  32.214 + 	 * a file structure, and inode and a free file descriptor.
  32.215 + 	 */
  32.216 +-	error = ep_getfd(&fd, &inode, &file, ep);
  32.217 ++	error = ep_getfd(&fd, &inode, &file, ep, &eventpoll_fops);
  32.218 + 	if (error)
  32.219 + 		goto eexit_2;
  32.220 + 
  32.221 +@@ -710,8 +708,8 @@ eexit_1:
  32.222 + /*
  32.223 +  * Creates the file descriptor to be used by the epoll interface.
  32.224 +  */
  32.225 +-static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
  32.226 +-		    struct eventpoll *ep)
  32.227 ++int ep_getfd(int *efd, struct inode **einode, struct file **efile,
  32.228 ++		    struct eventpoll *ep, struct file_operations *fops)
  32.229 + {
  32.230 + 	struct qstr this;
  32.231 + 	char name[32];
  32.232 +@@ -727,7 +725,7 @@ static int ep_getfd(int *efd, struct ino
  32.233 + 		goto eexit_1;
  32.234 + 
  32.235 + 	/* Allocates an inode from the eventpoll file system */
  32.236 +-	inode = ep_eventpoll_inode();
  32.237 ++	inode = ep_eventpoll_inode(fops);
  32.238 + 	error = PTR_ERR(inode);
  32.239 + 	if (IS_ERR(inode))
  32.240 + 		goto eexit_2;
  32.241 +@@ -758,7 +756,7 @@ static int ep_getfd(int *efd, struct ino
  32.242 + 
  32.243 + 	file->f_pos = 0;
  32.244 + 	file->f_flags = O_RDONLY;
  32.245 +-	file->f_op = &eventpoll_fops;
  32.246 ++	file->f_op = fops;
  32.247 + 	file->f_mode = FMODE_READ;
  32.248 + 	file->f_version = 0;
  32.249 + 	file->private_data = ep;
  32.250 +@@ -1574,7 +1572,7 @@ static int eventpollfs_delete_dentry(str
  32.251 + }
  32.252 + 
  32.253 + 
  32.254 +-static struct inode *ep_eventpoll_inode(void)
  32.255 ++static struct inode *ep_eventpoll_inode(struct file_operations *fops)
  32.256 + {
  32.257 + 	int error = -ENOMEM;
  32.258 + 	struct inode *inode = new_inode(eventpoll_mnt->mnt_sb);
  32.259 +@@ -1582,7 +1580,7 @@ static struct inode *ep_eventpoll_inode(
  32.260 + 	if (!inode)
  32.261 + 		goto eexit_1;
  32.262 + 
  32.263 +-	inode->i_fop = &eventpoll_fops;
  32.264 ++	inode->i_fop = fops;
  32.265 + 
  32.266 + 	/*
  32.267 + 	 * Mark the inode dirty from the very beginning,
  32.268 +
  32.269 +diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/aio.h ./include/linux/aio.h
  32.270 +--- ../pristine-linux-2.6.16-rc5/include/linux/aio.h	2006-03-14 14:10:21.597916731 +0000
  32.271 ++++ ./include/linux/aio.h	2006-03-16 10:05:39.848833028 +0000
  32.272 +@@ -191,6 +191,11 @@ struct kioctx {
  32.273 + 	struct aio_ring_info	ring_info;
  32.274 + 
  32.275 + 	struct work_struct	wq;
  32.276 ++#ifdef CONFIG_EPOLL
  32.277 ++	// poll integration
  32.278 ++	wait_queue_head_t       poll_wait;
  32.279 ++	struct file		*file;
  32.280 ++#endif
  32.281 + };
  32.282 + 
  32.283 + /* prototypes */
  32.284 +
  32.285 +diff -pruN ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h ./include/linux/eventpoll.h
  32.286 +--- ../pristine-linux-2.6.16-rc5/include/linux/eventpoll.h	2006-01-03 03:21:10.000000000 +0000
  32.287 ++++ ./include/linux/eventpoll.h	2006-03-16 10:08:51.577809317 +0000
  32.288 +@@ -86,6 +86,12 @@ static inline void eventpoll_release(str
  32.289 + }
  32.290 + 
  32.291 + 
  32.292 ++/*
  32.293 ++ * called by aio code to create fd that can poll the  aio event queueQ
  32.294 ++ */
  32.295 ++struct eventpoll;
  32.296 ++int ep_getfd(int *efd, struct inode **einode, struct file **efile,
  32.297 ++             struct eventpoll *ep, struct file_operations *fops);
  32.298 + #else
  32.299 + 
  32.300 + static inline void eventpoll_init_file(struct file *file) {}
    33.1 --- a/patches/linux-2.6.16.13/net-csum.patch	Tue Jul 25 09:51:50 2006 -0600
    33.2 +++ b/patches/linux-2.6.16.13/net-csum.patch	Tue Jul 25 12:19:05 2006 -0600
    33.3 @@ -1,40 +1,39 @@
    33.4  diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c ./net/ipv4/netfilter/ip_nat_proto_tcp.c
    33.5  --- ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_tcp.c	2006-05-02 22:38:44.000000000 +0100
    33.6 -+++ ./net/ipv4/netfilter/ip_nat_proto_tcp.c	2006-05-04 17:41:37.000000000 +0100
    33.7 -@@ -129,10 +129,14 @@ tcp_manip_pkt(struct sk_buff **pskb,
    33.8 ++++ ./net/ipv4/netfilter/ip_nat_proto_tcp.c	2006-05-16 13:28:19.000000000 +0100
    33.9 +@@ -129,7 +129,12 @@ tcp_manip_pkt(struct sk_buff **pskb,
   33.10   	if (hdrsize < sizeof(*hdr))
   33.11   		return 1;
   33.12   
   33.13  -	hdr->check = ip_nat_cheat_check(~oldip, newip,
   33.14 -+	if ((*pskb)->proto_csum_blank) {
   33.15 ++#ifdef CONFIG_XEN
   33.16 ++	if ((*pskb)->proto_csum_blank)
   33.17  +		hdr->check = ip_nat_cheat_check(oldip, ~newip, hdr->check);
   33.18 -+	} else {
   33.19 ++	else
   33.20 ++#endif
   33.21  +		hdr->check = ip_nat_cheat_check(~oldip, newip,
   33.22   					ip_nat_cheat_check(oldport ^ 0xFFFF,
   33.23   							   newport,
   33.24   							   hdr->check));
   33.25 -+	}
   33.26 - 	return 1;
   33.27 - }
   33.28 - 
   33.29  diff -pruN ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c ./net/ipv4/netfilter/ip_nat_proto_udp.c
   33.30  --- ../pristine-linux-2.6.16.13/net/ipv4/netfilter/ip_nat_proto_udp.c	2006-05-02 22:38:44.000000000 +0100
   33.31 -+++ ./net/ipv4/netfilter/ip_nat_proto_udp.c	2006-05-04 17:41:37.000000000 +0100
   33.32 -@@ -113,11 +113,16 @@ udp_manip_pkt(struct sk_buff **pskb,
   33.33 ++++ ./net/ipv4/netfilter/ip_nat_proto_udp.c	2006-05-16 13:30:14.000000000 +0100
   33.34 +@@ -113,11 +113,17 @@ udp_manip_pkt(struct sk_buff **pskb,
   33.35   		newport = tuple->dst.u.udp.port;
   33.36   		portptr = &hdr->dest;
   33.37   	}
   33.38  -	if (hdr->check) /* 0 is a special case meaning no checksum */
   33.39  -		hdr->check = ip_nat_cheat_check(~oldip, newip,
   33.40  +	if (hdr->check) { /* 0 is a special case meaning no checksum */
   33.41 -+		if ((*pskb)->proto_csum_blank) {
   33.42 ++#ifdef CONFIG_XEN
   33.43 ++		if ((*pskb)->proto_csum_blank)
   33.44  +			hdr->check = ip_nat_cheat_check(oldip, ~newip, hdr->check);
   33.45 -+		} else {
   33.46 ++		else
   33.47 ++#endif
   33.48  +			hdr->check = ip_nat_cheat_check(~oldip, newip,
   33.49   					ip_nat_cheat_check(*portptr ^ 0xFFFF,
   33.50   							   newport,
   33.51   							   hdr->check));
   33.52 -+		}
   33.53  +	}
   33.54   	*portptr = newport;
   33.55   	return 1;
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/patches/linux-2.6.16.13/net-gso-0-base.patch	Tue Jul 25 12:19:05 2006 -0600
    34.3 @@ -0,0 +1,2907 @@
    34.4 +diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
    34.5 +index 3c0a5ba..847cedb 100644
    34.6 +--- a/Documentation/networking/netdevices.txt
    34.7 ++++ b/Documentation/networking/netdevices.txt
    34.8 +@@ -42,9 +42,9 @@ dev->get_stats:
    34.9 + 	Context: nominally process, but don't sleep inside an rwlock
   34.10 + 
   34.11 + dev->hard_start_xmit:
   34.12 +-	Synchronization: dev->xmit_lock spinlock.
   34.13 ++	Synchronization: netif_tx_lock spinlock.
   34.14 + 	When the driver sets NETIF_F_LLTX in dev->features this will be
   34.15 +-	called without holding xmit_lock. In this case the driver 
   34.16 ++	called without holding netif_tx_lock. In this case the driver
   34.17 + 	has to lock by itself when needed. It is recommended to use a try lock
   34.18 + 	for this and return -1 when the spin lock fails. 
   34.19 + 	The locking there should also properly protect against 
   34.20 +@@ -62,12 +62,12 @@ dev->hard_start_xmit:
   34.21 + 	  Only valid when NETIF_F_LLTX is set.
   34.22 + 
   34.23 + dev->tx_timeout:
   34.24 +-	Synchronization: dev->xmit_lock spinlock.
   34.25 ++	Synchronization: netif_tx_lock spinlock.
   34.26 + 	Context: BHs disabled
   34.27 + 	Notes: netif_queue_stopped() is guaranteed true
   34.28 + 
   34.29 + dev->set_multicast_list:
   34.30 +-	Synchronization: dev->xmit_lock spinlock.
   34.31 ++	Synchronization: netif_tx_lock spinlock.
   34.32 + 	Context: BHs disabled
   34.33 + 
   34.34 + dev->poll:
   34.35 +diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
   34.36 +index 4be9769..2e7cac7 100644
   34.37 +--- a/drivers/block/aoe/aoenet.c
   34.38 ++++ b/drivers/block/aoe/aoenet.c
   34.39 +@@ -95,9 +95,8 @@ mac_addr(char addr[6])
   34.40 + static struct sk_buff *
   34.41 + skb_check(struct sk_buff *skb)
   34.42 + {
   34.43 +-	if (skb_is_nonlinear(skb))
   34.44 + 	if ((skb = skb_share_check(skb, GFP_ATOMIC)))
   34.45 +-	if (skb_linearize(skb, GFP_ATOMIC) < 0) {
   34.46 ++	if (skb_linearize(skb)) {
   34.47 + 		dev_kfree_skb(skb);
   34.48 + 		return NULL;
   34.49 + 	}
   34.50 +diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
   34.51 +index a2408d7..c90e620 100644
   34.52 +--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
   34.53 ++++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
   34.54 +@@ -821,7 +821,8 @@ void ipoib_mcast_restart_task(void *dev_
   34.55 + 
   34.56 + 	ipoib_mcast_stop_thread(dev, 0);
   34.57 + 
   34.58 +-	spin_lock_irqsave(&dev->xmit_lock, flags);
   34.59 ++	local_irq_save(flags);
   34.60 ++	netif_tx_lock(dev);
   34.61 + 	spin_lock(&priv->lock);
   34.62 + 
   34.63 + 	/*
   34.64 +@@ -896,7 +897,8 @@ void ipoib_mcast_restart_task(void *dev_
   34.65 + 	}
   34.66 + 
   34.67 + 	spin_unlock(&priv->lock);
   34.68 +-	spin_unlock_irqrestore(&dev->xmit_lock, flags);
   34.69 ++	netif_tx_unlock(dev);
   34.70 ++	local_irq_restore(flags);
   34.71 + 
   34.72 + 	/* We have to cancel outside of the spinlock */
   34.73 + 	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
   34.74 +diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
   34.75 +index 6711eb6..8d2351f 100644
   34.76 +--- a/drivers/media/dvb/dvb-core/dvb_net.c
   34.77 ++++ b/drivers/media/dvb/dvb-core/dvb_net.c
   34.78 +@@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void 
   34.79 + 
   34.80 + 	dvb_net_feed_stop(dev);
   34.81 + 	priv->rx_mode = RX_MODE_UNI;
   34.82 +-	spin_lock_bh(&dev->xmit_lock);
   34.83 ++	netif_tx_lock_bh(dev);
   34.84 + 
   34.85 + 	if (dev->flags & IFF_PROMISC) {
   34.86 + 		dprintk("%s: promiscuous mode\n", dev->name);
   34.87 +@@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void 
   34.88 + 		}
   34.89 + 	}
   34.90 + 
   34.91 +-	spin_unlock_bh(&dev->xmit_lock);
   34.92 ++	netif_tx_unlock_bh(dev);
   34.93 + 	dvb_net_feed_start(dev);
   34.94 + }
   34.95 + 
   34.96 +diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
   34.97 +index dd41049..6615583 100644
   34.98 +--- a/drivers/net/8139cp.c
   34.99 ++++ b/drivers/net/8139cp.c
  34.100 +@@ -794,7 +794,7 @@ #endif
  34.101 + 	entry = cp->tx_head;
  34.102 + 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
  34.103 + 	if (dev->features & NETIF_F_TSO)
  34.104 +-		mss = skb_shinfo(skb)->tso_size;
  34.105 ++		mss = skb_shinfo(skb)->gso_size;
  34.106 + 
  34.107 + 	if (skb_shinfo(skb)->nr_frags == 0) {
  34.108 + 		struct cp_desc *txd = &cp->tx_ring[entry];
  34.109 +diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
  34.110 +index a24200d..b5e39a1 100644
  34.111 +--- a/drivers/net/bnx2.c
  34.112 ++++ b/drivers/net/bnx2.c
  34.113 +@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
  34.114 + 		skb = tx_buf->skb;
  34.115 + #ifdef BCM_TSO 
  34.116 + 		/* partial BD completions possible with TSO packets */
  34.117 +-		if (skb_shinfo(skb)->tso_size) {
  34.118 ++		if (skb_shinfo(skb)->gso_size) {
  34.119 + 			u16 last_idx, last_ring_idx;
  34.120 + 
  34.121 + 			last_idx = sw_cons +
  34.122 +@@ -1948,7 +1948,7 @@ bnx2_poll(struct net_device *dev, int *b
  34.123 + 	return 1;
  34.124 + }
  34.125 + 
  34.126 +-/* Called with rtnl_lock from vlan functions and also dev->xmit_lock
  34.127 ++/* Called with rtnl_lock from vlan functions and also netif_tx_lock
  34.128 +  * from set_multicast.
  34.129 +  */
  34.130 + static void
  34.131 +@@ -4403,7 +4403,7 @@ bnx2_vlan_rx_kill_vid(struct net_device 
  34.132 + }
  34.133 + #endif
  34.134 + 
  34.135 +-/* Called with dev->xmit_lock.
  34.136 ++/* Called with netif_tx_lock.
  34.137 +  * hard_start_xmit is pseudo-lockless - a lock is only required when
  34.138 +  * the tx queue is full. This way, we get the benefit of lockless
  34.139 +  * operations most of the time without the complexities to handle
  34.140 +@@ -4441,7 +4441,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
  34.141 + 			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
  34.142 + 	}
  34.143 + #ifdef BCM_TSO 
  34.144 +-	if ((mss = skb_shinfo(skb)->tso_size) &&
  34.145 ++	if ((mss = skb_shinfo(skb)->gso_size) &&
  34.146 + 		(skb->len > (bp->dev->mtu + ETH_HLEN))) {
  34.147 + 		u32 tcp_opt_len, ip_tcp_len;
  34.148 + 
  34.149 +diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
  34.150 +index bcf9f17..e970921 100644
  34.151 +--- a/drivers/net/bonding/bond_main.c
  34.152 ++++ b/drivers/net/bonding/bond_main.c
  34.153 +@@ -1145,8 +1145,7 @@ int bond_sethwaddr(struct net_device *bo
  34.154 + }
  34.155 + 
  34.156 + #define BOND_INTERSECT_FEATURES \
  34.157 +-	(NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM|\
  34.158 +-	NETIF_F_TSO|NETIF_F_UFO)
  34.159 ++	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
  34.160 + 
  34.161 + /* 
  34.162 +  * Compute the common dev->feature set available to all slaves.  Some
  34.163 +@@ -1164,9 +1163,7 @@ static int bond_compute_features(struct 
  34.164 + 		features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
  34.165 + 
  34.166 + 	if ((features & NETIF_F_SG) && 
  34.167 +-	    !(features & (NETIF_F_IP_CSUM |
  34.168 +-			  NETIF_F_NO_CSUM |
  34.169 +-			  NETIF_F_HW_CSUM)))
  34.170 ++	    !(features & NETIF_F_ALL_CSUM))
  34.171 + 		features &= ~NETIF_F_SG;
  34.172 + 
  34.173 + 	/* 
  34.174 +@@ -4147,7 +4144,7 @@ static int bond_init(struct net_device *
  34.175 + 	 */
  34.176 + 	bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
  34.177 + 
  34.178 +-	/* don't acquire bond device's xmit_lock when 
  34.179 ++	/* don't acquire bond device's netif_tx_lock when
  34.180 + 	 * transmitting */
  34.181 + 	bond_dev->features |= NETIF_F_LLTX;
  34.182 + 
  34.183 +diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
  34.184 +index 30ff8ea..7b7d360 100644
  34.185 +--- a/drivers/net/chelsio/sge.c
  34.186 ++++ b/drivers/net/chelsio/sge.c
  34.187 +@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
  34.188 + 	struct cpl_tx_pkt *cpl;
  34.189 + 
  34.190 + #ifdef NETIF_F_TSO
  34.191 +-	if (skb_shinfo(skb)->tso_size) {
  34.192 ++	if (skb_shinfo(skb)->gso_size) {
  34.193 + 		int eth_type;
  34.194 + 		struct cpl_tx_pkt_lso *hdr;
  34.195 + 
  34.196 +@@ -1434,7 +1434,7 @@ #ifdef NETIF_F_TSO
  34.197 + 		hdr->ip_hdr_words = skb->nh.iph->ihl;
  34.198 + 		hdr->tcp_hdr_words = skb->h.th->doff;
  34.199 + 		hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
  34.200 +-						skb_shinfo(skb)->tso_size));
  34.201 ++						skb_shinfo(skb)->gso_size));
  34.202 + 		hdr->len = htonl(skb->len - sizeof(*hdr));
  34.203 + 		cpl = (struct cpl_tx_pkt *)hdr;
  34.204 + 		sge->stats.tx_lso_pkts++;
  34.205 +diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
  34.206 +index fa29402..681d284 100644
  34.207 +--- a/drivers/net/e1000/e1000_main.c
  34.208 ++++ b/drivers/net/e1000/e1000_main.c
  34.209 +@@ -2526,7 +2526,7 @@ #ifdef NETIF_F_TSO
  34.210 + 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
  34.211 + 	int err;
  34.212 + 
  34.213 +-	if (skb_shinfo(skb)->tso_size) {
  34.214 ++	if (skb_shinfo(skb)->gso_size) {
  34.215 + 		if (skb_header_cloned(skb)) {
  34.216 + 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
  34.217 + 			if (err)
  34.218 +@@ -2534,7 +2534,7 @@ #ifdef NETIF_F_TSO
  34.219 + 		}
  34.220 + 
  34.221 + 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
  34.222 +-		mss = skb_shinfo(skb)->tso_size;
  34.223 ++		mss = skb_shinfo(skb)->gso_size;
  34.224 + 		if (skb->protocol == ntohs(ETH_P_IP)) {
  34.225 + 			skb->nh.iph->tot_len = 0;
  34.226 + 			skb->nh.iph->check = 0;
  34.227 +@@ -2651,7 +2651,7 @@ #ifdef NETIF_F_TSO
  34.228 + 		 * tso gets written back prematurely before the data is fully
  34.229 + 		 * DMAd to the controller */
  34.230 + 		if (!skb->data_len && tx_ring->last_tx_tso &&
  34.231 +-				!skb_shinfo(skb)->tso_size) {
  34.232 ++				!skb_shinfo(skb)->gso_size) {
  34.233 + 			tx_ring->last_tx_tso = 0;
  34.234 + 			size -= 4;
  34.235 + 		}
  34.236 +@@ -2893,7 +2893,7 @@ #endif
  34.237 + 	}
  34.238 + 
  34.239 + #ifdef NETIF_F_TSO
  34.240 +-	mss = skb_shinfo(skb)->tso_size;
  34.241 ++	mss = skb_shinfo(skb)->gso_size;
  34.242 + 	/* The controller does a simple calculation to 
  34.243 + 	 * make sure there is enough room in the FIFO before
  34.244 + 	 * initiating the DMA for each buffer.  The calc is:
  34.245 +@@ -2935,7 +2935,7 @@ #endif
  34.246 + #ifdef NETIF_F_TSO
  34.247 + 	/* Controller Erratum workaround */
  34.248 + 	if (!skb->data_len && tx_ring->last_tx_tso &&
  34.249 +-		!skb_shinfo(skb)->tso_size)
  34.250 ++		!skb_shinfo(skb)->gso_size)
  34.251 + 		count++;
  34.252 + #endif
  34.253 + 
  34.254 +diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
  34.255 +index 3682ec6..c35f16e 100644
  34.256 +--- a/drivers/net/forcedeth.c
  34.257 ++++ b/drivers/net/forcedeth.c
  34.258 +@@ -482,9 +482,9 @@ #define LPA_1000HALF	0x0400
  34.259 +  * critical parts:
  34.260 +  * - rx is (pseudo-) lockless: it relies on the single-threading provided
  34.261 +  *	by the arch code for interrupts.
  34.262 +- * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission
  34.263 ++ * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
  34.264 +  *	needs dev->priv->lock :-(
  34.265 +- * - set_multicast_list: preparation lockless, relies on dev->xmit_lock.
  34.266 ++ * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
  34.267 +  */
  34.268 + 
  34.269 + /* in dev: base, irq */
  34.270 +@@ -1016,7 +1016,7 @@ static void drain_ring(struct net_device
  34.271 + 
  34.272 + /*
  34.273 +  * nv_start_xmit: dev->hard_start_xmit function
  34.274 +- * Called with dev->xmit_lock held.
  34.275 ++ * Called with netif_tx_lock held.
  34.276 +  */
  34.277 + static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
  34.278 + {
  34.279 +@@ -1105,8 +1105,8 @@ static int nv_start_xmit(struct sk_buff 
  34.280 + 	np->tx_skbuff[nr] = skb;
  34.281 + 
  34.282 + #ifdef NETIF_F_TSO
  34.283 +-	if (skb_shinfo(skb)->tso_size)
  34.284 +-		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
  34.285 ++	if (skb_shinfo(skb)->gso_size)
  34.286 ++		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
  34.287 + 	else
  34.288 + #endif
  34.289 + 	tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
  34.290 +@@ -1203,7 +1203,7 @@ static void nv_tx_done(struct net_device
  34.291 + 
  34.292 + /*
  34.293 +  * nv_tx_timeout: dev->tx_timeout function
  34.294 +- * Called with dev->xmit_lock held.
  34.295 ++ * Called with netif_tx_lock held.
  34.296 +  */
  34.297 + static void nv_tx_timeout(struct net_device *dev)
  34.298 + {
  34.299 +@@ -1524,7 +1524,7 @@ static int nv_change_mtu(struct net_devi
  34.300 + 		 * Changing the MTU is a rare event, it shouldn't matter.
  34.301 + 		 */
  34.302 + 		disable_irq(dev->irq);
  34.303 +-		spin_lock_bh(&dev->xmit_lock);
  34.304 ++		netif_tx_lock_bh(dev);
  34.305 + 		spin_lock(&np->lock);
  34.306 + 		/* stop engines */
  34.307 + 		nv_stop_rx(dev);
  34.308 +@@ -1559,7 +1559,7 @@ static int nv_change_mtu(struct net_devi
  34.309 + 		nv_start_rx(dev);
  34.310 + 		nv_start_tx(dev);
  34.311 + 		spin_unlock(&np->lock);
  34.312 +-		spin_unlock_bh(&dev->xmit_lock);
  34.313 ++		netif_tx_unlock_bh(dev);
  34.314 + 		enable_irq(dev->irq);
  34.315 + 	}
  34.316 + 	return 0;
  34.317 +@@ -1594,7 +1594,7 @@ static int nv_set_mac_address(struct net
  34.318 + 	memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
  34.319 + 
  34.320 + 	if (netif_running(dev)) {
  34.321 +-		spin_lock_bh(&dev->xmit_lock);
  34.322 ++		netif_tx_lock_bh(dev);
  34.323 + 		spin_lock_irq(&np->lock);
  34.324 + 
  34.325 + 		/* stop rx engine */
  34.326 +@@ -1606,7 +1606,7 @@ static int nv_set_mac_address(struct net
  34.327 + 		/* restart rx engine */
  34.328 + 		nv_start_rx(dev);
  34.329 + 		spin_unlock_irq(&np->lock);
  34.330 +-		spin_unlock_bh(&dev->xmit_lock);
  34.331 ++		netif_tx_unlock_bh(dev);
  34.332 + 	} else {
  34.333 + 		nv_copy_mac_to_hw(dev);
  34.334 + 	}
  34.335 +@@ -1615,7 +1615,7 @@ static int nv_set_mac_address(struct net
  34.336 + 
  34.337 + /*
  34.338 +  * nv_set_multicast: dev->set_multicast function
  34.339 +- * Called with dev->xmit_lock held.
  34.340 ++ * Called with netif_tx_lock held.
  34.341 +  */
  34.342 + static void nv_set_multicast(struct net_device *dev)
  34.343 + {
  34.344 +diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
  34.345 +index 102c1f0..d12605f 100644
  34.346 +--- a/drivers/net/hamradio/6pack.c
  34.347 ++++ b/drivers/net/hamradio/6pack.c
  34.348 +@@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net
  34.349 + {
  34.350 + 	struct sockaddr_ax25 *sa = addr;
  34.351 + 
  34.352 +-	spin_lock_irq(&dev->xmit_lock);
  34.353 ++	netif_tx_lock_bh(dev);
  34.354 + 	memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
  34.355 +-	spin_unlock_irq(&dev->xmit_lock);
  34.356 ++	netif_tx_unlock_bh(dev);
  34.357 + 
  34.358 + 	return 0;
  34.359 + }
  34.360 +@@ -767,9 +767,9 @@ static int sixpack_ioctl(struct tty_stru
  34.361 + 			break;
  34.362 + 		}
  34.363 + 
  34.364 +-		spin_lock_irq(&dev->xmit_lock);
  34.365 ++		netif_tx_lock_bh(dev);
  34.366 + 		memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
  34.367 +-		spin_unlock_irq(&dev->xmit_lock);
  34.368 ++		netif_tx_unlock_bh(dev);
  34.369 + 
  34.370 + 		err = 0;
  34.371 + 		break;
  34.372 +diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
  34.373 +index dc5e9d5..5c66f5a 100644
  34.374 +--- a/drivers/net/hamradio/mkiss.c
  34.375 ++++ b/drivers/net/hamradio/mkiss.c
  34.376 +@@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net
  34.377 + {
  34.378 + 	struct sockaddr_ax25 *sa = addr;
  34.379 + 
  34.380 +-	spin_lock_irq(&dev->xmit_lock);
  34.381 ++	netif_tx_lock_bh(dev);
  34.382 + 	memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
  34.383 +-	spin_unlock_irq(&dev->xmit_lock);
  34.384 ++	netif_tx_unlock_bh(dev);
  34.385 + 
  34.386 + 	return 0;
  34.387 + }
  34.388 +@@ -886,9 +886,9 @@ static int mkiss_ioctl(struct tty_struct
  34.389 + 			break;
  34.390 + 		}
  34.391 + 
  34.392 +-		spin_lock_irq(&dev->xmit_lock);
  34.393 ++		netif_tx_lock_bh(dev);
  34.394 + 		memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
  34.395 +-		spin_unlock_irq(&dev->xmit_lock);
  34.396 ++		netif_tx_unlock_bh(dev);
  34.397 + 
  34.398 + 		err = 0;
  34.399 + 		break;
  34.400 +diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
  34.401 +index 31fb2d7..2e222ef 100644
  34.402 +--- a/drivers/net/ifb.c
  34.403 ++++ b/drivers/net/ifb.c
  34.404 +@@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev
  34.405 + 	dp->st_task_enter++;
  34.406 + 	if ((skb = skb_peek(&dp->tq)) == NULL) {
  34.407 + 		dp->st_txq_refl_try++;
  34.408 +-		if (spin_trylock(&_dev->xmit_lock)) {
  34.409 ++		if (netif_tx_trylock(_dev)) {
  34.410 + 			dp->st_rxq_enter++;
  34.411 + 			while ((skb = skb_dequeue(&dp->rq)) != NULL) {
  34.412 + 				skb_queue_tail(&dp->tq, skb);
  34.413 + 				dp->st_rx2tx_tran++;
  34.414 + 			}
  34.415 +-			spin_unlock(&_dev->xmit_lock);
  34.416 ++			netif_tx_unlock(_dev);
  34.417 + 		} else {
  34.418 + 			/* reschedule */
  34.419 + 			dp->st_rxq_notenter++;
  34.420 +@@ -110,7 +110,7 @@ static void ri_tasklet(unsigned long dev
  34.421 + 		}
  34.422 + 	}
  34.423 + 
  34.424 +-	if (spin_trylock(&_dev->xmit_lock)) {
  34.425 ++	if (netif_tx_trylock(_dev)) {
  34.426 + 		dp->st_rxq_check++;
  34.427 + 		if ((skb = skb_peek(&dp->rq)) == NULL) {
  34.428 + 			dp->tasklet_pending = 0;
  34.429 +@@ -118,10 +118,10 @@ static void ri_tasklet(unsigned long dev
  34.430 + 				netif_wake_queue(_dev);
  34.431 + 		} else {
  34.432 + 			dp->st_rxq_rsch++;
  34.433 +-			spin_unlock(&_dev->xmit_lock);
  34.434 ++			netif_tx_unlock(_dev);
  34.435 + 			goto resched;
  34.436 + 		}
  34.437 +-		spin_unlock(&_dev->xmit_lock);
  34.438 ++		netif_tx_unlock(_dev);
  34.439 + 	} else {
  34.440 + resched:
  34.441 + 		dp->tasklet_pending = 1;
  34.442 +diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
  34.443 +index a9f49f0..339d4a7 100644
  34.444 +--- a/drivers/net/irda/vlsi_ir.c
  34.445 ++++ b/drivers/net/irda/vlsi_ir.c
  34.446 +@@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct s
  34.447 + 			    ||  (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
  34.448 + 			    	break;
  34.449 + 			udelay(100);
  34.450 +-			/* must not sleep here - we are called under xmit_lock! */
  34.451 ++			/* must not sleep here - called under netif_tx_lock! */
  34.452 + 		}
  34.453 + 	}
  34.454 + 
  34.455 +diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
  34.456 +index f9f77e4..bdab369 100644
  34.457 +--- a/drivers/net/ixgb/ixgb_main.c
  34.458 ++++ b/drivers/net/ixgb/ixgb_main.c
  34.459 +@@ -1163,7 +1163,7 @@ #ifdef NETIF_F_TSO
  34.460 + 	uint16_t ipcse, tucse, mss;
  34.461 + 	int err;
  34.462 + 
  34.463 +-	if(likely(skb_shinfo(skb)->tso_size)) {
  34.464 ++	if(likely(skb_shinfo(skb)->gso_size)) {
  34.465 + 		if (skb_header_cloned(skb)) {
  34.466 + 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
  34.467 + 			if (err)
  34.468 +@@ -1171,7 +1171,7 @@ #ifdef NETIF_F_TSO
  34.469 + 		}
  34.470 + 
  34.471 + 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
  34.472 +-		mss = skb_shinfo(skb)->tso_size;
  34.473 ++		mss = skb_shinfo(skb)->gso_size;
  34.474 + 		skb->nh.iph->tot_len = 0;
  34.475 + 		skb->nh.iph->check = 0;
  34.476 + 		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
  34.477 +diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
  34.478 +index 690a1aa..9bcaa80 100644
  34.479 +--- a/drivers/net/loopback.c
  34.480 ++++ b/drivers/net/loopback.c
  34.481 +@@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
  34.482 + 	struct iphdr *iph = skb->nh.iph;
  34.483 + 	struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
  34.484 + 	unsigned int doffset = (iph->ihl + th->doff) * 4;
  34.485 +-	unsigned int mtu = skb_shinfo(skb)->tso_size + doffset;
  34.486 ++	unsigned int mtu = skb_shinfo(skb)->gso_size + doffset;
  34.487 + 	unsigned int offset = 0;
  34.488 + 	u32 seq = ntohl(th->seq);
  34.489 + 	u16 id  = ntohs(iph->id);
  34.490 +@@ -139,7 +139,7 @@ #ifndef LOOPBACK_MUST_CHECKSUM
  34.491 + #endif
  34.492 + 
  34.493 + #ifdef LOOPBACK_TSO
  34.494 +-	if (skb_shinfo(skb)->tso_size) {
  34.495 ++	if (skb_shinfo(skb)->gso_size) {
  34.496 + 		BUG_ON(skb->protocol != htons(ETH_P_IP));
  34.497 + 		BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
  34.498 + 
  34.499 +diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
  34.500 +index c0998ef..0fac9d5 100644
  34.501 +--- a/drivers/net/mv643xx_eth.c
  34.502 ++++ b/drivers/net/mv643xx_eth.c
  34.503 +@@ -1107,7 +1107,7 @@ static int mv643xx_eth_start_xmit(struct
  34.504 + 
  34.505 + #ifdef MV643XX_CHECKSUM_OFFLOAD_TX
  34.506 + 	if (has_tiny_unaligned_frags(skb)) {
  34.507 +-		if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
  34.508 ++		if (__skb_linearize(skb)) {
  34.509 + 			stats->tx_dropped++;
  34.510 + 			printk(KERN_DEBUG "%s: failed to linearize tiny "
  34.511 + 					"unaligned fragment\n", dev->name);
  34.512 +diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
  34.513 +index 9d6d254..c9ed624 100644
  34.514 +--- a/drivers/net/natsemi.c
  34.515 ++++ b/drivers/net/natsemi.c
  34.516 +@@ -323,12 +323,12 @@ performance critical codepaths:
  34.517 + The rx process only runs in the interrupt handler. Access from outside
  34.518 + the interrupt handler is only permitted after disable_irq().
  34.519 + 
  34.520 +-The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap
  34.521 ++The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
  34.522 + is set, then access is permitted under spin_lock_irq(&np->lock).
  34.523 + 
  34.524 + Thus configuration functions that want to access everything must call
  34.525 + 	disable_irq(dev->irq);
  34.526 +-	spin_lock_bh(dev->xmit_lock);
  34.527 ++	netif_tx_lock_bh(dev);
  34.528 + 	spin_lock_irq(&np->lock);
  34.529 + 
  34.530 + IV. Notes
  34.531 +diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
  34.532 +index 8cc0d0b..e53b313 100644
  34.533 +--- a/drivers/net/r8169.c
  34.534 ++++ b/drivers/net/r8169.c
  34.535 +@@ -2171,7 +2171,7 @@ static int rtl8169_xmit_frags(struct rtl
  34.536 + static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
  34.537 + {
  34.538 + 	if (dev->features & NETIF_F_TSO) {
  34.539 +-		u32 mss = skb_shinfo(skb)->tso_size;
  34.540 ++		u32 mss = skb_shinfo(skb)->gso_size;
  34.541 + 
  34.542 + 		if (mss)
  34.543 + 			return LargeSend | ((mss & MSSMask) << MSSShift);
  34.544 +diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
  34.545 +index b7f00d6..439f45f 100644
  34.546 +--- a/drivers/net/s2io.c
  34.547 ++++ b/drivers/net/s2io.c
  34.548 +@@ -3522,8 +3522,8 @@ #endif
  34.549 + 	txdp->Control_1 = 0;
  34.550 + 	txdp->Control_2 = 0;
  34.551 + #ifdef NETIF_F_TSO
  34.552 +-	mss = skb_shinfo(skb)->tso_size;
  34.553 +-	if (mss) {
  34.554 ++	mss = skb_shinfo(skb)->gso_size;
  34.555 ++	if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) {
  34.556 + 		txdp->Control_1 |= TXD_TCP_LSO_EN;
  34.557 + 		txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
  34.558 + 	}
  34.559 +@@ -3543,10 +3543,10 @@ #endif
  34.560 + 	}
  34.561 + 
  34.562 + 	frg_len = skb->len - skb->data_len;
  34.563 +-	if (skb_shinfo(skb)->ufo_size) {
  34.564 ++	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) {
  34.565 + 		int ufo_size;
  34.566 + 
  34.567 +-		ufo_size = skb_shinfo(skb)->ufo_size;
  34.568 ++		ufo_size = skb_shinfo(skb)->gso_size;
  34.569 + 		ufo_size &= ~7;
  34.570 + 		txdp->Control_1 |= TXD_UFO_EN;
  34.571 + 		txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
  34.572 +@@ -3572,7 +3572,7 @@ #endif
  34.573 + 	txdp->Host_Control = (unsigned long) skb;
  34.574 + 	txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
  34.575 + 
  34.576 +-	if (skb_shinfo(skb)->ufo_size)
  34.577 ++	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  34.578 + 		txdp->Control_1 |= TXD_UFO_EN;
  34.579 + 
  34.580 + 	frg_cnt = skb_shinfo(skb)->nr_frags;
  34.581 +@@ -3587,12 +3587,12 @@ #endif
  34.582 + 		    (sp->pdev, frag->page, frag->page_offset,
  34.583 + 		     frag->size, PCI_DMA_TODEVICE);
  34.584 + 		txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
  34.585 +-		if (skb_shinfo(skb)->ufo_size)
  34.586 ++		if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  34.587 + 			txdp->Control_1 |= TXD_UFO_EN;
  34.588 + 	}
  34.589 + 	txdp->Control_1 |= TXD_GATHER_CODE_LAST;
  34.590 + 
  34.591 +-	if (skb_shinfo(skb)->ufo_size)
  34.592 ++	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  34.593 + 		frg_cnt++; /* as Txd0 was used for inband header */
  34.594 + 
  34.595 + 	tx_fifo = mac_control->tx_FIFO_start[queue];
  34.596 +@@ -3606,7 +3606,7 @@ #ifdef NETIF_F_TSO
  34.597 + 	if (mss)
  34.598 + 		val64 |= TX_FIFO_SPECIAL_FUNC;
  34.599 + #endif
  34.600 +-	if (skb_shinfo(skb)->ufo_size)
  34.601 ++	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  34.602 + 		val64 |= TX_FIFO_SPECIAL_FUNC;
  34.603 + 	writeq(val64, &tx_fifo->List_Control);
  34.604 + 
  34.605 +diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
  34.606 +index 0618cd5..2a55eb3 100644
  34.607 +--- a/drivers/net/sky2.c
  34.608 ++++ b/drivers/net/sky2.c
  34.609 +@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
  34.610 + 	count = sizeof(dma_addr_t) / sizeof(u32);
  34.611 + 	count += skb_shinfo(skb)->nr_frags * count;
  34.612 + 
  34.613 +-	if (skb_shinfo(skb)->tso_size)
  34.614 ++	if (skb_shinfo(skb)->gso_size)
  34.615 + 		++count;
  34.616 + 
  34.617 + 	if (skb->ip_summed == CHECKSUM_HW)
  34.618 +@@ -1197,7 +1197,7 @@ static int sky2_xmit_frame(struct sk_buf
  34.619 + 	}
  34.620 + 
  34.621 + 	/* Check for TCP Segmentation Offload */
  34.622 +-	mss = skb_shinfo(skb)->tso_size;
  34.623 ++	mss = skb_shinfo(skb)->gso_size;
  34.624 + 	if (mss != 0) {
  34.625 + 		/* just drop the packet if non-linear expansion fails */
  34.626 + 		if (skb_header_cloned(skb) &&
  34.627 +diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
  34.628 +index caf4102..fc9164a 100644
  34.629 +--- a/drivers/net/tg3.c
  34.630 ++++ b/drivers/net/tg3.c
  34.631 +@@ -3664,7 +3664,7 @@ static int tg3_start_xmit(struct sk_buff
  34.632 + #if TG3_TSO_SUPPORT != 0
  34.633 + 	mss = 0;
  34.634 + 	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
  34.635 +-	    (mss = skb_shinfo(skb)->tso_size) != 0) {
  34.636 ++	    (mss = skb_shinfo(skb)->gso_size) != 0) {
  34.637 + 		int tcp_opt_len, ip_tcp_len;
  34.638 + 
  34.639 + 		if (skb_header_cloned(skb) &&
  34.640 +diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
  34.641 +index 5b1af39..11de5af 100644
  34.642 +--- a/drivers/net/tulip/winbond-840.c
  34.643 ++++ b/drivers/net/tulip/winbond-840.c
  34.644 +@@ -1605,11 +1605,11 @@ #ifdef CONFIG_PM
  34.645 +  * - get_stats:
  34.646 +  * 	spin_lock_irq(np->lock), doesn't touch hw if not present
  34.647 +  * - hard_start_xmit:
  34.648 +- * 	netif_stop_queue + spin_unlock_wait(&dev->xmit_lock);
  34.649 ++ * 	synchronize_irq + netif_tx_disable;
  34.650 +  * - tx_timeout:
  34.651 +- * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
  34.652 ++ * 	netif_device_detach + netif_tx_disable;
  34.653 +  * - set_multicast_list
  34.654 +- * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
  34.655 ++ * 	netif_device_detach + netif_tx_disable;
  34.656 +  * - interrupt handler
  34.657 +  * 	doesn't touch hw if not present, synchronize_irq waits for
  34.658 +  * 	running instances of the interrupt handler.
  34.659 +@@ -1635,11 +1635,10 @@ static int w840_suspend (struct pci_dev 
  34.660 + 		netif_device_detach(dev);
  34.661 + 		update_csr6(dev, 0);
  34.662 + 		iowrite32(0, ioaddr + IntrEnable);
  34.663 +-		netif_stop_queue(dev);
  34.664 + 		spin_unlock_irq(&np->lock);
  34.665 + 
  34.666 +-		spin_unlock_wait(&dev->xmit_lock);
  34.667 + 		synchronize_irq(dev->irq);
  34.668 ++		netif_tx_disable(dev);
  34.669 + 	
  34.670 + 		np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
  34.671 + 
  34.672 +diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
  34.673 +index 4c76cb7..30c48c9 100644
  34.674 +--- a/drivers/net/typhoon.c
  34.675 ++++ b/drivers/net/typhoon.c
  34.676 +@@ -340,7 +340,7 @@ #define typhoon_synchronize_irq(x) synch
  34.677 + #endif
  34.678 + 
  34.679 + #if defined(NETIF_F_TSO)
  34.680 +-#define skb_tso_size(x)		(skb_shinfo(x)->tso_size)
  34.681 ++#define skb_tso_size(x)		(skb_shinfo(x)->gso_size)
  34.682 + #define TSO_NUM_DESCRIPTORS	2
  34.683 + #define TSO_OFFLOAD_ON		TYPHOON_OFFLOAD_TCP_SEGMENT
  34.684 + #else
  34.685 +diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
  34.686 +index ed1f837..2eb6b5f 100644
  34.687 +--- a/drivers/net/via-velocity.c
  34.688 ++++ b/drivers/net/via-velocity.c
  34.689 +@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff 
  34.690 + 
  34.691 + 	int pktlen = skb->len;
  34.692 + 
  34.693 ++#ifdef VELOCITY_ZERO_COPY_SUPPORT
  34.694 ++	if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
  34.695 ++		kfree_skb(skb);
  34.696 ++		return 0;
  34.697 ++	}
  34.698 ++#endif
  34.699 ++
  34.700 + 	spin_lock_irqsave(&vptr->lock, flags);
  34.701 + 
  34.702 + 	index = vptr->td_curr[qnum];
  34.703 +@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff 
  34.704 + 	 */
  34.705 + 	if (pktlen < ETH_ZLEN) {
  34.706 + 		/* Cannot occur until ZC support */
  34.707 +-		if(skb_linearize(skb, GFP_ATOMIC))
  34.708 +-			return 0; 
  34.709 + 		pktlen = ETH_ZLEN;
  34.710 + 		memcpy(tdinfo->buf, skb->data, skb->len);
  34.711 + 		memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
  34.712 +@@ -1933,7 +1938,6 @@ #ifdef VELOCITY_ZERO_COPY_SUPPORT
  34.713 + 		int nfrags = skb_shinfo(skb)->nr_frags;
  34.714 + 		tdinfo->skb = skb;
  34.715 + 		if (nfrags > 6) {
  34.716 +-			skb_linearize(skb, GFP_ATOMIC);
  34.717 + 			memcpy(tdinfo->buf, skb->data, skb->len);
  34.718 + 			tdinfo->skb_dma[0] = tdinfo->buf_dma;
  34.719 + 			td_ptr->tdesc0.pktsize = 
  34.720 +diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
  34.721 +index 6fd0bf7..75237c1 100644
  34.722 +--- a/drivers/net/wireless/orinoco.c
  34.723 ++++ b/drivers/net/wireless/orinoco.c
  34.724 +@@ -1835,7 +1835,9 @@ static int __orinoco_program_rids(struct
  34.725 + 	/* Set promiscuity / multicast*/
  34.726 + 	priv->promiscuous = 0;
  34.727 + 	priv->mc_count = 0;
  34.728 +-	__orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
  34.729 ++
  34.730 ++	/* FIXME: what about netif_tx_lock */
  34.731 ++	__orinoco_set_multicast_list(dev);
  34.732 + 
  34.733 + 	return 0;
  34.734 + }
  34.735 +diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
  34.736 +index 82cb4af..57cec40 100644
  34.737 +--- a/drivers/s390/net/qeth_eddp.c
  34.738 ++++ b/drivers/s390/net/qeth_eddp.c
  34.739 +@@ -421,7 +421,7 @@ #endif /* CONFIG_QETH_VLAN */
  34.740 +        }
  34.741 + 	tcph = eddp->skb->h.th;
  34.742 + 	while (eddp->skb_offset < eddp->skb->len) {
  34.743 +-		data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
  34.744 ++		data_len = min((int)skb_shinfo(eddp->skb)->gso_size,
  34.745 + 			       (int)(eddp->skb->len - eddp->skb_offset));
  34.746 + 		/* prepare qdio hdr */
  34.747 + 		if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
  34.748 +@@ -516,20 +516,20 @@ qeth_eddp_calc_num_pages(struct qeth_edd
  34.749 + 	
  34.750 + 	QETH_DBF_TEXT(trace, 5, "eddpcanp");
  34.751 + 	/* can we put multiple skbs in one page? */
  34.752 +-	skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
  34.753 ++	skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len);
  34.754 + 	if (skbs_per_page > 1){
  34.755 +-		ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
  34.756 ++		ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) /
  34.757 + 				 skbs_per_page + 1;
  34.758 + 		ctx->elements_per_skb = 1;
  34.759 + 	} else {
  34.760 + 		/* no -> how many elements per skb? */
  34.761 +-		ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
  34.762 ++		ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len +
  34.763 + 				     PAGE_SIZE) >> PAGE_SHIFT;
  34.764 + 		ctx->num_pages = ctx->elements_per_skb *
  34.765 +-				 (skb_shinfo(skb)->tso_segs + 1);
  34.766 ++				 (skb_shinfo(skb)->gso_segs + 1);
  34.767 + 	}
  34.768 + 	ctx->num_elements = ctx->elements_per_skb *
  34.769 +-			    (skb_shinfo(skb)->tso_segs + 1);
  34.770 ++			    (skb_shinfo(skb)->gso_segs + 1);
  34.771 + }
  34.772 + 
  34.773 + static inline struct qeth_eddp_context *
  34.774 +diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
  34.775 +index dba7f7f..d9cc997 100644
  34.776 +--- a/drivers/s390/net/qeth_main.c
  34.777 ++++ b/drivers/s390/net/qeth_main.c
  34.778 +@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
  34.779 + 	queue = card->qdio.out_qs
  34.780 + 		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
  34.781 + 
  34.782 +-	if (skb_shinfo(skb)->tso_size)
  34.783 ++	if (skb_shinfo(skb)->gso_size)
  34.784 + 		large_send = card->options.large_send;
  34.785 + 
  34.786 + 	/*are we able to do TSO ? If so ,prepare and send it from here */
  34.787 +@@ -4501,7 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
  34.788 + 		card->stats.tx_packets++;
  34.789 + 		card->stats.tx_bytes += skb->len;
  34.790 + #ifdef CONFIG_QETH_PERF_STATS
  34.791 +-		if (skb_shinfo(skb)->tso_size &&
  34.792 ++		if (skb_shinfo(skb)->gso_size &&
  34.793 + 		   !(large_send == QETH_LARGE_SEND_NO)) {
  34.794 + 			card->perf_stats.large_send_bytes += skb->len;
  34.795 + 			card->perf_stats.large_send_cnt++;
  34.796 +diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
  34.797 +index 1286dde..89cbf34 100644
  34.798 +--- a/drivers/s390/net/qeth_tso.h
  34.799 ++++ b/drivers/s390/net/qeth_tso.h
  34.800 +@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *c
  34.801 + 	hdr->ext.hdr_version = 1;
  34.802 + 	hdr->ext.hdr_len     = 28;
  34.803 + 	/*insert non-fix values */
  34.804 +-	hdr->ext.mss = skb_shinfo(skb)->tso_size;
  34.805 ++	hdr->ext.mss = skb_shinfo(skb)->gso_size;
  34.806 + 	hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
  34.807 + 	hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
  34.808 + 				       sizeof(struct qeth_hdr_tso));
  34.809 +diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
  34.810 +index 93535f0..9269df7 100644
  34.811 +--- a/include/linux/ethtool.h
  34.812 ++++ b/include/linux/ethtool.h
  34.813 +@@ -408,6 +408,8 @@ #define ETHTOOL_STSO		0x0000001f /* Set 
  34.814 + #define ETHTOOL_GPERMADDR	0x00000020 /* Get permanent hardware address */
  34.815 + #define ETHTOOL_GUFO		0x00000021 /* Get UFO enable (ethtool_value) */
  34.816 + #define ETHTOOL_SUFO		0x00000022 /* Set UFO enable (ethtool_value) */
  34.817 ++#define ETHTOOL_GGSO		0x00000023 /* Get GSO enable (ethtool_value) */
  34.818 ++#define ETHTOOL_SGSO		0x00000024 /* Set GSO enable (ethtool_value) */
  34.819 + 
  34.820 + /* compatibility with older code */
  34.821 + #define SPARC_ETH_GSET		ETHTOOL_GSET
  34.822 +diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
  34.823 +index 7fda03d..47b0965 100644
  34.824 +--- a/include/linux/netdevice.h
  34.825 ++++ b/include/linux/netdevice.h
  34.826 +@@ -230,7 +230,8 @@ enum netdev_state_t
  34.827 + 	__LINK_STATE_SCHED,
  34.828 + 	__LINK_STATE_NOCARRIER,
  34.829 + 	__LINK_STATE_RX_SCHED,
  34.830 +-	__LINK_STATE_LINKWATCH_PENDING
  34.831 ++	__LINK_STATE_LINKWATCH_PENDING,
  34.832 ++	__LINK_STATE_QDISC_RUNNING,
  34.833 + };
  34.834 + 
  34.835 + 
  34.836 +@@ -306,9 +307,17 @@ #define NETIF_F_HW_VLAN_TX	128	/* Transm
  34.837 + #define NETIF_F_HW_VLAN_RX	256	/* Receive VLAN hw acceleration */
  34.838 + #define NETIF_F_HW_VLAN_FILTER	512	/* Receive filtering on VLAN */
  34.839 + #define NETIF_F_VLAN_CHALLENGED	1024	/* Device cannot handle VLAN packets */
  34.840 +-#define NETIF_F_TSO		2048	/* Can offload TCP/IP segmentation */
  34.841 ++#define NETIF_F_GSO		2048	/* Enable software GSO. */
  34.842 + #define NETIF_F_LLTX		4096	/* LockLess TX */
  34.843 +-#define NETIF_F_UFO             8192    /* Can offload UDP Large Send*/
  34.844 ++
  34.845 ++	/* Segmentation offload features */
  34.846 ++#define NETIF_F_GSO_SHIFT	16
  34.847 ++#define NETIF_F_TSO		(SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
  34.848 ++#define NETIF_F_UFO		(SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT)
  34.849 ++#define NETIF_F_GSO_ROBUST	(SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
  34.850 ++
  34.851 ++#define NETIF_F_GEN_CSUM	(NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
  34.852 ++#define NETIF_F_ALL_CSUM	(NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
  34.853 + 
  34.854 + 	struct net_device	*next_sched;
  34.855 + 
  34.856 +@@ -394,6 +403,9 @@ #define NETIF_F_UFO             8192    
  34.857 + 	struct list_head	qdisc_list;
  34.858 + 	unsigned long		tx_queue_len;	/* Max frames per queue allowed */
  34.859 + 
  34.860 ++	/* Partially transmitted GSO packet. */
  34.861 ++	struct sk_buff		*gso_skb;
  34.862 ++
  34.863 + 	/* ingress path synchronizer */
  34.864 + 	spinlock_t		ingress_lock;
  34.865 + 	struct Qdisc		*qdisc_ingress;
  34.866 +@@ -402,7 +414,7 @@ #define NETIF_F_UFO             8192    
  34.867 +  * One part is mostly used on xmit path (device)
  34.868 +  */
  34.869 + 	/* hard_start_xmit synchronizer */
  34.870 +-	spinlock_t		xmit_lock ____cacheline_aligned_in_smp;
  34.871 ++	spinlock_t		_xmit_lock ____cacheline_aligned_in_smp;
  34.872 + 	/* cpu id of processor entered to hard_start_xmit or -1,
  34.873 + 	   if nobody entered there.
  34.874 + 	 */
  34.875 +@@ -527,6 +539,8 @@ struct packet_type {
  34.876 + 					 struct net_device *,
  34.877 + 					 struct packet_type *,
  34.878 + 					 struct net_device *);
  34.879 ++	struct sk_buff		*(*gso_segment)(struct sk_buff *skb,
  34.880 ++						int features);
  34.881 + 	void			*af_packet_priv;
  34.882 + 	struct list_head	list;
  34.883 + };
  34.884 +@@ -693,7 +707,8 @@ extern int		dev_change_name(struct net_d
  34.885 + extern int		dev_set_mtu(struct net_device *, int);
  34.886 + extern int		dev_set_mac_address(struct net_device *,
  34.887 + 					    struct sockaddr *);
  34.888 +-extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
  34.889 ++extern int		dev_hard_start_xmit(struct sk_buff *skb,
  34.890 ++					    struct net_device *dev);
  34.891 + 
  34.892 + extern void		dev_init(void);
  34.893 + 
  34.894 +@@ -900,11 +915,43 @@ static inline void __netif_rx_complete(s
  34.895 + 	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
  34.896 + }
  34.897 + 
  34.898 ++static inline void netif_tx_lock(struct net_device *dev)
  34.899 ++{
  34.900 ++	spin_lock(&dev->_xmit_lock);
  34.901 ++	dev->xmit_lock_owner = smp_processor_id();
  34.902 ++}
  34.903 ++
  34.904 ++static inline void netif_tx_lock_bh(struct net_device *dev)
  34.905 ++{
  34.906 ++	spin_lock_bh(&dev->_xmit_lock);
  34.907 ++	dev->xmit_lock_owner = smp_processor_id();
  34.908 ++}
  34.909 ++
  34.910 ++static inline int netif_tx_trylock(struct net_device *dev)
  34.911 ++{
  34.912 ++	int err = spin_trylock(&dev->_xmit_lock);
  34.913 ++	if (!err)
  34.914 ++		dev->xmit_lock_owner = smp_processor_id();
  34.915 ++	return err;
  34.916 ++}
  34.917 ++
  34.918 ++static inline void netif_tx_unlock(struct net_device *dev)
  34.919 ++{
  34.920 ++	dev->xmit_lock_owner = -1;
  34.921 ++	spin_unlock(&dev->_xmit_lock);
  34.922 ++}
  34.923 ++
  34.924 ++static inline void netif_tx_unlock_bh(struct net_device *dev)
  34.925 ++{
  34.926 ++	dev->xmit_lock_owner = -1;
  34.927 ++	spin_unlock_bh(&dev->_xmit_lock);
  34.928 ++}
  34.929 ++
  34.930 + static inline void netif_tx_disable(struct net_device *dev)
  34.931 + {
  34.932 +-	spin_lock_bh(&dev->xmit_lock);
  34.933 ++	netif_tx_lock_bh(dev);
  34.934 + 	netif_stop_queue(dev);
  34.935 +-	spin_unlock_bh(&dev->xmit_lock);
  34.936 ++	netif_tx_unlock_bh(dev);
  34.937 + }
  34.938 + 
  34.939 + /* These functions live elsewhere (drivers/net/net_init.c, but related) */
  34.940 +@@ -932,6 +979,7 @@ extern int		netdev_max_backlog;
  34.941 + extern int		weight_p;
  34.942 + extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
  34.943 + extern int skb_checksum_help(struct sk_buff *skb, int inward);
  34.944 ++extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features);
  34.945 + #ifdef CONFIG_BUG
  34.946 + extern void netdev_rx_csum_fault(struct net_device *dev);
  34.947 + #else
  34.948 +@@ -951,6 +999,18 @@ #endif
  34.949 + 
  34.950 + extern void linkwatch_run_queue(void);
  34.951 + 
  34.952 ++static inline int skb_gso_ok(struct sk_buff *skb, int features)
  34.953 ++{
  34.954 ++	int feature = skb_shinfo(skb)->gso_size ?
  34.955 ++		      skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
  34.956 ++	return (features & feature) == feature;
  34.957 ++}
  34.958 ++
  34.959 ++static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
  34.960 ++{
  34.961 ++	return !skb_gso_ok(skb, dev->features);
  34.962 ++}
  34.963 ++
  34.964 + #endif /* __KERNEL__ */
  34.965 + 
  34.966 + #endif	/* _LINUX_DEV_H */
  34.967 +diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
  34.968 +index ad7cc22..b19d45d 100644
  34.969 +--- a/include/linux/skbuff.h
  34.970 ++++ b/include/linux/skbuff.h
  34.971 +@@ -134,9 +134,10 @@ struct skb_frag_struct {
  34.972 + struct skb_shared_info {
  34.973 + 	atomic_t	dataref;
  34.974 + 	unsigned short	nr_frags;
  34.975 +-	unsigned short	tso_size;
  34.976 +-	unsigned short	tso_segs;
  34.977 +-	unsigned short  ufo_size;
  34.978 ++	unsigned short	gso_size;
  34.979 ++	/* Warning: this field is not always filled in (UFO)! */
  34.980 ++	unsigned short	gso_segs;
  34.981 ++	unsigned short  gso_type;
  34.982 + 	unsigned int    ip6_frag_id;
  34.983 + 	struct sk_buff	*frag_list;
  34.984 + 	skb_frag_t	frags[MAX_SKB_FRAGS];
  34.985 +@@ -168,6 +169,14 @@ enum {
  34.986 + 	SKB_FCLONE_CLONE,
  34.987 + };
  34.988 + 
  34.989 ++enum {
  34.990 ++	SKB_GSO_TCPV4 = 1 << 0,
  34.991 ++	SKB_GSO_UDPV4 = 1 << 1,
  34.992 ++
  34.993 ++	/* This indicates the skb is from an untrusted source. */
  34.994 ++	SKB_GSO_DODGY = 1 << 2,
  34.995 ++};
  34.996 ++
  34.997 + /** 
  34.998 +  *	struct sk_buff - socket buffer
  34.999 +  *	@next: Next buffer in list
 34.1000 +@@ -1148,18 +1157,34 @@ static inline int skb_can_coalesce(struc
 34.1001 + 	return 0;
 34.1002 + }
 34.1003 + 
 34.1004 ++static inline int __skb_linearize(struct sk_buff *skb)
 34.1005 ++{
 34.1006 ++	return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM;
 34.1007 ++}
 34.1008 ++
 34.1009 + /**
 34.1010 +  *	skb_linearize - convert paged skb to linear one
 34.1011 +  *	@skb: buffer to linarize
 34.1012 +- *	@gfp: allocation mode
 34.1013 +  *
 34.1014 +  *	If there is no free memory -ENOMEM is returned, otherwise zero
 34.1015 +  *	is returned and the old skb data released.
 34.1016 +  */
 34.1017 +-extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp);
 34.1018 +-static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp)
 34.1019 ++static inline int skb_linearize(struct sk_buff *skb)
 34.1020 ++{
 34.1021 ++	return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
 34.1022 ++}
 34.1023 ++
 34.1024 ++/**
 34.1025 ++ *	skb_linearize_cow - make sure skb is linear and writable
 34.1026 ++ *	@skb: buffer to process
 34.1027 ++ *
 34.1028 ++ *	If there is no free memory -ENOMEM is returned, otherwise zero
 34.1029 ++ *	is returned and the old skb data released.
 34.1030 ++ */
 34.1031 ++static inline int skb_linearize_cow(struct sk_buff *skb)
 34.1032 + {
 34.1033 +-	return __skb_linearize(skb, gfp);
 34.1034 ++	return skb_is_nonlinear(skb) || skb_cloned(skb) ?
 34.1035 ++	       __skb_linearize(skb) : 0;
 34.1036 + }
 34.1037 + 
 34.1038 + /**
 34.1039 +@@ -1254,6 +1279,7 @@ extern void	       skb_split(struct sk_b
 34.1040 + 				 struct sk_buff *skb1, const u32 len);
 34.1041 + 
 34.1042 + extern void	       skb_release_data(struct sk_buff *skb);
 34.1043 ++extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
 34.1044 + 
 34.1045 + static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
 34.1046 + 				       int len, void *buffer)
 34.1047 +diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
 34.1048 +index b94d1ad..75b5b93 100644
 34.1049 +--- a/include/net/pkt_sched.h
 34.1050 ++++ b/include/net/pkt_sched.h
 34.1051 +@@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_ge
 34.1052 + 		struct rtattr *tab);
 34.1053 + extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
 34.1054 + 
 34.1055 +-extern int qdisc_restart(struct net_device *dev);
 34.1056 ++extern void __qdisc_run(struct net_device *dev);
 34.1057 + 
 34.1058 + static inline void qdisc_run(struct net_device *dev)
 34.1059 + {
 34.1060 +-	while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0)
 34.1061 +-		/* NOTHING */;
 34.1062 ++	if (!netif_queue_stopped(dev) &&
 34.1063 ++	    !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
 34.1064 ++		__qdisc_run(dev);
 34.1065 + }
 34.1066 + 
 34.1067 + extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
 34.1068 +diff --git a/include/net/protocol.h b/include/net/protocol.h
 34.1069 +index 6dc5970..0d2dcdb 100644
 34.1070 +--- a/include/net/protocol.h
 34.1071 ++++ b/include/net/protocol.h
 34.1072 +@@ -37,6 +37,8 @@ #define MAX_INET_PROTOS	256		/* Must be 
 34.1073 + struct net_protocol {
 34.1074 + 	int			(*handler)(struct sk_buff *skb);
 34.1075 + 	void			(*err_handler)(struct sk_buff *skb, u32 info);
 34.1076 ++	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
 34.1077 ++					       int features);
 34.1078 + 	int			no_policy;
 34.1079 + };
 34.1080 + 
 34.1081 +diff --git a/include/net/sock.h b/include/net/sock.h
 34.1082 +index f63d0d5..a8e8d21 100644
 34.1083 +--- a/include/net/sock.h
 34.1084 ++++ b/include/net/sock.h
 34.1085 +@@ -1064,9 +1064,13 @@ static inline void sk_setup_caps(struct 
 34.1086 + {
 34.1087 + 	__sk_dst_set(sk, dst);
 34.1088 + 	sk->sk_route_caps = dst->dev->features;
 34.1089 ++	if (sk->sk_route_caps & NETIF_F_GSO)
 34.1090 ++		sk->sk_route_caps |= NETIF_F_TSO;
 34.1091 + 	if (sk->sk_route_caps & NETIF_F_TSO) {
 34.1092 + 		if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
 34.1093 + 			sk->sk_route_caps &= ~NETIF_F_TSO;
 34.1094 ++		else 
 34.1095 ++			sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
 34.1096 + 	}
 34.1097 + }
 34.1098 + 
 34.1099 +diff --git a/include/net/tcp.h b/include/net/tcp.h
 34.1100 +index 77f21c6..70e1d5f 100644
 34.1101 +--- a/include/net/tcp.h
 34.1102 ++++ b/include/net/tcp.h
 34.1103 +@@ -552,13 +552,13 @@ #include <net/tcp_ecn.h>
 34.1104 +  */
 34.1105 + static inline int tcp_skb_pcount(const struct sk_buff *skb)
 34.1106 + {
 34.1107 +-	return skb_shinfo(skb)->tso_segs;
 34.1108 ++	return skb_shinfo(skb)->gso_segs;
 34.1109 + }
 34.1110 + 
 34.1111 + /* This is valid iff tcp_skb_pcount() > 1. */
 34.1112 + static inline int tcp_skb_mss(const struct sk_buff *skb)
 34.1113 + {
 34.1114 +-	return skb_shinfo(skb)->tso_size;
 34.1115 ++	return skb_shinfo(skb)->gso_size;
 34.1116 + }
 34.1117 + 
 34.1118 + static inline void tcp_dec_pcount_approx(__u32 *count,
 34.1119 +@@ -1063,6 +1063,8 @@ extern struct request_sock_ops tcp_reque
 34.1120 + 
 34.1121 + extern int tcp_v4_destroy_sock(struct sock *sk);
 34.1122 + 
 34.1123 ++extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
 34.1124 ++
 34.1125 + #ifdef CONFIG_PROC_FS
 34.1126 + extern int  tcp4_proc_init(void);
 34.1127 + extern void tcp4_proc_exit(void);
 34.1128 +diff --git a/net/atm/clip.c b/net/atm/clip.c
 34.1129 +index 1842a4e..6dc21a7 100644
 34.1130 +--- a/net/atm/clip.c
 34.1131 ++++ b/net/atm/clip.c
 34.1132 +@@ -101,7 +101,7 @@ static void unlink_clip_vcc(struct clip_
 34.1133 + 		printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc);
 34.1134 + 		return;
 34.1135 + 	}
 34.1136 +-	spin_lock_bh(&entry->neigh->dev->xmit_lock);	/* block clip_start_xmit() */
 34.1137 ++	netif_tx_lock_bh(entry->neigh->dev);	/* block clip_start_xmit() */
 34.1138 + 	entry->neigh->used = jiffies;
 34.1139 + 	for (walk = &entry->vccs; *walk; walk = &(*walk)->next)
 34.1140 + 		if (*walk == clip_vcc) {
 34.1141 +@@ -125,7 +125,7 @@ static void unlink_clip_vcc(struct clip_
 34.1142 + 	printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc "
 34.1143 + 	  "0x%p)\n",entry,clip_vcc);
 34.1144 + out:
 34.1145 +-	spin_unlock_bh(&entry->neigh->dev->xmit_lock);
 34.1146 ++	netif_tx_unlock_bh(entry->neigh->dev);
 34.1147 + }
 34.1148 + 
 34.1149 + /* The neighbour entry n->lock is held. */
 34.1150 +diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
 34.1151 +index 0b33a7b..180e79b 100644
 34.1152 +--- a/net/bridge/br_device.c
 34.1153 ++++ b/net/bridge/br_device.c
 34.1154 +@@ -146,9 +146,9 @@ static int br_set_tx_csum(struct net_dev
 34.1155 + 	struct net_bridge *br = netdev_priv(dev);
 34.1156 + 
 34.1157 + 	if (data)
 34.1158 +-		br->feature_mask |= NETIF_F_IP_CSUM;
 34.1159 ++		br->feature_mask |= NETIF_F_NO_CSUM;
 34.1160 + 	else
 34.1161 +-		br->feature_mask &= ~NETIF_F_IP_CSUM;
 34.1162 ++		br->feature_mask &= ~NETIF_F_ALL_CSUM;
 34.1163 + 
 34.1164 + 	br_features_recompute(br);
 34.1165 + 	return 0;
 34.1166 +@@ -185,6 +185,6 @@ void br_dev_setup(struct net_device *dev
 34.1167 + 	dev->set_mac_address = br_set_mac_address;
 34.1168 + 	dev->priv_flags = IFF_EBRIDGE;
 34.1169 + 
 34.1170 +- 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
 34.1171 +- 		| NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_IP_CSUM;
 34.1172 ++ 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
 34.1173 ++ 			NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST;
 34.1174 + }
 34.1175 +diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
 34.1176 +index 2d24fb4..00b1128 100644
 34.1177 +--- a/net/bridge/br_forward.c
 34.1178 ++++ b/net/bridge/br_forward.c
 34.1179 +@@ -32,7 +32,7 @@ static inline int should_deliver(const s
 34.1180 + int br_dev_queue_push_xmit(struct sk_buff *skb)
 34.1181 + {
 34.1182 + 	/* drop mtu oversized packets except tso */
 34.1183 +-	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
 34.1184 ++	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
 34.1185 + 		kfree_skb(skb);
 34.1186 + 	else {
 34.1187 + #ifdef CONFIG_BRIDGE_NETFILTER
 34.1188 +diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
 34.1189 +index f36b35e..0617146 100644
 34.1190 +--- a/net/bridge/br_if.c
 34.1191 ++++ b/net/bridge/br_if.c
 34.1192 +@@ -385,17 +385,28 @@ void br_features_recompute(struct net_br
 34.1193 + 	struct net_bridge_port *p;
 34.1194 + 	unsigned long features, checksum;
 34.1195 + 
 34.1196 +-	features = br->feature_mask &~ NETIF_F_IP_CSUM;
 34.1197 +-	checksum = br->feature_mask & NETIF_F_IP_CSUM;
 34.1198 ++	checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0;
 34.1199 ++	features = br->feature_mask & ~NETIF_F_ALL_CSUM;
 34.1200 + 
 34.1201 + 	list_for_each_entry(p, &br->port_list, list) {
 34.1202 +-		if (!(p->dev->features 
 34.1203 +-		      & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)))
 34.1204 ++		unsigned long feature = p->dev->features;
 34.1205 ++
 34.1206 ++		if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
 34.1207 ++			checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
 34.1208 ++		if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
 34.1209 ++			checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
 34.1210 ++		if (!(feature & NETIF_F_IP_CSUM))
 34.1211 + 			checksum = 0;
 34.1212 +-		features &= p->dev->features;
 34.1213 ++
 34.1214 ++		if (feature & NETIF_F_GSO)
 34.1215 ++			feature |= NETIF_F_TSO;
 34.1216 ++		feature |= NETIF_F_GSO;
 34.1217 ++
 34.1218 ++		features &= feature;
 34.1219 + 	}
 34.1220 + 
 34.1221 +-	br->dev->features = features | checksum | NETIF_F_LLTX;
 34.1222 ++	br->dev->features = features | checksum | NETIF_F_LLTX |
 34.1223 ++			    NETIF_F_GSO_ROBUST;
 34.1224 + }
 34.1225 + 
 34.1226 + /* called with RTNL */
 34.1227 +diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
 34.1228 +index 9e27373..588207f 100644
 34.1229 +--- a/net/bridge/br_netfilter.c
 34.1230 ++++ b/net/bridge/br_netfilter.c
 34.1231 +@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
 34.1232 + {
 34.1233 + 	if (skb->protocol == htons(ETH_P_IP) &&
 34.1234 + 	    skb->len > skb->dev->mtu &&
 34.1235 +-	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
 34.1236 ++	    !skb_shinfo(skb)->gso_size)
 34.1237 + 		return ip_fragment(skb, br_dev_queue_push_xmit);
 34.1238 + 	else
 34.1239 + 		return br_dev_queue_push_xmit(skb);
 34.1240 +diff --git a/net/core/dev.c b/net/core/dev.c
 34.1241 +index 12a214c..32e1056 100644
 34.1242 +--- a/net/core/dev.c
 34.1243 ++++ b/net/core/dev.c
 34.1244 +@@ -115,6 +115,7 @@ #include <linux/wireless.h>		/* Note : w
 34.1245 + #include <net/iw_handler.h>
 34.1246 + #endif	/* CONFIG_NET_RADIO */
 34.1247 + #include <asm/current.h>
 34.1248 ++#include <linux/err.h>
 34.1249 + 
 34.1250 + /*
 34.1251 +  *	The list of packet types we will receive (as opposed to discard)
 34.1252 +@@ -1032,7 +1033,7 @@ static inline void net_timestamp(struct 
 34.1253 +  *	taps currently in use.
 34.1254 +  */
 34.1255 + 
 34.1256 +-void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 34.1257 ++static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 34.1258 + {
 34.1259 + 	struct packet_type *ptype;
 34.1260 + 
 34.1261 +@@ -1106,6 +1107,45 @@ out:	
 34.1262 + 	return ret;
 34.1263 + }
 34.1264 + 
 34.1265 ++/**
 34.1266 ++ *	skb_gso_segment - Perform segmentation on skb.
 34.1267 ++ *	@skb: buffer to segment
 34.1268 ++ *	@features: features for the output path (see dev->features)
 34.1269 ++ *
 34.1270 ++ *	This function segments the given skb and returns a list of segments.
 34.1271 ++ *
 34.1272 ++ *	It may return NULL if the skb requires no segmentation.  This is
 34.1273 ++ *	only possible when GSO is used for verifying header integrity.
 34.1274 ++ */
 34.1275 ++struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
 34.1276 ++{
 34.1277 ++	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
 34.1278 ++	struct packet_type *ptype;
 34.1279 ++	int type = skb->protocol;
 34.1280 ++
 34.1281 ++	BUG_ON(skb_shinfo(skb)->frag_list);
 34.1282 ++	BUG_ON(skb->ip_summed != CHECKSUM_HW);
 34.1283 ++
 34.1284 ++	skb->mac.raw = skb->data;
 34.1285 ++	skb->mac_len = skb->nh.raw - skb->data;
 34.1286 ++	__skb_pull(skb, skb->mac_len);
 34.1287 ++
 34.1288 ++	rcu_read_lock();
 34.1289 ++	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
 34.1290 ++		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
 34.1291 ++			segs = ptype->gso_segment(skb, features);
 34.1292 ++			break;
 34.1293 ++		}
 34.1294 ++	}
 34.1295 ++	rcu_read_unlock();
 34.1296 ++
 34.1297 ++	__skb_push(skb, skb->data - skb->mac.raw);
 34.1298 ++
 34.1299 ++	return segs;
 34.1300 ++}
 34.1301 ++
 34.1302 ++EXPORT_SYMBOL(skb_gso_segment);
 34.1303 ++
 34.1304 + /* Take action when hardware reception checksum errors are detected. */
 34.1305 + #ifdef CONFIG_BUG
 34.1306 + void netdev_rx_csum_fault(struct net_device *dev)
 34.1307 +@@ -1142,75 +1182,108 @@ #else
 34.1308 + #define illegal_highdma(dev, skb)	(0)
 34.1309 + #endif
 34.1310 + 
 34.1311 +-/* Keep head the same: replace data */
 34.1312 +-int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
 34.1313 +-{
 34.1314 +-	unsigned int size;
 34.1315 +-	u8 *data;
 34.1316 +-	long offset;
 34.1317 +-	struct skb_shared_info *ninfo;
 34.1318 +-	int headerlen = skb->data - skb->head;
 34.1319 +-	int expand = (skb->tail + skb->data_len) - skb->end;
 34.1320 +-
 34.1321 +-	if (skb_shared(skb))
 34.1322 +-		BUG();
 34.1323 +-
 34.1324 +-	if (expand <= 0)
 34.1325 +-		expand = 0;
 34.1326 +-
 34.1327 +-	size = skb->end - skb->head + expand;
 34.1328 +-	size = SKB_DATA_ALIGN(size);
 34.1329 +-	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
 34.1330 +-	if (!data)
 34.1331 +-		return -ENOMEM;
 34.1332 +-
 34.1333 +-	/* Copy entire thing */
 34.1334 +-	if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))
 34.1335 +-		BUG();
 34.1336 +-
 34.1337 +-	/* Set up shinfo */
 34.1338 +-	ninfo = (struct skb_shared_info*)(data + size);
 34.1339 +-	atomic_set(&ninfo->dataref, 1);
 34.1340 +-	ninfo->tso_size = skb_shinfo(skb)->tso_size;
 34.1341 +-	ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
 34.1342 +-	ninfo->nr_frags = 0;
 34.1343 +-	ninfo->frag_list = NULL;
 34.1344 +-
 34.1345 +-	/* Offset between the two in bytes */
 34.1346 +-	offset = data - skb->head;
 34.1347 +-
 34.1348 +-	/* Free old data. */
 34.1349 +-	skb_release_data(skb);
 34.1350 +-
 34.1351 +-	skb->head = data;
 34.1352 +-	skb->end  = data + size;
 34.1353 +-
 34.1354 +-	/* Set up new pointers */
 34.1355 +-	skb->h.raw   += offset;
 34.1356 +-	skb->nh.raw  += offset;
 34.1357 +-	skb->mac.raw += offset;
 34.1358 +-	skb->tail    += offset;
 34.1359 +-	skb->data    += offset;
 34.1360 +-
 34.1361 +-	/* We are no longer a clone, even if we were. */
 34.1362 +-	skb->cloned    = 0;
 34.1363 +-
 34.1364 +-	skb->tail     += skb->data_len;
 34.1365 +-	skb->data_len  = 0;
 34.1366 ++struct dev_gso_cb {
 34.1367 ++	void (*destructor)(struct sk_buff *skb);
 34.1368 ++};
 34.1369 ++
 34.1370 ++#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
 34.1371 ++
 34.1372 ++static void dev_gso_skb_destructor(struct sk_buff *skb)
 34.1373 ++{
 34.1374 ++	struct dev_gso_cb *cb;
 34.1375 ++
 34.1376 ++	do {
 34.1377 ++		struct sk_buff *nskb = skb->next;
 34.1378 ++
 34.1379 ++		skb->next = nskb->next;
 34.1380 ++		nskb->next = NULL;
 34.1381 ++		kfree_skb(nskb);
 34.1382 ++	} while (skb->next);
 34.1383 ++
 34.1384 ++	cb = DEV_GSO_CB(skb);
 34.1385 ++	if (cb->destructor)
 34.1386 ++		cb->destructor(skb);
 34.1387 ++}
 34.1388 ++
 34.1389 ++/**
 34.1390 ++ *	dev_gso_segment - Perform emulated hardware segmentation on skb.
 34.1391 ++ *	@skb: buffer to segment
 34.1392 ++ *
 34.1393 ++ *	This function segments the given skb and stores the list of segments
 34.1394 ++ *	in skb->next.
 34.1395 ++ */
 34.1396 ++static int dev_gso_segment(struct sk_buff *skb)
 34.1397 ++{
 34.1398 ++	struct net_device *dev = skb->dev;
 34.1399 ++	struct sk_buff *segs;
 34.1400 ++	int features = dev->features & ~(illegal_highdma(dev, skb) ?
 34.1401 ++					 NETIF_F_SG : 0);
 34.1402 ++
 34.1403 ++	segs = skb_gso_segment(skb, features);
 34.1404 ++
 34.1405 ++	/* Verifying header integrity only. */
 34.1406 ++	if (!segs)
 34.1407 ++		return 0;
 34.1408 ++
 34.1409 ++	if (unlikely(IS_ERR(segs)))
 34.1410 ++		return PTR_ERR(segs);
 34.1411 ++
 34.1412 ++	skb->next = segs;
 34.1413 ++	DEV_GSO_CB(skb)->destructor = skb->destructor;
 34.1414 ++	skb->destructor = dev_gso_skb_destructor;
 34.1415 ++
 34.1416 ++	return 0;
 34.1417 ++}
 34.1418 ++
 34.1419 ++int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 34.1420 ++{
 34.1421 ++	if (likely(!skb->next)) {
 34.1422 ++		if (netdev_nit)
 34.1423 ++			dev_queue_xmit_nit(skb, dev);
 34.1424 ++
 34.1425 ++		if (netif_needs_gso(dev, skb)) {
 34.1426 ++			if (unlikely(dev_gso_segment(skb)))
 34.1427 ++				goto out_kfree_skb;
 34.1428 ++			if (skb->next)
 34.1429 ++				goto gso;
 34.1430 ++		}
 34.1431 ++
 34.1432 ++		return dev->hard_start_xmit(skb, dev);
 34.1433 ++	}
 34.1434 ++
 34.1435 ++gso:
 34.1436 ++	do {
 34.1437 ++		struct sk_buff *nskb = skb->next;
 34.1438 ++		int rc;
 34.1439 ++
 34.1440 ++		skb->next = nskb->next;
 34.1441 ++		nskb->next = NULL;
 34.1442 ++		rc = dev->hard_start_xmit(nskb, dev);
 34.1443 ++		if (unlikely(rc)) {
 34.1444 ++			nskb->next = skb->next;
 34.1445 ++			skb->next = nskb;
 34.1446 ++			return rc;
 34.1447 ++		}
 34.1448 ++		if (unlikely(netif_queue_stopped(dev) && skb->next))
 34.1449 ++			return NETDEV_TX_BUSY;
 34.1450 ++	} while (skb->next);
 34.1451 ++	
 34.1452 ++	skb->destructor = DEV_GSO_CB(skb)->destructor;
 34.1453 ++
 34.1454 ++out_kfree_skb:
 34.1455 ++	kfree_skb(skb);
 34.1456 + 	return 0;
 34.1457 + }
 34.1458 + 
 34.1459 + #define HARD_TX_LOCK(dev, cpu) {			\
 34.1460 + 	if ((dev->features & NETIF_F_LLTX) == 0) {	\
 34.1461 +-		spin_lock(&dev->xmit_lock);		\
 34.1462 +-		dev->xmit_lock_owner = cpu;		\
 34.1463 ++		netif_tx_lock(dev);			\
 34.1464 + 	}						\
 34.1465 + }
 34.1466 + 
 34.1467 + #define HARD_TX_UNLOCK(dev) {				\
 34.1468 + 	if ((dev->features & NETIF_F_LLTX) == 0) {	\
 34.1469 +-		dev->xmit_lock_owner = -1;		\
 34.1470 +-		spin_unlock(&dev->xmit_lock);		\
 34.1471 ++		netif_tx_unlock(dev);			\
 34.1472 + 	}						\
 34.1473 + }
 34.1474 + 
 34.1475 +@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb)
 34.1476 + 	struct Qdisc *q;
 34.1477 + 	int rc = -ENOMEM;
 34.1478 + 
 34.1479 ++	/* GSO will handle the following emulations directly. */
 34.1480 ++	if (netif_needs_gso(dev, skb))
 34.1481 ++		goto gso;
 34.1482 ++
 34.1483 + 	if (skb_shinfo(skb)->frag_list &&
 34.1484 + 	    !(dev->features & NETIF_F_FRAGLIST) &&
 34.1485 +-	    __skb_linearize(skb, GFP_ATOMIC))
 34.1486 ++	    __skb_linearize(skb))
 34.1487 + 		goto out_kfree_skb;
 34.1488 + 
 34.1489 + 	/* Fragmented skb is linearized if device does not support SG,
 34.1490 +@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb)
 34.1491 + 	 */
 34.1492 + 	if (skb_shinfo(skb)->nr_frags &&
 34.1493 + 	    (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
 34.1494 +-	    __skb_linearize(skb, GFP_ATOMIC))
 34.1495 ++	    __skb_linearize(skb))
 34.1496 + 		goto out_kfree_skb;
 34.1497 + 
 34.1498 + 	/* If packet is not checksummed and device does not support
 34.1499 + 	 * checksumming for this protocol, complete checksumming here.
 34.1500 + 	 */
 34.1501 + 	if (skb->ip_summed == CHECKSUM_HW &&
 34.1502 +-	    (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
 34.1503 ++	    (!(dev->features & NETIF_F_GEN_CSUM) &&
 34.1504 + 	     (!(dev->features & NETIF_F_IP_CSUM) ||
 34.1505 + 	      skb->protocol != htons(ETH_P_IP))))
 34.1506 + 	      	if (skb_checksum_help(skb, 0))
 34.1507 + 	      		goto out_kfree_skb;
 34.1508 + 
 34.1509 ++gso:
 34.1510 + 	spin_lock_prefetch(&dev->queue_lock);
 34.1511 + 
 34.1512 + 	/* Disable soft irqs for various locks below. Also 
 34.1513 + 	 * stops preemption for RCU. 
 34.1514 + 	 */
 34.1515 +-	local_bh_disable(); 
 34.1516 ++	rcu_read_lock_bh(); 
 34.1517 + 
 34.1518 + 	/* Updates of qdisc are serialized by queue_lock. 
 34.1519 + 	 * The struct Qdisc which is pointed to by qdisc is now a 
 34.1520 +@@ -1309,8 +1387,8 @@ #endif
 34.1521 + 	/* The device has no queue. Common case for software devices:
 34.1522 + 	   loopback, all the sorts of tunnels...
 34.1523 + 
 34.1524 +-	   Really, it is unlikely that xmit_lock protection is necessary here.
 34.1525 +-	   (f.e. loopback and IP tunnels are clean ignoring statistics
 34.1526 ++	   Really, it is unlikely that netif_tx_lock protection is necessary
 34.1527 ++	   here.  (f.e. loopback and IP tunnels are clean ignoring statistics
 34.1528 + 	   counters.)
 34.1529 + 	   However, it is possible, that they rely on protection
 34.1530 + 	   made by us here.
 34.1531 +@@ -1326,11 +1404,8 @@ #endif
 34.1532 + 			HARD_TX_LOCK(dev, cpu);
 34.1533 + 
 34.1534 + 			if (!netif_queue_stopped(dev)) {
 34.1535 +-				if (netdev_nit)
 34.1536 +-					dev_queue_xmit_nit(skb, dev);
 34.1537 +-
 34.1538 + 				rc = 0;
 34.1539 +-				if (!dev->hard_start_xmit(skb, dev)) {
 34.1540 ++				if (!dev_hard_start_xmit(skb, dev)) {
 34.1541 + 					HARD_TX_UNLOCK(dev);
 34.1542 + 					goto out;
 34.1543 + 				}
 34.1544 +@@ -1349,13 +1424,13 @@ #endif
 34.1545 + 	}
 34.1546 + 
 34.1547 + 	rc = -ENETDOWN;
 34.1548 +-	local_bh_enable();
 34.1549 ++	rcu_read_unlock_bh();
 34.1550 + 
 34.1551 + out_kfree_skb:
 34.1552 + 	kfree_skb(skb);
 34.1553 + 	return rc;
 34.1554 + out:
 34.1555 +-	local_bh_enable();
 34.1556 ++	rcu_read_unlock_bh();
 34.1557 + 	return rc;
 34.1558 + }
 34.1559 + 
 34.1560 +@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device
 34.1561 + 	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
 34.1562 + 
 34.1563 + 	spin_lock_init(&dev->queue_lock);
 34.1564 +-	spin_lock_init(&dev->xmit_lock);
 34.1565 ++	spin_lock_init(&dev->_xmit_lock);
 34.1566 + 	dev->xmit_lock_owner = -1;
 34.1567 + #ifdef CONFIG_NET_CLS_ACT
 34.1568 + 	spin_lock_init(&dev->ingress_lock);
 34.1569 +@@ -2714,9 +2789,7 @@ #endif
 34.1570 + 
 34.1571 + 	/* Fix illegal SG+CSUM combinations. */
 34.1572 + 	if ((dev->features & NETIF_F_SG) &&
 34.1573 +-	    !(dev->features & (NETIF_F_IP_CSUM |
 34.1574 +-			       NETIF_F_NO_CSUM |
 34.1575 +-			       NETIF_F_HW_CSUM))) {
 34.1576 ++	    !(dev->features & NETIF_F_ALL_CSUM)) {
 34.1577 + 		printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
 34.1578 + 		       dev->name);
 34.1579 + 		dev->features &= ~NETIF_F_SG;
 34.1580 +@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init);
 34.1581 + EXPORT_SYMBOL(__dev_get_by_index);
 34.1582 + EXPORT_SYMBOL(__dev_get_by_name);
 34.1583 + EXPORT_SYMBOL(__dev_remove_pack);
 34.1584 +-EXPORT_SYMBOL(__skb_linearize);
 34.1585 + EXPORT_SYMBOL(dev_valid_name);
 34.1586 + EXPORT_SYMBOL(dev_add_pack);
 34.1587 + EXPORT_SYMBOL(dev_alloc_name);
 34.1588 +diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
 34.1589 +index 05d6085..c57d887 100644
 34.1590 +--- a/net/core/dev_mcast.c
 34.1591 ++++ b/net/core/dev_mcast.c
 34.1592 +@@ -62,7 +62,7 @@ #include <net/arp.h>
 34.1593 +  *	Device mc lists are changed by bh at least if IPv6 is enabled,
 34.1594 +  *	so that it must be bh protected.
 34.1595 +  *
 34.1596 +- *	We block accesses to device mc filters with dev->xmit_lock.
 34.1597 ++ *	We block accesses to device mc filters with netif_tx_lock.
 34.1598 +  */
 34.1599 + 
 34.1600 + /*
 34.1601 +@@ -93,9 +93,9 @@ static void __dev_mc_upload(struct net_d
 34.1602 + 
 34.1603 + void dev_mc_upload(struct net_device *dev)
 34.1604 + {
 34.1605 +-	spin_lock_bh(&dev->xmit_lock);
 34.1606 ++	netif_tx_lock_bh(dev);
 34.1607 + 	__dev_mc_upload(dev);
 34.1608 +-	spin_unlock_bh(&dev->xmit_lock);
 34.1609 ++	netif_tx_unlock_bh(dev);
 34.1610 + }
 34.1611 + 
 34.1612 + /*
 34.1613 +@@ -107,7 +107,7 @@ int dev_mc_delete(struct net_device *dev
 34.1614 + 	int err = 0;
 34.1615 + 	struct dev_mc_list *dmi, **dmip;
 34.1616 + 
 34.1617 +-	spin_lock_bh(&dev->xmit_lock);
 34.1618 ++	netif_tx_lock_bh(dev);
 34.1619 + 
 34.1620 + 	for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
 34.1621 + 		/*
 34.1622 +@@ -139,13 +139,13 @@ int dev_mc_delete(struct net_device *dev
 34.1623 + 			 */
 34.1624 + 			__dev_mc_upload(dev);
 34.1625 + 			
 34.1626 +-			spin_unlock_bh(&dev->xmit_lock);
 34.1627 ++			netif_tx_unlock_bh(dev);
 34.1628 + 			return 0;
 34.1629 + 		}
 34.1630 + 	}
 34.1631 + 	err = -ENOENT;
 34.1632 + done:
 34.1633 +-	spin_unlock_bh(&dev->xmit_lock);
 34.1634 ++	netif_tx_unlock_bh(dev);
 34.1635 + 	return err;
 34.1636 + }
 34.1637 + 
 34.1638 +@@ -160,7 +160,7 @@ int dev_mc_add(struct net_device *dev, v
 34.1639 + 
 34.1640 + 	dmi1 = kmalloc(sizeof(*dmi), GFP_ATOMIC);
 34.1641 + 
 34.1642 +-	spin_lock_bh(&dev->xmit_lock);
 34.1643 ++	netif_tx_lock_bh(dev);
 34.1644 + 	for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
 34.1645 + 		if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
 34.1646 + 		    dmi->dmi_addrlen == alen) {
 34.1647 +@@ -176,7 +176,7 @@ int dev_mc_add(struct net_device *dev, v
 34.1648 + 	}
 34.1649 + 
 34.1650 + 	if ((dmi = dmi1) == NULL) {
 34.1651 +-		spin_unlock_bh(&dev->xmit_lock);
 34.1652 ++		netif_tx_unlock_bh(dev);
 34.1653 + 		return -ENOMEM;
 34.1654 + 	}
 34.1655 + 	memcpy(dmi->dmi_addr, addr, alen);
 34.1656 +@@ -189,11 +189,11 @@ int dev_mc_add(struct net_device *dev, v
 34.1657 + 
 34.1658 + 	__dev_mc_upload(dev);
 34.1659 + 	
 34.1660 +-	spin_unlock_bh(&dev->xmit_lock);
 34.1661 ++	netif_tx_unlock_bh(dev);
 34.1662 + 	return 0;
 34.1663 + 
 34.1664 + done:
 34.1665 +-	spin_unlock_bh(&dev->xmit_lock);
 34.1666 ++	netif_tx_unlock_bh(dev);
 34.1667 + 	kfree(dmi1);
 34.1668 + 	return err;
 34.1669 + }
 34.1670 +@@ -204,7 +204,7 @@ done:
 34.1671 + 
 34.1672 + void dev_mc_discard(struct net_device *dev)
 34.1673 + {
 34.1674 +-	spin_lock_bh(&dev->xmit_lock);
 34.1675 ++	netif_tx_lock_bh(dev);
 34.1676 + 	
 34.1677 + 	while (dev->mc_list != NULL) {
 34.1678 + 		struct dev_mc_list *tmp = dev->mc_list;
 34.1679 +@@ -215,7 +215,7 @@ void dev_mc_discard(struct net_device *d
 34.1680 + 	}
 34.1681 + 	dev->mc_count = 0;
 34.1682 + 
 34.1683 +-	spin_unlock_bh(&dev->xmit_lock);
 34.1684 ++	netif_tx_unlock_bh(dev);
 34.1685 + }
 34.1686 + 
 34.1687 + #ifdef CONFIG_PROC_FS
 34.1688 +@@ -250,7 +250,7 @@ static int dev_mc_seq_show(struct seq_fi
 34.1689 + 	struct dev_mc_list *m;
 34.1690 + 	struct net_device *dev = v;
 34.1691 + 
 34.1692 +-	spin_lock_bh(&dev->xmit_lock);
 34.1693 ++	netif_tx_lock_bh(dev);
 34.1694 + 	for (m = dev->mc_list; m; m = m->next) {
 34.1695 + 		int i;
 34.1696 + 
 34.1697 +@@ -262,7 +262,7 @@ static int dev_mc_seq_show(struct seq_fi
 34.1698 + 
 34.1699 + 		seq_putc(seq, '\n');
 34.1700 + 	}
 34.1701 +-	spin_unlock_bh(&dev->xmit_lock);
 34.1702 ++	netif_tx_unlock_bh(dev);
 34.1703 + 	return 0;
 34.1704 + }
 34.1705 + 
 34.1706 +diff --git a/net/core/ethtool.c b/net/core/ethtool.c
 34.1707 +index e6f7610..27ce168 100644
 34.1708 +--- a/net/core/ethtool.c
 34.1709 ++++ b/net/core/ethtool.c
 34.1710 +@@ -30,7 +30,7 @@ u32 ethtool_op_get_link(struct net_devic
 34.1711 + 
 34.1712 + u32 ethtool_op_get_tx_csum(struct net_device *dev)
 34.1713 + {
 34.1714 +-	return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0;
 34.1715 ++	return (dev->features & NETIF_F_ALL_CSUM) != 0;
 34.1716 + }
 34.1717 + 
 34.1718 + int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 34.1719 +@@ -551,9 +551,7 @@ static int ethtool_set_sg(struct net_dev
 34.1720 + 		return -EFAULT;
 34.1721 + 
 34.1722 + 	if (edata.data && 
 34.1723 +-	    !(dev->features & (NETIF_F_IP_CSUM |
 34.1724 +-			       NETIF_F_NO_CSUM |
 34.1725 +-			       NETIF_F_HW_CSUM)))
 34.1726 ++	    !(dev->features & NETIF_F_ALL_CSUM))
 34.1727 + 		return -EINVAL;
 34.1728 + 
 34.1729 + 	return __ethtool_set_sg(dev, edata.data);
 34.1730 +@@ -591,7 +589,7 @@ static int ethtool_set_tso(struct net_de
 34.1731 + 
 34.1732 + static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr)
 34.1733 + {
 34.1734 +-	struct ethtool_value edata = { ETHTOOL_GTSO };
 34.1735 ++	struct ethtool_value edata = { ETHTOOL_GUFO };
 34.1736 + 
 34.1737 + 	if (!dev->ethtool_ops->get_ufo)
 34.1738 + 		return -EOPNOTSUPP;
 34.1739 +@@ -600,6 +598,7 @@ static int ethtool_get_ufo(struct net_de
 34.1740 + 		 return -EFAULT;
 34.1741 + 	return 0;
 34.1742 + }
 34.1743 ++
 34.1744 + static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
 34.1745 + {
 34.1746 + 	struct ethtool_value edata;
 34.1747 +@@ -615,6 +614,29 @@ static int ethtool_set_ufo(struct net_de
 34.1748 + 	return dev->ethtool_ops->set_ufo(dev, edata.data);
 34.1749 + }
 34.1750 + 
 34.1751 ++static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
 34.1752 ++{
 34.1753 ++	struct ethtool_value edata = { ETHTOOL_GGSO };
 34.1754 ++
 34.1755 ++	edata.data = dev->features & NETIF_F_GSO;
 34.1756 ++	if (copy_to_user(useraddr, &edata, sizeof(edata)))
 34.1757 ++		 return -EFAULT;
 34.1758 ++	return 0;
 34.1759 ++}
 34.1760 ++
 34.1761 ++static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
 34.1762 ++{
 34.1763 ++	struct ethtool_value edata;
 34.1764 ++
 34.1765 ++	if (copy_from_user(&edata, useraddr, sizeof(edata)))
 34.1766 ++		return -EFAULT;
 34.1767 ++	if (edata.data)
 34.1768 ++		dev->features |= NETIF_F_GSO;
 34.1769 ++	else
 34.1770 ++		dev->features &= ~NETIF_F_GSO;
 34.1771 ++	return 0;
 34.1772 ++}
 34.1773 ++
 34.1774 + static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 34.1775 + {
 34.1776 + 	struct ethtool_test test;
 34.1777 +@@ -906,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
 34.1778 + 	case ETHTOOL_SUFO:
 34.1779 + 		rc = ethtool_set_ufo(dev, useraddr);
 34.1780 + 		break;
 34.1781 ++	case ETHTOOL_GGSO:
 34.1782 ++		rc = ethtool_get_gso(dev, useraddr);
 34.1783 ++		break;
 34.1784 ++	case ETHTOOL_SGSO:
 34.1785 ++		rc = ethtool_set_gso(dev, useraddr);
 34.1786 ++		break;
 34.1787 + 	default:
 34.1788 + 		rc =  -EOPNOTSUPP;
 34.1789 + 	}
 34.1790 +diff --git a/net/core/netpoll.c b/net/core/netpoll.c
 34.1791 +index ea51f8d..ec28d3b 100644
 34.1792 +--- a/net/core/netpoll.c
 34.1793 ++++ b/net/core/netpoll.c
 34.1794 +@@ -273,24 +273,21 @@ static void netpoll_send_skb(struct netp
 34.1795 + 
 34.1796 + 	do {
 34.1797 + 		npinfo->tries--;
 34.1798 +-		spin_lock(&np->dev->xmit_lock);
 34.1799 +-		np->dev->xmit_lock_owner = smp_processor_id();
 34.1800 ++		netif_tx_lock(np->dev);
 34.1801 + 
 34.1802 + 		/*
 34.1803 + 		 * network drivers do not expect to be called if the queue is
 34.1804 + 		 * stopped.
 34.1805 + 		 */
 34.1806 + 		if (netif_queue_stopped(np->dev)) {
 34.1807 +-			np->dev->xmit_lock_owner = -1;
 34.1808 +-			spin_unlock(&np->dev->xmit_lock);
 34.1809 ++			netif_tx_unlock(np->dev);
 34.1810 + 			netpoll_poll(np);
 34.1811 + 			udelay(50);
 34.1812 + 			continue;
 34.1813 + 		}
 34.1814 + 
 34.1815 + 		status = np->dev->hard_start_xmit(skb, np->dev);
 34.1816 +-		np->dev->xmit_lock_owner = -1;
 34.1817 +-		spin_unlock(&np->dev->xmit_lock);
 34.1818 ++		netif_tx_unlock(np->dev);
 34.1819 + 
 34.1820 + 		/* success */
 34.1821 + 		if(!status) {
 34.1822 +diff --git a/net/core/pktgen.c b/net/core/pktgen.c
 34.1823 +index da16f8f..2380347 100644
 34.1824 +--- a/net/core/pktgen.c
 34.1825 ++++ b/net/core/pktgen.c
 34.1826 +@@ -2582,7 +2582,7 @@ static __inline__ void pktgen_xmit(struc
 34.1827 + 		}
 34.1828 + 	}
 34.1829 + 	
 34.1830 +-	spin_lock_bh(&odev->xmit_lock);
 34.1831 ++	netif_tx_lock_bh(odev);
 34.1832 + 	if (!netif_queue_stopped(odev)) {
 34.1833 + 
 34.1834 + 		atomic_inc(&(pkt_dev->skb->users));
 34.1835 +@@ -2627,7 +2627,7 @@ retry_now:
 34.1836 + 		pkt_dev->next_tx_ns = 0;
 34.1837 +         }
 34.1838 + 
 34.1839 +-	spin_unlock_bh(&odev->xmit_lock);
 34.1840 ++	netif_tx_unlock_bh(odev);
 34.1841 + 	
 34.1842 + 	/* If pkt_dev->count is zero, then run forever */
 34.1843 + 	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
 34.1844 +diff --git a/net/core/skbuff.c b/net/core/skbuff.c
 34.1845 +index 2144952..46f56af 100644
 34.1846 +--- a/net/core/skbuff.c
 34.1847 ++++ b/net/core/skbuff.c
 34.1848 +@@ -164,9 +164,9 @@ struct sk_buff *__alloc_skb(unsigned int
 34.1849 + 	shinfo = skb_shinfo(skb);
 34.1850 + 	atomic_set(&shinfo->dataref, 1);
 34.1851 + 	shinfo->nr_frags  = 0;
 34.1852 +-	shinfo->tso_size = 0;
 34.1853 +-	shinfo->tso_segs = 0;
 34.1854 +-	shinfo->ufo_size = 0;
 34.1855 ++	shinfo->gso_size = 0;
 34.1856 ++	shinfo->gso_segs = 0;
 34.1857 ++	shinfo->gso_type = 0;
 34.1858 + 	shinfo->ip6_frag_id = 0;
 34.1859 + 	shinfo->frag_list = NULL;
 34.1860 + 
 34.1861 +@@ -230,8 +230,9 @@ struct sk_buff *alloc_skb_from_cache(kme
 34.1862 + 
 34.1863 + 	atomic_set(&(skb_shinfo(skb)->dataref), 1);
 34.1864 + 	skb_shinfo(skb)->nr_frags  = 0;
 34.1865 +-	skb_shinfo(skb)->tso_size = 0;
 34.1866 +-	skb_shinfo(skb)->tso_segs = 0;
 34.1867 ++	skb_shinfo(skb)->gso_size = 0;
 34.1868 ++	skb_shinfo(skb)->gso_segs = 0;
 34.1869 ++	skb_shinfo(skb)->gso_type = 0;
 34.1870 + 	skb_shinfo(skb)->frag_list = NULL;
 34.1871 + out:
 34.1872 + 	return skb;
 34.1873 +@@ -501,8 +502,9 @@ #endif
 34.1874 + 	new->tc_index	= old->tc_index;
 34.1875 + #endif
 34.1876 + 	atomic_set(&new->users, 1);
 34.1877 +-	skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size;
 34.1878 +-	skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs;
 34.1879 ++	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
 34.1880 ++	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
 34.1881 ++	skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
 34.1882 + }
 34.1883 + 
 34.1884 + /**
 34.1885 +@@ -1777,6 +1779,133 @@ int skb_append_datato_frags(struct sock 
 34.1886 + 	return 0;
 34.1887 + }
 34.1888 + 
 34.1889 ++/**
 34.1890 ++ *	skb_segment - Perform protocol segmentation on skb.
 34.1891 ++ *	@skb: buffer to segment
 34.1892 ++ *	@features: features for the output path (see dev->features)
 34.1893 ++ *
 34.1894 ++ *	This function performs segmentation on the given skb.  It returns
 34.1895 ++ *	the segment at the given position.  It returns NULL if there are
 34.1896 ++ *	no more segments to generate, or when an error is encountered.
 34.1897 ++ */
 34.1898 ++struct sk_buff *skb_segment(struct sk_buff *skb, int features)
 34.1899 ++{
 34.1900 ++	struct sk_buff *segs = NULL;
 34.1901 ++	struct sk_buff *tail = NULL;
 34.1902 ++	unsigned int mss = skb_shinfo(skb)->gso_size;
 34.1903 ++	unsigned int doffset = skb->data - skb->mac.raw;
 34.1904 ++	unsigned int offset = doffset;
 34.1905 ++	unsigned int headroom;
 34.1906 ++	unsigned int len;
 34.1907 ++	int sg = features & NETIF_F_SG;
 34.1908 ++	int nfrags = skb_shinfo(skb)->nr_frags;
 34.1909 ++	int err = -ENOMEM;
 34.1910 ++	int i = 0;
 34.1911 ++	int pos;
 34.1912 ++
 34.1913 ++	__skb_push(skb, doffset);
 34.1914 ++	headroom = skb_headroom(skb);
 34.1915 ++	pos = skb_headlen(skb);
 34.1916 ++
 34.1917 ++	do {
 34.1918 ++		struct sk_buff *nskb;
 34.1919 ++		skb_frag_t *frag;
 34.1920 ++		int hsize, nsize;
 34.1921 ++		int k;
 34.1922 ++		int size;
 34.1923 ++
 34.1924 ++		len = skb->len - offset;
 34.1925 ++		if (len > mss)
 34.1926 ++			len = mss;
 34.1927 ++
 34.1928 ++		hsize = skb_headlen(skb) - offset;
 34.1929 ++		if (hsize < 0)
 34.1930 ++			hsize = 0;
 34.1931 ++		nsize = hsize + doffset;
 34.1932 ++		if (nsize > len + doffset || !sg)
 34.1933 ++			nsize = len + doffset;
 34.1934 ++
 34.1935 ++		nskb = alloc_skb(nsize + headroom, GFP_ATOMIC);
 34.1936 ++		if (unlikely(!nskb))
 34.1937 ++			goto err;
 34.1938 ++
 34.1939 ++		if (segs)
 34.1940 ++			tail->next = nskb;
 34.1941 ++		else
 34.1942 ++			segs = nskb;
 34.1943 ++		tail = nskb;
 34.1944 ++
 34.1945 ++		nskb->dev = skb->dev;
 34.1946 ++		nskb->priority = skb->priority;
 34.1947 ++		nskb->protocol = skb->protocol;
 34.1948 ++		nskb->dst = dst_clone(skb->dst);
 34.1949 ++		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 34.1950 ++		nskb->pkt_type = skb->pkt_type;
 34.1951 ++		nskb->mac_len = skb->mac_len;
 34.1952 ++
 34.1953 ++		skb_reserve(nskb, headroom);
 34.1954 ++		nskb->mac.raw = nskb->data;
 34.1955 ++		nskb->nh.raw = nskb->data + skb->mac_len;
 34.1956 ++		nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
 34.1957 ++		memcpy(skb_put(nskb, doffset), skb->data, doffset);
 34.1958 ++
 34.1959 ++		if (!sg) {
 34.1960 ++			nskb->csum = skb_copy_and_csum_bits(skb, offset,
 34.1961 ++							    skb_put(nskb, len),
 34.1962 ++							    len, 0);
 34.1963 ++			continue;
 34.1964 ++		}
 34.1965 ++
 34.1966 ++		frag = skb_shinfo(nskb)->frags;
 34.1967 ++		k = 0;
 34.1968 ++
 34.1969 ++		nskb->ip_summed = CHECKSUM_HW;
 34.1970 ++		nskb->csum = skb->csum;
 34.1971 ++		memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
 34.1972 ++
 34.1973 ++		while (pos < offset + len) {
 34.1974 ++			BUG_ON(i >= nfrags);
 34.1975 ++
 34.1976 ++			*frag = skb_shinfo(skb)->frags[i];
 34.1977 ++			get_page(frag->page);
 34.1978 ++			size = frag->size;
 34.1979 ++
 34.1980 ++			if (pos < offset) {
 34.1981 ++				frag->page_offset += offset - pos;
 34.1982 ++				frag->size -= offset - pos;
 34.1983 ++			}
 34.1984 ++
 34.1985 ++			k++;
 34.1986 ++
 34.1987 ++			if (pos + size <= offset + len) {
 34.1988 ++				i++;
 34.1989 ++				pos += size;
 34.1990 ++			} else {
 34.1991 ++				frag->size -= pos + size - (offset + len);
 34.1992 ++				break;
 34.1993 ++			}
 34.1994 ++
 34.1995 ++			frag++;
 34.1996 ++		}
 34.1997 ++
 34.1998 ++		skb_shinfo(nskb)->nr_frags = k;
 34.1999 ++		nskb->data_len = len - hsize;
 34.2000 ++		nskb->len += nskb->data_len;
 34.2001 ++		nskb->truesize += nskb->data_len;
 34.2002 ++	} while ((offset += len) < skb->len);
 34.2003 ++
 34.2004 ++	return segs;
 34.2005 ++
 34.2006 ++err:
 34.2007 ++	while ((skb = segs)) {
 34.2008 ++		segs = skb->next;
 34.2009 ++		kfree(skb);
 34.2010 ++	}
 34.2011 ++	return ERR_PTR(err);
 34.2012 ++}
 34.2013 ++
 34.2014 ++EXPORT_SYMBOL_GPL(skb_segment);
 34.2015 ++
 34.2016 + void __init skb_init(void)
 34.2017 + {
 34.2018 + 	skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
 34.2019 +diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
 34.2020 +index 44bda85..2e3323a 100644
 34.2021 +--- a/net/decnet/dn_nsp_in.c
 34.2022 ++++ b/net/decnet/dn_nsp_in.c
 34.2023 +@@ -801,8 +801,7 @@ got_it:
 34.2024 + 		 * We linearize everything except data segments here.
 34.2025 + 		 */
 34.2026 + 		if (cb->nsp_flags & ~0x60) {
 34.2027 +-			if (unlikely(skb_is_nonlinear(skb)) &&
 34.2028 +-			    skb_linearize(skb, GFP_ATOMIC) != 0)
 34.2029 ++			if (unlikely(skb_linearize(skb)))
 34.2030 + 				goto free_out;
 34.2031 + 		}
 34.2032 + 
 34.2033 +diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
 34.2034 +index 3407f19..a0a25e0 100644
 34.2035 +--- a/net/decnet/dn_route.c
 34.2036 ++++ b/net/decnet/dn_route.c
 34.2037 +@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, st
 34.2038 + 			padlen);
 34.2039 + 
 34.2040 +         if (flags & DN_RT_PKT_CNTL) {
 34.2041 +-		if (unlikely(skb_is_nonlinear(skb)) &&
 34.2042 +-		    skb_linearize(skb, GFP_ATOMIC) != 0)
 34.2043 ++		if (unlikely(skb_linearize(skb)))
 34.2044 + 			goto dump_it;
 34.2045 + 
 34.2046 +                 switch(flags & DN_RT_CNTL_MSK) {
 34.2047 +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
 34.2048 +index 97c276f..5ba719e 100644
 34.2049 +--- a/net/ipv4/af_inet.c
 34.2050 ++++ b/net/ipv4/af_inet.c
 34.2051 +@@ -68,6 +68,7 @@
 34.2052 +  */
 34.2053 + 
 34.2054 + #include <linux/config.h>
 34.2055 ++#include <linux/err.h>
 34.2056 + #include <linux/errno.h>
 34.2057 + #include <linux/types.h>
 34.2058 + #include <linux/socket.h>
 34.2059 +@@ -1084,6 +1085,54 @@ int inet_sk_rebuild_header(struct sock *
 34.2060 + 
 34.2061 + EXPORT_SYMBOL(inet_sk_rebuild_header);
 34.2062 + 
 34.2063 ++static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
 34.2064 ++{
 34.2065 ++	struct sk_buff *segs = ERR_PTR(-EINVAL);
 34.2066 ++	struct iphdr *iph;
 34.2067 ++	struct net_protocol *ops;
 34.2068 ++	int proto;
 34.2069 ++	int ihl;
 34.2070 ++	int id;
 34.2071 ++
 34.2072 ++	if (!pskb_may_pull(skb, sizeof(*iph)))
 34.2073 ++		goto out;
 34.2074 ++
 34.2075 ++	iph = skb->nh.iph;
 34.2076 ++	ihl = iph->ihl * 4;
 34.2077 ++	if (ihl < sizeof(*iph))
 34.2078 ++		goto out;
 34.2079 ++
 34.2080 ++	if (!pskb_may_pull(skb, ihl))
 34.2081 ++		goto out;
 34.2082 ++
 34.2083 ++	skb->h.raw = __skb_pull(skb, ihl);
 34.2084 ++	iph = skb->nh.iph;
 34.2085 ++	id = ntohs(iph->id);
 34.2086 ++	proto = iph->protocol & (MAX_INET_PROTOS - 1);
 34.2087 ++	segs = ERR_PTR(-EPROTONOSUPPORT);
 34.2088 ++
 34.2089 ++	rcu_read_lock();
 34.2090 ++	ops = rcu_dereference(inet_protos[proto]);
 34.2091 ++	if (ops && ops->gso_segment)
 34.2092 ++		segs = ops->gso_segment(skb, features);
 34.2093 ++	rcu_read_unlock();
 34.2094 ++
 34.2095 ++	if (!segs || unlikely(IS_ERR(segs)))
 34.2096 ++		goto out;
 34.2097 ++
 34.2098 ++	skb = segs;
 34.2099 ++	do {
 34.2100 ++		iph = skb->nh.iph;
 34.2101 ++		iph->id = htons(id++);
 34.2102 ++		iph->tot_len = htons(skb->len - skb->mac_len);
 34.2103 ++		iph->check = 0;
 34.2104 ++		iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
 34.2105 ++	} while ((skb = skb->next));
 34.2106 ++
 34.2107 ++out:
 34.2108 ++	return segs;
 34.2109 ++}
 34.2110 ++
 34.2111 + #ifdef CONFIG_IP_MULTICAST
 34.2112 + static struct net_protocol igmp_protocol = {
 34.2113 + 	.handler =	igmp_rcv,
 34.2114 +@@ -1093,6 +1142,7 @@ #endif
 34.2115 + static struct net_protocol tcp_protocol = {
 34.2116 + 	.handler =	tcp_v4_rcv,
 34.2117 + 	.err_handler =	tcp_v4_err,
 34.2118 ++	.gso_segment =	tcp_tso_segment,
 34.2119 + 	.no_policy =	1,
 34.2120 + };
 34.2121 + 
 34.2122 +@@ -1138,6 +1188,7 @@ static int ipv4_proc_init(void);
 34.2123 + static struct packet_type ip_packet_type = {
 34.2124 + 	.type = __constant_htons(ETH_P_IP),
 34.2125 + 	.func = ip_rcv,
 34.2126 ++	.gso_segment = inet_gso_segment,
 34.2127 + };
 34.2128 + 
 34.2129 + static int __init inet_init(void)
 34.2130 +diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
 34.2131 +index 8dcba38..19c3c73 100644
 34.2132 +--- a/net/ipv4/ip_output.c
 34.2133 ++++ b/net/ipv4/ip_output.c
 34.2134 +@@ -210,8 +210,7 @@ #if defined(CONFIG_NETFILTER) && defined
 34.2135 + 		return dst_output(skb);
 34.2136 + 	}
 34.2137 + #endif
 34.2138 +-	if (skb->len > dst_mtu(skb->dst) &&
 34.2139 +-	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
 34.2140 ++	if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
 34.2141 + 		return ip_fragment(skb, ip_finish_output2);
 34.2142 + 	else
 34.2143 + 		return ip_finish_output2(skb);
 34.2144 +@@ -362,7 +361,7 @@ packet_routed:
 34.2145 + 	}
 34.2146 + 
 34.2147 + 	ip_select_ident_more(iph, &rt->u.dst, sk,
 34.2148 +-			     (skb_shinfo(skb)->tso_segs ?: 1) - 1);
 34.2149 ++			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 34.2150 + 
 34.2151 + 	/* Add an IP checksum. */
 34.2152 + 	ip_send_check(iph);
 34.2153 +@@ -743,7 +742,8 @@ static inline int ip_ufo_append_data(str
 34.2154 + 			       (length - transhdrlen));
 34.2155 + 	if (!err) {
 34.2156 + 		/* specify the length of each IP datagram fragment*/
 34.2157 +-		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
 34.2158 ++		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 34.2159 ++		skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
 34.2160 + 		__skb_queue_tail(&sk->sk_write_queue, skb);
 34.2161 + 
 34.2162 + 		return 0;
 34.2163 +@@ -839,7 +839,7 @@ int ip_append_data(struct sock *sk,
 34.2164 + 	 */
 34.2165 + 	if (transhdrlen &&
 34.2166 + 	    length + fragheaderlen <= mtu &&
 34.2167 +-	    rt->u.dst.dev->features&(NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) &&
 34.2168 ++	    rt->u.dst.dev->features & NETIF_F_ALL_CSUM &&
 34.2169 + 	    !exthdrlen)
 34.2170 + 		csummode = CHECKSUM_HW;
 34.2171 + 
 34.2172 +@@ -1086,14 +1086,16 @@ ssize_t	ip_append_page(struct sock *sk, 
 34.2173 + 
 34.2174 + 	inet->cork.length += size;
 34.2175 + 	if ((sk->sk_protocol == IPPROTO_UDP) &&
 34.2176 +-	    (rt->u.dst.dev->features & NETIF_F_UFO))
 34.2177 +-		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
 34.2178 ++	    (rt->u.dst.dev->features & NETIF_F_UFO)) {
 34.2179 ++		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 34.2180 ++		skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
 34.2181 ++	}
 34.2182 + 
 34.2183 + 
 34.2184 + 	while (size > 0) {
 34.2185 + 		int i;
 34.2186 + 
 34.2187 +-		if (skb_shinfo(skb)->ufo_size)
 34.2188 ++		if (skb_shinfo(skb)->gso_size)
 34.2189 + 			len = size;
 34.2190 + 		else {
 34.2191 + 
 34.2192 +diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
 34.2193 +index d64e2ec..7494823 100644
 34.2194 +--- a/net/ipv4/ipcomp.c
 34.2195 ++++ b/net/ipv4/ipcomp.c
 34.2196 +@@ -84,7 +84,7 @@ static int ipcomp_input(struct xfrm_stat
 34.2197 +                         struct xfrm_decap_state *decap, struct sk_buff *skb)
 34.2198 + {
 34.2199 + 	u8 nexthdr;
 34.2200 +-	int err = 0;
 34.2201 ++	int err = -ENOMEM;
 34.2202 + 	struct iphdr *iph;
 34.2203 + 	union {
 34.2204 + 		struct iphdr	iph;
 34.2205 +@@ -92,11 +92,8 @@ static int ipcomp_input(struct xfrm_stat
 34.2206 + 	} tmp_iph;
 34.2207 + 
 34.2208 + 
 34.2209 +-	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 34.2210 +-	    skb_linearize(skb, GFP_ATOMIC) != 0) {
 34.2211 +-	    	err = -ENOMEM;
 34.2212 ++	if (skb_linearize_cow(skb))
 34.2213 + 	    	goto out;
 34.2214 +-	}
 34.2215 + 
 34.2216 + 	skb->ip_summed = CHECKSUM_NONE;
 34.2217 + 
 34.2218 +@@ -171,10 +168,8 @@ static int ipcomp_output(struct xfrm_sta
 34.2219 + 		goto out_ok;
 34.2220 + 	}
 34.2221 + 
 34.2222 +-	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 34.2223 +-	    skb_linearize(skb, GFP_ATOMIC) != 0) {
 34.2224 ++	if (skb_linearize_cow(skb))
 34.2225 + 		goto out_ok;
 34.2226 +-	}
 34.2227 + 	
 34.2228 + 	err = ipcomp_compress(x, skb);
 34.2229 + 	iph = skb->nh.iph;
 34.2230 +diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
 34.2231 +index 00aa80e..84130c9 100644
 34.2232 +--- a/net/ipv4/tcp.c
 34.2233 ++++ b/net/ipv4/tcp.c
 34.2234 +@@ -257,6 +257,7 @@ #include <linux/smp_lock.h>
 34.2235 + #include <linux/fs.h>
 34.2236 + #include <linux/random.h>
 34.2237 + #include <linux/bootmem.h>
 34.2238 ++#include <linux/err.h>
 34.2239 + 
 34.2240 + #include <net/icmp.h>
 34.2241 + #include <net/tcp.h>
 34.2242 +@@ -570,7 +571,7 @@ new_segment:
 34.2243 + 		skb->ip_summed = CHECKSUM_HW;
 34.2244 + 		tp->write_seq += copy;
 34.2245 + 		TCP_SKB_CB(skb)->end_seq += copy;
 34.2246 +-		skb_shinfo(skb)->tso_segs = 0;
 34.2247 ++		skb_shinfo(skb)->gso_segs = 0;
 34.2248 + 
 34.2249 + 		if (!copied)
 34.2250 + 			TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
 34.2251 +@@ -621,14 +622,10 @@ ssize_t tcp_sendpage(struct socket *sock
 34.2252 + 	ssize_t res;
 34.2253 + 	struct sock *sk = sock->sk;
 34.2254 + 
 34.2255 +-#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
 34.2256 +-
 34.2257 + 	if (!(sk->sk_route_caps & NETIF_F_SG) ||
 34.2258 +-	    !(sk->sk_route_caps & TCP_ZC_CSUM_FLAGS))
 34.2259 ++	    !(sk->sk_route_caps & NETIF_F_ALL_CSUM))
 34.2260 + 		return sock_no_sendpage(sock, page, offset, size, flags);
 34.2261 + 
 34.2262 +-#undef TCP_ZC_CSUM_FLAGS
 34.2263 +-
 34.2264 + 	lock_sock(sk);
 34.2265 + 	TCP_CHECK_TIMER(sk);
 34.2266 + 	res = do_tcp_sendpages(sk, &page, offset, size, flags);
 34.2267 +@@ -725,9 +722,7 @@ new_segment:
 34.2268 + 				/*
 34.2269 + 				 * Check whether we can use HW checksum.
 34.2270 + 				 */
 34.2271 +-				if (sk->sk_route_caps &
 34.2272 +-				    (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM |
 34.2273 +-				     NETIF_F_HW_CSUM))
 34.2274 ++				if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
 34.2275 + 					skb->ip_summed = CHECKSUM_HW;
 34.2276 + 
 34.2277 + 				skb_entail(sk, tp, skb);
 34.2278 +@@ -823,7 +818,7 @@ new_segment:
 34.2279 + 
 34.2280 + 			tp->write_seq += copy;
 34.2281 + 			TCP_SKB_CB(skb)->end_seq += copy;
 34.2282 +-			skb_shinfo(skb)->tso_segs = 0;
 34.2283 ++			skb_shinfo(skb)->gso_segs = 0;
 34.2284 + 
 34.2285 + 			from += copy;
 34.2286 + 			copied += copy;
 34.2287 +@@ -2026,6 +2021,71 @@ int tcp_getsockopt(struct sock *sk, int 
 34.2288 + }
 34.2289 + 
 34.2290 + 
 34.2291 ++struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
 34.2292 ++{
 34.2293 ++	struct sk_buff *segs = ERR_PTR(-EINVAL);
 34.2294 ++	struct tcphdr *th;
 34.2295 ++	unsigned thlen;
 34.2296 ++	unsigned int seq;
 34.2297 ++	unsigned int delta;
 34.2298 ++	unsigned int oldlen;
 34.2299 ++	unsigned int len;
 34.2300 ++
 34.2301 ++	if (!pskb_may_pull(skb, sizeof(*th)))
 34.2302 ++		goto out;
 34.2303 ++
 34.2304 ++	th = skb->h.th;
 34.2305 ++	thlen = th->doff * 4;
 34.2306 ++	if (thlen < sizeof(*th))
 34.2307 ++		goto out;
 34.2308 ++
 34.2309 ++	if (!pskb_may_pull(skb, thlen))
 34.2310 ++		goto out;
 34.2311 ++
 34.2312 ++	segs = NULL;
 34.2313 ++	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST))
 34.2314 ++		goto out;
 34.2315 ++
 34.2316 ++	oldlen = (u16)~skb->len;
 34.2317 ++	__skb_pull(skb, thlen);
 34.2318 ++
 34.2319 ++	segs = skb_segment(skb, features);
 34.2320 ++	if (IS_ERR(segs))
 34.2321 ++		goto out;
 34.2322 ++
 34.2323 ++	len = skb_shinfo(skb)->gso_size;
 34.2324 ++	delta = htonl(oldlen + (thlen + len));
 34.2325 ++
 34.2326 ++	skb = segs;
 34.2327 ++	th = skb->h.th;
 34.2328 ++	seq = ntohl(th->seq);
 34.2329 ++
 34.2330 ++	do {
 34.2331 ++		th->fin = th->psh = 0;
 34.2332 ++
 34.2333 ++		th->check = ~csum_fold(th->check + delta);
 34.2334 ++		if (skb->ip_summed != CHECKSUM_HW)
 34.2335 ++			th->check = csum_fold(csum_partial(skb->h.raw, thlen,
 34.2336 ++							   skb->csum));
 34.2337 ++
 34.2338 ++		seq += len;
 34.2339 ++		skb = skb->next;
 34.2340 ++		th = skb->h.th;
 34.2341 ++
 34.2342 ++		th->seq = htonl(seq);
 34.2343 ++		th->cwr = 0;
 34.2344 ++	} while (skb->next);
 34.2345 ++
 34.2346 ++	delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
 34.2347 ++	th->check = ~csum_fold(th->check + delta);
 34.2348 ++	if (skb->ip_summed != CHECKSUM_HW)
 34.2349 ++		th->check = csum_fold(csum_partial(skb->h.raw, thlen,
 34.2350 ++						   skb->csum));
 34.2351 ++
 34.2352 ++out:
 34.2353 ++	return segs;
 34.2354 ++}
 34.2355 ++
 34.2356 + extern void __skb_cb_too_small_for_tcp(int, int);
 34.2357 + extern struct tcp_congestion_ops tcp_reno;
 34.2358 + 
 34.2359 +diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
 34.2360 +index e9a54ae..defe77a 100644
 34.2361 +--- a/net/ipv4/tcp_input.c
 34.2362 ++++ b/net/ipv4/tcp_input.c
 34.2363 +@@ -1072,7 +1072,7 @@ tcp_sacktag_write_queue(struct sock *sk,
 34.2364 + 				else
 34.2365 + 					pkt_len = (end_seq -
 34.2366 + 						   TCP_SKB_CB(skb)->seq);
 34.2367 +-				if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size))
 34.2368 ++				if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size))
 34.2369 + 					break;
 34.2370 + 				pcount = tcp_skb_pcount(skb);
 34.2371 + 			}
 34.2372 +diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
 34.2373 +index 310f2e6..ee01f69 100644
 34.2374 +--- a/net/ipv4/tcp_output.c
 34.2375 ++++ b/net/ipv4/tcp_output.c
 34.2376 +@@ -497,15 +497,17 @@ static void tcp_set_skb_tso_segs(struct 
 34.2377 + 		/* Avoid the costly divide in the normal
 34.2378 + 		 * non-TSO case.
 34.2379 + 		 */
 34.2380 +-		skb_shinfo(skb)->tso_segs = 1;
 34.2381 +-		skb_shinfo(skb)->tso_size = 0;
 34.2382 ++		skb_shinfo(skb)->gso_segs = 1;
 34.2383 ++		skb_shinfo(skb)->gso_size = 0;
 34.2384 ++		skb_shinfo(skb)->gso_type = 0;
 34.2385 + 	} else {
 34.2386 + 		unsigned int factor;
 34.2387 + 
 34.2388 + 		factor = skb->len + (mss_now - 1);
 34.2389 + 		factor /= mss_now;
 34.2390 +-		skb_shinfo(skb)->tso_segs = factor;
 34.2391 +-		skb_shinfo(skb)->tso_size = mss_now;
 34.2392 ++		skb_shinfo(skb)->gso_segs = factor;
 34.2393 ++		skb_shinfo(skb)->gso_size = mss_now;
 34.2394 ++		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 34.2395 + 	}
 34.2396 + }
 34.2397 + 
 34.2398 +@@ -850,7 +852,7 @@ static int tcp_init_tso_segs(struct sock
 34.2399 + 
 34.2400 + 	if (!tso_segs ||
 34.2401 + 	    (tso_segs > 1 &&
 34.2402 +-	     skb_shinfo(skb)->tso_size != mss_now)) {
 34.2403 ++	     tcp_skb_mss(skb) != mss_now)) {
 34.2404 + 		tcp_set_skb_tso_segs(sk, skb, mss_now);
 34.2405 + 		tso_segs = tcp_skb_pcount(skb);
 34.2406 + 	}
 34.2407 +@@ -1510,8 +1512,9 @@ int tcp_retransmit_skb(struct sock *sk, 
 34.2408 + 	   tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
 34.2409 + 		if (!pskb_trim(skb, 0)) {
 34.2410 + 			TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
 34.2411 +-			skb_shinfo(skb)->tso_segs = 1;
 34.2412 +-			skb_shinfo(skb)->tso_size = 0;
 34.2413 ++			skb_shinfo(skb)->gso_segs = 1;
 34.2414 ++			skb_shinfo(skb)->gso_size = 0;
 34.2415 ++			skb_shinfo(skb)->gso_type = 0;
 34.2416 + 			skb->ip_summed = CHECKSUM_NONE;
 34.2417 + 			skb->csum = 0;
 34.2418 + 		}
 34.2419 +@@ -1716,8 +1719,9 @@ void tcp_send_fin(struct sock *sk)
 34.2420 + 		skb->csum = 0;
 34.2421 + 		TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
 34.2422 + 		TCP_SKB_CB(skb)->sacked = 0;
 34.2423 +-		skb_shinfo(skb)->tso_segs = 1;
 34.2424 +-		skb_shinfo(skb)->tso_size = 0;
 34.2425 ++		skb_shinfo(skb)->gso_segs = 1;
 34.2426 ++		skb_shinfo(skb)->gso_size = 0;
 34.2427 ++		skb_shinfo(skb)->gso_type = 0;
 34.2428 + 
 34.2429 + 		/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
 34.2430 + 		TCP_SKB_CB(skb)->seq = tp->write_seq;
 34.2431 +@@ -1749,8 +1753,9 @@ void tcp_send_active_reset(struct sock *
 34.2432 + 	skb->csum = 0;
 34.2433 + 	TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
 34.2434 + 	TCP_SKB_CB(skb)->sacked = 0;
 34.2435 +-	skb_shinfo(skb)->tso_segs = 1;
 34.2436 +-	skb_shinfo(skb)->tso_size = 0;
 34.2437 ++	skb_shinfo(skb)->gso_segs = 1;
 34.2438 ++	skb_shinfo(skb)->gso_size = 0;
 34.2439 ++	skb_shinfo(skb)->gso_type = 0;
 34.2440 + 
 34.2441 + 	/* Send it off. */
 34.2442 + 	TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
 34.2443 +@@ -1833,8 +1838,9 @@ struct sk_buff * tcp_make_synack(struct 
 34.2444 + 	TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
 34.2445 + 	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
 34.2446 + 	TCP_SKB_CB(skb)->sacked = 0;
 34.2447 +-	skb_shinfo(skb)->tso_segs = 1;
 34.2448 +-	skb_shinfo(skb)->tso_size = 0;
 34.2449 ++	skb_shinfo(skb)->gso_segs = 1;
 34.2450 ++	skb_shinfo(skb)->gso_size = 0;
 34.2451 ++	skb_shinfo(skb)->gso_type = 0;
 34.2452 + 	th->seq = htonl(TCP_SKB_CB(skb)->seq);
 34.2453 + 	th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
 34.2454 + 	if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
 34.2455 +@@ -1937,8 +1943,9 @@ int tcp_connect(struct sock *sk)
 34.2456 + 	TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
 34.2457 + 	TCP_ECN_send_syn(sk, tp, buff);
 34.2458 + 	TCP_SKB_CB(buff)->sacked = 0;
 34.2459 +-	skb_shinfo(buff)->tso_segs = 1;
 34.2460 +-	skb_shinfo(buff)->tso_size = 0;
 34.2461 ++	skb_shinfo(buff)->gso_segs = 1;
 34.2462 ++	skb_shinfo(buff)->gso_size = 0;
 34.2463 ++	skb_shinfo(buff)->gso_type = 0;
 34.2464 + 	buff->csum = 0;
 34.2465 + 	TCP_SKB_CB(buff)->seq = tp->write_seq++;
 34.2466 + 	TCP_SKB_CB(buff)->end_seq = tp->write_seq;
 34.2467 +@@ -2042,8 +2049,9 @@ void tcp_send_ack(struct sock *sk)
 34.2468 + 		buff->csum = 0;
 34.2469 + 		TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
 34.2470 + 		TCP_SKB_CB(buff)->sacked = 0;
 34.2471 +-		skb_shinfo(buff)->tso_segs = 1;
 34.2472 +-		skb_shinfo(buff)->tso_size = 0;
 34.2473 ++		skb_shinfo(buff)->gso_segs = 1;
 34.2474 ++		skb_shinfo(buff)->gso_size = 0;
 34.2475 ++		skb_shinfo(buff)->gso_type = 0;
 34.2476 + 
 34.2477 + 		/* Send it off, this clears delayed acks for us. */
 34.2478 + 		TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
 34.2479 +@@ -2078,8 +2086,9 @@ static int tcp_xmit_probe_skb(struct soc
 34.2480 + 	skb->csum = 0;
 34.2481 + 	TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
 34.2482 + 	TCP_SKB_CB(skb)->sacked = urgent;
 34.2483 +-	skb_shinfo(skb)->tso_segs = 1;
 34.2484 +-	skb_shinfo(skb)->tso_size = 0;
 34.2485 ++	skb_shinfo(skb)->gso_segs = 1;
 34.2486 ++	skb_shinfo(skb)->gso_size = 0;
 34.2487 ++	skb_shinfo(skb)->gso_type = 0;
 34.2488 + 
 34.2489 + 	/* Use a previous sequence.  This should cause the other
 34.2490 + 	 * end to send an ack.  Don't queue or clone SKB, just
 34.2491 +diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
 34.2492 +index 32ad229..737c1db 100644
 34.2493 +--- a/net/ipv4/xfrm4_output.c
 34.2494 ++++ b/net/ipv4/xfrm4_output.c
 34.2495 +@@ -9,6 +9,8 @@
 34.2496 +  */
 34.2497 + 
 34.2498 + #include <linux/compiler.h>
 34.2499 ++#include <linux/if_ether.h>
 34.2500 ++#include <linux/kernel.h>
 34.2501 + #include <linux/skbuff.h>
 34.2502 + #include <linux/spinlock.h>
 34.2503 + #include <linux/netfilter_ipv4.h>
 34.2504 +@@ -152,16 +154,10 @@ error_nolock:
 34.2505 + 	goto out_exit;
 34.2506 + }
 34.2507 + 
 34.2508 +-static int xfrm4_output_finish(struct sk_buff *skb)
 34.2509 ++static int xfrm4_output_finish2(struct sk_buff *skb)
 34.2510 + {
 34.2511 + 	int err;
 34.2512 + 
 34.2513 +-#ifdef CONFIG_NETFILTER
 34.2514 +-	if (!skb->dst->xfrm) {
 34.2515 +-		IPCB(skb)->flags |= IPSKB_REROUTED;
 34.2516 +-		return dst_output(skb);
 34.2517 +-	}
 34.2518 +-#endif
 34.2519 + 	while (likely((err = xfrm4_output_one(skb)) == 0)) {
 34.2520 + 		nf_reset(skb);
 34.2521 + 
 34.2522 +@@ -174,7 +170,7 @@ #endif
 34.2523 + 			return dst_output(skb);
 34.2524 + 
 34.2525 + 		err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
 34.2526 +-			      skb->dst->dev, xfrm4_output_finish);
 34.2527 ++			      skb->dst->dev, xfrm4_output_finish2);
 34.2528 + 		if (unlikely(err != 1))
 34.2529 + 			break;
 34.2530 + 	}
 34.2531 +@@ -182,6 +178,48 @@ #endif
 34.2532 + 	return err;
 34.2533 + }
 34.2534 + 
 34.2535 ++static int xfrm4_output_finish(struct sk_buff *skb)
 34.2536 ++{
 34.2537 ++	struct sk_buff *segs;
 34.2538 ++
 34.2539 ++#ifdef CONFIG_NETFILTER
 34.2540 ++	if (!skb->dst->xfrm) {
 34.2541 ++		IPCB(skb)->flags |= IPSKB_REROUTED;
 34.2542 ++		return dst_output(skb);
 34.2543 ++	}
 34.2544 ++#endif
 34.2545 ++
 34.2546 ++	if (!skb_shinfo(skb)->gso_size)
 34.2547 ++		return xfrm4_output_finish2(skb);
 34.2548 ++
 34.2549 ++	skb->protocol = htons(ETH_P_IP);
 34.2550 ++	segs = skb_gso_segment(skb, 0);
 34.2551 ++	kfree_skb(skb);
 34.2552 ++	if (unlikely(IS_ERR(segs)))
 34.2553 ++		return PTR_ERR(segs);
 34.2554 ++
 34.2555 ++	do {
 34.2556 ++		struct sk_buff *nskb = segs->next;
 34.2557 ++		int err;
 34.2558 ++
 34.2559 ++		segs->next = NULL;
 34.2560 ++		err = xfrm4_output_finish2(segs);
 34.2561 ++
 34.2562 ++		if (unlikely(err)) {
 34.2563 ++			while ((segs = nskb)) {
 34.2564 ++				nskb = segs->next;
 34.2565 ++				segs->next = NULL;
 34.2566 ++				kfree_skb(segs);
 34.2567 ++			}
 34.2568 ++			return err;
 34.2569 ++		}
 34.2570 ++
 34.2571 ++		segs = nskb;
 34.2572 ++	} while (segs);
 34.2573 ++
 34.2574 ++	return 0;
 34.2575 ++}
 34.2576 ++
 34.2577 + int xfrm4_output(struct sk_buff *skb)
 34.2578 + {
 34.2579 + 	return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
 34.2580 +diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
 34.2581 +index 5bf70b1..cf5d17e 100644
 34.2582 +--- a/net/ipv6/ip6_output.c
 34.2583 ++++ b/net/ipv6/ip6_output.c
 34.2584 +@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
 34.2585 + 
 34.2586 + int ip6_output(struct sk_buff *skb)
 34.2587 + {
 34.2588 +-	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) ||
 34.2589 ++	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
 34.2590 + 				dst_allfrag(skb->dst))
 34.2591 + 		return ip6_fragment(skb, ip6_output2);
 34.2592 + 	else
 34.2593 +@@ -829,8 +829,9 @@ static inline int ip6_ufo_append_data(st
 34.2594 + 		struct frag_hdr fhdr;
 34.2595 + 
 34.2596 + 		/* specify the length of each IP datagram fragment*/
 34.2597 +-		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) - 
 34.2598 +-						sizeof(struct frag_hdr);
 34.2599 ++		skb_shinfo(skb)->gso_size = mtu - fragheaderlen - 
 34.2600 ++					    sizeof(struct frag_hdr);
 34.2601 ++		skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
 34.2602 + 		ipv6_select_ident(skb, &fhdr);
 34.2603 + 		skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
 34.2604 + 		__skb_queue_tail(&sk->sk_write_queue, skb);
 34.2605 +diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
 34.2606 +index d511a88..ef56d5d 100644
 34.2607 +--- a/net/ipv6/ipcomp6.c
 34.2608 ++++ b/net/ipv6/ipcomp6.c
 34.2609 +@@ -64,7 +64,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
 34.2610 + 
 34.2611 + static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 34.2612 + {
 34.2613 +-	int err = 0;
 34.2614 ++	int err = -ENOMEM;
 34.2615 + 	u8 nexthdr = 0;
 34.2616 + 	int hdr_len = skb->h.raw - skb->nh.raw;
 34.2617 + 	unsigned char *tmp_hdr = NULL;
 34.2618 +@@ -75,11 +75,8 @@ static int ipcomp6_input(struct xfrm_sta
 34.2619 + 	struct crypto_tfm *tfm;
 34.2620 + 	int cpu;
 34.2621 + 
 34.2622 +-	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 34.2623 +-		skb_linearize(skb, GFP_ATOMIC) != 0) {
 34.2624 +-		err = -ENOMEM;
 34.2625 ++	if (skb_linearize_cow(skb))
 34.2626 + 		goto out;
 34.2627 +-	}
 34.2628 + 
 34.2629 + 	skb->ip_summed = CHECKSUM_NONE;
 34.2630 + 
 34.2631 +@@ -158,10 +155,8 @@ static int ipcomp6_output(struct xfrm_st
 34.2632 + 		goto out_ok;
 34.2633 + 	}
 34.2634 + 
 34.2635 +-	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 34.2636 +-		skb_linearize(skb, GFP_ATOMIC) != 0) {
 34.2637 ++	if (skb_linearize_cow(skb))
 34.2638 + 		goto out_ok;
 34.2639 +-	}
 34.2640 + 
 34.2641 + 	/* compression */
 34.2642 + 	plen = skb->len - hdr_len;
 34.2643 +diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
 34.2644 +index 8024217..39bdeec 100644
 34.2645 +--- a/net/ipv6/xfrm6_output.c
 34.2646 ++++ b/net/ipv6/xfrm6_output.c
 34.2647 +@@ -151,7 +151,7 @@ error_nolock:
 34.2648 + 	goto out_exit;
 34.2649 + }
 34.2650 + 
 34.2651 +-static int xfrm6_output_finish(struct sk_buff *skb)
 34.2652 ++static int xfrm6_output_finish2(struct sk_buff *skb)
 34.2653 + {
 34.2654 + 	int err;
 34.2655 + 
 34.2656 +@@ -167,7 +167,7 @@ static int xfrm6_output_finish(struct sk
 34.2657 + 			return dst_output(skb);
 34.2658 + 
 34.2659 + 		err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
 34.2660 +-			      skb->dst->dev, xfrm6_output_finish);
 34.2661 ++			      skb->dst->dev, xfrm6_output_finish2);
 34.2662 + 		if (unlikely(err != 1))
 34.2663 + 			break;
 34.2664 + 	}
 34.2665 +@@ -175,6 +175,41 @@ static int xfrm6_output_finish(struct sk
 34.2666 + 	return err;
 34.2667 + }
 34.2668 + 
 34.2669 ++static int xfrm6_output_finish(struct sk_buff *skb)
 34.2670 ++{
 34.2671 ++	struct sk_buff *segs;
 34.2672 ++
 34.2673 ++	if (!skb_shinfo(skb)->gso_size)
 34.2674 ++		return xfrm6_output_finish2(skb);
 34.2675 ++
 34.2676 ++	skb->protocol = htons(ETH_P_IP);
 34.2677 ++	segs = skb_gso_segment(skb, 0);
 34.2678 ++	kfree_skb(skb);
 34.2679 ++	if (unlikely(IS_ERR(segs)))
 34.2680 ++		return PTR_ERR(segs);
 34.2681 ++
 34.2682 ++	do {
 34.2683 ++		struct sk_buff *nskb = segs->next;
 34.2684 ++		int err;
 34.2685 ++
 34.2686 ++		segs->next = NULL;
 34.2687 ++		err = xfrm6_output_finish2(segs);
 34.2688 ++
 34.2689 ++		if (unlikely(err)) {
 34.2690 ++			while ((segs = nskb)) {
 34.2691 ++				nskb = segs->next;
 34.2692 ++				segs->next = NULL;
 34.2693 ++				kfree_skb(segs);
 34.2694 ++			}
 34.2695 ++			return err;
 34.2696 ++		}
 34.2697 ++
 34.2698 ++		segs = nskb;
 34.2699 ++	} while (segs);
 34.2700 ++
 34.2701 ++	return 0;
 34.2702 ++}
 34.2703 ++
 34.2704 + int xfrm6_output(struct sk_buff *skb)
 34.2705 + {
 34.2706 + 	return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
 34.2707 +diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
 34.2708 +index 99ceb91..28c9efd 100644
 34.2709 +--- a/net/sched/sch_generic.c
 34.2710 ++++ b/net/sched/sch_generic.c
 34.2711 +@@ -72,9 +72,9 @@ void qdisc_unlock_tree(struct net_device
 34.2712 +    dev->queue_lock serializes queue accesses for this device
 34.2713 +    AND dev->qdisc pointer itself.
 34.2714 + 
 34.2715 +-   dev->xmit_lock serializes accesses to device driver.
 34.2716 ++   netif_tx_lock serializes accesses to device driver.
 34.2717 + 
 34.2718 +-   dev->queue_lock and dev->xmit_lock are mutually exclusive,
 34.2719 ++   dev->queue_lock and netif_tx_lock are mutually exclusive,
 34.2720 +    if one is grabbed, another must be free.
 34.2721 +  */
 34.2722 + 
 34.2723 +@@ -90,14 +90,17 @@ void qdisc_unlock_tree(struct net_device
 34.2724 +    NOTE: Called under dev->queue_lock with locally disabled BH.
 34.2725 + */
 34.2726 + 
 34.2727 +-int qdisc_restart(struct net_device *dev)
 34.2728 ++static inline int qdisc_restart(struct net_device *dev)
 34.2729 + {
 34.2730 + 	struct Qdisc *q = dev->qdisc;
 34.2731 + 	struct sk_buff *skb;
 34.2732 + 
 34.2733 + 	/* Dequeue packet */
 34.2734 +-	if ((skb = q->dequeue(q)) != NULL) {
 34.2735 ++	if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
 34.2736 + 		unsigned nolock = (dev->features & NETIF_F_LLTX);
 34.2737 ++
 34.2738 ++		dev->gso_skb = NULL;
 34.2739 ++
 34.2740 + 		/*
 34.2741 + 		 * When the driver has LLTX set it does its own locking
 34.2742 + 		 * in start_xmit. No need to add additional overhead by
 34.2743 +@@ -108,7 +111,7 @@ int qdisc_restart(struct net_device *dev
 34.2744 + 		 * will be requeued.
 34.2745 + 		 */
 34.2746 + 		if (!nolock) {
 34.2747 +-			if (!spin_trylock(&dev->xmit_lock)) {
 34.2748 ++			if (!netif_tx_trylock(dev)) {
 34.2749 + 			collision:
 34.2750 + 				/* So, someone grabbed the driver. */
 34.2751 + 				
 34.2752 +@@ -126,8 +129,6 @@ int qdisc_restart(struct net_device *dev
 34.2753 + 				__get_cpu_var(netdev_rx_stat).cpu_collision++;
 34.2754 + 				goto requeue;
 34.2755 + 			}
 34.2756 +-			/* Remember that the driver is grabbed by us. */
 34.2757 +-			dev->xmit_lock_owner = smp_processor_id();
 34.2758 + 		}
 34.2759 + 		
 34.2760 + 		{
 34.2761 +@@ -136,14 +137,11 @@ int qdisc_restart(struct net_device *dev
 34.2762 + 
 34.2763 + 			if (!netif_queue_stopped(dev)) {
 34.2764 + 				int ret;
 34.2765 +-				if (netdev_nit)
 34.2766 +-					dev_queue_xmit_nit(skb, dev);
 34.2767 + 
 34.2768 +-				ret = dev->hard_start_xmit(skb, dev);
 34.2769 ++				ret = dev_hard_start_xmit(skb, dev);
 34.2770 + 				if (ret == NETDEV_TX_OK) { 
 34.2771 + 					if (!nolock) {
 34.2772 +-						dev->xmit_lock_owner = -1;
 34.2773 +-						spin_unlock(&dev->xmit_lock);
 34.2774 ++						netif_tx_unlock(dev);
 34.2775 + 					}
 34.2776 + 					spin_lock(&dev->queue_lock);
 34.2777 + 					return -1;
 34.2778 +@@ -157,8 +155,7 @@ int qdisc_restart(struct net_device *dev
 34.2779 + 			/* NETDEV_TX_BUSY - we need to requeue */
 34.2780 + 			/* Release the driver */
 34.2781 + 			if (!nolock) { 
 34.2782 +-				dev->xmit_lock_owner = -1;
 34.2783 +-				spin_unlock(&dev->xmit_lock);
 34.2784 ++				netif_tx_unlock(dev);
 34.2785 + 			} 
 34.2786 + 			spin_lock(&dev->queue_lock);
 34.2787 + 			q = dev->qdisc;
 34.2788 +@@ -175,7 +172,10 @@ int qdisc_restart(struct net_device *dev
 34.2789 + 		 */
 34.2790 + 
 34.2791 + requeue:
 34.2792 +-		q->ops->requeue(skb, q);
 34.2793 ++		if (skb->next)
 34.2794 ++			dev->gso_skb = skb;
 34.2795 ++		else
 34.2796 ++			q->ops->requeue(skb, q);
 34.2797 + 		netif_schedule(dev);
 34.2798 + 		return 1;
 34.2799 + 	}
 34.2800 +@@ -183,11 +183,23 @@ requeue:
 34.2801 + 	return q->q.qlen;
 34.2802 + }
 34.2803 + 
 34.2804 ++void __qdisc_run(struct net_device *dev)
 34.2805 ++{
 34.2806 ++	if (unlikely(dev->qdisc == &noop_qdisc))
 34.2807 ++		goto out;
 34.2808 ++
 34.2809 ++	while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
 34.2810 ++		/* NOTHING */;
 34.2811 ++
 34.2812 ++out:
 34.2813 ++	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
 34.2814 ++}
 34.2815 ++
 34.2816 + static void dev_watchdog(unsigned long arg)
 34.2817 + {
 34.2818 + 	struct net_device *dev = (struct net_device *)arg;
 34.2819 + 
 34.2820 +-	spin_lock(&dev->xmit_lock);
 34.2821 ++	netif_tx_lock(dev);
 34.2822 + 	if (dev->qdisc != &noop_qdisc) {
 34.2823 + 		if (netif_device_present(dev) &&
 34.2824 + 		    netif_running(dev) &&
 34.2825 +@@ -201,7 +213,7 @@ static void dev_watchdog(unsigned long a
 34.2826 + 				dev_hold(dev);
 34.2827 + 		}
 34.2828 + 	}
 34.2829 +-	spin_unlock(&dev->xmit_lock);
 34.2830 ++	netif_tx_unlock(dev);
 34.2831 + 
 34.2832 + 	dev_put(dev);
 34.2833 + }
 34.2834 +@@ -225,17 +237,17 @@ void __netdev_watchdog_up(struct net_dev
 34.2835 + 
 34.2836 + static void dev_watchdog_up(struct net_device *dev)
 34.2837 + {
 34.2838 +-	spin_lock_bh(&dev->xmit_lock);
 34.2839 ++	netif_tx_lock_bh(dev);
 34.2840 + 	__netdev_watchdog_up(dev);
 34.2841 +-	spin_unlock_bh(&dev->xmit_lock);
 34.2842 ++	netif_tx_unlock_bh(dev);
 34.2843 + }
 34.2844 + 
 34.2845 + static void dev_watchdog_down(struct net_device *dev)
 34.2846 + {
 34.2847 +-	spin_lock_bh(&dev->xmit_lock);
 34.2848 ++	netif_tx_lock_bh(dev);
 34.2849 + 	if (del_timer(&dev->watchdog_timer))
 34.2850 + 		__dev_put(dev);
 34.2851 +-	spin_unlock_bh(&dev->xmit_lock);
 34.2852 ++	netif_tx_unlock_bh(dev);
 34.2853 + }
 34.2854 + 
 34.2855 + void netif_carrier_on(struct net_device *dev)
 34.2856 +@@ -577,10 +589,17 @@ void dev_deactivate(struct net_device *d
 34.2857 + 
 34.2858 + 	dev_watchdog_down(dev);
 34.2859 + 
 34.2860 +-	while (test_bit(__LINK_STATE_SCHED, &dev->state))
 34.2861 ++	/* Wait for outstanding dev_queue_xmit calls. */
 34.2862 ++	synchronize_rcu();
 34.2863 ++
 34.2864 ++	/* Wait for outstanding qdisc_run calls. */
 34.2865 ++	while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
 34.2866 + 		yield();
 34.2867 + 
 34.2868 +-	spin_unlock_wait(&dev->xmit_lock);
 34.2869 ++	if (dev->gso_skb) {
 34.2870 ++		kfree_skb(dev->gso_skb);
 34.2871 ++		dev->gso_skb = NULL;
 34.2872 ++	}
 34.2873 + }
 34.2874 + 
 34.2875 + void dev_init_scheduler(struct net_device *dev)
 34.2876 +@@ -622,6 +641,5 @@ EXPORT_SYMBOL(qdisc_create_dflt);
 34.2877 + EXPORT_SYMBOL(qdisc_alloc);
 34.2878 + EXPORT_SYMBOL(qdisc_destroy);
 34.2879 + EXPORT_SYMBOL(qdisc_reset);
 34.2880 +-EXPORT_SYMBOL(qdisc_restart);
 34.2881 + EXPORT_SYMBOL(qdisc_lock_tree);
 34.2882 + EXPORT_SYMBOL(qdisc_unlock_tree);
 34.2883 +diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
 34.2884 +index 79b8ef3..4c16ad5 100644
 34.2885 +--- a/net/sched/sch_teql.c
 34.2886 ++++ b/net/sched/sch_teql.c
 34.2887 +@@ -302,20 +302,17 @@ restart:
 34.2888 + 
 34.2889 + 		switch (teql_resolve(skb, skb_res, slave)) {
 34.2890 + 		case 0:
 34.2891 +-			if (spin_trylock(&slave->xmit_lock)) {
 34.2892 +-				slave->xmit_lock_owner = smp_processor_id();
 34.2893 ++			if (netif_tx_trylock(slave)) {
 34.2894 + 				if (!netif_queue_stopped(slave) &&
 34.2895 + 				    slave->hard_start_xmit(skb, slave) == 0) {
 34.2896 +-					slave->xmit_lock_owner = -1;
 34.2897 +-					spin_unlock(&slave->xmit_lock);
 34.2898 ++					netif_tx_unlock(slave);
 34.2899 + 					master->slaves = NEXT_SLAVE(q);
 34.2900 + 					netif_wake_queue(dev);
 34.2901 + 					master->stats.tx_packets++;
 34.2902 + 					master->stats.tx_bytes += len;
 34.2903 + 					return 0;
 34.2904 + 				}
 34.2905 +-				slave->xmit_lock_owner = -1;
 34.2906 +-				spin_unlock(&slave->xmit_lock);
 34.2907 ++				netif_tx_unlock(slave);
 34.2908 + 			}
 34.2909 + 			if (netif_queue_stopped(dev))
 34.2910 + 				busy = 1;
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/patches/linux-2.6.16.13/net-gso-1-check-dodgy.patch	Tue Jul 25 12:19:05 2006 -0600
    35.3 @@ -0,0 +1,27 @@
    35.4 +diff -urp a/net/ipv4/tcp.c b/net/ipv4/tcp.c
    35.5 +--- a/net/ipv4/tcp.c	2006-07-25 14:42:53.194910626 +0100
    35.6 ++++ b/net/ipv4/tcp.c	2006-07-25 14:41:00.955501910 +0100
    35.7 +@@ -2042,13 +2042,19 @@ struct sk_buff *tcp_tso_segment(struct s
    35.8 + 	if (!pskb_may_pull(skb, thlen))
    35.9 + 		goto out;
   35.10 + 
   35.11 +-	segs = NULL;
   35.12 +-	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST))
   35.13 +-		goto out;
   35.14 +-
   35.15 + 	oldlen = (u16)~skb->len;
   35.16 + 	__skb_pull(skb, thlen);
   35.17 + 
   35.18 ++	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
   35.19 ++		/* Packet is from an untrusted source, reset gso_segs. */
   35.20 ++		int mss = skb_shinfo(skb)->gso_size;
   35.21 ++
   35.22 ++		skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss;
   35.23 ++
   35.24 ++		segs = NULL;
   35.25 ++		goto out;
   35.26 ++	}
   35.27 ++
   35.28 + 	segs = skb_segment(skb, features);
   35.29 + 	if (IS_ERR(segs))
   35.30 + 		goto out;
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/patches/linux-2.6.16.13/net-gso-2-checksum-fix.patch	Tue Jul 25 12:19:05 2006 -0600
    36.3 @@ -0,0 +1,451 @@
    36.4 +diff -urp a/drivers/net/bnx2.c b/drivers/net/bnx2.c
    36.5 +--- a/drivers/net/bnx2.c	2006-07-25 14:41:00.905507519 +0100
    36.6 ++++ b/drivers/net/bnx2.c	2006-07-25 14:36:00.288561400 +0100
    36.7 +@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
    36.8 + 		skb = tx_buf->skb;
    36.9 + #ifdef BCM_TSO 
   36.10 + 		/* partial BD completions possible with TSO packets */
   36.11 +-		if (skb_shinfo(skb)->gso_size) {
   36.12 ++		if (skb_is_gso(skb)) {
   36.13 + 			u16 last_idx, last_ring_idx;
   36.14 + 
   36.15 + 			last_idx = sw_cons +
   36.16 +diff -urp a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
   36.17 +--- a/drivers/net/chelsio/sge.c	2006-07-25 14:41:00.908507183 +0100
   36.18 ++++ b/drivers/net/chelsio/sge.c	2006-07-25 14:36:00.291561087 +0100
   36.19 +@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
   36.20 + 	struct cpl_tx_pkt *cpl;
   36.21 + 
   36.22 + #ifdef NETIF_F_TSO
   36.23 +-	if (skb_shinfo(skb)->gso_size) {
   36.24 ++	if (skb_is_gso(skb)) {
   36.25 + 		int eth_type;
   36.26 + 		struct cpl_tx_pkt_lso *hdr;
   36.27 + 
   36.28 +diff -urp a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
   36.29 +--- a/drivers/net/e1000/e1000_main.c	2006-07-25 14:41:00.910506958 +0100
   36.30 ++++ b/drivers/net/e1000/e1000_main.c	2006-07-25 14:36:00.293560878 +0100
   36.31 +@@ -2526,7 +2526,7 @@ e1000_tso(struct e1000_adapter *adapter,
   36.32 + 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
   36.33 + 	int err;
   36.34 + 
   36.35 +-	if (skb_shinfo(skb)->gso_size) {
   36.36 ++	if (skb_is_gso(skb)) {
   36.37 + 		if (skb_header_cloned(skb)) {
   36.38 + 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
   36.39 + 			if (err)
   36.40 +@@ -2651,7 +2651,7 @@ e1000_tx_map(struct e1000_adapter *adapt
   36.41 + 		 * tso gets written back prematurely before the data is fully
   36.42 + 		 * DMAd to the controller */
   36.43 + 		if (!skb->data_len && tx_ring->last_tx_tso &&
   36.44 +-				!skb_shinfo(skb)->gso_size) {
   36.45 ++		    !skb_is_gso(skb)) {
   36.46 + 			tx_ring->last_tx_tso = 0;
   36.47 + 			size -= 4;
   36.48 + 		}
   36.49 +@@ -2934,8 +2934,7 @@ e1000_xmit_frame(struct sk_buff *skb, st
   36.50 + 
   36.51 + #ifdef NETIF_F_TSO
   36.52 + 	/* Controller Erratum workaround */
   36.53 +-	if (!skb->data_len && tx_ring->last_tx_tso &&
   36.54 +-		!skb_shinfo(skb)->gso_size)
   36.55 ++	if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
   36.56 + 		count++;
   36.57 + #endif
   36.58 + 
   36.59 +diff -urp a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
   36.60 +--- a/drivers/net/forcedeth.c	2006-07-25 14:41:00.912506734 +0100
   36.61 ++++ b/drivers/net/forcedeth.c	2006-07-25 14:36:00.295560669 +0100
   36.62 +@@ -1105,7 +1105,7 @@ static int nv_start_xmit(struct sk_buff 
   36.63 + 	np->tx_skbuff[nr] = skb;
   36.64 + 
   36.65 + #ifdef NETIF_F_TSO
   36.66 +-	if (skb_shinfo(skb)->gso_size)
   36.67 ++	if (skb_is_gso(skb))
   36.68 + 		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
   36.69 + 	else
   36.70 + #endif
   36.71 +diff -urp a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
   36.72 +--- a/drivers/net/ixgb/ixgb_main.c	2006-07-25 14:41:00.915506397 +0100
   36.73 ++++ b/drivers/net/ixgb/ixgb_main.c	2006-07-25 14:36:00.298560355 +0100
   36.74 +@@ -1163,7 +1163,7 @@ ixgb_tso(struct ixgb_adapter *adapter, s
   36.75 + 	uint16_t ipcse, tucse, mss;
   36.76 + 	int err;
   36.77 + 
   36.78 +-	if(likely(skb_shinfo(skb)->gso_size)) {
   36.79 ++	if (likely(skb_is_gso(skb))) {
   36.80 + 		if (skb_header_cloned(skb)) {
   36.81 + 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
   36.82 + 			if (err)
   36.83 +diff -urp a/drivers/net/loopback.c b/drivers/net/loopback.c
   36.84 +--- a/drivers/net/loopback.c	2006-07-25 14:41:00.915506397 +0100
   36.85 ++++ b/drivers/net/loopback.c	2006-07-25 14:36:00.298560355 +0100
   36.86 +@@ -139,7 +139,7 @@ static int loopback_xmit(struct sk_buff 
   36.87 + #endif
   36.88 + 
   36.89 + #ifdef LOOPBACK_TSO
   36.90 +-	if (skb_shinfo(skb)->gso_size) {
   36.91 ++	if (skb_is_gso(skb)) {
   36.92 + 		BUG_ON(skb->protocol != htons(ETH_P_IP));
   36.93 + 		BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
   36.94 + 
   36.95 +diff -urp a/drivers/net/sky2.c b/drivers/net/sky2.c
   36.96 +--- a/drivers/net/sky2.c	2006-07-25 14:41:00.924505388 +0100
   36.97 ++++ b/drivers/net/sky2.c	2006-07-25 14:36:00.306559519 +0100
   36.98 +@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
   36.99 + 	count = sizeof(dma_addr_t) / sizeof(u32);
  36.100 + 	count += skb_shinfo(skb)->nr_frags * count;
  36.101 + 
  36.102 +-	if (skb_shinfo(skb)->gso_size)
  36.103 ++	if (skb_is_gso(skb))
  36.104 + 		++count;
  36.105 + 
  36.106 + 	if (skb->ip_summed == CHECKSUM_HW)
  36.107 +diff -urp a/drivers/net/typhoon.c b/drivers/net/typhoon.c
  36.108 +--- a/drivers/net/typhoon.c	2006-07-25 14:41:00.931504603 +0100
  36.109 ++++ b/drivers/net/typhoon.c	2006-07-25 14:36:00.314558683 +0100
  36.110 +@@ -805,7 +805,7 @@ typhoon_start_tx(struct sk_buff *skb, st
  36.111 + 	 * If problems develop with TSO, check this first.
  36.112 + 	 */
  36.113 + 	numDesc = skb_shinfo(skb)->nr_frags + 1;
  36.114 +-	if(skb_tso_size(skb))
  36.115 ++	if (skb_is_gso(skb))
  36.116 + 		numDesc++;
  36.117 + 
  36.118 + 	/* When checking for free space in the ring, we need to also
  36.119 +@@ -845,7 +845,7 @@ typhoon_start_tx(struct sk_buff *skb, st
  36.120 + 				TYPHOON_TX_PF_VLAN_TAG_SHIFT);
  36.121 + 	}
  36.122 + 
  36.123 +-	if(skb_tso_size(skb)) {
  36.124 ++	if (skb_is_gso(skb)) {
  36.125 + 		first_txd->processFlags |= TYPHOON_TX_PF_TCP_SEGMENT;
  36.126 + 		first_txd->numDesc++;
  36.127 + 
  36.128 +diff -urp a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
  36.129 +--- a/drivers/s390/net/qeth_main.c	2006-07-25 14:41:00.939503705 +0100
  36.130 ++++ b/drivers/s390/net/qeth_main.c	2006-07-25 14:36:00.321557952 +0100
  36.131 +@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
  36.132 + 	queue = card->qdio.out_qs
  36.133 + 		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
  36.134 + 
  36.135 +-	if (skb_shinfo(skb)->gso_size)
  36.136 ++	if (skb_is_gso(skb))
  36.137 + 		large_send = card->options.large_send;
  36.138 + 
  36.139 + 	/*are we able to do TSO ? If so ,prepare and send it from here */
  36.140 +@@ -4501,8 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
  36.141 + 		card->stats.tx_packets++;
  36.142 + 		card->stats.tx_bytes += skb->len;
  36.143 + #ifdef CONFIG_QETH_PERF_STATS
  36.144 +-		if (skb_shinfo(skb)->gso_size &&
  36.145 +-		   !(large_send == QETH_LARGE_SEND_NO)) {
  36.146 ++		if (skb_is_gso(skb) && !(large_send == QETH_LARGE_SEND_NO)) {
  36.147 + 			card->perf_stats.large_send_bytes += skb->len;
  36.148 + 			card->perf_stats.large_send_cnt++;
  36.149 + 		}
  36.150 +diff -urp a/include/linux/netdevice.h b/include/linux/netdevice.h
  36.151 +--- a/include/linux/netdevice.h	2006-07-25 14:41:00.940503593 +0100
  36.152 ++++ b/include/linux/netdevice.h	2006-07-25 14:36:00.323557743 +0100
  36.153 +@@ -541,6 +541,7 @@ struct packet_type {
  36.154 + 					 struct net_device *);
  36.155 + 	struct sk_buff		*(*gso_segment)(struct sk_buff *skb,
  36.156 + 						int features);
  36.157 ++	int			(*gso_send_check)(struct sk_buff *skb);
  36.158 + 	void			*af_packet_priv;
  36.159 + 	struct list_head	list;
  36.160 + };
  36.161 +@@ -1001,14 +1002,15 @@ extern void linkwatch_run_queue(void);
  36.162 + 
  36.163 + static inline int skb_gso_ok(struct sk_buff *skb, int features)
  36.164 + {
  36.165 +-	int feature = skb_shinfo(skb)->gso_size ?
  36.166 +-		      skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
  36.167 ++	int feature = skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT;
  36.168 + 	return (features & feature) == feature;
  36.169 + }
  36.170 + 
  36.171 + static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
  36.172 + {
  36.173 +-	return !skb_gso_ok(skb, dev->features);
  36.174 ++	return skb_is_gso(skb) &&
  36.175 ++	       (!skb_gso_ok(skb, dev->features) ||
  36.176 ++		unlikely(skb->ip_summed != CHECKSUM_HW));
  36.177 + }
  36.178 + 
  36.179 + #endif /* __KERNEL__ */
  36.180 +diff -urp a/include/linux/skbuff.h b/include/linux/skbuff.h
  36.181 +--- a/include/linux/skbuff.h	2006-07-25 14:41:00.941503481 +0100
  36.182 ++++ b/include/linux/skbuff.h	2006-07-25 14:36:00.323557743 +0100
  36.183 +@@ -1403,5 +1403,10 @@ static inline void nf_bridge_get(struct 
  36.184 + static inline void nf_reset(struct sk_buff *skb) {}
  36.185 + #endif /* CONFIG_NETFILTER */
  36.186 + 
  36.187 ++static inline int skb_is_gso(const struct sk_buff *skb)
  36.188 ++{
  36.189 ++	return skb_shinfo(skb)->gso_size;
  36.190 ++}
  36.191 ++
  36.192 + #endif	/* __KERNEL__ */
  36.193 + #endif	/* _LINUX_SKBUFF_H */
  36.194 +diff -urp a/include/net/protocol.h b/include/net/protocol.h
  36.195 +--- a/include/net/protocol.h	2006-07-25 14:41:00.942503369 +0100
  36.196 ++++ b/include/net/protocol.h	2006-07-25 14:36:00.324557639 +0100
  36.197 +@@ -37,6 +37,7 @@
  36.198 + struct net_protocol {
  36.199 + 	int			(*handler)(struct sk_buff *skb);
  36.200 + 	void			(*err_handler)(struct sk_buff *skb, u32 info);
  36.201 ++	int			(*gso_send_check)(struct sk_buff *skb);
  36.202 + 	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
  36.203 + 					       int features);
  36.204 + 	int			no_policy;
  36.205 +diff -urp a/include/net/tcp.h b/include/net/tcp.h
  36.206 +--- a/include/net/tcp.h	2006-07-25 14:41:00.943503256 +0100
  36.207 ++++ b/include/net/tcp.h	2006-07-25 14:36:00.325557534 +0100
  36.208 +@@ -1063,6 +1063,7 @@ extern struct request_sock_ops tcp_reque
  36.209 + 
  36.210 + extern int tcp_v4_destroy_sock(struct sock *sk);
  36.211 + 
  36.212 ++extern int tcp_v4_gso_send_check(struct sk_buff *skb);
  36.213 + extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
  36.214 + 
  36.215 + #ifdef CONFIG_PROC_FS
  36.216 +diff -urp a/net/bridge/br_forward.c b/net/bridge/br_forward.c
  36.217 +--- a/net/bridge/br_forward.c	2006-07-25 14:41:00.944503144 +0100
  36.218 ++++ b/net/bridge/br_forward.c	2006-07-25 14:36:00.326557430 +0100
  36.219 +@@ -32,7 +32,7 @@ static inline int should_deliver(const s
  36.220 + int br_dev_queue_push_xmit(struct sk_buff *skb)
  36.221 + {
  36.222 + 	/* drop mtu oversized packets except tso */
  36.223 +-	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
  36.224 ++	if (skb->len > skb->dev->mtu && !skb_is_gso(skb))
  36.225 + 		kfree_skb(skb);
  36.226 + 	else {
  36.227 + #ifdef CONFIG_BRIDGE_NETFILTER
  36.228 +diff -urp a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
  36.229 +--- a/net/bridge/br_netfilter.c	2006-07-25 14:41:00.945503032 +0100
  36.230 ++++ b/net/bridge/br_netfilter.c	2006-07-25 14:36:00.327557325 +0100
  36.231 +@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
  36.232 + {
  36.233 + 	if (skb->protocol == htons(ETH_P_IP) &&
  36.234 + 	    skb->len > skb->dev->mtu &&
  36.235 +-	    !skb_shinfo(skb)->gso_size)
  36.236 ++	    !skb_is_gso(skb))
  36.237 + 		return ip_fragment(skb, br_dev_queue_push_xmit);
  36.238 + 	else
  36.239 + 		return br_dev_queue_push_xmit(skb);
  36.240 +diff -urp a/net/core/dev.c b/net/core/dev.c
  36.241 +--- a/net/core/dev.c	2006-07-25 14:41:00.947502808 +0100
  36.242 ++++ b/net/core/dev.c	2006-07-25 14:36:00.329557116 +0100
  36.243 +@@ -1083,9 +1083,17 @@ int skb_checksum_help(struct sk_buff *sk
  36.244 + 	unsigned int csum;
  36.245 + 	int ret = 0, offset = skb->h.raw - skb->data;
  36.246 + 
  36.247 +-	if (inward) {
  36.248 +-		skb->ip_summed = CHECKSUM_NONE;
  36.249 +-		goto out;
  36.250 ++	if (inward)
  36.251 ++		goto out_set_summed;
  36.252 ++
  36.253 ++	if (unlikely(skb_shinfo(skb)->gso_size)) {
  36.254 ++		static int warned;
  36.255 ++
  36.256 ++		WARN_ON(!warned);
  36.257 ++		warned = 1;
  36.258 ++
  36.259 ++		/* Let GSO fix up the checksum. */
  36.260 ++		goto out_set_summed;
  36.261 + 	}
  36.262 + 
  36.263 + 	if (skb_cloned(skb)) {
  36.264 +@@ -1102,6 +1110,8 @@ int skb_checksum_help(struct sk_buff *sk
  36.265 + 	BUG_ON(skb->csum + 2 > offset);
  36.266 + 
  36.267 + 	*(u16*)(skb->h.raw + skb->csum) = csum_fold(csum);
  36.268 ++
  36.269 ++out_set_summed:
  36.270 + 	skb->ip_summed = CHECKSUM_NONE;
  36.271 + out:	
  36.272 + 	return ret;
  36.273 +@@ -1122,17 +1132,35 @@ struct sk_buff *skb_gso_segment(struct s
  36.274 + 	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
  36.275 + 	struct packet_type *ptype;
  36.276 + 	int type = skb->protocol;
  36.277 ++	int err;
  36.278 + 
  36.279 + 	BUG_ON(skb_shinfo(skb)->frag_list);
  36.280 +-	BUG_ON(skb->ip_summed != CHECKSUM_HW);
  36.281 + 
  36.282 + 	skb->mac.raw = skb->data;
  36.283 + 	skb->mac_len = skb->nh.raw - skb->data;
  36.284 + 	__skb_pull(skb, skb->mac_len);
  36.285 + 
  36.286 ++	if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
  36.287 ++		static int warned;
  36.288 ++
  36.289 ++		WARN_ON(!warned);
  36.290 ++		warned = 1;
  36.291 ++
  36.292 ++		if (skb_header_cloned(skb) &&
  36.293 ++		    (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
  36.294 ++			return ERR_PTR(err);
  36.295 ++	}
  36.296 ++
  36.297 + 	rcu_read_lock();
  36.298 + 	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
  36.299 + 		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
  36.300 ++			if (unlikely(skb->ip_summed != CHECKSUM_HW)) {
  36.301 ++				err = ptype->gso_send_check(skb);
  36.302 ++				segs = ERR_PTR(err);
  36.303 ++				if (err || skb_gso_ok(skb, features))
  36.304 ++					break;
  36.305 ++				__skb_push(skb, skb->data - skb->nh.raw);
  36.306 ++			}
  36.307 + 			segs = ptype->gso_segment(skb, features);
  36.308 + 			break;
  36.309 + 		}
  36.310 +diff -urp a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
  36.311 +--- a/net/ipv4/af_inet.c	2006-07-25 14:41:00.952502247 +0100
  36.312 ++++ b/net/ipv4/af_inet.c	2006-07-25 14:36:00.334556594 +0100
  36.313 +@@ -1085,6 +1085,40 @@ int inet_sk_rebuild_header(struct sock *
  36.314 + 
  36.315 + EXPORT_SYMBOL(inet_sk_rebuild_header);
  36.316 + 
  36.317 ++static int inet_gso_send_check(struct sk_buff *skb)
  36.318 ++{
  36.319 ++	struct iphdr *iph;
  36.320 ++	struct net_protocol *ops;
  36.321 ++	int proto;
  36.322 ++	int ihl;
  36.323 ++	int err = -EINVAL;
  36.324 ++
  36.325 ++	if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
  36.326 ++		goto out;
  36.327 ++
  36.328 ++	iph = skb->nh.iph;
  36.329 ++	ihl = iph->ihl * 4;
  36.330 ++	if (ihl < sizeof(*iph))
  36.331 ++		goto out;
  36.332 ++
  36.333 ++	if (unlikely(!pskb_may_pull(skb, ihl)))
  36.334 ++		goto out;
  36.335 ++
  36.336 ++	skb->h.raw = __skb_pull(skb, ihl);
  36.337 ++	iph = skb->nh.iph;
  36.338 ++	proto = iph->protocol & (MAX_INET_PROTOS - 1);
  36.339 ++	err = -EPROTONOSUPPORT;
  36.340 ++
  36.341 ++	rcu_read_lock();
  36.342 ++	ops = rcu_dereference(inet_protos[proto]);
  36.343 ++	if (likely(ops && ops->gso_send_check))
  36.344 ++		err = ops->gso_send_check(skb);
  36.345 ++	rcu_read_unlock();
  36.346 ++
  36.347 ++out:
  36.348 ++	return err;
  36.349 ++}
  36.350 ++
  36.351 + static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
  36.352 + {
  36.353 + 	struct sk_buff *segs = ERR_PTR(-EINVAL);
  36.354 +@@ -1142,6 +1176,7 @@ static struct net_protocol igmp_protocol
  36.355 + static struct net_protocol tcp_protocol = {
  36.356 + 	.handler =	tcp_v4_rcv,
  36.357 + 	.err_handler =	tcp_v4_err,
  36.358 ++	.gso_send_check = tcp_v4_gso_send_check,
  36.359 + 	.gso_segment =	tcp_tso_segment,
  36.360 + 	.no_policy =	1,
  36.361 + };
  36.362 +@@ -1188,6 +1223,7 @@ static int ipv4_proc_init(void);
  36.363 + static struct packet_type ip_packet_type = {
  36.364 + 	.type = __constant_htons(ETH_P_IP),
  36.365 + 	.func = ip_rcv,
  36.366 ++	.gso_send_check = inet_gso_send_check,
  36.367 + 	.gso_segment = inet_gso_segment,
  36.368 + };
  36.369 + 
  36.370 +diff -urp a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
  36.371 +--- a/net/ipv4/ip_output.c	2006-07-25 14:41:00.953502135 +0100
  36.372 ++++ b/net/ipv4/ip_output.c	2006-07-25 14:36:00.335556489 +0100
  36.373 +@@ -210,7 +210,7 @@ static inline int ip_finish_output(struc
  36.374 + 		return dst_output(skb);
  36.375 + 	}
  36.376 + #endif
  36.377 +-	if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
  36.378 ++	if (skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb))
  36.379 + 		return ip_fragment(skb, ip_finish_output2);
  36.380 + 	else
  36.381 + 		return ip_finish_output2(skb);
  36.382 +@@ -1095,7 +1095,7 @@ ssize_t	ip_append_page(struct sock *sk, 
  36.383 + 	while (size > 0) {
  36.384 + 		int i;
  36.385 + 
  36.386 +-		if (skb_shinfo(skb)->gso_size)
  36.387 ++		if (skb_is_gso(skb))
  36.388 + 			len = size;
  36.389 + 		else {
  36.390 + 
  36.391 +diff -urp a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
  36.392 +--- a/net/ipv4/tcp_ipv4.c	2006-07-25 14:39:15.985080788 +0100
  36.393 ++++ b/net/ipv4/tcp_ipv4.c	2006-07-25 14:36:00.339556071 +0100
  36.394 +@@ -495,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk, 
  36.395 + 	}
  36.396 + }
  36.397 + 
  36.398 ++int tcp_v4_gso_send_check(struct sk_buff *skb)
  36.399 ++{
  36.400 ++	struct iphdr *iph;
  36.401 ++	struct tcphdr *th;
  36.402 ++
  36.403 ++	if (!pskb_may_pull(skb, sizeof(*th)))
  36.404 ++		return -EINVAL;
  36.405 ++
  36.406 ++	iph = skb->nh.iph;
  36.407 ++	th = skb->h.th;
  36.408 ++
  36.409 ++	th->check = 0;
  36.410 ++	th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0);
  36.411 ++	skb->csum = offsetof(struct tcphdr, check);
  36.412 ++	skb->ip_summed = CHECKSUM_HW;
  36.413 ++	return 0;
  36.414 ++}
  36.415 ++
  36.416 + /*
  36.417 +  *	This routine will send an RST to the other tcp.
  36.418 +  *
  36.419 +diff -urp a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
  36.420 +--- a/net/ipv4/xfrm4_output.c	2006-07-25 14:41:00.958501574 +0100
  36.421 ++++ b/net/ipv4/xfrm4_output.c	2006-07-25 14:36:00.341555862 +0100
  36.422 +@@ -189,7 +189,7 @@ static int xfrm4_output_finish(struct sk
  36.423 + 	}
  36.424 + #endif
  36.425 + 
  36.426 +-	if (!skb_shinfo(skb)->gso_size)
  36.427 ++	if (!skb_is_gso(skb))
  36.428 + 		return xfrm4_output_finish2(skb);
  36.429 + 
  36.430 + 	skb->protocol = htons(ETH_P_IP);
  36.431 +diff -urp a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
  36.432 +--- a/net/ipv6/ip6_output.c	2006-07-25 14:41:00.959501461 +0100
  36.433 ++++ b/net/ipv6/ip6_output.c	2006-07-25 14:36:00.341555862 +0100
  36.434 +@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
  36.435 + 
  36.436 + int ip6_output(struct sk_buff *skb)
  36.437 + {
  36.438 +-	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
  36.439 ++	if ((skb->len > dst_mtu(skb->dst) && !skb_is_gso(skb)) ||
  36.440 + 				dst_allfrag(skb->dst))
  36.441 + 		return ip6_fragment(skb, ip6_output2);
  36.442 + 	else
  36.443 +diff -urp a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
  36.444 +--- a/net/ipv6/xfrm6_output.c	2006-07-25 14:41:00.960501349 +0100
  36.445 ++++ b/net/ipv6/xfrm6_output.c	2006-07-25 14:36:00.342555758 +0100
  36.446 +@@ -179,7 +179,7 @@ static int xfrm6_output_finish(struct sk
  36.447 + {
  36.448 + 	struct sk_buff *segs;
  36.449 + 
  36.450 +-	if (!skb_shinfo(skb)->gso_size)
  36.451 ++	if (!skb_is_gso(skb))
  36.452 + 		return xfrm6_output_finish2(skb);
  36.453 + 
  36.454 + 	skb->protocol = htons(ETH_P_IP);
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/patches/linux-2.6.16.13/net-gso-3-fix-errorcheck.patch	Tue Jul 25 12:19:05 2006 -0600
    37.3 @@ -0,0 +1,17 @@
    37.4 +diff -urp a/include/linux/netdevice.h b/include/linux/netdevice.h
    37.5 +--- a/include/linux/netdevice.h	2006-07-25 15:16:39.314333975 +0100
    37.6 ++++ b/include/linux/netdevice.h	2006-07-25 15:19:37.298320799 +0100
    37.7 +@@ -930,10 +930,10 @@ static inline void netif_tx_lock_bh(stru
    37.8 + 
    37.9 + static inline int netif_tx_trylock(struct net_device *dev)
   37.10 + {
   37.11 +-	int err = spin_trylock(&dev->_xmit_lock);
   37.12 +-	if (!err)
   37.13 ++	int ok = spin_trylock(&dev->_xmit_lock);
   37.14 ++	if (likely(ok))
   37.15 + 		dev->xmit_lock_owner = smp_processor_id();
   37.16 +-	return err;
   37.17 ++	return ok;
   37.18 + }
   37.19 + 
   37.20 + static inline void netif_tx_unlock(struct net_device *dev)
    38.1 --- a/patches/linux-2.6.16.13/net-gso.patch	Tue Jul 25 09:51:50 2006 -0600
    38.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.3 @@ -1,2913 +0,0 @@
    38.4 -diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt
    38.5 -index 3c0a5ba..847cedb 100644
    38.6 ---- a/Documentation/networking/netdevices.txt
    38.7 -+++ b/Documentation/networking/netdevices.txt
    38.8 -@@ -42,9 +42,9 @@ dev->get_stats:
    38.9 - 	Context: nominally process, but don't sleep inside an rwlock
   38.10 - 
   38.11 - dev->hard_start_xmit:
   38.12 --	Synchronization: dev->xmit_lock spinlock.
   38.13 -+	Synchronization: netif_tx_lock spinlock.
   38.14 - 	When the driver sets NETIF_F_LLTX in dev->features this will be
   38.15 --	called without holding xmit_lock. In this case the driver 
   38.16 -+	called without holding netif_tx_lock. In this case the driver
   38.17 - 	has to lock by itself when needed. It is recommended to use a try lock
   38.18 - 	for this and return -1 when the spin lock fails. 
   38.19 - 	The locking there should also properly protect against 
   38.20 -@@ -62,12 +62,12 @@ dev->hard_start_xmit:
   38.21 - 	  Only valid when NETIF_F_LLTX is set.
   38.22 - 
   38.23 - dev->tx_timeout:
   38.24 --	Synchronization: dev->xmit_lock spinlock.
   38.25 -+	Synchronization: netif_tx_lock spinlock.
   38.26 - 	Context: BHs disabled
   38.27 - 	Notes: netif_queue_stopped() is guaranteed true
   38.28 - 
   38.29 - dev->set_multicast_list:
   38.30 --	Synchronization: dev->xmit_lock spinlock.
   38.31 -+	Synchronization: netif_tx_lock spinlock.
   38.32 - 	Context: BHs disabled
   38.33 - 
   38.34 - dev->poll:
   38.35 -diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
   38.36 -index 4be9769..2e7cac7 100644
   38.37 ---- a/drivers/block/aoe/aoenet.c
   38.38 -+++ b/drivers/block/aoe/aoenet.c
   38.39 -@@ -95,9 +95,8 @@ mac_addr(char addr[6])
   38.40 - static struct sk_buff *
   38.41 - skb_check(struct sk_buff *skb)
   38.42 - {
   38.43 --	if (skb_is_nonlinear(skb))
   38.44 - 	if ((skb = skb_share_check(skb, GFP_ATOMIC)))
   38.45 --	if (skb_linearize(skb, GFP_ATOMIC) < 0) {
   38.46 -+	if (skb_linearize(skb)) {
   38.47 - 		dev_kfree_skb(skb);
   38.48 - 		return NULL;
   38.49 - 	}
   38.50 -diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
   38.51 -index a2408d7..c90e620 100644
   38.52 ---- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
   38.53 -+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
   38.54 -@@ -821,7 +821,8 @@ void ipoib_mcast_restart_task(void *dev_
   38.55 - 
   38.56 - 	ipoib_mcast_stop_thread(dev, 0);
   38.57 - 
   38.58 --	spin_lock_irqsave(&dev->xmit_lock, flags);
   38.59 -+	local_irq_save(flags);
   38.60 -+	netif_tx_lock(dev);
   38.61 - 	spin_lock(&priv->lock);
   38.62 - 
   38.63 - 	/*
   38.64 -@@ -896,7 +897,8 @@ void ipoib_mcast_restart_task(void *dev_
   38.65 - 	}
   38.66 - 
   38.67 - 	spin_unlock(&priv->lock);
   38.68 --	spin_unlock_irqrestore(&dev->xmit_lock, flags);
   38.69 -+	netif_tx_unlock(dev);
   38.70 -+	local_irq_restore(flags);
   38.71 - 
   38.72 - 	/* We have to cancel outside of the spinlock */
   38.73 - 	list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
   38.74 -diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
   38.75 -index 6711eb6..8d2351f 100644
   38.76 ---- a/drivers/media/dvb/dvb-core/dvb_net.c
   38.77 -+++ b/drivers/media/dvb/dvb-core/dvb_net.c
   38.78 -@@ -1052,7 +1052,7 @@ static void wq_set_multicast_list (void 
   38.79 - 
   38.80 - 	dvb_net_feed_stop(dev);
   38.81 - 	priv->rx_mode = RX_MODE_UNI;
   38.82 --	spin_lock_bh(&dev->xmit_lock);
   38.83 -+	netif_tx_lock_bh(dev);
   38.84 - 
   38.85 - 	if (dev->flags & IFF_PROMISC) {
   38.86 - 		dprintk("%s: promiscuous mode\n", dev->name);
   38.87 -@@ -1077,7 +1077,7 @@ static void wq_set_multicast_list (void 
   38.88 - 		}
   38.89 - 	}
   38.90 - 
   38.91 --	spin_unlock_bh(&dev->xmit_lock);
   38.92 -+	netif_tx_unlock_bh(dev);
   38.93 - 	dvb_net_feed_start(dev);
   38.94 - }
   38.95 - 
   38.96 -diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
   38.97 -index dd41049..6615583 100644
   38.98 ---- a/drivers/net/8139cp.c
   38.99 -+++ b/drivers/net/8139cp.c
  38.100 -@@ -794,7 +794,7 @@ #endif
  38.101 - 	entry = cp->tx_head;
  38.102 - 	eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
  38.103 - 	if (dev->features & NETIF_F_TSO)
  38.104 --		mss = skb_shinfo(skb)->tso_size;
  38.105 -+		mss = skb_shinfo(skb)->gso_size;
  38.106 - 
  38.107 - 	if (skb_shinfo(skb)->nr_frags == 0) {
  38.108 - 		struct cp_desc *txd = &cp->tx_ring[entry];
  38.109 -diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
  38.110 -index a24200d..b5e39a1 100644
  38.111 ---- a/drivers/net/bnx2.c
  38.112 -+++ b/drivers/net/bnx2.c
  38.113 -@@ -1593,7 +1593,7 @@ bnx2_tx_int(struct bnx2 *bp)
  38.114 - 		skb = tx_buf->skb;
  38.115 - #ifdef BCM_TSO 
  38.116 - 		/* partial BD completions possible with TSO packets */
  38.117 --		if (skb_shinfo(skb)->tso_size) {
  38.118 -+		if (skb_shinfo(skb)->gso_size) {
  38.119 - 			u16 last_idx, last_ring_idx;
  38.120 - 
  38.121 - 			last_idx = sw_cons +
  38.122 -@@ -1948,7 +1948,7 @@ bnx2_poll(struct net_device *dev, int *b
  38.123 - 	return 1;
  38.124 - }
  38.125 - 
  38.126 --/* Called with rtnl_lock from vlan functions and also dev->xmit_lock
  38.127 -+/* Called with rtnl_lock from vlan functions and also netif_tx_lock
  38.128 -  * from set_multicast.
  38.129 -  */
  38.130 - static void
  38.131 -@@ -4403,7 +4403,7 @@ bnx2_vlan_rx_kill_vid(struct net_device 
  38.132 - }
  38.133 - #endif
  38.134 - 
  38.135 --/* Called with dev->xmit_lock.
  38.136 -+/* Called with netif_tx_lock.
  38.137 -  * hard_start_xmit is pseudo-lockless - a lock is only required when
  38.138 -  * the tx queue is full. This way, we get the benefit of lockless
  38.139 -  * operations most of the time without the complexities to handle
  38.140 -@@ -4441,7 +4441,7 @@ bnx2_start_xmit(struct sk_buff *skb, str
  38.141 - 			(TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
  38.142 - 	}
  38.143 - #ifdef BCM_TSO 
  38.144 --	if ((mss = skb_shinfo(skb)->tso_size) &&
  38.145 -+	if ((mss = skb_shinfo(skb)->gso_size) &&
  38.146 - 		(skb->len > (bp->dev->mtu + ETH_HLEN))) {
  38.147 - 		u32 tcp_opt_len, ip_tcp_len;
  38.148 - 
  38.149 -diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
  38.150 -index bcf9f17..e970921 100644
  38.151 ---- a/drivers/net/bonding/bond_main.c
  38.152 -+++ b/drivers/net/bonding/bond_main.c
  38.153 -@@ -1145,8 +1145,7 @@ int bond_sethwaddr(struct net_device *bo
  38.154 - }
  38.155 - 
  38.156 - #define BOND_INTERSECT_FEATURES \
  38.157 --	(NETIF_F_SG|NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM|\
  38.158 --	NETIF_F_TSO|NETIF_F_UFO)
  38.159 -+	(NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_TSO | NETIF_F_UFO)
  38.160 - 
  38.161 - /* 
  38.162 -  * Compute the common dev->feature set available to all slaves.  Some
  38.163 -@@ -1164,9 +1163,7 @@ static int bond_compute_features(struct 
  38.164 - 		features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
  38.165 - 
  38.166 - 	if ((features & NETIF_F_SG) && 
  38.167 --	    !(features & (NETIF_F_IP_CSUM |
  38.168 --			  NETIF_F_NO_CSUM |
  38.169 --			  NETIF_F_HW_CSUM)))
  38.170 -+	    !(features & NETIF_F_ALL_CSUM))
  38.171 - 		features &= ~NETIF_F_SG;
  38.172 - 
  38.173 - 	/* 
  38.174 -@@ -4147,7 +4144,7 @@ static int bond_init(struct net_device *
  38.175 - 	 */
  38.176 - 	bond_dev->features |= NETIF_F_VLAN_CHALLENGED;
  38.177 - 
  38.178 --	/* don't acquire bond device's xmit_lock when 
  38.179 -+	/* don't acquire bond device's netif_tx_lock when
  38.180 - 	 * transmitting */
  38.181 - 	bond_dev->features |= NETIF_F_LLTX;
  38.182 - 
  38.183 -diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
  38.184 -index 30ff8ea..7b7d360 100644
  38.185 ---- a/drivers/net/chelsio/sge.c
  38.186 -+++ b/drivers/net/chelsio/sge.c
  38.187 -@@ -1419,7 +1419,7 @@ int t1_start_xmit(struct sk_buff *skb, s
  38.188 - 	struct cpl_tx_pkt *cpl;
  38.189 - 
  38.190 - #ifdef NETIF_F_TSO
  38.191 --	if (skb_shinfo(skb)->tso_size) {
  38.192 -+	if (skb_shinfo(skb)->gso_size) {
  38.193 - 		int eth_type;
  38.194 - 		struct cpl_tx_pkt_lso *hdr;
  38.195 - 
  38.196 -@@ -1434,7 +1434,7 @@ #ifdef NETIF_F_TSO
  38.197 - 		hdr->ip_hdr_words = skb->nh.iph->ihl;
  38.198 - 		hdr->tcp_hdr_words = skb->h.th->doff;
  38.199 - 		hdr->eth_type_mss = htons(MK_ETH_TYPE_MSS(eth_type,
  38.200 --						skb_shinfo(skb)->tso_size));
  38.201 -+						skb_shinfo(skb)->gso_size));
  38.202 - 		hdr->len = htonl(skb->len - sizeof(*hdr));
  38.203 - 		cpl = (struct cpl_tx_pkt *)hdr;
  38.204 - 		sge->stats.tx_lso_pkts++;
  38.205 -diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
  38.206 -index fa29402..681d284 100644
  38.207 ---- a/drivers/net/e1000/e1000_main.c
  38.208 -+++ b/drivers/net/e1000/e1000_main.c
  38.209 -@@ -2526,7 +2526,7 @@ #ifdef NETIF_F_TSO
  38.210 - 	uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
  38.211 - 	int err;
  38.212 - 
  38.213 --	if (skb_shinfo(skb)->tso_size) {
  38.214 -+	if (skb_shinfo(skb)->gso_size) {
  38.215 - 		if (skb_header_cloned(skb)) {
  38.216 - 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
  38.217 - 			if (err)
  38.218 -@@ -2534,7 +2534,7 @@ #ifdef NETIF_F_TSO
  38.219 - 		}
  38.220 - 
  38.221 - 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
  38.222 --		mss = skb_shinfo(skb)->tso_size;
  38.223 -+		mss = skb_shinfo(skb)->gso_size;
  38.224 - 		if (skb->protocol == ntohs(ETH_P_IP)) {
  38.225 - 			skb->nh.iph->tot_len = 0;
  38.226 - 			skb->nh.iph->check = 0;
  38.227 -@@ -2651,7 +2651,7 @@ #ifdef NETIF_F_TSO
  38.228 - 		 * tso gets written back prematurely before the data is fully
  38.229 - 		 * DMAd to the controller */
  38.230 - 		if (!skb->data_len && tx_ring->last_tx_tso &&
  38.231 --				!skb_shinfo(skb)->tso_size) {
  38.232 -+				!skb_shinfo(skb)->gso_size) {
  38.233 - 			tx_ring->last_tx_tso = 0;
  38.234 - 			size -= 4;
  38.235 - 		}
  38.236 -@@ -2893,7 +2893,7 @@ #endif
  38.237 - 	}
  38.238 - 
  38.239 - #ifdef NETIF_F_TSO
  38.240 --	mss = skb_shinfo(skb)->tso_size;
  38.241 -+	mss = skb_shinfo(skb)->gso_size;
  38.242 - 	/* The controller does a simple calculation to 
  38.243 - 	 * make sure there is enough room in the FIFO before
  38.244 - 	 * initiating the DMA for each buffer.  The calc is:
  38.245 -@@ -2935,7 +2935,7 @@ #endif
  38.246 - #ifdef NETIF_F_TSO
  38.247 - 	/* Controller Erratum workaround */
  38.248 - 	if (!skb->data_len && tx_ring->last_tx_tso &&
  38.249 --		!skb_shinfo(skb)->tso_size)
  38.250 -+		!skb_shinfo(skb)->gso_size)
  38.251 - 		count++;
  38.252 - #endif
  38.253 - 
  38.254 -diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
  38.255 -index 3682ec6..c35f16e 100644
  38.256 ---- a/drivers/net/forcedeth.c
  38.257 -+++ b/drivers/net/forcedeth.c
  38.258 -@@ -482,9 +482,9 @@ #define LPA_1000HALF	0x0400
  38.259 -  * critical parts:
  38.260 -  * - rx is (pseudo-) lockless: it relies on the single-threading provided
  38.261 -  *	by the arch code for interrupts.
  38.262 -- * - tx setup is lockless: it relies on dev->xmit_lock. Actual submission
  38.263 -+ * - tx setup is lockless: it relies on netif_tx_lock. Actual submission
  38.264 -  *	needs dev->priv->lock :-(
  38.265 -- * - set_multicast_list: preparation lockless, relies on dev->xmit_lock.
  38.266 -+ * - set_multicast_list: preparation lockless, relies on netif_tx_lock.
  38.267 -  */
  38.268 - 
  38.269 - /* in dev: base, irq */
  38.270 -@@ -1016,7 +1016,7 @@ static void drain_ring(struct net_device
  38.271 - 
  38.272 - /*
  38.273 -  * nv_start_xmit: dev->hard_start_xmit function
  38.274 -- * Called with dev->xmit_lock held.
  38.275 -+ * Called with netif_tx_lock held.
  38.276 -  */
  38.277 - static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
  38.278 - {
  38.279 -@@ -1105,8 +1105,8 @@ static int nv_start_xmit(struct sk_buff 
  38.280 - 	np->tx_skbuff[nr] = skb;
  38.281 - 
  38.282 - #ifdef NETIF_F_TSO
  38.283 --	if (skb_shinfo(skb)->tso_size)
  38.284 --		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT);
  38.285 -+	if (skb_shinfo(skb)->gso_size)
  38.286 -+		tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
  38.287 - 	else
  38.288 - #endif
  38.289 - 	tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0);
  38.290 -@@ -1203,7 +1203,7 @@ static void nv_tx_done(struct net_device
  38.291 - 
  38.292 - /*
  38.293 -  * nv_tx_timeout: dev->tx_timeout function
  38.294 -- * Called with dev->xmit_lock held.
  38.295 -+ * Called with netif_tx_lock held.
  38.296 -  */
  38.297 - static void nv_tx_timeout(struct net_device *dev)
  38.298 - {
  38.299 -@@ -1524,7 +1524,7 @@ static int nv_change_mtu(struct net_devi
  38.300 - 		 * Changing the MTU is a rare event, it shouldn't matter.
  38.301 - 		 */
  38.302 - 		disable_irq(dev->irq);
  38.303 --		spin_lock_bh(&dev->xmit_lock);
  38.304 -+		netif_tx_lock_bh(dev);
  38.305 - 		spin_lock(&np->lock);
  38.306 - 		/* stop engines */
  38.307 - 		nv_stop_rx(dev);
  38.308 -@@ -1559,7 +1559,7 @@ static int nv_change_mtu(struct net_devi
  38.309 - 		nv_start_rx(dev);
  38.310 - 		nv_start_tx(dev);
  38.311 - 		spin_unlock(&np->lock);
  38.312 --		spin_unlock_bh(&dev->xmit_lock);
  38.313 -+		netif_tx_unlock_bh(dev);
  38.314 - 		enable_irq(dev->irq);
  38.315 - 	}
  38.316 - 	return 0;
  38.317 -@@ -1594,7 +1594,7 @@ static int nv_set_mac_address(struct net
  38.318 - 	memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN);
  38.319 - 
  38.320 - 	if (netif_running(dev)) {
  38.321 --		spin_lock_bh(&dev->xmit_lock);
  38.322 -+		netif_tx_lock_bh(dev);
  38.323 - 		spin_lock_irq(&np->lock);
  38.324 - 
  38.325 - 		/* stop rx engine */
  38.326 -@@ -1606,7 +1606,7 @@ static int nv_set_mac_address(struct net
  38.327 - 		/* restart rx engine */
  38.328 - 		nv_start_rx(dev);
  38.329 - 		spin_unlock_irq(&np->lock);
  38.330 --		spin_unlock_bh(&dev->xmit_lock);
  38.331 -+		netif_tx_unlock_bh(dev);
  38.332 - 	} else {
  38.333 - 		nv_copy_mac_to_hw(dev);
  38.334 - 	}
  38.335 -@@ -1615,7 +1615,7 @@ static int nv_set_mac_address(struct net
  38.336 - 
  38.337 - /*
  38.338 -  * nv_set_multicast: dev->set_multicast function
  38.339 -- * Called with dev->xmit_lock held.
  38.340 -+ * Called with netif_tx_lock held.
  38.341 -  */
  38.342 - static void nv_set_multicast(struct net_device *dev)
  38.343 - {
  38.344 -diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
  38.345 -index 102c1f0..d12605f 100644
  38.346 ---- a/drivers/net/hamradio/6pack.c
  38.347 -+++ b/drivers/net/hamradio/6pack.c
  38.348 -@@ -308,9 +308,9 @@ static int sp_set_mac_address(struct net
  38.349 - {
  38.350 - 	struct sockaddr_ax25 *sa = addr;
  38.351 - 
  38.352 --	spin_lock_irq(&dev->xmit_lock);
  38.353 -+	netif_tx_lock_bh(dev);
  38.354 - 	memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
  38.355 --	spin_unlock_irq(&dev->xmit_lock);
  38.356 -+	netif_tx_unlock_bh(dev);
  38.357 - 
  38.358 - 	return 0;
  38.359 - }
  38.360 -@@ -767,9 +767,9 @@ static int sixpack_ioctl(struct tty_stru
  38.361 - 			break;
  38.362 - 		}
  38.363 - 
  38.364 --		spin_lock_irq(&dev->xmit_lock);
  38.365 -+		netif_tx_lock_bh(dev);
  38.366 - 		memcpy(dev->dev_addr, &addr, AX25_ADDR_LEN);
  38.367 --		spin_unlock_irq(&dev->xmit_lock);
  38.368 -+		netif_tx_unlock_bh(dev);
  38.369 - 
  38.370 - 		err = 0;
  38.371 - 		break;
  38.372 -diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
  38.373 -index dc5e9d5..5c66f5a 100644
  38.374 ---- a/drivers/net/hamradio/mkiss.c
  38.375 -+++ b/drivers/net/hamradio/mkiss.c
  38.376 -@@ -357,9 +357,9 @@ static int ax_set_mac_address(struct net
  38.377 - {
  38.378 - 	struct sockaddr_ax25 *sa = addr;
  38.379 - 
  38.380 --	spin_lock_irq(&dev->xmit_lock);
  38.381 -+	netif_tx_lock_bh(dev);
  38.382 - 	memcpy(dev->dev_addr, &sa->sax25_call, AX25_ADDR_LEN);
  38.383 --	spin_unlock_irq(&dev->xmit_lock);
  38.384 -+	netif_tx_unlock_bh(dev);
  38.385 - 
  38.386 - 	return 0;
  38.387 - }
  38.388 -@@ -886,9 +886,9 @@ static int mkiss_ioctl(struct tty_struct
  38.389 - 			break;
  38.390 - 		}
  38.391 - 
  38.392 --		spin_lock_irq(&dev->xmit_lock);
  38.393 -+		netif_tx_lock_bh(dev);
  38.394 - 		memcpy(dev->dev_addr, addr, AX25_ADDR_LEN);
  38.395 --		spin_unlock_irq(&dev->xmit_lock);
  38.396 -+		netif_tx_unlock_bh(dev);
  38.397 - 
  38.398 - 		err = 0;
  38.399 - 		break;
  38.400 -diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
  38.401 -index 31fb2d7..2e222ef 100644
  38.402 ---- a/drivers/net/ifb.c
  38.403 -+++ b/drivers/net/ifb.c
  38.404 -@@ -76,13 +76,13 @@ static void ri_tasklet(unsigned long dev
  38.405 - 	dp->st_task_enter++;
  38.406 - 	if ((skb = skb_peek(&dp->tq)) == NULL) {
  38.407 - 		dp->st_txq_refl_try++;
  38.408 --		if (spin_trylock(&_dev->xmit_lock)) {
  38.409 -+		if (netif_tx_trylock(_dev)) {
  38.410 - 			dp->st_rxq_enter++;
  38.411 - 			while ((skb = skb_dequeue(&dp->rq)) != NULL) {
  38.412 - 				skb_queue_tail(&dp->tq, skb);
  38.413 - 				dp->st_rx2tx_tran++;
  38.414 - 			}
  38.415 --			spin_unlock(&_dev->xmit_lock);
  38.416 -+			netif_tx_unlock(_dev);
  38.417 - 		} else {
  38.418 - 			/* reschedule */
  38.419 - 			dp->st_rxq_notenter++;
  38.420 -@@ -110,7 +110,7 @@ static void ri_tasklet(unsigned long dev
  38.421 - 		}
  38.422 - 	}
  38.423 - 
  38.424 --	if (spin_trylock(&_dev->xmit_lock)) {
  38.425 -+	if (netif_tx_trylock(_dev)) {
  38.426 - 		dp->st_rxq_check++;
  38.427 - 		if ((skb = skb_peek(&dp->rq)) == NULL) {
  38.428 - 			dp->tasklet_pending = 0;
  38.429 -@@ -118,10 +118,10 @@ static void ri_tasklet(unsigned long dev
  38.430 - 				netif_wake_queue(_dev);
  38.431 - 		} else {
  38.432 - 			dp->st_rxq_rsch++;
  38.433 --			spin_unlock(&_dev->xmit_lock);
  38.434 -+			netif_tx_unlock(_dev);
  38.435 - 			goto resched;
  38.436 - 		}
  38.437 --		spin_unlock(&_dev->xmit_lock);
  38.438 -+		netif_tx_unlock(_dev);
  38.439 - 	} else {
  38.440 - resched:
  38.441 - 		dp->tasklet_pending = 1;
  38.442 -diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
  38.443 -index a9f49f0..339d4a7 100644
  38.444 ---- a/drivers/net/irda/vlsi_ir.c
  38.445 -+++ b/drivers/net/irda/vlsi_ir.c
  38.446 -@@ -959,7 +959,7 @@ static int vlsi_hard_start_xmit(struct s
  38.447 - 			    ||  (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
  38.448 - 			    	break;
  38.449 - 			udelay(100);
  38.450 --			/* must not sleep here - we are called under xmit_lock! */
  38.451 -+			/* must not sleep here - called under netif_tx_lock! */
  38.452 - 		}
  38.453 - 	}
  38.454 - 
  38.455 -diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
  38.456 -index f9f77e4..bdab369 100644
  38.457 ---- a/drivers/net/ixgb/ixgb_main.c
  38.458 -+++ b/drivers/net/ixgb/ixgb_main.c
  38.459 -@@ -1163,7 +1163,7 @@ #ifdef NETIF_F_TSO
  38.460 - 	uint16_t ipcse, tucse, mss;
  38.461 - 	int err;
  38.462 - 
  38.463 --	if(likely(skb_shinfo(skb)->tso_size)) {
  38.464 -+	if(likely(skb_shinfo(skb)->gso_size)) {
  38.465 - 		if (skb_header_cloned(skb)) {
  38.466 - 			err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
  38.467 - 			if (err)
  38.468 -@@ -1171,7 +1171,7 @@ #ifdef NETIF_F_TSO
  38.469 - 		}
  38.470 - 
  38.471 - 		hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2));
  38.472 --		mss = skb_shinfo(skb)->tso_size;
  38.473 -+		mss = skb_shinfo(skb)->gso_size;
  38.474 - 		skb->nh.iph->tot_len = 0;
  38.475 - 		skb->nh.iph->check = 0;
  38.476 - 		skb->h.th->check = ~csum_tcpudp_magic(skb->nh.iph->saddr,
  38.477 -diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
  38.478 -index 690a1aa..9bcaa80 100644
  38.479 ---- a/drivers/net/loopback.c
  38.480 -+++ b/drivers/net/loopback.c
  38.481 -@@ -74,7 +74,7 @@ static void emulate_large_send_offload(s
  38.482 - 	struct iphdr *iph = skb->nh.iph;
  38.483 - 	struct tcphdr *th = (struct tcphdr*)(skb->nh.raw + (iph->ihl * 4));
  38.484 - 	unsigned int doffset = (iph->ihl + th->doff) * 4;
  38.485 --	unsigned int mtu = skb_shinfo(skb)->tso_size + doffset;
  38.486 -+	unsigned int mtu = skb_shinfo(skb)->gso_size + doffset;
  38.487 - 	unsigned int offset = 0;
  38.488 - 	u32 seq = ntohl(th->seq);
  38.489 - 	u16 id  = ntohs(iph->id);
  38.490 -@@ -139,7 +139,7 @@ #ifndef LOOPBACK_MUST_CHECKSUM
  38.491 - #endif
  38.492 - 
  38.493 - #ifdef LOOPBACK_TSO
  38.494 --	if (skb_shinfo(skb)->tso_size) {
  38.495 -+	if (skb_shinfo(skb)->gso_size) {
  38.496 - 		BUG_ON(skb->protocol != htons(ETH_P_IP));
  38.497 - 		BUG_ON(skb->nh.iph->protocol != IPPROTO_TCP);
  38.498 - 
  38.499 -diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
  38.500 -index c0998ef..0fac9d5 100644
  38.501 ---- a/drivers/net/mv643xx_eth.c
  38.502 -+++ b/drivers/net/mv643xx_eth.c
  38.503 -@@ -1107,7 +1107,7 @@ static int mv643xx_eth_start_xmit(struct
  38.504 - 
  38.505 - #ifdef MV643XX_CHECKSUM_OFFLOAD_TX
  38.506 - 	if (has_tiny_unaligned_frags(skb)) {
  38.507 --		if ((skb_linearize(skb, GFP_ATOMIC) != 0)) {
  38.508 -+		if (__skb_linearize(skb)) {
  38.509 - 			stats->tx_dropped++;
  38.510 - 			printk(KERN_DEBUG "%s: failed to linearize tiny "
  38.511 - 					"unaligned fragment\n", dev->name);
  38.512 -diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
  38.513 -index 9d6d254..c9ed624 100644
  38.514 ---- a/drivers/net/natsemi.c
  38.515 -+++ b/drivers/net/natsemi.c
  38.516 -@@ -323,12 +323,12 @@ performance critical codepaths:
  38.517 - The rx process only runs in the interrupt handler. Access from outside
  38.518 - the interrupt handler is only permitted after disable_irq().
  38.519 - 
  38.520 --The rx process usually runs under the dev->xmit_lock. If np->intr_tx_reap
  38.521 -+The rx process usually runs under the netif_tx_lock. If np->intr_tx_reap
  38.522 - is set, then access is permitted under spin_lock_irq(&np->lock).
  38.523 - 
  38.524 - Thus configuration functions that want to access everything must call
  38.525 - 	disable_irq(dev->irq);
  38.526 --	spin_lock_bh(dev->xmit_lock);
  38.527 -+	netif_tx_lock_bh(dev);
  38.528 - 	spin_lock_irq(&np->lock);
  38.529 - 
  38.530 - IV. Notes
  38.531 -diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
  38.532 -index 8cc0d0b..e53b313 100644
  38.533 ---- a/drivers/net/r8169.c
  38.534 -+++ b/drivers/net/r8169.c
  38.535 -@@ -2171,7 +2171,7 @@ static int rtl8169_xmit_frags(struct rtl
  38.536 - static inline u32 rtl8169_tso_csum(struct sk_buff *skb, struct net_device *dev)
  38.537 - {
  38.538 - 	if (dev->features & NETIF_F_TSO) {
  38.539 --		u32 mss = skb_shinfo(skb)->tso_size;
  38.540 -+		u32 mss = skb_shinfo(skb)->gso_size;
  38.541 - 
  38.542 - 		if (mss)
  38.543 - 			return LargeSend | ((mss & MSSMask) << MSSShift);
  38.544 -diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
  38.545 -index b7f00d6..439f45f 100644
  38.546 ---- a/drivers/net/s2io.c
  38.547 -+++ b/drivers/net/s2io.c
  38.548 -@@ -3522,8 +3522,8 @@ #endif
  38.549 - 	txdp->Control_1 = 0;
  38.550 - 	txdp->Control_2 = 0;
  38.551 - #ifdef NETIF_F_TSO
  38.552 --	mss = skb_shinfo(skb)->tso_size;
  38.553 --	if (mss) {
  38.554 -+	mss = skb_shinfo(skb)->gso_size;
  38.555 -+	if (skb_shinfo(skb)->gso_type == SKB_GSO_TCPV4) {
  38.556 - 		txdp->Control_1 |= TXD_TCP_LSO_EN;
  38.557 - 		txdp->Control_1 |= TXD_TCP_LSO_MSS(mss);
  38.558 - 	}
  38.559 -@@ -3543,10 +3543,10 @@ #endif
  38.560 - 	}
  38.561 - 
  38.562 - 	frg_len = skb->len - skb->data_len;
  38.563 --	if (skb_shinfo(skb)->ufo_size) {
  38.564 -+	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4) {
  38.565 - 		int ufo_size;
  38.566 - 
  38.567 --		ufo_size = skb_shinfo(skb)->ufo_size;
  38.568 -+		ufo_size = skb_shinfo(skb)->gso_size;
  38.569 - 		ufo_size &= ~7;
  38.570 - 		txdp->Control_1 |= TXD_UFO_EN;
  38.571 - 		txdp->Control_1 |= TXD_UFO_MSS(ufo_size);
  38.572 -@@ -3572,7 +3572,7 @@ #endif
  38.573 - 	txdp->Host_Control = (unsigned long) skb;
  38.574 - 	txdp->Control_1 |= TXD_BUFFER0_SIZE(frg_len);
  38.575 - 
  38.576 --	if (skb_shinfo(skb)->ufo_size)
  38.577 -+	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  38.578 - 		txdp->Control_1 |= TXD_UFO_EN;
  38.579 - 
  38.580 - 	frg_cnt = skb_shinfo(skb)->nr_frags;
  38.581 -@@ -3587,12 +3587,12 @@ #endif
  38.582 - 		    (sp->pdev, frag->page, frag->page_offset,
  38.583 - 		     frag->size, PCI_DMA_TODEVICE);
  38.584 - 		txdp->Control_1 = TXD_BUFFER0_SIZE(frag->size);
  38.585 --		if (skb_shinfo(skb)->ufo_size)
  38.586 -+		if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  38.587 - 			txdp->Control_1 |= TXD_UFO_EN;
  38.588 - 	}
  38.589 - 	txdp->Control_1 |= TXD_GATHER_CODE_LAST;
  38.590 - 
  38.591 --	if (skb_shinfo(skb)->ufo_size)
  38.592 -+	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  38.593 - 		frg_cnt++; /* as Txd0 was used for inband header */
  38.594 - 
  38.595 - 	tx_fifo = mac_control->tx_FIFO_start[queue];
  38.596 -@@ -3606,7 +3606,7 @@ #ifdef NETIF_F_TSO
  38.597 - 	if (mss)
  38.598 - 		val64 |= TX_FIFO_SPECIAL_FUNC;
  38.599 - #endif
  38.600 --	if (skb_shinfo(skb)->ufo_size)
  38.601 -+	if (skb_shinfo(skb)->gso_type == SKB_GSO_UDPV4)
  38.602 - 		val64 |= TX_FIFO_SPECIAL_FUNC;
  38.603 - 	writeq(val64, &tx_fifo->List_Control);
  38.604 - 
  38.605 -diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
  38.606 -index 0618cd5..2a55eb3 100644
  38.607 ---- a/drivers/net/sky2.c
  38.608 -+++ b/drivers/net/sky2.c
  38.609 -@@ -1125,7 +1125,7 @@ static unsigned tx_le_req(const struct s
  38.610 - 	count = sizeof(dma_addr_t) / sizeof(u32);
  38.611 - 	count += skb_shinfo(skb)->nr_frags * count;
  38.612 - 
  38.613 --	if (skb_shinfo(skb)->tso_size)
  38.614 -+	if (skb_shinfo(skb)->gso_size)
  38.615 - 		++count;
  38.616 - 
  38.617 - 	if (skb->ip_summed == CHECKSUM_HW)
  38.618 -@@ -1197,7 +1197,7 @@ static int sky2_xmit_frame(struct sk_buf
  38.619 - 	}
  38.620 - 
  38.621 - 	/* Check for TCP Segmentation Offload */
  38.622 --	mss = skb_shinfo(skb)->tso_size;
  38.623 -+	mss = skb_shinfo(skb)->gso_size;
  38.624 - 	if (mss != 0) {
  38.625 - 		/* just drop the packet if non-linear expansion fails */
  38.626 - 		if (skb_header_cloned(skb) &&
  38.627 -diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
  38.628 -index caf4102..fc9164a 100644
  38.629 ---- a/drivers/net/tg3.c
  38.630 -+++ b/drivers/net/tg3.c
  38.631 -@@ -3664,7 +3664,7 @@ static int tg3_start_xmit(struct sk_buff
  38.632 - #if TG3_TSO_SUPPORT != 0
  38.633 - 	mss = 0;
  38.634 - 	if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
  38.635 --	    (mss = skb_shinfo(skb)->tso_size) != 0) {
  38.636 -+	    (mss = skb_shinfo(skb)->gso_size) != 0) {
  38.637 - 		int tcp_opt_len, ip_tcp_len;
  38.638 - 
  38.639 - 		if (skb_header_cloned(skb) &&
  38.640 -diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
  38.641 -index 5b1af39..11de5af 100644
  38.642 ---- a/drivers/net/tulip/winbond-840.c
  38.643 -+++ b/drivers/net/tulip/winbond-840.c
  38.644 -@@ -1605,11 +1605,11 @@ #ifdef CONFIG_PM
  38.645 -  * - get_stats:
  38.646 -  * 	spin_lock_irq(np->lock), doesn't touch hw if not present
  38.647 -  * - hard_start_xmit:
  38.648 -- * 	netif_stop_queue + spin_unlock_wait(&dev->xmit_lock);
  38.649 -+ * 	synchronize_irq + netif_tx_disable;
  38.650 -  * - tx_timeout:
  38.651 -- * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
  38.652 -+ * 	netif_device_detach + netif_tx_disable;
  38.653 -  * - set_multicast_list
  38.654 -- * 	netif_device_detach + spin_unlock_wait(&dev->xmit_lock);
  38.655 -+ * 	netif_device_detach + netif_tx_disable;
  38.656 -  * - interrupt handler
  38.657 -  * 	doesn't touch hw if not present, synchronize_irq waits for
  38.658 -  * 	running instances of the interrupt handler.
  38.659 -@@ -1635,11 +1635,10 @@ static int w840_suspend (struct pci_dev 
  38.660 - 		netif_device_detach(dev);
  38.661 - 		update_csr6(dev, 0);
  38.662 - 		iowrite32(0, ioaddr + IntrEnable);
  38.663 --		netif_stop_queue(dev);
  38.664 - 		spin_unlock_irq(&np->lock);
  38.665 - 
  38.666 --		spin_unlock_wait(&dev->xmit_lock);
  38.667 - 		synchronize_irq(dev->irq);
  38.668 -+		netif_tx_disable(dev);
  38.669 - 	
  38.670 - 		np->stats.rx_missed_errors += ioread32(ioaddr + RxMissed) & 0xffff;
  38.671 - 
  38.672 -diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
  38.673 -index 4c76cb7..30c48c9 100644
  38.674 ---- a/drivers/net/typhoon.c
  38.675 -+++ b/drivers/net/typhoon.c
  38.676 -@@ -340,7 +340,7 @@ #define typhoon_synchronize_irq(x) synch
  38.677 - #endif
  38.678 - 
  38.679 - #if defined(NETIF_F_TSO)
  38.680 --#define skb_tso_size(x)		(skb_shinfo(x)->tso_size)
  38.681 -+#define skb_tso_size(x)		(skb_shinfo(x)->gso_size)
  38.682 - #define TSO_NUM_DESCRIPTORS	2
  38.683 - #define TSO_OFFLOAD_ON		TYPHOON_OFFLOAD_TCP_SEGMENT
  38.684 - #else
  38.685 -diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
  38.686 -index ed1f837..2eb6b5f 100644
  38.687 ---- a/drivers/net/via-velocity.c
  38.688 -+++ b/drivers/net/via-velocity.c
  38.689 -@@ -1899,6 +1899,13 @@ static int velocity_xmit(struct sk_buff 
  38.690 - 
  38.691 - 	int pktlen = skb->len;
  38.692 - 
  38.693 -+#ifdef VELOCITY_ZERO_COPY_SUPPORT
  38.694 -+	if (skb_shinfo(skb)->nr_frags > 6 && __skb_linearize(skb)) {
  38.695 -+		kfree_skb(skb);
  38.696 -+		return 0;
  38.697 -+	}
  38.698 -+#endif
  38.699 -+
  38.700 - 	spin_lock_irqsave(&vptr->lock, flags);
  38.701 - 
  38.702 - 	index = vptr->td_curr[qnum];
  38.703 -@@ -1914,8 +1921,6 @@ static int velocity_xmit(struct sk_buff 
  38.704 - 	 */
  38.705 - 	if (pktlen < ETH_ZLEN) {
  38.706 - 		/* Cannot occur until ZC support */
  38.707 --		if(skb_linearize(skb, GFP_ATOMIC))
  38.708 --			return 0; 
  38.709 - 		pktlen = ETH_ZLEN;
  38.710 - 		memcpy(tdinfo->buf, skb->data, skb->len);
  38.711 - 		memset(tdinfo->buf + skb->len, 0, ETH_ZLEN - skb->len);
  38.712 -@@ -1933,7 +1938,6 @@ #ifdef VELOCITY_ZERO_COPY_SUPPORT
  38.713 - 		int nfrags = skb_shinfo(skb)->nr_frags;
  38.714 - 		tdinfo->skb = skb;
  38.715 - 		if (nfrags > 6) {
  38.716 --			skb_linearize(skb, GFP_ATOMIC);
  38.717 - 			memcpy(tdinfo->buf, skb->data, skb->len);
  38.718 - 			tdinfo->skb_dma[0] = tdinfo->buf_dma;
  38.719 - 			td_ptr->tdesc0.pktsize = 
  38.720 -diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
  38.721 -index 6fd0bf7..75237c1 100644
  38.722 ---- a/drivers/net/wireless/orinoco.c
  38.723 -+++ b/drivers/net/wireless/orinoco.c
  38.724 -@@ -1835,7 +1835,9 @@ static int __orinoco_program_rids(struct
  38.725 - 	/* Set promiscuity / multicast*/
  38.726 - 	priv->promiscuous = 0;
  38.727 - 	priv->mc_count = 0;
  38.728 --	__orinoco_set_multicast_list(dev); /* FIXME: what about the xmit_lock */
  38.729 -+
  38.730 -+	/* FIXME: what about netif_tx_lock */
  38.731 -+	__orinoco_set_multicast_list(dev);
  38.732 - 
  38.733 - 	return 0;
  38.734 - }
  38.735 -diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c
  38.736 -index 82cb4af..57cec40 100644
  38.737 ---- a/drivers/s390/net/qeth_eddp.c
  38.738 -+++ b/drivers/s390/net/qeth_eddp.c
  38.739 -@@ -421,7 +421,7 @@ #endif /* CONFIG_QETH_VLAN */
  38.740 -        }
  38.741 - 	tcph = eddp->skb->h.th;
  38.742 - 	while (eddp->skb_offset < eddp->skb->len) {
  38.743 --		data_len = min((int)skb_shinfo(eddp->skb)->tso_size,
  38.744 -+		data_len = min((int)skb_shinfo(eddp->skb)->gso_size,
  38.745 - 			       (int)(eddp->skb->len - eddp->skb_offset));
  38.746 - 		/* prepare qdio hdr */
  38.747 - 		if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){
  38.748 -@@ -516,20 +516,20 @@ qeth_eddp_calc_num_pages(struct qeth_edd
  38.749 - 	
  38.750 - 	QETH_DBF_TEXT(trace, 5, "eddpcanp");
  38.751 - 	/* can we put multiple skbs in one page? */
  38.752 --	skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);
  38.753 -+	skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->gso_size + hdr_len);
  38.754 - 	if (skbs_per_page > 1){
  38.755 --		ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /
  38.756 -+		ctx->num_pages = (skb_shinfo(skb)->gso_segs + 1) /
  38.757 - 				 skbs_per_page + 1;
  38.758 - 		ctx->elements_per_skb = 1;
  38.759 - 	} else {
  38.760 - 		/* no -> how many elements per skb? */
  38.761 --		ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +
  38.762 -+		ctx->elements_per_skb = (skb_shinfo(skb)->gso_size + hdr_len +
  38.763 - 				     PAGE_SIZE) >> PAGE_SHIFT;
  38.764 - 		ctx->num_pages = ctx->elements_per_skb *
  38.765 --				 (skb_shinfo(skb)->tso_segs + 1);
  38.766 -+				 (skb_shinfo(skb)->gso_segs + 1);
  38.767 - 	}
  38.768 - 	ctx->num_elements = ctx->elements_per_skb *
  38.769 --			    (skb_shinfo(skb)->tso_segs + 1);
  38.770 -+			    (skb_shinfo(skb)->gso_segs + 1);
  38.771 - }
  38.772 - 
  38.773 - static inline struct qeth_eddp_context *
  38.774 -diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
  38.775 -index dba7f7f..d9cc997 100644
  38.776 ---- a/drivers/s390/net/qeth_main.c
  38.777 -+++ b/drivers/s390/net/qeth_main.c
  38.778 -@@ -4454,7 +4454,7 @@ qeth_send_packet(struct qeth_card *card,
  38.779 - 	queue = card->qdio.out_qs
  38.780 - 		[qeth_get_priority_queue(card, skb, ipv, cast_type)];
  38.781 - 
  38.782 --	if (skb_shinfo(skb)->tso_size)
  38.783 -+	if (skb_shinfo(skb)->gso_size)
  38.784 - 		large_send = card->options.large_send;
  38.785 - 
  38.786 - 	/*are we able to do TSO ? If so ,prepare and send it from here */
  38.787 -@@ -4501,7 +4501,7 @@ qeth_send_packet(struct qeth_card *card,
  38.788 - 		card->stats.tx_packets++;
  38.789 - 		card->stats.tx_bytes += skb->len;
  38.790 - #ifdef CONFIG_QETH_PERF_STATS
  38.791 --		if (skb_shinfo(skb)->tso_size &&
  38.792 -+		if (skb_shinfo(skb)->gso_size &&
  38.793 - 		   !(large_send == QETH_LARGE_SEND_NO)) {
  38.794 - 			card->perf_stats.large_send_bytes += skb->len;
  38.795 - 			card->perf_stats.large_send_cnt++;
  38.796 -diff --git a/drivers/s390/net/qeth_tso.h b/drivers/s390/net/qeth_tso.h
  38.797 -index 1286dde..89cbf34 100644
  38.798 ---- a/drivers/s390/net/qeth_tso.h
  38.799 -+++ b/drivers/s390/net/qeth_tso.h
  38.800 -@@ -51,7 +51,7 @@ qeth_tso_fill_header(struct qeth_card *c
  38.801 - 	hdr->ext.hdr_version = 1;
  38.802 - 	hdr->ext.hdr_len     = 28;
  38.803 - 	/*insert non-fix values */
  38.804 --	hdr->ext.mss = skb_shinfo(skb)->tso_size;
  38.805 -+	hdr->ext.mss = skb_shinfo(skb)->gso_size;
  38.806 - 	hdr->ext.dg_hdr_len = (__u16)(iph->ihl*4 + tcph->doff*4);
  38.807 - 	hdr->ext.payload_len = (__u16)(skb->len - hdr->ext.dg_hdr_len -
  38.808 - 				       sizeof(struct qeth_hdr_tso));
  38.809 -diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
  38.810 -index 93535f0..9269df7 100644
  38.811 ---- a/include/linux/ethtool.h
  38.812 -+++ b/include/linux/ethtool.h
  38.813 -@@ -408,6 +408,8 @@ #define ETHTOOL_STSO		0x0000001f /* Set 
  38.814 - #define ETHTOOL_GPERMADDR	0x00000020 /* Get permanent hardware address */
  38.815 - #define ETHTOOL_GUFO		0x00000021 /* Get UFO enable (ethtool_value) */
  38.816 - #define ETHTOOL_SUFO		0x00000022 /* Set UFO enable (ethtool_value) */
  38.817 -+#define ETHTOOL_GGSO		0x00000023 /* Get GSO enable (ethtool_value) */
  38.818 -+#define ETHTOOL_SGSO		0x00000024 /* Set GSO enable (ethtool_value) */
  38.819 - 
  38.820 - /* compatibility with older code */
  38.821 - #define SPARC_ETH_GSET		ETHTOOL_GSET
  38.822 -diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
  38.823 -index 7fda03d..47b0965 100644
  38.824 ---- a/include/linux/netdevice.h
  38.825 -+++ b/include/linux/netdevice.h
  38.826 -@@ -230,7 +230,8 @@ enum netdev_state_t
  38.827 - 	__LINK_STATE_SCHED,
  38.828 - 	__LINK_STATE_NOCARRIER,
  38.829 - 	__LINK_STATE_RX_SCHED,
  38.830 --	__LINK_STATE_LINKWATCH_PENDING
  38.831 -+	__LINK_STATE_LINKWATCH_PENDING,
  38.832 -+	__LINK_STATE_QDISC_RUNNING,
  38.833 - };
  38.834 - 
  38.835 - 
  38.836 -@@ -306,9 +307,17 @@ #define NETIF_F_HW_VLAN_TX	128	/* Transm
  38.837 - #define NETIF_F_HW_VLAN_RX	256	/* Receive VLAN hw acceleration */
  38.838 - #define NETIF_F_HW_VLAN_FILTER	512	/* Receive filtering on VLAN */
  38.839 - #define NETIF_F_VLAN_CHALLENGED	1024	/* Device cannot handle VLAN packets */
  38.840 --#define NETIF_F_TSO		2048	/* Can offload TCP/IP segmentation */
  38.841 -+#define NETIF_F_GSO		2048	/* Enable software GSO. */
  38.842 - #define NETIF_F_LLTX		4096	/* LockLess TX */
  38.843 --#define NETIF_F_UFO             8192    /* Can offload UDP Large Send*/
  38.844 -+
  38.845 -+	/* Segmentation offload features */
  38.846 -+#define NETIF_F_GSO_SHIFT	16
  38.847 -+#define NETIF_F_TSO		(SKB_GSO_TCPV4 << NETIF_F_GSO_SHIFT)
  38.848 -+#define NETIF_F_UFO		(SKB_GSO_UDPV4 << NETIF_F_GSO_SHIFT)
  38.849 -+#define NETIF_F_GSO_ROBUST	(SKB_GSO_DODGY << NETIF_F_GSO_SHIFT)
  38.850 -+
  38.851 -+#define NETIF_F_GEN_CSUM	(NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
  38.852 -+#define NETIF_F_ALL_CSUM	(NETIF_F_IP_CSUM | NETIF_F_GEN_CSUM)
  38.853 - 
  38.854 - 	struct net_device	*next_sched;
  38.855 - 
  38.856 -@@ -394,6 +403,9 @@ #define NETIF_F_UFO             8192    
  38.857 - 	struct list_head	qdisc_list;
  38.858 - 	unsigned long		tx_queue_len;	/* Max frames per queue allowed */
  38.859 - 
  38.860 -+	/* Partially transmitted GSO packet. */
  38.861 -+	struct sk_buff		*gso_skb;
  38.862 -+
  38.863 - 	/* ingress path synchronizer */
  38.864 - 	spinlock_t		ingress_lock;
  38.865 - 	struct Qdisc		*qdisc_ingress;
  38.866 -@@ -402,7 +414,7 @@ #define NETIF_F_UFO             8192    
  38.867 -  * One part is mostly used on xmit path (device)
  38.868 -  */
  38.869 - 	/* hard_start_xmit synchronizer */
  38.870 --	spinlock_t		xmit_lock ____cacheline_aligned_in_smp;
  38.871 -+	spinlock_t		_xmit_lock ____cacheline_aligned_in_smp;
  38.872 - 	/* cpu id of processor entered to hard_start_xmit or -1,
  38.873 - 	   if nobody entered there.
  38.874 - 	 */
  38.875 -@@ -527,6 +539,8 @@ struct packet_type {
  38.876 - 					 struct net_device *,
  38.877 - 					 struct packet_type *,
  38.878 - 					 struct net_device *);
  38.879 -+	struct sk_buff		*(*gso_segment)(struct sk_buff *skb,
  38.880 -+						int features);
  38.881 - 	void			*af_packet_priv;
  38.882 - 	struct list_head	list;
  38.883 - };
  38.884 -@@ -693,7 +707,8 @@ extern int		dev_change_name(struct net_d
  38.885 - extern int		dev_set_mtu(struct net_device *, int);
  38.886 - extern int		dev_set_mac_address(struct net_device *,
  38.887 - 					    struct sockaddr *);
  38.888 --extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
  38.889 -+extern int		dev_hard_start_xmit(struct sk_buff *skb,
  38.890 -+					    struct net_device *dev);
  38.891 - 
  38.892 - extern void		dev_init(void);
  38.893 - 
  38.894 -@@ -900,11 +915,43 @@ static inline void __netif_rx_complete(s
  38.895 - 	clear_bit(__LINK_STATE_RX_SCHED, &dev->state);
  38.896 - }
  38.897 - 
  38.898 -+static inline void netif_tx_lock(struct net_device *dev)
  38.899 -+{
  38.900 -+	spin_lock(&dev->_xmit_lock);
  38.901 -+	dev->xmit_lock_owner = smp_processor_id();
  38.902 -+}
  38.903 -+
  38.904 -+static inline void netif_tx_lock_bh(struct net_device *dev)
  38.905 -+{
  38.906 -+	spin_lock_bh(&dev->_xmit_lock);
  38.907 -+	dev->xmit_lock_owner = smp_processor_id();
  38.908 -+}
  38.909 -+
  38.910 -+static inline int netif_tx_trylock(struct net_device *dev)
  38.911 -+{
  38.912 -+	int err = spin_trylock(&dev->_xmit_lock);
  38.913 -+	if (!err)
  38.914 -+		dev->xmit_lock_owner = smp_processor_id();
  38.915 -+	return err;
  38.916 -+}
  38.917 -+
  38.918 -+static inline void netif_tx_unlock(struct net_device *dev)
  38.919 -+{
  38.920 -+	dev->xmit_lock_owner = -1;
  38.921 -+	spin_unlock(&dev->_xmit_lock);
  38.922 -+}
  38.923 -+
  38.924 -+static inline void netif_tx_unlock_bh(struct net_device *dev)
  38.925 -+{
  38.926 -+	dev->xmit_lock_owner = -1;
  38.927 -+	spin_unlock_bh(&dev->_xmit_lock);
  38.928 -+}
  38.929 -+
  38.930 - static inline void netif_tx_disable(struct net_device *dev)
  38.931 - {
  38.932 --	spin_lock_bh(&dev->xmit_lock);
  38.933 -+	netif_tx_lock_bh(dev);
  38.934 - 	netif_stop_queue(dev);
  38.935 --	spin_unlock_bh(&dev->xmit_lock);
  38.936 -+	netif_tx_unlock_bh(dev);
  38.937 - }
  38.938 - 
  38.939 - /* These functions live elsewhere (drivers/net/net_init.c, but related) */
  38.940 -@@ -932,6 +979,7 @@ extern int		netdev_max_backlog;
  38.941 - extern int		weight_p;
  38.942 - extern int		netdev_set_master(struct net_device *dev, struct net_device *master);
  38.943 - extern int skb_checksum_help(struct sk_buff *skb, int inward);
  38.944 -+extern struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features);
  38.945 - #ifdef CONFIG_BUG
  38.946 - extern void netdev_rx_csum_fault(struct net_device *dev);
  38.947 - #else
  38.948 -@@ -951,6 +999,18 @@ #endif
  38.949 - 
  38.950 - extern void linkwatch_run_queue(void);
  38.951 - 
  38.952 -+static inline int skb_gso_ok(struct sk_buff *skb, int features)
  38.953 -+{
  38.954 -+	int feature = skb_shinfo(skb)->gso_size ?
  38.955 -+		      skb_shinfo(skb)->gso_type << NETIF_F_GSO_SHIFT : 0;
  38.956 -+	return (features & feature) == feature;
  38.957 -+}
  38.958 -+
  38.959 -+static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
  38.960 -+{
  38.961 -+	return !skb_gso_ok(skb, dev->features);
  38.962 -+}
  38.963 -+
  38.964 - #endif /* __KERNEL__ */
  38.965 - 
  38.966 - #endif	/* _LINUX_DEV_H */
  38.967 -diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
  38.968 -index ad7cc22..b19d45d 100644
  38.969 ---- a/include/linux/skbuff.h
  38.970 -+++ b/include/linux/skbuff.h
  38.971 -@@ -134,9 +134,10 @@ struct skb_frag_struct {
  38.972 - struct skb_shared_info {
  38.973 - 	atomic_t	dataref;
  38.974 - 	unsigned short	nr_frags;
  38.975 --	unsigned short	tso_size;
  38.976 --	unsigned short	tso_segs;
  38.977 --	unsigned short  ufo_size;
  38.978 -+	unsigned short	gso_size;
  38.979 -+	/* Warning: this field is not always filled in (UFO)! */
  38.980 -+	unsigned short	gso_segs;
  38.981 -+	unsigned short  gso_type;
  38.982 - 	unsigned int    ip6_frag_id;
  38.983 - 	struct sk_buff	*frag_list;
  38.984 - 	skb_frag_t	frags[MAX_SKB_FRAGS];
  38.985 -@@ -168,6 +169,14 @@ enum {
  38.986 - 	SKB_FCLONE_CLONE,
  38.987 - };
  38.988 - 
  38.989 -+enum {
  38.990 -+	SKB_GSO_TCPV4 = 1 << 0,
  38.991 -+	SKB_GSO_UDPV4 = 1 << 1,
  38.992 -+
  38.993 -+	/* This indicates the skb is from an untrusted source. */
  38.994 -+	SKB_GSO_DODGY = 1 << 2,
  38.995 -+};
  38.996 -+
  38.997 - /** 
  38.998 -  *	struct sk_buff - socket buffer
  38.999 -  *	@next: Next buffer in list
 38.1000 -@@ -1148,18 +1157,34 @@ static inline int skb_can_coalesce(struc
 38.1001 - 	return 0;
 38.1002 - }
 38.1003 - 
 38.1004 -+static inline int __skb_linearize(struct sk_buff *skb)
 38.1005 -+{
 38.1006 -+	return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM;
 38.1007 -+}
 38.1008 -+
 38.1009 - /**
 38.1010 -  *	skb_linearize - convert paged skb to linear one
 38.1011 -  *	@skb: buffer to linarize
 38.1012 -- *	@gfp: allocation mode
 38.1013 -  *
 38.1014 -  *	If there is no free memory -ENOMEM is returned, otherwise zero
 38.1015 -  *	is returned and the old skb data released.
 38.1016 -  */
 38.1017 --extern int __skb_linearize(struct sk_buff *skb, gfp_t gfp);
 38.1018 --static inline int skb_linearize(struct sk_buff *skb, gfp_t gfp)
 38.1019 -+static inline int skb_linearize(struct sk_buff *skb)
 38.1020 -+{
 38.1021 -+	return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0;
 38.1022 -+}
 38.1023 -+
 38.1024 -+/**
 38.1025 -+ *	skb_linearize_cow - make sure skb is linear and writable
 38.1026 -+ *	@skb: buffer to process
 38.1027 -+ *
 38.1028 -+ *	If there is no free memory -ENOMEM is returned, otherwise zero
 38.1029 -+ *	is returned and the old skb data released.
 38.1030 -+ */
 38.1031 -+static inline int skb_linearize_cow(struct sk_buff *skb)
 38.1032 - {
 38.1033 --	return __skb_linearize(skb, gfp);
 38.1034 -+	return skb_is_nonlinear(skb) || skb_cloned(skb) ?
 38.1035 -+	       __skb_linearize(skb) : 0;
 38.1036 - }
 38.1037 - 
 38.1038 - /**
 38.1039 -@@ -1254,6 +1279,7 @@ extern void	       skb_split(struct sk_b
 38.1040 - 				 struct sk_buff *skb1, const u32 len);
 38.1041 - 
 38.1042 - extern void	       skb_release_data(struct sk_buff *skb);
 38.1043 -+extern struct sk_buff *skb_segment(struct sk_buff *skb, int features);
 38.1044 - 
 38.1045 - static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
 38.1046 - 				       int len, void *buffer)
 38.1047 -diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
 38.1048 -index b94d1ad..75b5b93 100644
 38.1049 ---- a/include/net/pkt_sched.h
 38.1050 -+++ b/include/net/pkt_sched.h
 38.1051 -@@ -218,12 +218,13 @@ extern struct qdisc_rate_table *qdisc_ge
 38.1052 - 		struct rtattr *tab);
 38.1053 - extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
 38.1054 - 
 38.1055 --extern int qdisc_restart(struct net_device *dev);
 38.1056 -+extern void __qdisc_run(struct net_device *dev);
 38.1057 - 
 38.1058 - static inline void qdisc_run(struct net_device *dev)
 38.1059 - {
 38.1060 --	while (!netif_queue_stopped(dev) && qdisc_restart(dev) < 0)
 38.1061 --		/* NOTHING */;
 38.1062 -+	if (!netif_queue_stopped(dev) &&
 38.1063 -+	    !test_and_set_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
 38.1064 -+		__qdisc_run(dev);
 38.1065 - }
 38.1066 - 
 38.1067 - extern int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
 38.1068 -diff --git a/include/net/protocol.h b/include/net/protocol.h
 38.1069 -index 6dc5970..0d2dcdb 100644
 38.1070 ---- a/include/net/protocol.h
 38.1071 -+++ b/include/net/protocol.h
 38.1072 -@@ -37,6 +37,8 @@ #define MAX_INET_PROTOS	256		/* Must be 
 38.1073 - struct net_protocol {
 38.1074 - 	int			(*handler)(struct sk_buff *skb);
 38.1075 - 	void			(*err_handler)(struct sk_buff *skb, u32 info);
 38.1076 -+	struct sk_buff	       *(*gso_segment)(struct sk_buff *skb,
 38.1077 -+					       int features);
 38.1078 - 	int			no_policy;
 38.1079 - };
 38.1080 - 
 38.1081 -diff --git a/include/net/sock.h b/include/net/sock.h
 38.1082 -index f63d0d5..a8e8d21 100644
 38.1083 ---- a/include/net/sock.h
 38.1084 -+++ b/include/net/sock.h
 38.1085 -@@ -1064,9 +1064,13 @@ static inline void sk_setup_caps(struct 
 38.1086 - {
 38.1087 - 	__sk_dst_set(sk, dst);
 38.1088 - 	sk->sk_route_caps = dst->dev->features;
 38.1089 -+	if (sk->sk_route_caps & NETIF_F_GSO)
 38.1090 -+		sk->sk_route_caps |= NETIF_F_TSO;
 38.1091 - 	if (sk->sk_route_caps & NETIF_F_TSO) {
 38.1092 - 		if (sock_flag(sk, SOCK_NO_LARGESEND) || dst->header_len)
 38.1093 - 			sk->sk_route_caps &= ~NETIF_F_TSO;
 38.1094 -+		else 
 38.1095 -+			sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM;
 38.1096 - 	}
 38.1097 - }
 38.1098 - 
 38.1099 -diff --git a/include/net/tcp.h b/include/net/tcp.h
 38.1100 -index 77f21c6..70e1d5f 100644
 38.1101 ---- a/include/net/tcp.h
 38.1102 -+++ b/include/net/tcp.h
 38.1103 -@@ -552,13 +552,13 @@ #include <net/tcp_ecn.h>
 38.1104 -  */
 38.1105 - static inline int tcp_skb_pcount(const struct sk_buff *skb)
 38.1106 - {
 38.1107 --	return skb_shinfo(skb)->tso_segs;
 38.1108 -+	return skb_shinfo(skb)->gso_segs;
 38.1109 - }
 38.1110 - 
 38.1111 - /* This is valid iff tcp_skb_pcount() > 1. */
 38.1112 - static inline int tcp_skb_mss(const struct sk_buff *skb)
 38.1113 - {
 38.1114 --	return skb_shinfo(skb)->tso_size;
 38.1115 -+	return skb_shinfo(skb)->gso_size;
 38.1116 - }
 38.1117 - 
 38.1118 - static inline void tcp_dec_pcount_approx(__u32 *count,
 38.1119 -@@ -1063,6 +1063,8 @@ extern struct request_sock_ops tcp_reque
 38.1120 - 
 38.1121 - extern int tcp_v4_destroy_sock(struct sock *sk);
 38.1122 - 
 38.1123 -+extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features);
 38.1124 -+
 38.1125 - #ifdef CONFIG_PROC_FS
 38.1126 - extern int  tcp4_proc_init(void);
 38.1127 - extern void tcp4_proc_exit(void);
 38.1128 -diff --git a/net/atm/clip.c b/net/atm/clip.c
 38.1129 -index 1842a4e..6dc21a7 100644
 38.1130 ---- a/net/atm/clip.c
 38.1131 -+++ b/net/atm/clip.c
 38.1132 -@@ -101,7 +101,7 @@ static void unlink_clip_vcc(struct clip_
 38.1133 - 		printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n",clip_vcc);
 38.1134 - 		return;
 38.1135 - 	}
 38.1136 --	spin_lock_bh(&entry->neigh->dev->xmit_lock);	/* block clip_start_xmit() */
 38.1137 -+	netif_tx_lock_bh(entry->neigh->dev);	/* block clip_start_xmit() */
 38.1138 - 	entry->neigh->used = jiffies;
 38.1139 - 	for (walk = &entry->vccs; *walk; walk = &(*walk)->next)
 38.1140 - 		if (*walk == clip_vcc) {
 38.1141 -@@ -125,7 +125,7 @@ static void unlink_clip_vcc(struct clip_
 38.1142 - 	printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc "
 38.1143 - 	  "0x%p)\n",entry,clip_vcc);
 38.1144 - out:
 38.1145 --	spin_unlock_bh(&entry->neigh->dev->xmit_lock);
 38.1146 -+	netif_tx_unlock_bh(entry->neigh->dev);
 38.1147 - }
 38.1148 - 
 38.1149 - /* The neighbour entry n->lock is held. */
 38.1150 -diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
 38.1151 -index 0b33a7b..180e79b 100644
 38.1152 ---- a/net/bridge/br_device.c
 38.1153 -+++ b/net/bridge/br_device.c
 38.1154 -@@ -146,9 +146,9 @@ static int br_set_tx_csum(struct net_dev
 38.1155 - 	struct net_bridge *br = netdev_priv(dev);
 38.1156 - 
 38.1157 - 	if (data)
 38.1158 --		br->feature_mask |= NETIF_F_IP_CSUM;
 38.1159 -+		br->feature_mask |= NETIF_F_NO_CSUM;
 38.1160 - 	else
 38.1161 --		br->feature_mask &= ~NETIF_F_IP_CSUM;
 38.1162 -+		br->feature_mask &= ~NETIF_F_ALL_CSUM;
 38.1163 - 
 38.1164 - 	br_features_recompute(br);
 38.1165 - 	return 0;
 38.1166 -@@ -185,6 +185,6 @@ void br_dev_setup(struct net_device *dev
 38.1167 - 	dev->set_mac_address = br_set_mac_address;
 38.1168 - 	dev->priv_flags = IFF_EBRIDGE;
 38.1169 - 
 38.1170 -- 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST
 38.1171 -- 		| NETIF_F_HIGHDMA | NETIF_F_TSO | NETIF_F_IP_CSUM;
 38.1172 -+ 	dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA |
 38.1173 -+ 			NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_GSO_ROBUST;
 38.1174 - }
 38.1175 -diff --git a/net/bridge/br_forward.c b/net/bridge/br_forward.c
 38.1176 -index 2d24fb4..00b1128 100644
 38.1177 ---- a/net/bridge/br_forward.c
 38.1178 -+++ b/net/bridge/br_forward.c
 38.1179 -@@ -32,7 +32,7 @@ static inline int should_deliver(const s
 38.1180 - int br_dev_queue_push_xmit(struct sk_buff *skb)
 38.1181 - {
 38.1182 - 	/* drop mtu oversized packets except tso */
 38.1183 --	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->tso_size)
 38.1184 -+	if (skb->len > skb->dev->mtu && !skb_shinfo(skb)->gso_size)
 38.1185 - 		kfree_skb(skb);
 38.1186 - 	else {
 38.1187 - #ifdef CONFIG_BRIDGE_NETFILTER
 38.1188 -diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
 38.1189 -index f36b35e..0617146 100644
 38.1190 ---- a/net/bridge/br_if.c
 38.1191 -+++ b/net/bridge/br_if.c
 38.1192 -@@ -385,17 +385,28 @@ void br_features_recompute(struct net_br
 38.1193 - 	struct net_bridge_port *p;
 38.1194 - 	unsigned long features, checksum;
 38.1195 - 
 38.1196 --	features = br->feature_mask &~ NETIF_F_IP_CSUM;
 38.1197 --	checksum = br->feature_mask & NETIF_F_IP_CSUM;
 38.1198 -+	checksum = br->feature_mask & NETIF_F_ALL_CSUM ? NETIF_F_NO_CSUM : 0;
 38.1199 -+	features = br->feature_mask & ~NETIF_F_ALL_CSUM;
 38.1200 - 
 38.1201 - 	list_for_each_entry(p, &br->port_list, list) {
 38.1202 --		if (!(p->dev->features 
 38.1203 --		      & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)))
 38.1204 -+		unsigned long feature = p->dev->features;
 38.1205 -+
 38.1206 -+		if (checksum & NETIF_F_NO_CSUM && !(feature & NETIF_F_NO_CSUM))
 38.1207 -+			checksum ^= NETIF_F_NO_CSUM | NETIF_F_HW_CSUM;
 38.1208 -+		if (checksum & NETIF_F_HW_CSUM && !(feature & NETIF_F_HW_CSUM))
 38.1209 -+			checksum ^= NETIF_F_HW_CSUM | NETIF_F_IP_CSUM;
 38.1210 -+		if (!(feature & NETIF_F_IP_CSUM))
 38.1211 - 			checksum = 0;
 38.1212 --		features &= p->dev->features;
 38.1213 -+
 38.1214 -+		if (feature & NETIF_F_GSO)
 38.1215 -+			feature |= NETIF_F_TSO;
 38.1216 -+		feature |= NETIF_F_GSO;
 38.1217 -+
 38.1218 -+		features &= feature;
 38.1219 - 	}
 38.1220 - 
 38.1221 --	br->dev->features = features | checksum | NETIF_F_LLTX;
 38.1222 -+	br->dev->features = features | checksum | NETIF_F_LLTX |
 38.1223 -+			    NETIF_F_GSO_ROBUST;
 38.1224 - }
 38.1225 - 
 38.1226 - /* called with RTNL */
 38.1227 -diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
 38.1228 -index 9e27373..588207f 100644
 38.1229 ---- a/net/bridge/br_netfilter.c
 38.1230 -+++ b/net/bridge/br_netfilter.c
 38.1231 -@@ -743,7 +743,7 @@ static int br_nf_dev_queue_xmit(struct s
 38.1232 - {
 38.1233 - 	if (skb->protocol == htons(ETH_P_IP) &&
 38.1234 - 	    skb->len > skb->dev->mtu &&
 38.1235 --	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
 38.1236 -+	    !skb_shinfo(skb)->gso_size)
 38.1237 - 		return ip_fragment(skb, br_dev_queue_push_xmit);
 38.1238 - 	else
 38.1239 - 		return br_dev_queue_push_xmit(skb);
 38.1240 -diff --git a/net/core/dev.c b/net/core/dev.c
 38.1241 -index 12a214c..32e1056 100644
 38.1242 ---- a/net/core/dev.c
 38.1243 -+++ b/net/core/dev.c
 38.1244 -@@ -115,6 +115,7 @@ #include <linux/wireless.h>		/* Note : w
 38.1245 - #include <net/iw_handler.h>
 38.1246 - #endif	/* CONFIG_NET_RADIO */
 38.1247 - #include <asm/current.h>
 38.1248 -+#include <linux/err.h>
 38.1249 - 
 38.1250 - /*
 38.1251 -  *	The list of packet types we will receive (as opposed to discard)
 38.1252 -@@ -1032,7 +1033,7 @@ static inline void net_timestamp(struct 
 38.1253 -  *	taps currently in use.
 38.1254 -  */
 38.1255 - 
 38.1256 --void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 38.1257 -+static void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
 38.1258 - {
 38.1259 - 	struct packet_type *ptype;
 38.1260 - 
 38.1261 -@@ -1106,6 +1107,45 @@ out:	
 38.1262 - 	return ret;
 38.1263 - }
 38.1264 - 
 38.1265 -+/**
 38.1266 -+ *	skb_gso_segment - Perform segmentation on skb.
 38.1267 -+ *	@skb: buffer to segment
 38.1268 -+ *	@features: features for the output path (see dev->features)
 38.1269 -+ *
 38.1270 -+ *	This function segments the given skb and returns a list of segments.
 38.1271 -+ *
 38.1272 -+ *	It may return NULL if the skb requires no segmentation.  This is
 38.1273 -+ *	only possible when GSO is used for verifying header integrity.
 38.1274 -+ */
 38.1275 -+struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features)
 38.1276 -+{
 38.1277 -+	struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT);
 38.1278 -+	struct packet_type *ptype;
 38.1279 -+	int type = skb->protocol;
 38.1280 -+
 38.1281 -+	BUG_ON(skb_shinfo(skb)->frag_list);
 38.1282 -+	BUG_ON(skb->ip_summed != CHECKSUM_HW);
 38.1283 -+
 38.1284 -+	skb->mac.raw = skb->data;
 38.1285 -+	skb->mac_len = skb->nh.raw - skb->data;
 38.1286 -+	__skb_pull(skb, skb->mac_len);
 38.1287 -+
 38.1288 -+	rcu_read_lock();
 38.1289 -+	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type) & 15], list) {
 38.1290 -+		if (ptype->type == type && !ptype->dev && ptype->gso_segment) {
 38.1291 -+			segs = ptype->gso_segment(skb, features);
 38.1292 -+			break;
 38.1293 -+		}
 38.1294 -+	}
 38.1295 -+	rcu_read_unlock();
 38.1296 -+
 38.1297 -+	__skb_push(skb, skb->data - skb->mac.raw);
 38.1298 -+
 38.1299 -+	return segs;
 38.1300 -+}
 38.1301 -+
 38.1302 -+EXPORT_SYMBOL(skb_gso_segment);
 38.1303 -+
 38.1304 - /* Take action when hardware reception checksum errors are detected. */
 38.1305 - #ifdef CONFIG_BUG
 38.1306 - void netdev_rx_csum_fault(struct net_device *dev)
 38.1307 -@@ -1142,75 +1182,108 @@ #else
 38.1308 - #define illegal_highdma(dev, skb)	(0)
 38.1309 - #endif
 38.1310 - 
 38.1311 --/* Keep head the same: replace data */
 38.1312 --int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
 38.1313 --{
 38.1314 --	unsigned int size;
 38.1315 --	u8 *data;
 38.1316 --	long offset;
 38.1317 --	struct skb_shared_info *ninfo;
 38.1318 --	int headerlen = skb->data - skb->head;
 38.1319 --	int expand = (skb->tail + skb->data_len) - skb->end;
 38.1320 --
 38.1321 --	if (skb_shared(skb))
 38.1322 --		BUG();
 38.1323 --
 38.1324 --	if (expand <= 0)
 38.1325 --		expand = 0;
 38.1326 --
 38.1327 --	size = skb->end - skb->head + expand;
 38.1328 --	size = SKB_DATA_ALIGN(size);
 38.1329 --	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
 38.1330 --	if (!data)
 38.1331 --		return -ENOMEM;
 38.1332 --
 38.1333 --	/* Copy entire thing */
 38.1334 --	if (skb_copy_bits(skb, -headerlen, data, headerlen + skb->len))
 38.1335 --		BUG();
 38.1336 --
 38.1337 --	/* Set up shinfo */
 38.1338 --	ninfo = (struct skb_shared_info*)(data + size);
 38.1339 --	atomic_set(&ninfo->dataref, 1);
 38.1340 --	ninfo->tso_size = skb_shinfo(skb)->tso_size;
 38.1341 --	ninfo->tso_segs = skb_shinfo(skb)->tso_segs;
 38.1342 --	ninfo->nr_frags = 0;
 38.1343 --	ninfo->frag_list = NULL;
 38.1344 --
 38.1345 --	/* Offset between the two in bytes */
 38.1346 --	offset = data - skb->head;
 38.1347 --
 38.1348 --	/* Free old data. */
 38.1349 --	skb_release_data(skb);
 38.1350 --
 38.1351 --	skb->head = data;
 38.1352 --	skb->end  = data + size;
 38.1353 --
 38.1354 --	/* Set up new pointers */
 38.1355 --	skb->h.raw   += offset;
 38.1356 --	skb->nh.raw  += offset;
 38.1357 --	skb->mac.raw += offset;
 38.1358 --	skb->tail    += offset;
 38.1359 --	skb->data    += offset;
 38.1360 --
 38.1361 --	/* We are no longer a clone, even if we were. */
 38.1362 --	skb->cloned    = 0;
 38.1363 --
 38.1364 --	skb->tail     += skb->data_len;
 38.1365 --	skb->data_len  = 0;
 38.1366 -+struct dev_gso_cb {
 38.1367 -+	void (*destructor)(struct sk_buff *skb);
 38.1368 -+};
 38.1369 -+
 38.1370 -+#define DEV_GSO_CB(skb) ((struct dev_gso_cb *)(skb)->cb)
 38.1371 -+
 38.1372 -+static void dev_gso_skb_destructor(struct sk_buff *skb)
 38.1373 -+{
 38.1374 -+	struct dev_gso_cb *cb;
 38.1375 -+
 38.1376 -+	do {
 38.1377 -+		struct sk_buff *nskb = skb->next;
 38.1378 -+
 38.1379 -+		skb->next = nskb->next;
 38.1380 -+		nskb->next = NULL;
 38.1381 -+		kfree_skb(nskb);
 38.1382 -+	} while (skb->next);
 38.1383 -+
 38.1384 -+	cb = DEV_GSO_CB(skb);
 38.1385 -+	if (cb->destructor)
 38.1386 -+		cb->destructor(skb);
 38.1387 -+}
 38.1388 -+
 38.1389 -+/**
 38.1390 -+ *	dev_gso_segment - Perform emulated hardware segmentation on skb.
 38.1391 -+ *	@skb: buffer to segment
 38.1392 -+ *
 38.1393 -+ *	This function segments the given skb and stores the list of segments
 38.1394 -+ *	in skb->next.
 38.1395 -+ */
 38.1396 -+static int dev_gso_segment(struct sk_buff *skb)
 38.1397 -+{
 38.1398 -+	struct net_device *dev = skb->dev;
 38.1399 -+	struct sk_buff *segs;
 38.1400 -+	int features = dev->features & ~(illegal_highdma(dev, skb) ?
 38.1401 -+					 NETIF_F_SG : 0);
 38.1402 -+
 38.1403 -+	segs = skb_gso_segment(skb, features);
 38.1404 -+
 38.1405 -+	/* Verifying header integrity only. */
 38.1406 -+	if (!segs)
 38.1407 -+		return 0;
 38.1408 -+
 38.1409 -+	if (unlikely(IS_ERR(segs)))
 38.1410 -+		return PTR_ERR(segs);
 38.1411 -+
 38.1412 -+	skb->next = segs;
 38.1413 -+	DEV_GSO_CB(skb)->destructor = skb->destructor;
 38.1414 -+	skb->destructor = dev_gso_skb_destructor;
 38.1415 -+
 38.1416 -+	return 0;
 38.1417 -+}
 38.1418 -+
 38.1419 -+int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 38.1420 -+{
 38.1421 -+	if (likely(!skb->next)) {
 38.1422 -+		if (netdev_nit)
 38.1423 -+			dev_queue_xmit_nit(skb, dev);
 38.1424 -+
 38.1425 -+		if (netif_needs_gso(dev, skb)) {
 38.1426 -+			if (unlikely(dev_gso_segment(skb)))
 38.1427 -+				goto out_kfree_skb;
 38.1428 -+			if (skb->next)
 38.1429 -+				goto gso;
 38.1430 -+		}
 38.1431 -+
 38.1432 -+		return dev->hard_start_xmit(skb, dev);
 38.1433 -+	}
 38.1434 -+
 38.1435 -+gso:
 38.1436 -+	do {
 38.1437 -+		struct sk_buff *nskb = skb->next;
 38.1438 -+		int rc;
 38.1439 -+
 38.1440 -+		skb->next = nskb->next;
 38.1441 -+		nskb->next = NULL;
 38.1442 -+		rc = dev->hard_start_xmit(nskb, dev);
 38.1443 -+		if (unlikely(rc)) {
 38.1444 -+			nskb->next = skb->next;
 38.1445 -+			skb->next = nskb;
 38.1446 -+			return rc;
 38.1447 -+		}
 38.1448 -+		if (unlikely(netif_queue_stopped(dev) && skb->next))
 38.1449 -+			return NETDEV_TX_BUSY;
 38.1450 -+	} while (skb->next);
 38.1451 -+	
 38.1452 -+	skb->destructor = DEV_GSO_CB(skb)->destructor;
 38.1453 -+
 38.1454 -+out_kfree_skb:
 38.1455 -+	kfree_skb(skb);
 38.1456 - 	return 0;
 38.1457 - }
 38.1458 - 
 38.1459 - #define HARD_TX_LOCK(dev, cpu) {			\
 38.1460 - 	if ((dev->features & NETIF_F_LLTX) == 0) {	\
 38.1461 --		spin_lock(&dev->xmit_lock);		\
 38.1462 --		dev->xmit_lock_owner = cpu;		\
 38.1463 -+		netif_tx_lock(dev);			\
 38.1464 - 	}						\
 38.1465 - }
 38.1466 - 
 38.1467 - #define HARD_TX_UNLOCK(dev) {				\
 38.1468 - 	if ((dev->features & NETIF_F_LLTX) == 0) {	\
 38.1469 --		dev->xmit_lock_owner = -1;		\
 38.1470 --		spin_unlock(&dev->xmit_lock);		\
 38.1471 -+		netif_tx_unlock(dev);			\
 38.1472 - 	}						\
 38.1473 - }
 38.1474 - 
 38.1475 -@@ -1246,9 +1319,13 @@ int dev_queue_xmit(struct sk_buff *skb)
 38.1476 - 	struct Qdisc *q;
 38.1477 - 	int rc = -ENOMEM;
 38.1478 - 
 38.1479 -+	/* GSO will handle the following emulations directly. */
 38.1480 -+	if (netif_needs_gso(dev, skb))
 38.1481 -+		goto gso;
 38.1482 -+
 38.1483 - 	if (skb_shinfo(skb)->frag_list &&
 38.1484 - 	    !(dev->features & NETIF_F_FRAGLIST) &&
 38.1485 --	    __skb_linearize(skb, GFP_ATOMIC))
 38.1486 -+	    __skb_linearize(skb))
 38.1487 - 		goto out_kfree_skb;
 38.1488 - 
 38.1489 - 	/* Fragmented skb is linearized if device does not support SG,
 38.1490 -@@ -1257,25 +1334,26 @@ int dev_queue_xmit(struct sk_buff *skb)
 38.1491 - 	 */
 38.1492 - 	if (skb_shinfo(skb)->nr_frags &&
 38.1493 - 	    (!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
 38.1494 --	    __skb_linearize(skb, GFP_ATOMIC))
 38.1495 -+	    __skb_linearize(skb))
 38.1496 - 		goto out_kfree_skb;
 38.1497 - 
 38.1498 - 	/* If packet is not checksummed and device does not support
 38.1499 - 	 * checksumming for this protocol, complete checksumming here.
 38.1500 - 	 */
 38.1501 - 	if (skb->ip_summed == CHECKSUM_HW &&
 38.1502 --	    (!(dev->features & (NETIF_F_HW_CSUM | NETIF_F_NO_CSUM)) &&
 38.1503 -+	    (!(dev->features & NETIF_F_GEN_CSUM) &&
 38.1504 - 	     (!(dev->features & NETIF_F_IP_CSUM) ||
 38.1505 - 	      skb->protocol != htons(ETH_P_IP))))
 38.1506 - 	      	if (skb_checksum_help(skb, 0))
 38.1507 - 	      		goto out_kfree_skb;
 38.1508 - 
 38.1509 -+gso:
 38.1510 - 	spin_lock_prefetch(&dev->queue_lock);
 38.1511 - 
 38.1512 - 	/* Disable soft irqs for various locks below. Also 
 38.1513 - 	 * stops preemption for RCU. 
 38.1514 - 	 */
 38.1515 --	local_bh_disable(); 
 38.1516 -+	rcu_read_lock_bh(); 
 38.1517 - 
 38.1518 - 	/* Updates of qdisc are serialized by queue_lock. 
 38.1519 - 	 * The struct Qdisc which is pointed to by qdisc is now a 
 38.1520 -@@ -1309,8 +1387,8 @@ #endif
 38.1521 - 	/* The device has no queue. Common case for software devices:
 38.1522 - 	   loopback, all the sorts of tunnels...
 38.1523 - 
 38.1524 --	   Really, it is unlikely that xmit_lock protection is necessary here.
 38.1525 --	   (f.e. loopback and IP tunnels are clean ignoring statistics
 38.1526 -+	   Really, it is unlikely that netif_tx_lock protection is necessary
 38.1527 -+	   here.  (f.e. loopback and IP tunnels are clean ignoring statistics
 38.1528 - 	   counters.)
 38.1529 - 	   However, it is possible, that they rely on protection
 38.1530 - 	   made by us here.
 38.1531 -@@ -1326,11 +1404,8 @@ #endif
 38.1532 - 			HARD_TX_LOCK(dev, cpu);
 38.1533 - 
 38.1534 - 			if (!netif_queue_stopped(dev)) {
 38.1535 --				if (netdev_nit)
 38.1536 --					dev_queue_xmit_nit(skb, dev);
 38.1537 --
 38.1538 - 				rc = 0;
 38.1539 --				if (!dev->hard_start_xmit(skb, dev)) {
 38.1540 -+				if (!dev_hard_start_xmit(skb, dev)) {
 38.1541 - 					HARD_TX_UNLOCK(dev);
 38.1542 - 					goto out;
 38.1543 - 				}
 38.1544 -@@ -1349,13 +1424,13 @@ #endif
 38.1545 - 	}
 38.1546 - 
 38.1547 - 	rc = -ENETDOWN;
 38.1548 --	local_bh_enable();
 38.1549 -+	rcu_read_unlock_bh();
 38.1550 - 
 38.1551 - out_kfree_skb:
 38.1552 - 	kfree_skb(skb);
 38.1553 - 	return rc;
 38.1554 - out:
 38.1555 --	local_bh_enable();
 38.1556 -+	rcu_read_unlock_bh();
 38.1557 - 	return rc;
 38.1558 - }
 38.1559 - 
 38.1560 -@@ -2670,7 +2745,7 @@ int register_netdevice(struct net_device
 38.1561 - 	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);
 38.1562 - 
 38.1563 - 	spin_lock_init(&dev->queue_lock);
 38.1564 --	spin_lock_init(&dev->xmit_lock);
 38.1565 -+	spin_lock_init(&dev->_xmit_lock);
 38.1566 - 	dev->xmit_lock_owner = -1;
 38.1567 - #ifdef CONFIG_NET_CLS_ACT
 38.1568 - 	spin_lock_init(&dev->ingress_lock);
 38.1569 -@@ -2714,9 +2789,7 @@ #endif
 38.1570 - 
 38.1571 - 	/* Fix illegal SG+CSUM combinations. */
 38.1572 - 	if ((dev->features & NETIF_F_SG) &&
 38.1573 --	    !(dev->features & (NETIF_F_IP_CSUM |
 38.1574 --			       NETIF_F_NO_CSUM |
 38.1575 --			       NETIF_F_HW_CSUM))) {
 38.1576 -+	    !(dev->features & NETIF_F_ALL_CSUM)) {
 38.1577 - 		printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
 38.1578 - 		       dev->name);
 38.1579 - 		dev->features &= ~NETIF_F_SG;
 38.1580 -@@ -3268,7 +3341,6 @@ subsys_initcall(net_dev_init);
 38.1581 - EXPORT_SYMBOL(__dev_get_by_index);
 38.1582 - EXPORT_SYMBOL(__dev_get_by_name);
 38.1583 - EXPORT_SYMBOL(__dev_remove_pack);
 38.1584 --EXPORT_SYMBOL(__skb_linearize);
 38.1585 - EXPORT_SYMBOL(dev_valid_name);
 38.1586 - EXPORT_SYMBOL(dev_add_pack);
 38.1587 - EXPORT_SYMBOL(dev_alloc_name);
 38.1588 -diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c
 38.1589 -index 05d6085..c57d887 100644
 38.1590 ---- a/net/core/dev_mcast.c
 38.1591 -+++ b/net/core/dev_mcast.c
 38.1592 -@@ -62,7 +62,7 @@ #include <net/arp.h>
 38.1593 -  *	Device mc lists are changed by bh at least if IPv6 is enabled,
 38.1594 -  *	so that it must be bh protected.
 38.1595 -  *
 38.1596 -- *	We block accesses to device mc filters with dev->xmit_lock.
 38.1597 -+ *	We block accesses to device mc filters with netif_tx_lock.
 38.1598 -  */
 38.1599 - 
 38.1600 - /*
 38.1601 -@@ -93,9 +93,9 @@ static void __dev_mc_upload(struct net_d
 38.1602 - 
 38.1603 - void dev_mc_upload(struct net_device *dev)
 38.1604 - {
 38.1605 --	spin_lock_bh(&dev->xmit_lock);
 38.1606 -+	netif_tx_lock_bh(dev);
 38.1607 - 	__dev_mc_upload(dev);
 38.1608 --	spin_unlock_bh(&dev->xmit_lock);
 38.1609 -+	netif_tx_unlock_bh(dev);
 38.1610 - }
 38.1611 - 
 38.1612 - /*
 38.1613 -@@ -107,7 +107,7 @@ int dev_mc_delete(struct net_device *dev
 38.1614 - 	int err = 0;
 38.1615 - 	struct dev_mc_list *dmi, **dmip;
 38.1616 - 
 38.1617 --	spin_lock_bh(&dev->xmit_lock);
 38.1618 -+	netif_tx_lock_bh(dev);
 38.1619 - 
 38.1620 - 	for (dmip = &dev->mc_list; (dmi = *dmip) != NULL; dmip = &dmi->next) {
 38.1621 - 		/*
 38.1622 -@@ -139,13 +139,13 @@ int dev_mc_delete(struct net_device *dev
 38.1623 - 			 */
 38.1624 - 			__dev_mc_upload(dev);
 38.1625 - 			
 38.1626 --			spin_unlock_bh(&dev->xmit_lock);
 38.1627 -+			netif_tx_unlock_bh(dev);
 38.1628 - 			return 0;
 38.1629 - 		}
 38.1630 - 	}
 38.1631 - 	err = -ENOENT;
 38.1632 - done:
 38.1633 --	spin_unlock_bh(&dev->xmit_lock);
 38.1634 -+	netif_tx_unlock_bh(dev);
 38.1635 - 	return err;
 38.1636 - }
 38.1637 - 
 38.1638 -@@ -160,7 +160,7 @@ int dev_mc_add(struct net_device *dev, v
 38.1639 - 
 38.1640 - 	dmi1 = kmalloc(sizeof(*dmi), GFP_ATOMIC);
 38.1641 - 
 38.1642 --	spin_lock_bh(&dev->xmit_lock);
 38.1643 -+	netif_tx_lock_bh(dev);
 38.1644 - 	for (dmi = dev->mc_list; dmi != NULL; dmi = dmi->next) {
 38.1645 - 		if (memcmp(dmi->dmi_addr, addr, dmi->dmi_addrlen) == 0 &&
 38.1646 - 		    dmi->dmi_addrlen == alen) {
 38.1647 -@@ -176,7 +176,7 @@ int dev_mc_add(struct net_device *dev, v
 38.1648 - 	}
 38.1649 - 
 38.1650 - 	if ((dmi = dmi1) == NULL) {
 38.1651 --		spin_unlock_bh(&dev->xmit_lock);
 38.1652 -+		netif_tx_unlock_bh(dev);
 38.1653 - 		return -ENOMEM;
 38.1654 - 	}
 38.1655 - 	memcpy(dmi->dmi_addr, addr, alen);
 38.1656 -@@ -189,11 +189,11 @@ int dev_mc_add(struct net_device *dev, v
 38.1657 - 
 38.1658 - 	__dev_mc_upload(dev);
 38.1659 - 	
 38.1660 --	spin_unlock_bh(&dev->xmit_lock);
 38.1661 -+	netif_tx_unlock_bh(dev);
 38.1662 - 	return 0;
 38.1663 - 
 38.1664 - done:
 38.1665 --	spin_unlock_bh(&dev->xmit_lock);
 38.1666 -+	netif_tx_unlock_bh(dev);
 38.1667 - 	kfree(dmi1);
 38.1668 - 	return err;
 38.1669 - }
 38.1670 -@@ -204,7 +204,7 @@ done:
 38.1671 - 
 38.1672 - void dev_mc_discard(struct net_device *dev)
 38.1673 - {
 38.1674 --	spin_lock_bh(&dev->xmit_lock);
 38.1675 -+	netif_tx_lock_bh(dev);
 38.1676 - 	
 38.1677 - 	while (dev->mc_list != NULL) {
 38.1678 - 		struct dev_mc_list *tmp = dev->mc_list;
 38.1679 -@@ -215,7 +215,7 @@ void dev_mc_discard(struct net_device *d
 38.1680 - 	}
 38.1681 - 	dev->mc_count = 0;
 38.1682 - 
 38.1683 --	spin_unlock_bh(&dev->xmit_lock);
 38.1684 -+	netif_tx_unlock_bh(dev);
 38.1685 - }
 38.1686 - 
 38.1687 - #ifdef CONFIG_PROC_FS
 38.1688 -@@ -250,7 +250,7 @@ static int dev_mc_seq_show(struct seq_fi
 38.1689 - 	struct dev_mc_list *m;
 38.1690 - 	struct net_device *dev = v;
 38.1691 - 
 38.1692 --	spin_lock_bh(&dev->xmit_lock);
 38.1693 -+	netif_tx_lock_bh(dev);
 38.1694 - 	for (m = dev->mc_list; m; m = m->next) {
 38.1695 - 		int i;
 38.1696 - 
 38.1697 -@@ -262,7 +262,7 @@ static int dev_mc_seq_show(struct seq_fi
 38.1698 - 
 38.1699 - 		seq_putc(seq, '\n');
 38.1700 - 	}
 38.1701 --	spin_unlock_bh(&dev->xmit_lock);
 38.1702 -+	netif_tx_unlock_bh(dev);
 38.1703 - 	return 0;
 38.1704 - }
 38.1705 - 
 38.1706 -diff --git a/net/core/ethtool.c b/net/core/ethtool.c
 38.1707 -index e6f7610..27ce168 100644
 38.1708 ---- a/net/core/ethtool.c
 38.1709 -+++ b/net/core/ethtool.c
 38.1710 -@@ -30,7 +30,7 @@ u32 ethtool_op_get_link(struct net_devic
 38.1711 - 
 38.1712 - u32 ethtool_op_get_tx_csum(struct net_device *dev)
 38.1713 - {
 38.1714 --	return (dev->features & (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM)) != 0;
 38.1715 -+	return (dev->features & NETIF_F_ALL_CSUM) != 0;
 38.1716 - }
 38.1717 - 
 38.1718 - int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
 38.1719 -@@ -551,9 +551,7 @@ static int ethtool_set_sg(struct net_dev
 38.1720 - 		return -EFAULT;
 38.1721 - 
 38.1722 - 	if (edata.data && 
 38.1723 --	    !(dev->features & (NETIF_F_IP_CSUM |
 38.1724 --			       NETIF_F_NO_CSUM |
 38.1725 --			       NETIF_F_HW_CSUM)))
 38.1726 -+	    !(dev->features & NETIF_F_ALL_CSUM))
 38.1727 - 		return -EINVAL;
 38.1728 - 
 38.1729 - 	return __ethtool_set_sg(dev, edata.data);
 38.1730 -@@ -591,7 +589,7 @@ static int ethtool_set_tso(struct net_de
 38.1731 - 
 38.1732 - static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr)
 38.1733 - {
 38.1734 --	struct ethtool_value edata = { ETHTOOL_GTSO };
 38.1735 -+	struct ethtool_value edata = { ETHTOOL_GUFO };
 38.1736 - 
 38.1737 - 	if (!dev->ethtool_ops->get_ufo)
 38.1738 - 		return -EOPNOTSUPP;
 38.1739 -@@ -600,6 +598,7 @@ static int ethtool_get_ufo(struct net_de
 38.1740 - 		 return -EFAULT;
 38.1741 - 	return 0;
 38.1742 - }
 38.1743 -+
 38.1744 - static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
 38.1745 - {
 38.1746 - 	struct ethtool_value edata;
 38.1747 -@@ -615,6 +614,29 @@ static int ethtool_set_ufo(struct net_de
 38.1748 - 	return dev->ethtool_ops->set_ufo(dev, edata.data);
 38.1749 - }
 38.1750 - 
 38.1751 -+static int ethtool_get_gso(struct net_device *dev, char __user *useraddr)
 38.1752 -+{
 38.1753 -+	struct ethtool_value edata = { ETHTOOL_GGSO };
 38.1754 -+
 38.1755 -+	edata.data = dev->features & NETIF_F_GSO;
 38.1756 -+	if (copy_to_user(useraddr, &edata, sizeof(edata)))
 38.1757 -+		 return -EFAULT;
 38.1758 -+	return 0;
 38.1759 -+}
 38.1760 -+
 38.1761 -+static int ethtool_set_gso(struct net_device *dev, char __user *useraddr)
 38.1762 -+{
 38.1763 -+	struct ethtool_value edata;
 38.1764 -+
 38.1765 -+	if (copy_from_user(&edata, useraddr, sizeof(edata)))
 38.1766 -+		return -EFAULT;
 38.1767 -+	if (edata.data)
 38.1768 -+		dev->features |= NETIF_F_GSO;
 38.1769 -+	else
 38.1770 -+		dev->features &= ~NETIF_F_GSO;
 38.1771 -+	return 0;
 38.1772 -+}
 38.1773 -+
 38.1774 - static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
 38.1775 - {
 38.1776 - 	struct ethtool_test test;
 38.1777 -@@ -906,6 +928,12 @@ int dev_ethtool(struct ifreq *ifr)
 38.1778 - 	case ETHTOOL_SUFO:
 38.1779 - 		rc = ethtool_set_ufo(dev, useraddr);
 38.1780 - 		break;
 38.1781 -+	case ETHTOOL_GGSO:
 38.1782 -+		rc = ethtool_get_gso(dev, useraddr);
 38.1783 -+		break;
 38.1784 -+	case ETHTOOL_SGSO:
 38.1785 -+		rc = ethtool_set_gso(dev, useraddr);
 38.1786 -+		break;
 38.1787 - 	default:
 38.1788 - 		rc =  -EOPNOTSUPP;
 38.1789 - 	}
 38.1790 -diff --git a/net/core/netpoll.c b/net/core/netpoll.c
 38.1791 -index ea51f8d..ec28d3b 100644
 38.1792 ---- a/net/core/netpoll.c
 38.1793 -+++ b/net/core/netpoll.c
 38.1794 -@@ -273,24 +273,21 @@ static void netpoll_send_skb(struct netp
 38.1795 - 
 38.1796 - 	do {
 38.1797 - 		npinfo->tries--;
 38.1798 --		spin_lock(&np->dev->xmit_lock);
 38.1799 --		np->dev->xmit_lock_owner = smp_processor_id();
 38.1800 -+		netif_tx_lock(np->dev);
 38.1801 - 
 38.1802 - 		/*
 38.1803 - 		 * network drivers do not expect to be called if the queue is
 38.1804 - 		 * stopped.
 38.1805 - 		 */
 38.1806 - 		if (netif_queue_stopped(np->dev)) {
 38.1807 --			np->dev->xmit_lock_owner = -1;
 38.1808 --			spin_unlock(&np->dev->xmit_lock);
 38.1809 -+			netif_tx_unlock(np->dev);
 38.1810 - 			netpoll_poll(np);
 38.1811 - 			udelay(50);
 38.1812 - 			continue;
 38.1813 - 		}
 38.1814 - 
 38.1815 - 		status = np->dev->hard_start_xmit(skb, np->dev);
 38.1816 --		np->dev->xmit_lock_owner = -1;
 38.1817 --		spin_unlock(&np->dev->xmit_lock);
 38.1818 -+		netif_tx_unlock(np->dev);
 38.1819 - 
 38.1820 - 		/* success */
 38.1821 - 		if(!status) {
 38.1822 -diff --git a/net/core/pktgen.c b/net/core/pktgen.c
 38.1823 -index da16f8f..2380347 100644
 38.1824 ---- a/net/core/pktgen.c
 38.1825 -+++ b/net/core/pktgen.c
 38.1826 -@@ -2582,7 +2582,7 @@ static __inline__ void pktgen_xmit(struc
 38.1827 - 		}
 38.1828 - 	}
 38.1829 - 	
 38.1830 --	spin_lock_bh(&odev->xmit_lock);
 38.1831 -+	netif_tx_lock_bh(odev);
 38.1832 - 	if (!netif_queue_stopped(odev)) {
 38.1833 - 
 38.1834 - 		atomic_inc(&(pkt_dev->skb->users));
 38.1835 -@@ -2627,7 +2627,7 @@ retry_now:
 38.1836 - 		pkt_dev->next_tx_ns = 0;
 38.1837 -         }
 38.1838 - 
 38.1839 --	spin_unlock_bh(&odev->xmit_lock);
 38.1840 -+	netif_tx_unlock_bh(odev);
 38.1841 - 	
 38.1842 - 	/* If pkt_dev->count is zero, then run forever */
 38.1843 - 	if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
 38.1844 -diff --git a/net/core/skbuff.c b/net/core/skbuff.c
 38.1845 -index 2144952..46f56af 100644
 38.1846 ---- a/net/core/skbuff.c
 38.1847 -+++ b/net/core/skbuff.c
 38.1848 -@@ -164,9 +164,9 @@ struct sk_buff *__alloc_skb(unsigned int
 38.1849 - 	shinfo = skb_shinfo(skb);
 38.1850 - 	atomic_set(&shinfo->dataref, 1);
 38.1851 - 	shinfo->nr_frags  = 0;
 38.1852 --	shinfo->tso_size = 0;
 38.1853 --	shinfo->tso_segs = 0;
 38.1854 --	shinfo->ufo_size = 0;
 38.1855 -+	shinfo->gso_size = 0;
 38.1856 -+	shinfo->gso_segs = 0;
 38.1857 -+	shinfo->gso_type = 0;
 38.1858 - 	shinfo->ip6_frag_id = 0;
 38.1859 - 	shinfo->frag_list = NULL;
 38.1860 - 
 38.1861 -@@ -230,8 +230,9 @@ struct sk_buff *alloc_skb_from_cache(kme
 38.1862 - 
 38.1863 - 	atomic_set(&(skb_shinfo(skb)->dataref), 1);
 38.1864 - 	skb_shinfo(skb)->nr_frags  = 0;
 38.1865 --	skb_shinfo(skb)->tso_size = 0;
 38.1866 --	skb_shinfo(skb)->tso_segs = 0;
 38.1867 -+	skb_shinfo(skb)->gso_size = 0;
 38.1868 -+	skb_shinfo(skb)->gso_segs = 0;
 38.1869 -+	skb_shinfo(skb)->gso_type = 0;
 38.1870 - 	skb_shinfo(skb)->frag_list = NULL;
 38.1871 - out:
 38.1872 - 	return skb;
 38.1873 -@@ -501,8 +502,9 @@ #endif
 38.1874 - 	new->tc_index	= old->tc_index;
 38.1875 - #endif
 38.1876 - 	atomic_set(&new->users, 1);
 38.1877 --	skb_shinfo(new)->tso_size = skb_shinfo(old)->tso_size;
 38.1878 --	skb_shinfo(new)->tso_segs = skb_shinfo(old)->tso_segs;
 38.1879 -+	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
 38.1880 -+	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
 38.1881 -+	skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type;
 38.1882 - }
 38.1883 - 
 38.1884 - /**
 38.1885 -@@ -1777,6 +1779,133 @@ int skb_append_datato_frags(struct sock 
 38.1886 - 	return 0;
 38.1887 - }
 38.1888 - 
 38.1889 -+/**
 38.1890 -+ *	skb_segment - Perform protocol segmentation on skb.
 38.1891 -+ *	@skb: buffer to segment
 38.1892 -+ *	@features: features for the output path (see dev->features)
 38.1893 -+ *
 38.1894 -+ *	This function performs segmentation on the given skb.  It returns
 38.1895 -+ *	the segment at the given position.  It returns NULL if there are
 38.1896 -+ *	no more segments to generate, or when an error is encountered.
 38.1897 -+ */
 38.1898 -+struct sk_buff *skb_segment(struct sk_buff *skb, int features)
 38.1899 -+{
 38.1900 -+	struct sk_buff *segs = NULL;
 38.1901 -+	struct sk_buff *tail = NULL;
 38.1902 -+	unsigned int mss = skb_shinfo(skb)->gso_size;
 38.1903 -+	unsigned int doffset = skb->data - skb->mac.raw;
 38.1904 -+	unsigned int offset = doffset;
 38.1905 -+	unsigned int headroom;
 38.1906 -+	unsigned int len;
 38.1907 -+	int sg = features & NETIF_F_SG;
 38.1908 -+	int nfrags = skb_shinfo(skb)->nr_frags;
 38.1909 -+	int err = -ENOMEM;
 38.1910 -+	int i = 0;
 38.1911 -+	int pos;
 38.1912 -+
 38.1913 -+	__skb_push(skb, doffset);
 38.1914 -+	headroom = skb_headroom(skb);
 38.1915 -+	pos = skb_headlen(skb);
 38.1916 -+
 38.1917 -+	do {
 38.1918 -+		struct sk_buff *nskb;
 38.1919 -+		skb_frag_t *frag;
 38.1920 -+		int hsize, nsize;
 38.1921 -+		int k;
 38.1922 -+		int size;
 38.1923 -+
 38.1924 -+		len = skb->len - offset;
 38.1925 -+		if (len > mss)
 38.1926 -+			len = mss;
 38.1927 -+
 38.1928 -+		hsize = skb_headlen(skb) - offset;
 38.1929 -+		if (hsize < 0)
 38.1930 -+			hsize = 0;
 38.1931 -+		nsize = hsize + doffset;
 38.1932 -+		if (nsize > len + doffset || !sg)
 38.1933 -+			nsize = len + doffset;
 38.1934 -+
 38.1935 -+		nskb = alloc_skb(nsize + headroom, GFP_ATOMIC);
 38.1936 -+		if (unlikely(!nskb))
 38.1937 -+			goto err;
 38.1938 -+
 38.1939 -+		if (segs)
 38.1940 -+			tail->next = nskb;
 38.1941 -+		else
 38.1942 -+			segs = nskb;
 38.1943 -+		tail = nskb;
 38.1944 -+
 38.1945 -+		nskb->dev = skb->dev;
 38.1946 -+		nskb->priority = skb->priority;
 38.1947 -+		nskb->protocol = skb->protocol;
 38.1948 -+		nskb->dst = dst_clone(skb->dst);
 38.1949 -+		memcpy(nskb->cb, skb->cb, sizeof(skb->cb));
 38.1950 -+		nskb->pkt_type = skb->pkt_type;
 38.1951 -+		nskb->mac_len = skb->mac_len;
 38.1952 -+
 38.1953 -+		skb_reserve(nskb, headroom);
 38.1954 -+		nskb->mac.raw = nskb->data;
 38.1955 -+		nskb->nh.raw = nskb->data + skb->mac_len;
 38.1956 -+		nskb->h.raw = nskb->nh.raw + (skb->h.raw - skb->nh.raw);
 38.1957 -+		memcpy(skb_put(nskb, doffset), skb->data, doffset);
 38.1958 -+
 38.1959 -+		if (!sg) {
 38.1960 -+			nskb->csum = skb_copy_and_csum_bits(skb, offset,
 38.1961 -+							    skb_put(nskb, len),
 38.1962 -+							    len, 0);
 38.1963 -+			continue;
 38.1964 -+		}
 38.1965 -+
 38.1966 -+		frag = skb_shinfo(nskb)->frags;
 38.1967 -+		k = 0;
 38.1968 -+
 38.1969 -+		nskb->ip_summed = CHECKSUM_HW;
 38.1970 -+		nskb->csum = skb->csum;
 38.1971 -+		memcpy(skb_put(nskb, hsize), skb->data + offset, hsize);
 38.1972 -+
 38.1973 -+		while (pos < offset + len) {
 38.1974 -+			BUG_ON(i >= nfrags);
 38.1975 -+
 38.1976 -+			*frag = skb_shinfo(skb)->frags[i];
 38.1977 -+			get_page(frag->page);
 38.1978 -+			size = frag->size;
 38.1979 -+
 38.1980 -+			if (pos < offset) {
 38.1981 -+				frag->page_offset += offset - pos;
 38.1982 -+				frag->size -= offset - pos;
 38.1983 -+			}
 38.1984 -+
 38.1985 -+			k++;
 38.1986 -+
 38.1987 -+			if (pos + size <= offset + len) {
 38.1988 -+				i++;
 38.1989 -+				pos += size;
 38.1990 -+			} else {
 38.1991 -+				frag->size -= pos + size - (offset + len);
 38.1992 -+				break;
 38.1993 -+			}
 38.1994 -+
 38.1995 -+			frag++;
 38.1996 -+		}
 38.1997 -+
 38.1998 -+		skb_shinfo(nskb)->nr_frags = k;
 38.1999 -+		nskb->data_len = len - hsize;
 38.2000 -+		nskb->len += nskb->data_len;
 38.2001 -+		nskb->truesize += nskb->data_len;
 38.2002 -+	} while ((offset += len) < skb->len);
 38.2003 -+
 38.2004 -+	return segs;
 38.2005 -+
 38.2006 -+err:
 38.2007 -+	while ((skb = segs)) {
 38.2008 -+		segs = skb->next;
 38.2009 -+		kfree(skb);
 38.2010 -+	}
 38.2011 -+	return ERR_PTR(err);
 38.2012 -+}
 38.2013 -+
 38.2014 -+EXPORT_SYMBOL_GPL(skb_segment);
 38.2015 -+
 38.2016 - void __init skb_init(void)
 38.2017 - {
 38.2018 - 	skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
 38.2019 -diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
 38.2020 -index 44bda85..2e3323a 100644
 38.2021 ---- a/net/decnet/dn_nsp_in.c
 38.2022 -+++ b/net/decnet/dn_nsp_in.c
 38.2023 -@@ -801,8 +801,7 @@ got_it:
 38.2024 - 		 * We linearize everything except data segments here.
 38.2025 - 		 */
 38.2026 - 		if (cb->nsp_flags & ~0x60) {
 38.2027 --			if (unlikely(skb_is_nonlinear(skb)) &&
 38.2028 --			    skb_linearize(skb, GFP_ATOMIC) != 0)
 38.2029 -+			if (unlikely(skb_linearize(skb)))
 38.2030 - 				goto free_out;
 38.2031 - 		}
 38.2032 - 
 38.2033 -diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
 38.2034 -index 3407f19..a0a25e0 100644
 38.2035 ---- a/net/decnet/dn_route.c
 38.2036 -+++ b/net/decnet/dn_route.c
 38.2037 -@@ -629,8 +629,7 @@ int dn_route_rcv(struct sk_buff *skb, st
 38.2038 - 			padlen);
 38.2039 - 
 38.2040 -         if (flags & DN_RT_PKT_CNTL) {
 38.2041 --		if (unlikely(skb_is_nonlinear(skb)) &&
 38.2042 --		    skb_linearize(skb, GFP_ATOMIC) != 0)
 38.2043 -+		if (unlikely(skb_linearize(skb)))
 38.2044 - 			goto dump_it;
 38.2045 - 
 38.2046 -                 switch(flags & DN_RT_CNTL_MSK) {
 38.2047 -diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
 38.2048 -index 97c276f..5ba719e 100644
 38.2049 ---- a/net/ipv4/af_inet.c
 38.2050 -+++ b/net/ipv4/af_inet.c
 38.2051 -@@ -68,6 +68,7 @@
 38.2052 -  */
 38.2053 - 
 38.2054 - #include <linux/config.h>
 38.2055 -+#include <linux/err.h>
 38.2056 - #include <linux/errno.h>
 38.2057 - #include <linux/types.h>
 38.2058 - #include <linux/socket.h>
 38.2059 -@@ -1084,6 +1085,54 @@ int inet_sk_rebuild_header(struct sock *
 38.2060 - 
 38.2061 - EXPORT_SYMBOL(inet_sk_rebuild_header);
 38.2062 - 
 38.2063 -+static struct sk_buff *inet_gso_segment(struct sk_buff *skb, int features)
 38.2064 -+{
 38.2065 -+	struct sk_buff *segs = ERR_PTR(-EINVAL);
 38.2066 -+	struct iphdr *iph;
 38.2067 -+	struct net_protocol *ops;
 38.2068 -+	int proto;
 38.2069 -+	int ihl;
 38.2070 -+	int id;
 38.2071 -+
 38.2072 -+	if (!pskb_may_pull(skb, sizeof(*iph)))
 38.2073 -+		goto out;
 38.2074 -+
 38.2075 -+	iph = skb->nh.iph;
 38.2076 -+	ihl = iph->ihl * 4;
 38.2077 -+	if (ihl < sizeof(*iph))
 38.2078 -+		goto out;
 38.2079 -+
 38.2080 -+	if (!pskb_may_pull(skb, ihl))
 38.2081 -+		goto out;
 38.2082 -+
 38.2083 -+	skb->h.raw = __skb_pull(skb, ihl);
 38.2084 -+	iph = skb->nh.iph;
 38.2085 -+	id = ntohs(iph->id);
 38.2086 -+	proto = iph->protocol & (MAX_INET_PROTOS - 1);
 38.2087 -+	segs = ERR_PTR(-EPROTONOSUPPORT);
 38.2088 -+
 38.2089 -+	rcu_read_lock();
 38.2090 -+	ops = rcu_dereference(inet_protos[proto]);
 38.2091 -+	if (ops && ops->gso_segment)
 38.2092 -+		segs = ops->gso_segment(skb, features);
 38.2093 -+	rcu_read_unlock();
 38.2094 -+
 38.2095 -+	if (!segs || unlikely(IS_ERR(segs)))
 38.2096 -+		goto out;
 38.2097 -+
 38.2098 -+	skb = segs;
 38.2099 -+	do {
 38.2100 -+		iph = skb->nh.iph;
 38.2101 -+		iph->id = htons(id++);
 38.2102 -+		iph->tot_len = htons(skb->len - skb->mac_len);
 38.2103 -+		iph->check = 0;
 38.2104 -+		iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
 38.2105 -+	} while ((skb = skb->next));
 38.2106 -+
 38.2107 -+out:
 38.2108 -+	return segs;
 38.2109 -+}
 38.2110 -+
 38.2111 - #ifdef CONFIG_IP_MULTICAST
 38.2112 - static struct net_protocol igmp_protocol = {
 38.2113 - 	.handler =	igmp_rcv,
 38.2114 -@@ -1093,6 +1142,7 @@ #endif
 38.2115 - static struct net_protocol tcp_protocol = {
 38.2116 - 	.handler =	tcp_v4_rcv,
 38.2117 - 	.err_handler =	tcp_v4_err,
 38.2118 -+	.gso_segment =	tcp_tso_segment,
 38.2119 - 	.no_policy =	1,
 38.2120 - };
 38.2121 - 
 38.2122 -@@ -1138,6 +1188,7 @@ static int ipv4_proc_init(void);
 38.2123 - static struct packet_type ip_packet_type = {
 38.2124 - 	.type = __constant_htons(ETH_P_IP),
 38.2125 - 	.func = ip_rcv,
 38.2126 -+	.gso_segment = inet_gso_segment,
 38.2127 - };
 38.2128 - 
 38.2129 - static int __init inet_init(void)
 38.2130 -diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
 38.2131 -index 8dcba38..19c3c73 100644
 38.2132 ---- a/net/ipv4/ip_output.c
 38.2133 -+++ b/net/ipv4/ip_output.c
 38.2134 -@@ -210,8 +210,7 @@ #if defined(CONFIG_NETFILTER) && defined
 38.2135 - 		return dst_output(skb);
 38.2136 - 	}
 38.2137 - #endif
 38.2138 --	if (skb->len > dst_mtu(skb->dst) &&
 38.2139 --	    !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size))
 38.2140 -+	if (skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size)
 38.2141 - 		return ip_fragment(skb, ip_finish_output2);
 38.2142 - 	else
 38.2143 - 		return ip_finish_output2(skb);
 38.2144 -@@ -362,7 +361,7 @@ packet_routed:
 38.2145 - 	}
 38.2146 - 
 38.2147 - 	ip_select_ident_more(iph, &rt->u.dst, sk,
 38.2148 --			     (skb_shinfo(skb)->tso_segs ?: 1) - 1);
 38.2149 -+			     (skb_shinfo(skb)->gso_segs ?: 1) - 1);
 38.2150 - 
 38.2151 - 	/* Add an IP checksum. */
 38.2152 - 	ip_send_check(iph);
 38.2153 -@@ -743,7 +742,8 @@ static inline int ip_ufo_append_data(str
 38.2154 - 			       (length - transhdrlen));
 38.2155 - 	if (!err) {
 38.2156 - 		/* specify the length of each IP datagram fragment*/
 38.2157 --		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
 38.2158 -+		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 38.2159 -+		skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
 38.2160 - 		__skb_queue_tail(&sk->sk_write_queue, skb);
 38.2161 - 
 38.2162 - 		return 0;
 38.2163 -@@ -839,7 +839,7 @@ int ip_append_data(struct sock *sk,
 38.2164 - 	 */
 38.2165 - 	if (transhdrlen &&
 38.2166 - 	    length + fragheaderlen <= mtu &&
 38.2167 --	    rt->u.dst.dev->features&(NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) &&
 38.2168 -+	    rt->u.dst.dev->features & NETIF_F_ALL_CSUM &&
 38.2169 - 	    !exthdrlen)
 38.2170 - 		csummode = CHECKSUM_HW;
 38.2171 - 
 38.2172 -@@ -1086,14 +1086,16 @@ ssize_t	ip_append_page(struct sock *sk, 
 38.2173 - 
 38.2174 - 	inet->cork.length += size;
 38.2175 - 	if ((sk->sk_protocol == IPPROTO_UDP) &&
 38.2176 --	    (rt->u.dst.dev->features & NETIF_F_UFO))
 38.2177 --		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen);
 38.2178 -+	    (rt->u.dst.dev->features & NETIF_F_UFO)) {
 38.2179 -+		skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
 38.2180 -+		skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
 38.2181 -+	}
 38.2182 - 
 38.2183 - 
 38.2184 - 	while (size > 0) {
 38.2185 - 		int i;
 38.2186 - 
 38.2187 --		if (skb_shinfo(skb)->ufo_size)
 38.2188 -+		if (skb_shinfo(skb)->gso_size)
 38.2189 - 			len = size;
 38.2190 - 		else {
 38.2191 - 
 38.2192 -diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
 38.2193 -index d64e2ec..7494823 100644
 38.2194 ---- a/net/ipv4/ipcomp.c
 38.2195 -+++ b/net/ipv4/ipcomp.c
 38.2196 -@@ -84,7 +84,7 @@ static int ipcomp_input(struct xfrm_stat
 38.2197 -                         struct xfrm_decap_state *decap, struct sk_buff *skb)
 38.2198 - {
 38.2199 - 	u8 nexthdr;
 38.2200 --	int err = 0;
 38.2201 -+	int err = -ENOMEM;
 38.2202 - 	struct iphdr *iph;
 38.2203 - 	union {
 38.2204 - 		struct iphdr	iph;
 38.2205 -@@ -92,11 +92,8 @@ static int ipcomp_input(struct xfrm_stat
 38.2206 - 	} tmp_iph;
 38.2207 - 
 38.2208 - 
 38.2209 --	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 38.2210 --	    skb_linearize(skb, GFP_ATOMIC) != 0) {
 38.2211 --	    	err = -ENOMEM;
 38.2212 -+	if (skb_linearize_cow(skb))
 38.2213 - 	    	goto out;
 38.2214 --	}
 38.2215 - 
 38.2216 - 	skb->ip_summed = CHECKSUM_NONE;
 38.2217 - 
 38.2218 -@@ -171,10 +168,8 @@ static int ipcomp_output(struct xfrm_sta
 38.2219 - 		goto out_ok;
 38.2220 - 	}
 38.2221 - 
 38.2222 --	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 38.2223 --	    skb_linearize(skb, GFP_ATOMIC) != 0) {
 38.2224 -+	if (skb_linearize_cow(skb))
 38.2225 - 		goto out_ok;
 38.2226 --	}
 38.2227 - 	
 38.2228 - 	err = ipcomp_compress(x, skb);
 38.2229 - 	iph = skb->nh.iph;
 38.2230 -diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
 38.2231 -index 00aa80e..30c81a8 100644
 38.2232 ---- a/net/ipv4/tcp.c
 38.2233 -+++ b/net/ipv4/tcp.c
 38.2234 -@@ -257,6 +257,7 @@ #include <linux/smp_lock.h>
 38.2235 - #include <linux/fs.h>
 38.2236 - #include <linux/random.h>
 38.2237 - #include <linux/bootmem.h>
 38.2238 -+#include <linux/err.h>
 38.2239 - 
 38.2240 - #include <net/icmp.h>
 38.2241 - #include <net/tcp.h>
 38.2242 -@@ -570,7 +571,7 @@ new_segment:
 38.2243 - 		skb->ip_summed = CHECKSUM_HW;
 38.2244 - 		tp->write_seq += copy;
 38.2245 - 		TCP_SKB_CB(skb)->end_seq += copy;
 38.2246 --		skb_shinfo(skb)->tso_segs = 0;
 38.2247 -+		skb_shinfo(skb)->gso_segs = 0;
 38.2248 - 
 38.2249 - 		if (!copied)
 38.2250 - 			TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH;
 38.2251 -@@ -621,14 +622,10 @@ ssize_t tcp_sendpage(struct socket *sock
 38.2252 - 	ssize_t res;
 38.2253 - 	struct sock *sk = sock->sk;
 38.2254 - 
 38.2255 --#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM)
 38.2256 --
 38.2257 - 	if (!(sk->sk_route_caps & NETIF_F_SG) ||
 38.2258 --	    !(sk->sk_route_caps & TCP_ZC_CSUM_FLAGS))
 38.2259 -+	    !(sk->sk_route_caps & NETIF_F_ALL_CSUM))
 38.2260 - 		return sock_no_sendpage(sock, page, offset, size, flags);
 38.2261 - 
 38.2262 --#undef TCP_ZC_CSUM_FLAGS
 38.2263 --
 38.2264 - 	lock_sock(sk);
 38.2265 - 	TCP_CHECK_TIMER(sk);
 38.2266 - 	res = do_tcp_sendpages(sk, &page, offset, size, flags);
 38.2267 -@@ -725,9 +722,7 @@ new_segment:
 38.2268 - 				/*
 38.2269 - 				 * Check whether we can use HW checksum.
 38.2270 - 				 */
 38.2271 --				if (sk->sk_route_caps &
 38.2272 --				    (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM |
 38.2273 --				     NETIF_F_HW_CSUM))
 38.2274 -+				if (sk->sk_route_caps & NETIF_F_ALL_CSUM)
 38.2275 - 					skb->ip_summed = CHECKSUM_HW;
 38.2276 - 
 38.2277 - 				skb_entail(sk, tp, skb);
 38.2278 -@@ -823,7 +818,7 @@ new_segment:
 38.2279 - 
 38.2280 - 			tp->write_seq += copy;
 38.2281 - 			TCP_SKB_CB(skb)->end_seq += copy;
 38.2282 --			skb_shinfo(skb)->tso_segs = 0;
 38.2283 -+			skb_shinfo(skb)->gso_segs = 0;
 38.2284 - 
 38.2285 - 			from += copy;
 38.2286 - 			copied += copy;
 38.2287 -@@ -2026,6 +2021,77 @@ int tcp_getsockopt(struct sock *sk, int 
 38.2288 - }
 38.2289 - 
 38.2290 - 
 38.2291 -+struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
 38.2292 -+{
 38.2293 -+	struct sk_buff *segs = ERR_PTR(-EINVAL);
 38.2294 -+	struct tcphdr *th;
 38.2295 -+	unsigned thlen;
 38.2296 -+	unsigned int seq;
 38.2297 -+	unsigned int delta;
 38.2298 -+	unsigned int oldlen;
 38.2299 -+	unsigned int len;
 38.2300 -+
 38.2301 -+	if (!pskb_may_pull(skb, sizeof(*th)))
 38.2302 -+		goto out;
 38.2303 -+
 38.2304 -+	th = skb->h.th;
 38.2305 -+	thlen = th->doff * 4;
 38.2306 -+	if (thlen < sizeof(*th))
 38.2307 -+		goto out;
 38.2308 -+
 38.2309 -+	if (!pskb_may_pull(skb, thlen))
 38.2310 -+		goto out;
 38.2311 -+
 38.2312 -+	oldlen = (u16)~skb->len;
 38.2313 -+	__skb_pull(skb, thlen);
 38.2314 -+
 38.2315 -+	if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
 38.2316 -+		/* Packet is from an untrusted source, reset gso_segs. */
 38.2317 -+		int mss = skb_shinfo(skb)->gso_size;
 38.2318 -+
 38.2319 -+		skb_shinfo(skb)->gso_segs = (skb->len + mss - 1) / mss;
 38.2320 -+
 38.2321 -+		segs = NULL;
 38.2322 -+		goto out;
 38.2323 -+	}
 38.2324 -+
 38.2325 -+	segs = skb_segment(skb, features);
 38.2326 -+	if (IS_ERR(segs))
 38.2327 -+		goto out;
 38.2328 -+
 38.2329 -+	len = skb_shinfo(skb)->gso_size;
 38.2330 -+	delta = htonl(oldlen + (thlen + len));
 38.2331 -+
 38.2332 -+	skb = segs;
 38.2333 -+	th = skb->h.th;
 38.2334 -+	seq = ntohl(th->seq);
 38.2335 -+
 38.2336 -+	do {
 38.2337 -+		th->fin = th->psh = 0;
 38.2338 -+
 38.2339 -+		th->check = ~csum_fold(th->check + delta);
 38.2340 -+		if (skb->ip_summed != CHECKSUM_HW)
 38.2341 -+			th->check = csum_fold(csum_partial(skb->h.raw, thlen,
 38.2342 -+							   skb->csum));
 38.2343 -+
 38.2344 -+		seq += len;
 38.2345 -+		skb = skb->next;
 38.2346 -+		th = skb->h.th;
 38.2347 -+
 38.2348 -+		th->seq = htonl(seq);
 38.2349 -+		th->cwr = 0;
 38.2350 -+	} while (skb->next);
 38.2351 -+
 38.2352 -+	delta = htonl(oldlen + (skb->tail - skb->h.raw) + skb->data_len);
 38.2353 -+	th->check = ~csum_fold(th->check + delta);
 38.2354 -+	if (skb->ip_summed != CHECKSUM_HW)
 38.2355 -+		th->check = csum_fold(csum_partial(skb->h.raw, thlen,
 38.2356 -+						   skb->csum));
 38.2357 -+
 38.2358 -+out:
 38.2359 -+	return segs;
 38.2360 -+}
 38.2361 -+
 38.2362 - extern void __skb_cb_too_small_for_tcp(int, int);
 38.2363 - extern struct tcp_congestion_ops tcp_reno;
 38.2364 - 
 38.2365 -diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
 38.2366 -index e9a54ae..defe77a 100644
 38.2367 ---- a/net/ipv4/tcp_input.c
 38.2368 -+++ b/net/ipv4/tcp_input.c
 38.2369 -@@ -1072,7 +1072,7 @@ tcp_sacktag_write_queue(struct sock *sk,
 38.2370 - 				else
 38.2371 - 					pkt_len = (end_seq -
 38.2372 - 						   TCP_SKB_CB(skb)->seq);
 38.2373 --				if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->tso_size))
 38.2374 -+				if (tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size))
 38.2375 - 					break;
 38.2376 - 				pcount = tcp_skb_pcount(skb);
 38.2377 - 			}
 38.2378 -diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
 38.2379 -index 310f2e6..ee01f69 100644
 38.2380 ---- a/net/ipv4/tcp_output.c
 38.2381 -+++ b/net/ipv4/tcp_output.c
 38.2382 -@@ -497,15 +497,17 @@ static void tcp_set_skb_tso_segs(struct 
 38.2383 - 		/* Avoid the costly divide in the normal
 38.2384 - 		 * non-TSO case.
 38.2385 - 		 */
 38.2386 --		skb_shinfo(skb)->tso_segs = 1;
 38.2387 --		skb_shinfo(skb)->tso_size = 0;
 38.2388 -+		skb_shinfo(skb)->gso_segs = 1;
 38.2389 -+		skb_shinfo(skb)->gso_size = 0;
 38.2390 -+		skb_shinfo(skb)->gso_type = 0;
 38.2391 - 	} else {
 38.2392 - 		unsigned int factor;
 38.2393 - 
 38.2394 - 		factor = skb->len + (mss_now - 1);
 38.2395 - 		factor /= mss_now;
 38.2396 --		skb_shinfo(skb)->tso_segs = factor;
 38.2397 --		skb_shinfo(skb)->tso_size = mss_now;
 38.2398 -+		skb_shinfo(skb)->gso_segs = factor;
 38.2399 -+		skb_shinfo(skb)->gso_size = mss_now;
 38.2400 -+		skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
 38.2401 - 	}
 38.2402 - }
 38.2403 - 
 38.2404 -@@ -850,7 +852,7 @@ static int tcp_init_tso_segs(struct sock
 38.2405 - 
 38.2406 - 	if (!tso_segs ||
 38.2407 - 	    (tso_segs > 1 &&
 38.2408 --	     skb_shinfo(skb)->tso_size != mss_now)) {
 38.2409 -+	     tcp_skb_mss(skb) != mss_now)) {
 38.2410 - 		tcp_set_skb_tso_segs(sk, skb, mss_now);
 38.2411 - 		tso_segs = tcp_skb_pcount(skb);
 38.2412 - 	}
 38.2413 -@@ -1510,8 +1512,9 @@ int tcp_retransmit_skb(struct sock *sk, 
 38.2414 - 	   tp->snd_una == (TCP_SKB_CB(skb)->end_seq - 1)) {
 38.2415 - 		if (!pskb_trim(skb, 0)) {
 38.2416 - 			TCP_SKB_CB(skb)->seq = TCP_SKB_CB(skb)->end_seq - 1;
 38.2417 --			skb_shinfo(skb)->tso_segs = 1;
 38.2418 --			skb_shinfo(skb)->tso_size = 0;
 38.2419 -+			skb_shinfo(skb)->gso_segs = 1;
 38.2420 -+			skb_shinfo(skb)->gso_size = 0;
 38.2421 -+			skb_shinfo(skb)->gso_type = 0;
 38.2422 - 			skb->ip_summed = CHECKSUM_NONE;
 38.2423 - 			skb->csum = 0;
 38.2424 - 		}
 38.2425 -@@ -1716,8 +1719,9 @@ void tcp_send_fin(struct sock *sk)
 38.2426 - 		skb->csum = 0;
 38.2427 - 		TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_FIN);
 38.2428 - 		TCP_SKB_CB(skb)->sacked = 0;
 38.2429 --		skb_shinfo(skb)->tso_segs = 1;
 38.2430 --		skb_shinfo(skb)->tso_size = 0;
 38.2431 -+		skb_shinfo(skb)->gso_segs = 1;
 38.2432 -+		skb_shinfo(skb)->gso_size = 0;
 38.2433 -+		skb_shinfo(skb)->gso_type = 0;
 38.2434 - 
 38.2435 - 		/* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */
 38.2436 - 		TCP_SKB_CB(skb)->seq = tp->write_seq;
 38.2437 -@@ -1749,8 +1753,9 @@ void tcp_send_active_reset(struct sock *
 38.2438 - 	skb->csum = 0;
 38.2439 - 	TCP_SKB_CB(skb)->flags = (TCPCB_FLAG_ACK | TCPCB_FLAG_RST);
 38.2440 - 	TCP_SKB_CB(skb)->sacked = 0;
 38.2441 --	skb_shinfo(skb)->tso_segs = 1;
 38.2442 --	skb_shinfo(skb)->tso_size = 0;
 38.2443 -+	skb_shinfo(skb)->gso_segs = 1;
 38.2444 -+	skb_shinfo(skb)->gso_size = 0;
 38.2445 -+	skb_shinfo(skb)->gso_type = 0;
 38.2446 - 
 38.2447 - 	/* Send it off. */
 38.2448 - 	TCP_SKB_CB(skb)->seq = tcp_acceptable_seq(sk, tp);
 38.2449 -@@ -1833,8 +1838,9 @@ struct sk_buff * tcp_make_synack(struct 
 38.2450 - 	TCP_SKB_CB(skb)->seq = tcp_rsk(req)->snt_isn;
 38.2451 - 	TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1;
 38.2452 - 	TCP_SKB_CB(skb)->sacked = 0;
 38.2453 --	skb_shinfo(skb)->tso_segs = 1;
 38.2454 --	skb_shinfo(skb)->tso_size = 0;
 38.2455 -+	skb_shinfo(skb)->gso_segs = 1;
 38.2456 -+	skb_shinfo(skb)->gso_size = 0;
 38.2457 -+	skb_shinfo(skb)->gso_type = 0;
 38.2458 - 	th->seq = htonl(TCP_SKB_CB(skb)->seq);
 38.2459 - 	th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);
 38.2460 - 	if (req->rcv_wnd == 0) { /* ignored for retransmitted syns */
 38.2461 -@@ -1937,8 +1943,9 @@ int tcp_connect(struct sock *sk)
 38.2462 - 	TCP_SKB_CB(buff)->flags = TCPCB_FLAG_SYN;
 38.2463 - 	TCP_ECN_send_syn(sk, tp, buff);
 38.2464 - 	TCP_SKB_CB(buff)->sacked = 0;
 38.2465 --	skb_shinfo(buff)->tso_segs = 1;
 38.2466 --	skb_shinfo(buff)->tso_size = 0;
 38.2467 -+	skb_shinfo(buff)->gso_segs = 1;
 38.2468 -+	skb_shinfo(buff)->gso_size = 0;
 38.2469 -+	skb_shinfo(buff)->gso_type = 0;
 38.2470 - 	buff->csum = 0;
 38.2471 - 	TCP_SKB_CB(buff)->seq = tp->write_seq++;
 38.2472 - 	TCP_SKB_CB(buff)->end_seq = tp->write_seq;
 38.2473 -@@ -2042,8 +2049,9 @@ void tcp_send_ack(struct sock *sk)
 38.2474 - 		buff->csum = 0;
 38.2475 - 		TCP_SKB_CB(buff)->flags = TCPCB_FLAG_ACK;
 38.2476 - 		TCP_SKB_CB(buff)->sacked = 0;
 38.2477 --		skb_shinfo(buff)->tso_segs = 1;
 38.2478 --		skb_shinfo(buff)->tso_size = 0;
 38.2479 -+		skb_shinfo(buff)->gso_segs = 1;
 38.2480 -+		skb_shinfo(buff)->gso_size = 0;
 38.2481 -+		skb_shinfo(buff)->gso_type = 0;
 38.2482 - 
 38.2483 - 		/* Send it off, this clears delayed acks for us. */
 38.2484 - 		TCP_SKB_CB(buff)->seq = TCP_SKB_CB(buff)->end_seq = tcp_acceptable_seq(sk, tp);
 38.2485 -@@ -2078,8 +2086,9 @@ static int tcp_xmit_probe_skb(struct soc
 38.2486 - 	skb->csum = 0;
 38.2487 - 	TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK;
 38.2488 - 	TCP_SKB_CB(skb)->sacked = urgent;
 38.2489 --	skb_shinfo(skb)->tso_segs = 1;
 38.2490 --	skb_shinfo(skb)->tso_size = 0;
 38.2491 -+	skb_shinfo(skb)->gso_segs = 1;
 38.2492 -+	skb_shinfo(skb)->gso_size = 0;
 38.2493 -+	skb_shinfo(skb)->gso_type = 0;
 38.2494 - 
 38.2495 - 	/* Use a previous sequence.  This should cause the other
 38.2496 - 	 * end to send an ack.  Don't queue or clone SKB, just
 38.2497 -diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
 38.2498 -index 32ad229..737c1db 100644
 38.2499 ---- a/net/ipv4/xfrm4_output.c
 38.2500 -+++ b/net/ipv4/xfrm4_output.c
 38.2501 -@@ -9,6 +9,8 @@
 38.2502 -  */
 38.2503 - 
 38.2504 - #include <linux/compiler.h>
 38.2505 -+#include <linux/if_ether.h>
 38.2506 -+#include <linux/kernel.h>
 38.2507 - #include <linux/skbuff.h>
 38.2508 - #include <linux/spinlock.h>
 38.2509 - #include <linux/netfilter_ipv4.h>
 38.2510 -@@ -152,16 +154,10 @@ error_nolock:
 38.2511 - 	goto out_exit;
 38.2512 - }
 38.2513 - 
 38.2514 --static int xfrm4_output_finish(struct sk_buff *skb)
 38.2515 -+static int xfrm4_output_finish2(struct sk_buff *skb)
 38.2516 - {
 38.2517 - 	int err;
 38.2518 - 
 38.2519 --#ifdef CONFIG_NETFILTER
 38.2520 --	if (!skb->dst->xfrm) {
 38.2521 --		IPCB(skb)->flags |= IPSKB_REROUTED;
 38.2522 --		return dst_output(skb);
 38.2523 --	}
 38.2524 --#endif
 38.2525 - 	while (likely((err = xfrm4_output_one(skb)) == 0)) {
 38.2526 - 		nf_reset(skb);
 38.2527 - 
 38.2528 -@@ -174,7 +170,7 @@ #endif
 38.2529 - 			return dst_output(skb);
 38.2530 - 
 38.2531 - 		err = nf_hook(PF_INET, NF_IP_POST_ROUTING, &skb, NULL,
 38.2532 --			      skb->dst->dev, xfrm4_output_finish);
 38.2533 -+			      skb->dst->dev, xfrm4_output_finish2);
 38.2534 - 		if (unlikely(err != 1))
 38.2535 - 			break;
 38.2536 - 	}
 38.2537 -@@ -182,6 +178,48 @@ #endif
 38.2538 - 	return err;
 38.2539 - }
 38.2540 - 
 38.2541 -+static int xfrm4_output_finish(struct sk_buff *skb)
 38.2542 -+{
 38.2543 -+	struct sk_buff *segs;
 38.2544 -+
 38.2545 -+#ifdef CONFIG_NETFILTER
 38.2546 -+	if (!skb->dst->xfrm) {
 38.2547 -+		IPCB(skb)->flags |= IPSKB_REROUTED;
 38.2548 -+		return dst_output(skb);
 38.2549 -+	}
 38.2550 -+#endif
 38.2551 -+
 38.2552 -+	if (!skb_shinfo(skb)->gso_size)
 38.2553 -+		return xfrm4_output_finish2(skb);
 38.2554 -+
 38.2555 -+	skb->protocol = htons(ETH_P_IP);
 38.2556 -+	segs = skb_gso_segment(skb, 0);
 38.2557 -+	kfree_skb(skb);
 38.2558 -+	if (unlikely(IS_ERR(segs)))
 38.2559 -+		return PTR_ERR(segs);
 38.2560 -+
 38.2561 -+	do {
 38.2562 -+		struct sk_buff *nskb = segs->next;
 38.2563 -+		int err;
 38.2564 -+
 38.2565 -+		segs->next = NULL;
 38.2566 -+		err = xfrm4_output_finish2(segs);
 38.2567 -+
 38.2568 -+		if (unlikely(err)) {
 38.2569 -+			while ((segs = nskb)) {
 38.2570 -+				nskb = segs->next;
 38.2571 -+				segs->next = NULL;
 38.2572 -+				kfree_skb(segs);
 38.2573 -+			}
 38.2574 -+			return err;
 38.2575 -+		}
 38.2576 -+
 38.2577 -+		segs = nskb;
 38.2578 -+	} while (segs);
 38.2579 -+
 38.2580 -+	return 0;
 38.2581 -+}
 38.2582 -+
 38.2583 - int xfrm4_output(struct sk_buff *skb)
 38.2584 - {
 38.2585 - 	return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
 38.2586 -diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
 38.2587 -index 5bf70b1..cf5d17e 100644
 38.2588 ---- a/net/ipv6/ip6_output.c
 38.2589 -+++ b/net/ipv6/ip6_output.c
 38.2590 -@@ -147,7 +147,7 @@ static int ip6_output2(struct sk_buff *s
 38.2591 - 
 38.2592 - int ip6_output(struct sk_buff *skb)
 38.2593 - {
 38.2594 --	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->ufo_size) ||
 38.2595 -+	if ((skb->len > dst_mtu(skb->dst) && !skb_shinfo(skb)->gso_size) ||
 38.2596 - 				dst_allfrag(skb->dst))
 38.2597 - 		return ip6_fragment(skb, ip6_output2);
 38.2598 - 	else
 38.2599 -@@ -829,8 +829,9 @@ static inline int ip6_ufo_append_data(st
 38.2600 - 		struct frag_hdr fhdr;
 38.2601 - 
 38.2602 - 		/* specify the length of each IP datagram fragment*/
 38.2603 --		skb_shinfo(skb)->ufo_size = (mtu - fragheaderlen) - 
 38.2604 --						sizeof(struct frag_hdr);
 38.2605 -+		skb_shinfo(skb)->gso_size = mtu - fragheaderlen - 
 38.2606 -+					    sizeof(struct frag_hdr);
 38.2607 -+		skb_shinfo(skb)->gso_type = SKB_GSO_UDPV4;
 38.2608 - 		ipv6_select_ident(skb, &fhdr);
 38.2609 - 		skb_shinfo(skb)->ip6_frag_id = fhdr.identification;
 38.2610 - 		__skb_queue_tail(&sk->sk_write_queue, skb);
 38.2611 -diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
 38.2612 -index d511a88..ef56d5d 100644
 38.2613 ---- a/net/ipv6/ipcomp6.c
 38.2614 -+++ b/net/ipv6/ipcomp6.c
 38.2615 -@@ -64,7 +64,7 @@ static LIST_HEAD(ipcomp6_tfms_list);
 38.2616 - 
 38.2617 - static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
 38.2618 - {
 38.2619 --	int err = 0;
 38.2620 -+	int err = -ENOMEM;
 38.2621 - 	u8 nexthdr = 0;
 38.2622 - 	int hdr_len = skb->h.raw - skb->nh.raw;
 38.2623 - 	unsigned char *tmp_hdr = NULL;
 38.2624 -@@ -75,11 +75,8 @@ static int ipcomp6_input(struct xfrm_sta
 38.2625 - 	struct crypto_tfm *tfm;
 38.2626 - 	int cpu;
 38.2627 - 
 38.2628 --	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 38.2629 --		skb_linearize(skb, GFP_ATOMIC) != 0) {
 38.2630 --		err = -ENOMEM;
 38.2631 -+	if (skb_linearize_cow(skb))
 38.2632 - 		goto out;
 38.2633 --	}
 38.2634 - 
 38.2635 - 	skb->ip_summed = CHECKSUM_NONE;
 38.2636 - 
 38.2637 -@@ -158,10 +155,8 @@ static int ipcomp6_output(struct xfrm_st
 38.2638 - 		goto out_ok;
 38.2639 - 	}
 38.2640 - 
 38.2641 --	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
 38.2642 --		skb_linearize(skb, GFP_ATOMIC) != 0) {
 38.2643 -+	if (skb_linearize_cow(skb))
 38.2644 - 		goto out_ok;
 38.2645 --	}
 38.2646 - 
 38.2647 - 	/* compression */
 38.2648 - 	plen = skb->len - hdr_len;
 38.2649 -diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
 38.2650 -index 8024217..39bdeec 100644
 38.2651 ---- a/net/ipv6/xfrm6_output.c
 38.2652 -+++ b/net/ipv6/xfrm6_output.c
 38.2653 -@@ -151,7 +151,7 @@ error_nolock:
 38.2654 - 	goto out_exit;
 38.2655 - }
 38.2656 - 
 38.2657 --static int xfrm6_output_finish(struct sk_buff *skb)
 38.2658 -+static int xfrm6_output_finish2(struct sk_buff *skb)
 38.2659 - {
 38.2660 - 	int err;
 38.2661 - 
 38.2662 -@@ -167,7 +167,7 @@ static int xfrm6_output_finish(struct sk
 38.2663 - 			return dst_output(skb);
 38.2664 - 
 38.2665 - 		err = nf_hook(PF_INET6, NF_IP6_POST_ROUTING, &skb, NULL,
 38.2666 --			      skb->dst->dev, xfrm6_output_finish);
 38.2667 -+			      skb->dst->dev, xfrm6_output_finish2);
 38.2668 - 		if (unlikely(err != 1))
 38.2669 - 			break;
 38.2670 - 	}
 38.2671 -@@ -175,6 +175,41 @@ static int xfrm6_output_finish(struct sk
 38.2672 - 	return err;
 38.2673 - }
 38.2674 - 
 38.2675 -+static int xfrm6_output_finish(struct sk_buff *skb)
 38.2676 -+{
 38.2677 -+	struct sk_buff *segs;
 38.2678 -+
 38.2679 -+	if (!skb_shinfo(skb)->gso_size)
 38.2680 -+		return xfrm6_output_finish2(skb);
 38.2681 -+
 38.2682 -+	skb->protocol = htons(ETH_P_IP);
 38.2683 -+	segs = skb_gso_segment(skb, 0);
 38.2684 -+	kfree_skb(skb);
 38.2685 -+	if (unlikely(IS_ERR(segs)))
 38.2686 -+		return PTR_ERR(segs);
 38.2687 -+
 38.2688 -+	do {
 38.2689 -+		struct sk_buff *nskb = segs->next;
 38.2690 -+		int err;
 38.2691 -+
 38.2692 -+		segs->next = NULL;
 38.2693 -+		err = xfrm6_output_finish2(segs);
 38.2694 -+
 38.2695 -+		if (unlikely(err)) {
 38.2696 -+			while ((segs = nskb)) {
 38.2697 -+				nskb = segs->next;
 38.2698 -+				segs->next = NULL;
 38.2699 -+				kfree_skb(segs);
 38.2700 -+			}
 38.2701 -+			return err;
 38.2702 -+		}
 38.2703 -+
 38.2704 -+		segs = nskb;
 38.2705 -+	} while (segs);
 38.2706 -+
 38.2707 -+	return 0;
 38.2708 -+}
 38.2709 -+
 38.2710 - int xfrm6_output(struct sk_buff *skb)
 38.2711 - {
 38.2712 - 	return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
 38.2713 -diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
 38.2714 -index 99ceb91..28c9efd 100644
 38.2715 ---- a/net/sched/sch_generic.c
 38.2716 -+++ b/net/sched/sch_generic.c
 38.2717 -@@ -72,9 +72,9 @@ void qdisc_unlock_tree(struct net_device
 38.2718 -    dev->queue_lock serializes queue accesses for this device
 38.2719 -    AND dev->qdisc pointer itself.
 38.2720 - 
 38.2721 --   dev->xmit_lock serializes accesses to device driver.
 38.2722 -+   netif_tx_lock serializes accesses to device driver.
 38.2723 - 
 38.2724 --   dev->queue_lock and dev->xmit_lock are mutually exclusive,
 38.2725 -+   dev->queue_lock and netif_tx_lock are mutually exclusive,
 38.2726 -    if one is grabbed, another must be free.
 38.2727 -  */
 38.2728 - 
 38.2729 -@@ -90,14 +90,17 @@ void qdisc_unlock_tree(struct net_device
 38.2730 -    NOTE: Called under dev->queue_lock with locally disabled BH.
 38.2731 - */
 38.2732 - 
 38.2733 --int qdisc_restart(struct net_device *dev)
 38.2734 -+static inline int qdisc_restart(struct net_device *dev)
 38.2735 - {
 38.2736 - 	struct Qdisc *q = dev->qdisc;
 38.2737 - 	struct sk_buff *skb;
 38.2738 - 
 38.2739 - 	/* Dequeue packet */
 38.2740 --	if ((skb = q->dequeue(q)) != NULL) {
 38.2741 -+	if (((skb = dev->gso_skb)) || ((skb = q->dequeue(q)))) {
 38.2742 - 		unsigned nolock = (dev->features & NETIF_F_LLTX);
 38.2743 -+
 38.2744 -+		dev->gso_skb = NULL;
 38.2745 -+
 38.2746 - 		/*
 38.2747 - 		 * When the driver has LLTX set it does its own locking
 38.2748 - 		 * in start_xmit. No need to add additional overhead by
 38.2749 -@@ -108,7 +111,7 @@ int qdisc_restart(struct net_device *dev
 38.2750 - 		 * will be requeued.
 38.2751 - 		 */
 38.2752 - 		if (!nolock) {
 38.2753 --			if (!spin_trylock(&dev->xmit_lock)) {
 38.2754 -+			if (!netif_tx_trylock(dev)) {
 38.2755 - 			collision:
 38.2756 - 				/* So, someone grabbed the driver. */
 38.2757 - 				
 38.2758 -@@ -126,8 +129,6 @@ int qdisc_restart(struct net_device *dev
 38.2759 - 				__get_cpu_var(netdev_rx_stat).cpu_collision++;
 38.2760 - 				goto requeue;
 38.2761 - 			}
 38.2762 --			/* Remember that the driver is grabbed by us. */
 38.2763 --			dev->xmit_lock_owner = smp_processor_id();
 38.2764 - 		}
 38.2765 - 		
 38.2766 - 		{
 38.2767 -@@ -136,14 +137,11 @@ int qdisc_restart(struct net_device *dev
 38.2768 - 
 38.2769 - 			if (!netif_queue_stopped(dev)) {
 38.2770 - 				int ret;
 38.2771 --				if (netdev_nit)
 38.2772 --					dev_queue_xmit_nit(skb, dev);
 38.2773 - 
 38.2774 --				ret = dev->hard_start_xmit(skb, dev);
 38.2775 -+				ret = dev_hard_start_xmit(skb, dev);
 38.2776 - 				if (ret == NETDEV_TX_OK) { 
 38.2777 - 					if (!nolock) {
 38.2778 --						dev->xmit_lock_owner = -1;
 38.2779 --						spin_unlock(&dev->xmit_lock);
 38.2780 -+						netif_tx_unlock(dev);
 38.2781 - 					}
 38.2782 - 					spin_lock(&dev->queue_lock);
 38.2783 - 					return -1;
 38.2784 -@@ -157,8 +155,7 @@ int qdisc_restart(struct net_device *dev
 38.2785 - 			/* NETDEV_TX_BUSY - we need to requeue */
 38.2786 - 			/* Release the driver */
 38.2787 - 			if (!nolock) { 
 38.2788 --				dev->xmit_lock_owner = -1;
 38.2789 --				spin_unlock(&dev->xmit_lock);
 38.2790 -+				netif_tx_unlock(dev);
 38.2791 - 			} 
 38.2792 - 			spin_lock(&dev->queue_lock);
 38.2793 - 			q = dev->qdisc;
 38.2794 -@@ -175,7 +172,10 @@ int qdisc_restart(struct net_device *dev
 38.2795 - 		 */
 38.2796 - 
 38.2797 - requeue:
 38.2798 --		q->ops->requeue(skb, q);
 38.2799 -+		if (skb->next)
 38.2800 -+			dev->gso_skb = skb;
 38.2801 -+		else
 38.2802 -+			q->ops->requeue(skb, q);
 38.2803 - 		netif_schedule(dev);
 38.2804 - 		return 1;
 38.2805 - 	}
 38.2806 -@@ -183,11 +183,23 @@ requeue:
 38.2807 - 	return q->q.qlen;
 38.2808 - }
 38.2809 - 
 38.2810 -+void __qdisc_run(struct net_device *dev)
 38.2811 -+{
 38.2812 -+	if (unlikely(dev->qdisc == &noop_qdisc))
 38.2813 -+		goto out;
 38.2814 -+
 38.2815 -+	while (qdisc_restart(dev) < 0 && !netif_queue_stopped(dev))
 38.2816 -+		/* NOTHING */;
 38.2817 -+
 38.2818 -+out:
 38.2819 -+	clear_bit(__LINK_STATE_QDISC_RUNNING, &dev->state);
 38.2820 -+}
 38.2821 -+
 38.2822 - static void dev_watchdog(unsigned long arg)
 38.2823 - {
 38.2824 - 	struct net_device *dev = (struct net_device *)arg;
 38.2825 - 
 38.2826 --	spin_lock(&dev->xmit_lock);
 38.2827 -+	netif_tx_lock(dev);
 38.2828 - 	if (dev->qdisc != &noop_qdisc) {
 38.2829 - 		if (netif_device_present(dev) &&
 38.2830 - 		    netif_running(dev) &&
 38.2831 -@@ -201,7 +213,7 @@ static void dev_watchdog(unsigned long a
 38.2832 - 				dev_hold(dev);
 38.2833 - 		}
 38.2834 - 	}
 38.2835 --	spin_unlock(&dev->xmit_lock);
 38.2836 -+	netif_tx_unlock(dev);
 38.2837 - 
 38.2838 - 	dev_put(dev);
 38.2839 - }
 38.2840 -@@ -225,17 +237,17 @@ void __netdev_watchdog_up(struct net_dev
 38.2841 - 
 38.2842 - static void dev_watchdog_up(struct net_device *dev)
 38.2843 - {
 38.2844 --	spin_lock_bh(&dev->xmit_lock);
 38.2845 -+	netif_tx_lock_bh(dev);
 38.2846 - 	__netdev_watchdog_up(dev);
 38.2847 --	spin_unlock_bh(&dev->xmit_lock);
 38.2848 -+	netif_tx_unlock_bh(dev);
 38.2849 - }
 38.2850 - 
 38.2851 - static void dev_watchdog_down(struct net_device *dev)
 38.2852 - {
 38.2853 --	spin_lock_bh(&dev->xmit_lock);
 38.2854 -+	netif_tx_lock_bh(dev);
 38.2855 - 	if (del_timer(&dev->watchdog_timer))
 38.2856 - 		__dev_put(dev);
 38.2857 --	spin_unlock_bh(&dev->xmit_lock);
 38.2858 -+	netif_tx_unlock_bh(dev);
 38.2859 - }
 38.2860 - 
 38.2861 - void netif_carrier_on(struct net_device *dev)
 38.2862 -@@ -577,10 +589,17 @@ void dev_deactivate(struct net_device *d
 38.2863 - 
 38.2864 - 	dev_watchdog_down(dev);
 38.2865 - 
 38.2866 --	while (test_bit(__LINK_STATE_SCHED, &dev->state))
 38.2867 -+	/* Wait for outstanding dev_queue_xmit calls. */
 38.2868 -+	synchronize_rcu();
 38.2869 -+
 38.2870 -+	/* Wait for outstanding qdisc_run calls. */
 38.2871 -+	while (test_bit(__LINK_STATE_QDISC_RUNNING, &dev->state))
 38.2872 - 		yield();
 38.2873 - 
 38.2874 --	spin_unlock_wait(&dev->xmit_lock);
 38.2875 -+	if (dev->gso_skb) {
 38.2876 -+		kfree_skb(dev->gso_skb);
 38.2877 -+		dev->gso_skb = NULL;
 38.2878 -+	}
 38.2879 - }
 38.2880 - 
 38.2881 - void dev_init_scheduler(struct net_device *dev)
 38.2882 -@@ -622,6 +641,5 @@ EXPORT_SYMBOL(qdisc_create_dflt);
 38.2883 - EXPORT_SYMBOL(qdisc_alloc);
 38.2884 - EXPORT_SYMBOL(qdisc_destroy);
 38.2885 - EXPORT_SYMBOL(qdisc_reset);
 38.2886 --EXPORT_SYMBOL(qdisc_restart);
 38.2887 - EXPORT_SYMBOL(qdisc_lock_tree);
 38.2888 - EXPORT_SYMBOL(qdisc_unlock_tree);
 38.2889 -diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c
 38.2890 -index 79b8ef3..4c16ad5 100644
 38.2891 ---- a/net/sched/sch_teql.c
 38.2892 -+++ b/net/sched/sch_teql.c
 38.2893 -@@ -302,20 +302,17 @@ restart:
 38.2894 - 
 38.2895 - 		switch (teql_resolve(skb, skb_res, slave)) {
 38.2896 - 		case 0:
 38.2897 --			if (spin_trylock(&slave->xmit_lock)) {
 38.2898 --				slave->xmit_lock_owner = smp_processor_id();
 38.2899 -+			if (netif_tx_trylock(slave)) {
 38.2900 - 				if (!netif_queue_stopped(slave) &&
 38.2901 - 				    slave->hard_start_xmit(skb, slave) == 0) {
 38.2902 --					slave->xmit_lock_owner = -1;
 38.2903 --					spin_unlock(&slave->xmit_lock);
 38.2904 -+					netif_tx_unlock(slave);
 38.2905 - 					master->slaves = NEXT_SLAVE(q);
 38.2906 - 					netif_wake_queue(dev);
 38.2907 - 					master->stats.tx_packets++;
 38.2908 - 					master->stats.tx_bytes += len;
 38.2909 - 					return 0;
 38.2910 - 				}
 38.2911 --				slave->xmit_lock_owner = -1;
 38.2912 --				spin_unlock(&slave->xmit_lock);
 38.2913 -+				netif_tx_unlock(slave);
 38.2914 - 			}
 38.2915 - 			if (netif_queue_stopped(dev))
 38.2916 - 				busy = 1;
    39.1 --- a/patches/linux-2.6.16.13/xenoprof-generic.patch	Tue Jul 25 09:51:50 2006 -0600
    39.2 +++ b/patches/linux-2.6.16.13/xenoprof-generic.patch	Tue Jul 25 12:19:05 2006 -0600
    39.3 @@ -1,6 +1,6 @@
    39.4 -diff -pru ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.c ./drivers/oprofile/buffer_sync.c
    39.5 ---- ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.c	2006-05-03 05:38:44.000000000 +0800
    39.6 -+++ ./drivers/oprofile/buffer_sync.c	2006-06-27 12:14:53.000000000 +0800
    39.7 +diff -Naur orig/drivers/oprofile/buffer_sync.c new/drivers/oprofile/buffer_sync.c
    39.8 +--- orig/drivers/oprofile/buffer_sync.c	2006-05-02 14:38:44.000000000 -0700
    39.9 ++++ new/drivers/oprofile/buffer_sync.c	2006-07-06 18:19:05.000000000 -0700
   39.10  @@ -6,6 +6,10 @@
   39.11    *
   39.12    * @author John Levon <levon@movementarian.org>
   39.13 @@ -12,7 +12,7 @@ diff -pru ../pristine-linux-2.6.16.13/dr
   39.14    * This is the core of the buffer management. Each
   39.15    * CPU buffer is processed and entered into the
   39.16    * global event buffer. Such processing is necessary
   39.17 -@@ -275,15 +279,30 @@ static void add_cpu_switch(int i)
   39.18 +@@ -275,15 +279,31 @@
   39.19   	last_cookie = INVALID_COOKIE;
   39.20   }
   39.21   
   39.22 @@ -34,22 +34,23 @@ diff -pru ../pristine-linux-2.6.16.13/dr
   39.23  +	case CPU_MODE_XEN:
   39.24  +		add_event_entry(XEN_ENTER_SWITCH_CODE);
   39.25  +	  	break;
   39.26 -+        case CPU_MODE_PASSIVE_START:
   39.27 -+                add_event_entry(PASSIVE_START_CODE);
   39.28 -+                break;
   39.29 -+        case CPU_MODE_PASSIVE_STOP:
   39.30 -+                add_event_entry(PASSIVE_STOP_CODE);
   39.31 -+                break;
   39.32  +	default:
   39.33  +		break;
   39.34  +	}
   39.35   }
   39.36  - 
   39.37  +
   39.38 ++static void add_domain_switch(unsigned long domain_id)
   39.39 ++{
   39.40 ++	add_event_entry(ESCAPE_CODE);
   39.41 ++	add_event_entry(DOMAIN_SWITCH_CODE);
   39.42 ++	add_event_entry(domain_id);
   39.43 ++}
   39.44 ++
   39.45   static void
   39.46   add_user_ctx_switch(struct task_struct const * task, unsigned long cookie)
   39.47   {
   39.48 -@@ -348,9 +367,9 @@ static int add_us_sample(struct mm_struc
   39.49 +@@ -348,9 +368,9 @@
   39.50    * for later lookup from userspace.
   39.51    */
   39.52   static int
   39.53 @@ -61,7 +62,7 @@ diff -pru ../pristine-linux-2.6.16.13/dr
   39.54   		add_sample_entry(s->eip, s->event);
   39.55   		return 1;
   39.56   	} else if (mm) {
   39.57 -@@ -496,10 +515,11 @@ void sync_buffer(int cpu)
   39.58 +@@ -496,10 +516,11 @@
   39.59   	struct mm_struct *mm = NULL;
   39.60   	struct task_struct * new;
   39.61   	unsigned long cookie = 0;
   39.62 @@ -70,34 +71,35 @@ diff -pru ../pristine-linux-2.6.16.13/dr
   39.63   	unsigned int i;
   39.64   	sync_buffer_state state = sb_buffer_start;
   39.65   	unsigned long available;
   39.66 -+	int domain_switch = NO_DOMAIN_SWITCH;
   39.67 ++	int domain_switch = 0;
   39.68   
   39.69   	down(&buffer_sem);
   39.70    
   39.71 -@@ -513,12 +533,19 @@ void sync_buffer(int cpu)
   39.72 +@@ -512,16 +533,18 @@
   39.73 + 	for (i = 0; i < available; ++i) {
   39.74   		struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
   39.75    
   39.76 - 		if (is_code(s->eip)) {
   39.77 +-		if (is_code(s->eip)) {
   39.78  -			if (s->event <= CPU_IS_KERNEL) {
   39.79 -+			if (s->event < CPU_TRACE_BEGIN) {
   39.80 - 				/* kernel/userspace switch */
   39.81 +-				/* kernel/userspace switch */
   39.82  -				in_kernel = s->event;
   39.83 ++		if (is_code(s->eip) && !domain_switch) {
   39.84 ++			if (s->event <= CPU_MODE_XEN) {
   39.85 ++				/* xen/kernel/userspace switch */
   39.86  +				cpu_mode = s->event;
   39.87   				if (state == sb_buffer_start)
   39.88   					state = sb_sample_start;
   39.89  -				add_kernel_ctx_switch(s->event);
   39.90 -+
   39.91 -+				if (s->event == CPU_MODE_PASSIVE_START)
   39.92 -+					domain_switch = DOMAIN_SWITCH_START_EVENT1;
   39.93 -+				else if (s->event == CPU_MODE_PASSIVE_STOP)
   39.94 -+					domain_switch = DOMAIN_SWITCH_STOP_EVENT1;
   39.95 -+
   39.96 -+				if (domain_switch != DOMAIN_SWITCH_START_EVENT2)
   39.97 -+					add_cpu_mode_switch(s->event);
   39.98 ++				add_cpu_mode_switch(s->event);
   39.99   			} else if (s->event == CPU_TRACE_BEGIN) {
  39.100   				state = sb_bt_start;
  39.101   				add_trace_begin();
  39.102 -@@ -535,11 +562,20 @@ void sync_buffer(int cpu)
  39.103 ++			} else if (s->event == CPU_DOMAIN_SWITCH) {
  39.104 ++					domain_switch = 1;				
  39.105 + 			} else {
  39.106 + 				struct mm_struct * oldmm = mm;
  39.107 + 
  39.108 +@@ -535,11 +558,16 @@
  39.109   				add_user_ctx_switch(new, cookie);
  39.110   			}
  39.111   		} else {
  39.112 @@ -106,13 +108,9 @@ diff -pru ../pristine-linux-2.6.16.13/dr
  39.113  -				if (state == sb_bt_start) {
  39.114  -					state = sb_bt_ignore;
  39.115  -					atomic_inc(&oprofile_stats.bt_lost_no_mapping);
  39.116 -+			if (domain_switch == DOMAIN_SWITCH_START_EVENT1) {
  39.117 -+			        add_event_entry(s->event);
  39.118 -+				domain_switch = DOMAIN_SWITCH_START_EVENT2;
  39.119 -+			} else if (domain_switch == DOMAIN_SWITCH_START_EVENT1) {
  39.120 -+				add_sample_entry(s->eip, s->event);
  39.121 -+			} else if (domain_switch == DOMAIN_SWITCH_STOP_EVENT1) {
  39.122 -+				domain_switch = NO_DOMAIN_SWITCH;
  39.123 ++			if (domain_switch) {
  39.124 ++				add_domain_switch(s->eip);
  39.125 ++				domain_switch = 0;
  39.126  +			} else {
  39.127  +				if (state >= sb_bt_start &&
  39.128  +				    !add_sample(mm, s, cpu_mode)) {
  39.129 @@ -123,24 +121,9 @@ diff -pru ../pristine-linux-2.6.16.13/dr
  39.130   				}
  39.131   			}
  39.132   		}
  39.133 -diff -pru ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.h ./drivers/oprofile/buffer_sync.h
  39.134 ---- ../pristine-linux-2.6.16.13/drivers/oprofile/buffer_sync.h	2006-05-03 05:38:44.000000000 +0800
  39.135 -+++ ./drivers/oprofile/buffer_sync.h	2006-06-27 12:12:09.000000000 +0800
  39.136 -@@ -9,6 +9,11 @@
  39.137 - 
  39.138 - #ifndef OPROFILE_BUFFER_SYNC_H
  39.139 - #define OPROFILE_BUFFER_SYNC_H
  39.140 -+
  39.141 -+#define NO_DOMAIN_SWITCH		-1
  39.142 -+#define DOMAIN_SWITCH_START_EVENT1	0
  39.143 -+#define DOMAIN_SWITCH_START_EVENT2	1
  39.144 -+#define DOMAIN_SWITCH_STOP_EVENT1	2
  39.145 -  
  39.146 - /* add the necessary profiling hooks */
  39.147 - int sync_start(void);
  39.148 -diff -pru ../pristine-linux-2.6.16.13/drivers/oprofile/cpu_buffer.c ./drivers/oprofile/cpu_buffer.c
  39.149 ---- ../pristine-linux-2.6.16.13/drivers/oprofile/cpu_buffer.c	2006-05-03 05:38:44.000000000 +0800
  39.150 -+++ ./drivers/oprofile/cpu_buffer.c	2006-06-19 22:43:53.000000000 +0800
  39.151 +diff -Naur orig/drivers/oprofile/cpu_buffer.c new/drivers/oprofile/cpu_buffer.c
  39.152 +--- orig/drivers/oprofile/cpu_buffer.c	2006-05-02 14:38:44.000000000 -0700
  39.153 ++++ new/drivers/oprofile/cpu_buffer.c	2006-07-06 18:19:05.000000000 -0700
  39.154  @@ -6,6 +6,10 @@
  39.155    *
  39.156    * @author John Levon <levon@movementarian.org>
  39.157 @@ -152,7 +135,16 @@ diff -pru ../pristine-linux-2.6.16.13/dr
  39.158    * Each CPU has a local buffer that stores PC value/event
  39.159    * pairs. We also log context switches when we notice them.
  39.160