Merge tag 'nfs-for-3.20-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Feb 2015 01:14:54 +0000 (17:14 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 12 Feb 2015 01:14:54 +0000 (17:14 -0800)
Pull NFS client updates from Trond Myklebust:
 "Highlights incluse:

  Features:
   - Removing the forced serialisation of open()/close() calls in
     NFSv4.x (x>0) makes for a significant performance improvement in
     metadata intensive workloads.
   - Full support for the pNFS "flexible files" layout type
   - Further RPC/RDMA client improvements from Chuck

  Bugfixes:
   - Stable fix: NFSv4.1 backchannel calls blocking operations with !TASK_RUNNING
   - Stable fix: pnfs_generic_pg_init_read/write can be called with lseg == NULL
   - Stable fix: Fix an Oopsable condition when nsm_mon_unmon is called
     as part of the namespace cleanup,
   - Stable fix: Ensure we reference the inode for return-on-close in
     delegreturn
   - Use SO_REUSEPORT to ensure that NFSv3 TCP connections can rebind to
     the same source address/port combination during a disconnect/
     reconnect event.  This is a requirement imposed by most NFSv3
     server duplicate reply cache implementations.

  Optimisations:
   - Ask for no NFSv4.1 delegations on OPEN if using O_DIRECT

  Other:
   - Add Anna Schumaker as co-maintainer for the NFS client"

* tag 'nfs-for-3.20-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (119 commits)
  SUNRPC: Cleanup to remove xs_tcp_close()
  pnfs: delete an unintended goto
  pnfs/flexfiles: Do not dprintk after the free
  SUNRPC: Fix stupid typo in xs_sock_set_reuseport
  SUNRPC: Define xs_tcp_fin_timeout only if CONFIG_SUNRPC_DEBUG
  SUNRPC: Handle connection reset more efficiently.
  SUNRPC: Remove the redundant XPRT_CONNECTION_CLOSE flag
  SUNRPC: Make xs_tcp_close() do a socket shutdown rather than a sock_release
  SUNRPC: Ensure xs_tcp_shutdown() requests a full close of the connection
  SUNRPC: Cleanup to remove remaining uses of XPRT_CONNECTION_ABORT
  SUNRPC: Remove TCP socket linger code
  SUNRPC: Remove TCP client connection reset hack
  SUNRPC: TCP/UDP always close the old socket before reconnecting
  SUNRPC: Add helpers to prevent socket create from racing
  SUNRPC: Ensure xs_reset_transport() resets the close connection flags
  SUNRPC: Do not clear the source port in xs_reset_transport
  SUNRPC: Handle EADDRINUSE on connect
  SUNRPC: Set SO_REUSEPORT socket option for TCP connections
  NFSv4.1: Fix pnfs_put_lseg races
  NFSv4.1: pnfs_send_layoutreturn should use GFP_NOFS
  ...

1  2 
MAINTAINERS
fs/nfs/delegation.c
fs/nfs/nfs4state.c
fs/nfs/pagelist.c
fs/nfs/write.c

diff --combined MAINTAINERS
index cc66549dd7613565b9ea906d5927c22a34413d22,b30d937c3ec8cdee88524ea77b6997747c9c5704..37c10098a6278fcbd2c30c13b662696e8497f466
@@@ -270,12 -270,12 +270,12 @@@ F:      drivers/acpi
  F:    drivers/pnp/pnpacpi/
  F:    include/linux/acpi.h
  F:    include/acpi/
 -F:    Documentation/acpi
 +F:    Documentation/acpi/
  F:    Documentation/ABI/testing/sysfs-bus-acpi
  F:    drivers/pci/*acpi*
  F:    drivers/pci/*/*acpi*
  F:    drivers/pci/*/*/*acpi*
 -F:    tools/power/acpi
 +F:    tools/power/acpi/
  
  ACPI COMPONENT ARCHITECTURE (ACPICA)
  M:    Robert Moore <robert.moore@intel.com>
@@@ -563,12 -563,6 +563,12 @@@ S:       Odd Fixe
  L:    linux-alpha@vger.kernel.org
  F:    arch/alpha/
  
 +ALTERA MAILBOX DRIVER
 +M:    Ley Foon Tan <lftan@altera.com>
 +L:    nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
 +S:    Maintained
 +F:    drivers/mailbox/mailbox-altera.c
 +
  ALTERA TRIPLE SPEED ETHERNET DRIVER
  M:    Vince Bridgers <vbridger@opensource.altera.com>
  L:    netdev@vger.kernel.org
@@@ -665,13 -659,6 +665,13 @@@ L:       linux-media@vger.kernel.or
  S:    Maintained
  F:    drivers/media/i2c/ad9389b*
  
 +ANALOG DEVICES INC ADV7180 DRIVER
 +M:    Lars-Peter Clausen <lars@metafoo.de>
 +L:    linux-media@vger.kernel.org
 +W:    http://ez.analog.com/community/linux-device-drivers
 +S:    Supported
 +F:    drivers/media/i2c/adv7180.c
 +
  ANALOG DEVICES INC ADV7511 DRIVER
  M:    Hans Verkuil <hans.verkuil@cisco.com>
  L:    linux-media@vger.kernel.org
@@@ -709,7 -696,7 +709,7 @@@ L: alsa-devel@alsa-project.org (moderat
  W:    http://blackfin.uclinux.org/
  S:    Supported
  F:    sound/soc/blackfin/*
 - 
 +
  ANALOG DEVICES INC IIO DRIVERS
  M:    Lars-Peter Clausen <lars@metafoo.de>
  M:    Michael Hennerich <Michael.Hennerich@analog.com>
@@@ -721,16 -708,6 +721,16 @@@ X:       drivers/iio/*/adjd
  F:    drivers/staging/iio/*/ad*
  F:    staging/iio/trigger/iio-trig-bfin-timer.c
  
 +ANDROID DRIVERS
 +M:    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 +M:    Arve Hjønnevåg <arve@android.com>
 +M:    Riley Andrews <riandrews@android.com>
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/gregkh/staging.git
 +L:    devel@driverdev.osuosl.org
 +S:    Supported
 +F:    drivers/android/
 +F:    drivers/staging/android/
 +
  AOA (Apple Onboard Audio) ALSA DRIVER
  M:    Johannes Berg <johannes@sipsolutions.net>
  L:    linuxppc-dev@lists.ozlabs.org
@@@ -777,6 -754,13 +777,6 @@@ L:        linux-media@vger.kernel.or
  S:    Maintained
  F:    drivers/media/i2c/aptina-pll.*
  
 -ARASAN COMPACT FLASH PATA CONTROLLER
 -M:    Viresh Kumar <viresh.linux@gmail.com>
 -L:    linux-ide@vger.kernel.org
 -S:    Maintained
 -F:    include/linux/pata_arasan_cf_data.h
 -F:    drivers/ata/pata_arasan_cf.c
 -
  ARC FRAMEBUFFER DRIVER
  M:    Jaya Kumar <jayalk@intworks.biz>
  S:    Maintained
@@@ -1599,7 -1583,6 +1599,7 @@@ N:      xilin
  F:    drivers/clocksource/cadence_ttc_timer.c
  F:    drivers/i2c/busses/i2c-cadence.c
  F:    drivers/mmc/host/sdhci-of-arasan.c
 +F:    drivers/edac/synopsys_edac.c
  
  ARM SMMU DRIVER
  M:    Will Deacon <will.deacon@arm.com>
@@@ -1674,6 -1657,7 +1674,6 @@@ M:      Jiri Slaby <jirislaby@gmail.com
  M:    Nick Kossifidis <mickflemm@gmail.com>
  M:    "Luis R. Rodriguez" <mcgrof@do-not-panic.com>
  L:    linux-wireless@vger.kernel.org
 -L:    ath5k-devel@lists.ath5k.org
  W:    http://wireless.kernel.org/en/users/Drivers/ath5k
  S:    Maintained
  F:    drivers/net/wireless/ath/ath5k/
@@@ -2362,8 -2346,7 +2362,8 @@@ CAN NETWORK LAYE
  M:    Oliver Hartkopp <socketcan@hartkopp.net>
  L:    linux-can@vger.kernel.org
  W:    http://gitorious.org/linux-can
 -T:    git git://gitorious.org/linux-can/linux-can-next.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
  S:    Maintained
  F:    Documentation/networking/can.txt
  F:    net/can/
@@@ -2378,8 -2361,7 +2378,8 @@@ M:      Wolfgang Grandegger <wg@grandegger.c
  M:    Marc Kleine-Budde <mkl@pengutronix.de>
  L:    linux-can@vger.kernel.org
  W:    http://gitorious.org/linux-can
 -T:    git git://gitorious.org/linux-can/linux-can-next.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can.git
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next.git
  S:    Maintained
  F:    drivers/net/can/
  F:    include/linux/can/dev.h
@@@ -3226,7 -3208,6 +3226,7 @@@ F:      Documentation
  X:    Documentation/ABI/
  X:    Documentation/devicetree/
  X:    Documentation/[a-z][a-z]_[A-Z][A-Z]/
 +T:    git git://git.lwn.net/linux-2.6.git docs-next
  
  DOUBLETALK DRIVER
  M:    "James R. Van Zandt" <jrv@vanzandt.mv.com>
@@@ -3486,14 -3467,6 +3486,14 @@@ M:    "Maciej W. Rozycki" <macro@linux-mip
  S:    Maintained
  F:    drivers/tty/serial/dz.*
  
 +E3X0 POWER BUTTON DRIVER
 +M:    Moritz Fischer <moritz.fischer@ettus.com>
 +L:    usrp-users@lists.ettus.com
 +W:    http://www.ettus.com
 +S:    Supported
 +F:    drivers/input/misc/e3x0-button.c
 +F:    Documentation/devicetree/bindings/input/e3x0-button.txt
 +
  E4000 MEDIA DRIVER
  M:    Antti Palosaari <crope@iki.fi>
  L:    linux-media@vger.kernel.org
@@@ -3535,8 -3508,6 +3535,8 @@@ M:      Borislav Petkov <bp@alien8.de
  M:    Mauro Carvalho Chehab <mchehab@osg.samsung.com>
  L:    linux-edac@vger.kernel.org
  W:    bluesmoke.sourceforge.net
 +T:    git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
 +T:    git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next
  S:    Supported
  F:    Documentation/edac.txt
  F:    drivers/edac/
@@@ -4784,14 -4755,14 +4784,14 @@@ S:   Supporte
  F:    drivers/net/ethernet/ibm/ibmveth.*
  
  IBM Power Virtual SCSI Device Drivers
 -M:    Nathan Fontenot <nfont@linux.vnet.ibm.com>
 +M:    Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
  L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    drivers/scsi/ibmvscsi/ibmvscsi*
  F:    drivers/scsi/ibmvscsi/viosrp.h
  
  IBM Power Virtual FC Device Drivers
 -M:    Brian King <brking@linux.vnet.ibm.com>
 +M:    Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
  L:    linux-scsi@vger.kernel.org
  S:    Supported
  F:    drivers/scsi/ibmvscsi/ibmvfc*
@@@ -4959,6 -4930,7 +4959,6 @@@ F:      include/uapi/linux/inotify.
  
  INPUT (KEYBOARD, MOUSE, JOYSTICK, TOUCHSCREEN) DRIVERS
  M:    Dmitry Torokhov <dmitry.torokhov@gmail.com>
 -M:    Dmitry Torokhov <dtor@mail.ru>
  L:    linux-input@vger.kernel.org
  Q:    http://patchwork.kernel.org/project/linux-input/list/
  T:    git git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git
@@@ -4977,19 -4949,10 +4977,19 @@@ F:   Documentation/input/multi-touch-prot
  F:    drivers/input/input-mt.c
  K:    \b(ABS|SYN)_MT_
  
 +INTEL ASoC BDW/HSW DRIVERS
 +M:    Jie Yang <yang.jie@linux.intel.com>
 +L:    alsa-devel@alsa-project.org
 +S:    Supported
 +F:    sound/soc/intel/sst-haswell*
 +F:    sound/soc/intel/sst-dsp*
 +F:    sound/soc/intel/sst-firmware.c
 +F:    sound/soc/intel/broadwell.c
 +F:    sound/soc/intel/haswell.c
 +
  INTEL C600 SERIES SAS CONTROLLER DRIVER
  M:    Intel SCU Linux support <intel-linux-scu@intel.com>
  M:    Artur Paszkiewicz <artur.paszkiewicz@intel.com>
 -M:    Dave Jiang <dave.jiang@intel.com>
  L:    linux-scsi@vger.kernel.org
  T:    git git://git.code.sf.net/p/intel-sas/isci
  S:    Supported
@@@ -5740,49 -5703,6 +5740,49 @@@ F:    drivers/lguest
  F:    include/linux/lguest*.h
  F:    tools/lguest/
  
 +LIBATA SUBSYSTEM (Serial and Parallel ATA drivers)
 +M:    Tejun Heo <tj@kernel.org>
 +L:    linux-ide@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 +S:    Maintained
 +F:    drivers/ata/
 +F:    include/linux/ata.h
 +F:    include/linux/libata.h
 +
 +LIBATA PATA ARASAN COMPACT FLASH CONTROLLER
 +M:    Viresh Kumar <viresh.linux@gmail.com>
 +L:    linux-ide@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 +S:    Maintained
 +F:    include/linux/pata_arasan_cf_data.h
 +F:    drivers/ata/pata_arasan_cf.c
 +
 +LIBATA PATA DRIVERS
 +M:    Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
 +M:    Tejun Heo <tj@kernel.org>
 +L:    linux-ide@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 +S:    Maintained
 +F:    drivers/ata/pata_*.c
 +F:    drivers/ata/ata_generic.c
 +
 +LIBATA SATA AHCI PLATFORM devices support
 +M:    Hans de Goede <hdegoede@redhat.com>
 +M:    Tejun Heo <tj@kernel.org>
 +L:    linux-ide@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 +S:    Maintained
 +F:    drivers/ata/ahci_platform.c
 +F:    drivers/ata/libahci_platform.c
 +F:    include/linux/ahci_platform.h
 +
 +LIBATA SATA PROMISE TX2/TX4 CONTROLLER DRIVER
 +M:    Mikael Pettersson <mikpelinux@gmail.com>
 +L:    linux-ide@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 +S:    Maintained
 +F:    drivers/ata/sata_promise.*
 +
  LIBLOCKDEP
  M:    Sasha Levin <sasha.levin@oracle.com>
  S:    Maintained
@@@ -5874,21 -5794,6 +5874,21 @@@ F:    Documentation/misc-devices/lis3lv02
  F:    drivers/misc/lis3lv02d/
  F:    drivers/platform/x86/hp_accel.c
  
 +LIVE PATCHING
 +M:    Josh Poimboeuf <jpoimboe@redhat.com>
 +M:    Seth Jennings <sjenning@redhat.com>
 +M:    Jiri Kosina <jkosina@suse.cz>
 +M:    Vojtech Pavlik <vojtech@suse.cz>
 +S:    Maintained
 +F:    kernel/livepatch/
 +F:    include/linux/livepatch.h
 +F:    arch/x86/include/asm/livepatch.h
 +F:    arch/x86/kernel/livepatch.c
 +F:    Documentation/ABI/testing/sysfs-kernel-livepatch
 +F:    samples/livepatch/
 +L:    live-patching@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching.git
 +
  LLC (802.2)
  M:    Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
  S:    Maintained
@@@ -6187,13 -6092,6 +6187,13 @@@ F:    Documentation/devicetree/bindings/i2
  F:    drivers/hwmon/max6697.c
  F:    include/linux/platform_data/max6697.h
  
 +MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS
 +M:    Krzysztof Kozlowski <k.kozlowski@samsung.com>
 +L:    linux-pm@vger.kernel.org
 +S:    Supported
 +F:    drivers/power/max14577_charger.c
 +F:    drivers/power/max77693_charger.c
 +
  MAXIRADIO FM RADIO RECEIVER DRIVER
  M:    Hans Verkuil <hverkuil@xs4all.nl>
  L:    linux-media@vger.kernel.org
@@@ -6224,6 -6122,14 +6224,6 @@@ F:     include/uapi/linux/meye.
  F:    include/uapi/linux/ivtv*
  F:    include/uapi/linux/uvcvideo.h
  
 -MEDIAVISION PRO MOVIE STUDIO DRIVER
 -M:    Hans Verkuil <hverkuil@xs4all.nl>
 -L:    linux-media@vger.kernel.org
 -T:    git git://linuxtv.org/media_tree.git
 -W:    http://linuxtv.org
 -S:    Odd Fixes
 -F:    drivers/media/parport/pms*
 -
  MEGARAID SCSI/SAS DRIVERS
  M:    Kashyap Desai <kashyap.desai@avagotech.com>
  M:    Sumit Saxena <sumit.saxena@avagotech.com>
@@@ -6672,7 -6578,6 +6672,7 @@@ F:      include/linux/netdevice.
  F:    include/uapi/linux/in.h
  F:    include/uapi/linux/net.h
  F:    include/uapi/linux/netdevice.h
 +F:    include/uapi/linux/net_namespace.h
  F:    tools/net/
  F:    tools/testing/selftests/net/
  F:    lib/random32.c
@@@ -6777,6 -6682,7 +6777,7 @@@ F:      Documentation/devicetree/bindings/ne
  
  NFS, SUNRPC, AND LOCKD CLIENTS
  M:    Trond Myklebust <trond.myklebust@primarydata.com>
+ M:    Anna Schumaker <anna.schumaker@netapp.com>
  L:    linux-nfs@vger.kernel.org
  W:    http://client.linux-nfs.org
  T:    git git://git.linux-nfs.org/projects/trondmy/linux-nfs.git
@@@ -7082,12 -6988,14 +7083,12 @@@ OPEN FIRMWARE AND FLATTENED DEVICE TRE
  M:    Grant Likely <grant.likely@linaro.org>
  M:    Rob Herring <robh+dt@kernel.org>
  L:    devicetree@vger.kernel.org
 -W:    http://fdt.secretlab.ca
 -T:    git git://git.secretlab.ca/git/linux-2.6.git
 +W:    http://www.devicetree.org/
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux.git
  S:    Maintained
  F:    drivers/of/
  F:    include/linux/of*.h
  F:    scripts/dtc/
 -K:    of_get_property
 -K:    of_match_table
  
  OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS
  M:    Rob Herring <robh+dt@kernel.org>
@@@ -7111,12 -7019,11 +7112,12 @@@ F:   arch/openrisc
  
  OPENVSWITCH
  M:    Pravin Shelar <pshelar@nicira.com>
 +L:    netdev@vger.kernel.org
  L:    dev@openvswitch.org
  W:    http://openvswitch.org
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/pshelar/openvswitch.git
  S:    Maintained
  F:    net/openvswitch/
 +F:    include/uapi/linux/openvswitch.h
  
  OPL4 DRIVER
  M:    Clemens Ladisch <clemens@ladisch.de>
@@@ -7314,14 -7221,6 +7315,14 @@@ F:    include/linux/pci
  F:    arch/x86/pci/
  F:    arch/x86/kernel/quirks.c
  
 +PCI DRIVER FOR ARM VERSATILE PLATFORM
 +M:    Rob Herring <robh@kernel.org>
 +L:    linux-pci@vger.kernel.org
 +L:    linux-arm-kernel@lists.infradead.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/pci/versatile.txt
 +F:    drivers/pci/host/pci-versatile.c
 +
  PCI DRIVER FOR APPLIEDMICRO XGENE
  M:    Tanmay Inamdar <tinamdar@apm.com>
  L:    linux-pci@vger.kernel.org
@@@ -7341,7 -7240,7 +7342,7 @@@ S:      Maintaine
  F:    drivers/pci/host/*layerscape*
  
  PCI DRIVER FOR IMX6
 -M:    Richard Zhu <r65037@freescale.com>
 +M:    Richard Zhu <Richard.Zhu@freescale.com>
  M:    Lucas Stach <l.stach@pengutronix.de>
  L:    linux-pci@vger.kernel.org
  L:    linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@@ -7511,7 -7410,6 +7512,7 @@@ F:      drivers/crypto/picoxcell
  PIN CONTROL SUBSYSTEM
  M:    Linus Walleij <linus.walleij@linaro.org>
  L:    linux-gpio@vger.kernel.org
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl.git
  S:    Maintained
  F:    drivers/pinctrl/
  F:    include/linux/pinctrl/
@@@ -7679,6 -7577,12 +7680,6 @@@ W:     http://wireless.kernel.org/en/users/
  S:    Obsolete
  F:    drivers/net/wireless/prism54/
  
 -PROMISE SATA TX2/TX4 CONTROLLER LIBATA DRIVER
 -M:    Mikael Pettersson <mikpelinux@gmail.com>
 -L:    linux-ide@vger.kernel.org
 -S:    Maintained
 -F:    drivers/ata/sata_promise.*
 -
  PS3 NETWORK SUPPORT
  M:    Geoff Levand <geoff@infradead.org>
  L:    netdev@vger.kernel.org
@@@ -7923,6 -7827,14 +7924,6 @@@ T:     git git://github.com/KrasnikovEugene
  S:    Supported
  F:    drivers/net/wireless/ath/wcn36xx/
  
 -QUICKCAM PARALLEL PORT WEBCAMS
 -M:    Hans Verkuil <hverkuil@xs4all.nl>
 -L:    linux-media@vger.kernel.org
 -T:    git git://linuxtv.org/media_tree.git
 -W:    http://linuxtv.org
 -S:    Odd Fixes
 -F:    drivers/media/parport/*-qcam*
 -
  RADOS BLOCK DEVICE (RBD)
  M:    Yehuda Sadeh <yehuda@inktank.com>
  M:    Sage Weil <sage@inktank.com>
@@@ -8111,13 -8023,6 +8112,13 @@@ S:    Maintaine
  F:    Documentation/rfkill.txt
  F:    net/rfkill/
  
 +RHASHTABLE
 +M:    Thomas Graf <tgraf@suug.ch>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    lib/rhashtable.c
 +F:    include/linux/rhashtable.h
 +
  RICOH SMARTMEDIA/XD DRIVER
  M:    Maxim Levitsky <maximlevitsky@gmail.com>
  S:    Maintained
@@@ -8460,6 -8365,12 +8461,6 @@@ F:     kernel/time/clocksource.
  F:    kernel/time/time*.c
  F:    kernel/time/ntp.c
  
 -TLG2300 VIDEO4LINUX-2 DRIVER
 -M:    Huang Shijie <shijie8@gmail.com>
 -M:    Hans Verkuil <hverkuil@xs4all.nl>
 -S:    Odd Fixes
 -F:    drivers/media/usb/tlg2300/
 -
  SC1200 WDT DRIVER
  M:    Zwane Mwaikambo <zwanem@gmail.com>
  S:    Maintained
@@@ -8645,6 -8556,25 +8646,6 @@@ S:     Maintaine
  F:    drivers/misc/phantom.c
  F:    include/uapi/linux/phantom.h
  
 -SERIAL ATA (SATA) SUBSYSTEM
 -M:    Tejun Heo <tj@kernel.org>
 -L:    linux-ide@vger.kernel.org
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 -S:    Supported
 -F:    drivers/ata/
 -F:    include/linux/ata.h
 -F:    include/linux/libata.h
 -
 -SERIAL ATA AHCI PLATFORM devices support
 -M:    Hans de Goede <hdegoede@redhat.com>
 -M:    Tejun Heo <tj@kernel.org>
 -L:    linux-ide@vger.kernel.org
 -T:    git git://git.kernel.org/pub/scm/linux/kernel/git/tj/libata.git
 -S:    Supported
 -F:    drivers/ata/ahci_platform.c
 -F:    drivers/ata/libahci_platform.c
 -F:    include/linux/ahci_platform.h
 -
  SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
  M:    Jayamohan Kallickal <jayamohan.kallickal@emulex.com>
  L:    linux-scsi@vger.kernel.org
@@@ -8825,15 -8755,6 +8826,15 @@@ S:    Maintaine
  F:    drivers/media/platform/davinci/
  F:    include/media/davinci/
  
 +TI AM437X VPFE DRIVER
 +M:    Lad, Prabhakar <prabhakar.csengg@gmail.com>
 +L:    linux-media@vger.kernel.org
 +W:    http://linuxtv.org/
 +Q:    http://patchwork.linuxtv.org/project/linux-media/list/
 +T:    git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
 +S:    Maintained
 +F:    drivers/media/platform/am437x/
 +
  SIS 190 ETHERNET DRIVER
  M:    Francois Romieu <romieu@fr.zoreil.com>
  L:    netdev@vger.kernel.org
@@@ -8915,8 -8836,6 +8916,8 @@@ F:      drivers/media/i2c/smiapp
  F:    include/media/smiapp.h
  F:    drivers/media/i2c/smiapp-pll.c
  F:    drivers/media/i2c/smiapp-pll.h
 +F:    include/uapi/linux/smiapp.h
 +F:    Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
  
  SMM665 HARDWARE MONITOR DRIVER
  M:    Guenter Roeck <linux@roeck-us.net>
@@@ -8983,7 -8902,6 +8984,7 @@@ SOFTLOGIC 6x10 MPEG CODE
  M:    Bluecherry Maintainers <maintainers@bluecherrydvr.com>
  M:    Andrey Utkin <andrey.utkin@corp.bluecherry.net>
  M:    Andrey Utkin <andrey.krieger.utkin@gmail.com>
 +M:    Ismael Luceno <ismael@iodev.co.uk>
  L:    linux-media@vger.kernel.org
  S:    Supported
  F:    drivers/media/pci/solo6x10/
@@@ -9296,13 -9214,6 +9297,13 @@@ F:    arch/m68k/sun3*
  F:    arch/m68k/include/asm/sun3*
  F:    drivers/net/ethernet/i825xx/sun3*
  
 +SUN4I LOW RES ADC ATTACHED TABLET KEYS DRIVER
 +M:    Hans de Goede <hdegoede@redhat.com>
 +L:    linux-input@vger.kernel.org
 +S:    Maintained
 +F:    Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
 +F:    drivers/input/keyboard/sun4i-lradc-keys.c
 +
  SUNDANCE NETWORK DRIVER
  M:    Denis Kirjanov <kda@linux-powerpc.org>
  L:    netdev@vger.kernel.org
@@@ -9311,6 -9222,7 +9312,6 @@@ F:      drivers/net/ethernet/dlink/sundance.
  
  SUPERH
  L:    linux-sh@vger.kernel.org
 -W:    http://www.linux-sh.org
  Q:    http://patchwork.kernel.org/project/linux-sh/list/
  S:    Orphan
  F:    Documentation/sh/
@@@ -9689,13 -9601,6 +9690,13 @@@ F:    drivers/power/lp8788-charger.
  F:    drivers/regulator/lp8788-*.c
  F:    include/linux/mfd/lp8788*.h
  
 +TI NETCP ETHERNET DRIVER
 +M:    Wingman Kwok <w-kwok2@ti.com>
 +M:    Murali Karicheri <m-karicheri2@ti.com>
 +L:    netdev@vger.kernel.org
 +S:    Maintained
 +F:    drivers/net/ethernet/ti/netcp*
 +
  TI TWL4030 SERIES SOC CODEC DRIVER
  M:    Peter Ujfalusi <peter.ujfalusi@ti.com>
  L:    alsa-devel@alsa-project.org (moderated for non-subscribers)
@@@ -10252,7 -10157,6 +10253,7 @@@ USERSPACE I/O (UIO
  M:    "Hans J. Koch" <hjk@hansjkoch.de>
  M:    Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  S:    Maintained
 +T:    git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
  F:    Documentation/DocBook/uio-howto.tmpl
  F:    drivers/uio/
  F:    include/linux/uio*.h
@@@ -10735,7 -10639,6 +10736,7 @@@ M:   Max Filippov <jcmvbkbc@gmail.com
  L:    linux-xtensa@linux-xtensa.org
  S:    Maintained
  F:    drivers/spi/spi-xtensa-xtfpga.c
 +F:    sound/soc/xtensa/xtfpga-i2s.c
  
  YAM DRIVER FOR AX.25
  M:    Jean-Paul Roubelat <jpr@f6fbb.org>
diff --combined fs/nfs/delegation.c
index 8cdb2b28a104c89216125c1c274ef94895121f07,16b754ee0d0909a500b8e61a9967a39d08a14034..da5433230bb1960bc78bafc17ced89f3bca76b65
@@@ -85,30 -85,25 +85,30 @@@ static int nfs_delegation_claim_locks(s
  {
        struct inode *inode = state->inode;
        struct file_lock *fl;
 +      struct file_lock_context *flctx = inode->i_flctx;
 +      struct list_head *list;
        int status = 0;
  
 -      if (inode->i_flock == NULL)
 +      if (flctx == NULL)
                goto out;
  
 -      /* Protect inode->i_flock using the i_lock */
 -      spin_lock(&inode->i_lock);
 -      for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
 -              if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
 -                      continue;
 +      list = &flctx->flc_posix;
 +      spin_lock(&flctx->flc_lock);
 +restart:
 +      list_for_each_entry(fl, list, fl_list) {
                if (nfs_file_open_context(fl->fl_file) != ctx)
                        continue;
 -              spin_unlock(&inode->i_lock);
 +              spin_unlock(&flctx->flc_lock);
                status = nfs4_lock_delegation_recall(fl, state, stateid);
                if (status < 0)
                        goto out;
 -              spin_lock(&inode->i_lock);
 +              spin_lock(&flctx->flc_lock);
 +      }
 +      if (list == &flctx->flc_posix) {
 +              list = &flctx->flc_flock;
 +              goto restart;
        }
 -      spin_unlock(&inode->i_lock);
 +      spin_unlock(&flctx->flc_lock);
  out:
        return status;
  }
@@@ -306,6 -301,17 +306,17 @@@ nfs_inode_detach_delegation(struct inod
        return nfs_detach_delegation(nfsi, delegation, server);
  }
  
+ static void
+ nfs_update_inplace_delegation(struct nfs_delegation *delegation,
+               const struct nfs_delegation *update)
+ {
+       if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
+               delegation->stateid.seqid = update->stateid.seqid;
+               smp_wmb();
+               delegation->type = update->type;
+       }
+ }
  /**
   * nfs_inode_set_delegation - set up a delegation on an inode
   * @inode: inode to which delegation applies
@@@ -339,9 -345,12 +350,12 @@@ int nfs_inode_set_delegation(struct ino
        old_delegation = rcu_dereference_protected(nfsi->delegation,
                                        lockdep_is_held(&clp->cl_lock));
        if (old_delegation != NULL) {
-               if (nfs4_stateid_match(&delegation->stateid,
-                                       &old_delegation->stateid) &&
-                               delegation->type == old_delegation->type) {
+               /* Is this an update of the existing delegation? */
+               if (nfs4_stateid_match_other(&old_delegation->stateid,
+                                       &delegation->stateid)) {
+                       nfs_update_inplace_delegation(old_delegation,
+                                       delegation);
+                       nfsi->delegation_state = old_delegation->type;
                        goto out;
                }
                /*
diff --combined fs/nfs/nfs4state.c
index a3bb22ab68c519412dc1a490728cc60560b659c1,590f096fd01179a039015d3d8f7efc5ad4055f30..5ad908e9ce9c332696ed52a85a5c4324a45d8b02
@@@ -1003,11 -1003,11 +1003,11 @@@ struct nfs_seqid *nfs_alloc_seqid(struc
        struct nfs_seqid *new;
  
        new = kmalloc(sizeof(*new), gfp_mask);
-       if (new != NULL) {
-               new->sequence = counter;
-               INIT_LIST_HEAD(&new->list);
-               new->task = NULL;
-       }
+       if (new == NULL)
+               return ERR_PTR(-ENOMEM);
+       new->sequence = counter;
+       INIT_LIST_HEAD(&new->list);
+       new->task = NULL;
        return new;
  }
  
@@@ -1015,7 -1015,7 +1015,7 @@@ void nfs_release_seqid(struct nfs_seqi
  {
        struct nfs_seqid_counter *sequence;
  
-       if (list_empty(&seqid->list))
+       if (seqid == NULL || list_empty(&seqid->list))
                return;
        sequence = seqid->sequence;
        spin_lock(&sequence->lock);
@@@ -1071,13 -1071,15 +1071,15 @@@ static void nfs_increment_seqid(int sta
  
  void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
  {
-       struct nfs4_state_owner *sp = container_of(seqid->sequence,
-                                       struct nfs4_state_owner, so_seqid);
-       struct nfs_server *server = sp->so_server;
+       struct nfs4_state_owner *sp;
+       if (seqid == NULL)
+               return;
  
+       sp = container_of(seqid->sequence, struct nfs4_state_owner, so_seqid);
        if (status == -NFS4ERR_BAD_SEQID)
                nfs4_drop_state_owner(sp);
-       if (!nfs4_has_session(server->nfs_client))
+       if (!nfs4_has_session(sp->so_server->nfs_client))
                nfs_increment_seqid(status, seqid);
  }
  
   */
  void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
  {
-       nfs_increment_seqid(status, seqid);
+       if (seqid != NULL)
+               nfs_increment_seqid(status, seqid);
  }
  
  int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
  {
-       struct nfs_seqid_counter *sequence = seqid->sequence;
+       struct nfs_seqid_counter *sequence;
        int status = 0;
  
+       if (seqid == NULL)
+               goto out;
+       sequence = seqid->sequence;
        spin_lock(&sequence->lock);
        seqid->task = task;
        if (list_empty(&seqid->list))
        status = -EAGAIN;
  unlock:
        spin_unlock(&sequence->lock);
+ out:
        return status;
  }
  
@@@ -1366,55 -1373,49 +1373,55 @@@ static int nfs4_reclaim_locks(struct nf
        struct nfs_inode *nfsi = NFS_I(inode);
        struct file_lock *fl;
        int status = 0;
 +      struct file_lock_context *flctx = inode->i_flctx;
 +      struct list_head *list;
  
 -      if (inode->i_flock == NULL)
 +      if (flctx == NULL)
                return 0;
  
 +      list = &flctx->flc_posix;
 +
        /* Guard against delegation returns and new lock/unlock calls */
        down_write(&nfsi->rwsem);
 -      /* Protect inode->i_flock using the BKL */
 -      spin_lock(&inode->i_lock);
 -      for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
 -              if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
 -                      continue;
 +      spin_lock(&flctx->flc_lock);
 +restart:
 +      list_for_each_entry(fl, list, fl_list) {
                if (nfs_file_open_context(fl->fl_file)->state != state)
                        continue;
 -              spin_unlock(&inode->i_lock);
 +              spin_unlock(&flctx->flc_lock);
                status = ops->recover_lock(state, fl);
                switch (status) {
 -                      case 0:
 -                              break;
 -                      case -ESTALE:
 -                      case -NFS4ERR_ADMIN_REVOKED:
 -                      case -NFS4ERR_STALE_STATEID:
 -                      case -NFS4ERR_BAD_STATEID:
 -                      case -NFS4ERR_EXPIRED:
 -                      case -NFS4ERR_NO_GRACE:
 -                      case -NFS4ERR_STALE_CLIENTID:
 -                      case -NFS4ERR_BADSESSION:
 -                      case -NFS4ERR_BADSLOT:
 -                      case -NFS4ERR_BAD_HIGH_SLOT:
 -                      case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
 -                              goto out;
 -                      default:
 -                              printk(KERN_ERR "NFS: %s: unhandled error %d\n",
 -                                       __func__, status);
 -                      case -ENOMEM:
 -                      case -NFS4ERR_DENIED:
 -                      case -NFS4ERR_RECLAIM_BAD:
 -                      case -NFS4ERR_RECLAIM_CONFLICT:
 -                              /* kill_proc(fl->fl_pid, SIGLOST, 1); */
 -                              status = 0;
 +              case 0:
 +                      break;
 +              case -ESTALE:
 +              case -NFS4ERR_ADMIN_REVOKED:
 +              case -NFS4ERR_STALE_STATEID:
 +              case -NFS4ERR_BAD_STATEID:
 +              case -NFS4ERR_EXPIRED:
 +              case -NFS4ERR_NO_GRACE:
 +              case -NFS4ERR_STALE_CLIENTID:
 +              case -NFS4ERR_BADSESSION:
 +              case -NFS4ERR_BADSLOT:
 +              case -NFS4ERR_BAD_HIGH_SLOT:
 +              case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
 +                      goto out;
 +              default:
 +                      pr_err("NFS: %s: unhandled error %d\n",
 +                                      __func__, status);
 +              case -ENOMEM:
 +              case -NFS4ERR_DENIED:
 +              case -NFS4ERR_RECLAIM_BAD:
 +              case -NFS4ERR_RECLAIM_CONFLICT:
 +                      /* kill_proc(fl->fl_pid, SIGLOST, 1); */
 +                      status = 0;
                }
 -              spin_lock(&inode->i_lock);
 +              spin_lock(&flctx->flc_lock);
        }
 -      spin_unlock(&inode->i_lock);
 +      if (list == &flctx->flc_posix) {
 +              list = &flctx->flc_flock;
 +              goto restart;
 +      }
 +      spin_unlock(&flctx->flc_lock);
  out:
        up_write(&nfsi->rwsem);
        return status;
diff --combined fs/nfs/pagelist.c
index 29c7f33c9cf1b666b88fee7dc1ed2882fdb76825,960c99f75d3f28abe3e44a74cd195eed6fda7c21..d57190a0d533134c2376c6556a8102e88996dd18
@@@ -42,21 -42,35 +42,35 @@@ static bool nfs_pgarray_set(struct nfs_
        return p->pagevec != NULL;
  }
  
+ struct nfs_pgio_mirror *
+ nfs_pgio_current_mirror(struct nfs_pageio_descriptor *desc)
+ {
+       return nfs_pgio_has_mirroring(desc) ?
+               &desc->pg_mirrors[desc->pg_mirror_idx] :
+               &desc->pg_mirrors[0];
+ }
+ EXPORT_SYMBOL_GPL(nfs_pgio_current_mirror);
  void nfs_pgheader_init(struct nfs_pageio_descriptor *desc,
                       struct nfs_pgio_header *hdr,
                       void (*release)(struct nfs_pgio_header *hdr))
  {
-       hdr->req = nfs_list_entry(desc->pg_list.next);
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
+       hdr->req = nfs_list_entry(mirror->pg_list.next);
        hdr->inode = desc->pg_inode;
        hdr->cred = hdr->req->wb_context->cred;
        hdr->io_start = req_offset(hdr->req);
-       hdr->good_bytes = desc->pg_count;
+       hdr->good_bytes = mirror->pg_count;
        hdr->dreq = desc->pg_dreq;
        hdr->layout_private = desc->pg_layout_private;
        hdr->release = release;
        hdr->completion_ops = desc->pg_completion_ops;
        if (hdr->completion_ops->init_hdr)
                hdr->completion_ops->init_hdr(hdr);
+       hdr->pgio_mirror_idx = desc->pg_mirror_idx;
  }
  EXPORT_SYMBOL_GPL(nfs_pgheader_init);
  
@@@ -480,7 -494,10 +494,10 @@@ nfs_wait_on_request(struct nfs_page *re
  size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc,
                           struct nfs_page *prev, struct nfs_page *req)
  {
-       if (desc->pg_count > desc->pg_bsize) {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
+       if (mirror->pg_count > mirror->pg_bsize) {
                /* should never happen */
                WARN_ON_ONCE(1);
                return 0;
         * Limit the request size so that we can still allocate a page array
         * for it without upsetting the slab allocator.
         */
-       if (((desc->pg_count + req->wb_bytes) >> PAGE_SHIFT) *
+       if (((mirror->pg_count + req->wb_bytes) >> PAGE_SHIFT) *
                        sizeof(struct page) > PAGE_SIZE)
                return 0;
  
-       return min(desc->pg_bsize - desc->pg_count, (size_t)req->wb_bytes);
+       return min(mirror->pg_bsize - mirror->pg_count, (size_t)req->wb_bytes);
  }
  EXPORT_SYMBOL_GPL(nfs_generic_pg_test);
  
@@@ -597,13 -614,14 +614,14 @@@ static void nfs_pgio_prepare(struct rpc
  }
  
  int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr,
+                     struct rpc_cred *cred, const struct nfs_rpc_ops *rpc_ops,
                      const struct rpc_call_ops *call_ops, int how, int flags)
  {
        struct rpc_task *task;
        struct rpc_message msg = {
                .rpc_argp = &hdr->args,
                .rpc_resp = &hdr->res,
-               .rpc_cred = hdr->cred,
+               .rpc_cred = cred,
        };
        struct rpc_task_setup task_setup_data = {
                .rpc_client = clnt,
        };
        int ret = 0;
  
-       hdr->rw_ops->rw_initiate(hdr, &msg, &task_setup_data, how);
+       hdr->rw_ops->rw_initiate(hdr, &msg, rpc_ops, &task_setup_data, how);
  
        dprintk("NFS: %5u initiated pgio call "
                "(req %s/%llu, %u bytes @ offset %llu)\n",
@@@ -650,10 -668,18 +668,18 @@@ EXPORT_SYMBOL_GPL(nfs_initiate_pgio)
  static int nfs_pgio_error(struct nfs_pageio_descriptor *desc,
                          struct nfs_pgio_header *hdr)
  {
+       struct nfs_pgio_mirror *mirror;
+       u32 midx;
        set_bit(NFS_IOHDR_REDO, &hdr->flags);
        nfs_pgio_data_destroy(hdr);
        hdr->completion_ops->completion(hdr);
-       desc->pg_completion_ops->error_cleanup(&desc->pg_list);
+       /* TODO: Make sure it's right to clean up all mirrors here
+        *       and not just hdr->pgio_mirror_idx */
+       for (midx = 0; midx < desc->pg_mirror_count; midx++) {
+               mirror = &desc->pg_mirrors[midx];
+               desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
+       }
        return -ENOMEM;
  }
  
@@@ -670,6 -696,17 +696,17 @@@ static void nfs_pgio_release(void *call
        hdr->completion_ops->completion(hdr);
  }
  
+ static void nfs_pageio_mirror_init(struct nfs_pgio_mirror *mirror,
+                                  unsigned int bsize)
+ {
+       INIT_LIST_HEAD(&mirror->pg_list);
+       mirror->pg_bytes_written = 0;
+       mirror->pg_count = 0;
+       mirror->pg_bsize = bsize;
+       mirror->pg_base = 0;
+       mirror->pg_recoalesce = 0;
+ }
  /**
   * nfs_pageio_init - initialise a page io descriptor
   * @desc: pointer to descriptor
@@@ -686,13 -723,10 +723,10 @@@ void nfs_pageio_init(struct nfs_pageio_
                     size_t bsize,
                     int io_flags)
  {
-       INIT_LIST_HEAD(&desc->pg_list);
-       desc->pg_bytes_written = 0;
-       desc->pg_count = 0;
-       desc->pg_bsize = bsize;
-       desc->pg_base = 0;
+       struct nfs_pgio_mirror *new;
+       int i;
        desc->pg_moreio = 0;
-       desc->pg_recoalesce = 0;
        desc->pg_inode = inode;
        desc->pg_ops = pg_ops;
        desc->pg_completion_ops = compl_ops;
        desc->pg_lseg = NULL;
        desc->pg_dreq = NULL;
        desc->pg_layout_private = NULL;
+       desc->pg_bsize = bsize;
+       desc->pg_mirror_count = 1;
+       desc->pg_mirror_idx = 0;
+       if (pg_ops->pg_get_mirror_count) {
+               /* until we have a request, we don't have an lseg and no
+                * idea how many mirrors there will be */
+               new = kcalloc(NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX,
+                             sizeof(struct nfs_pgio_mirror), GFP_KERNEL);
+               desc->pg_mirrors_dynamic = new;
+               desc->pg_mirrors = new;
+               for (i = 0; i < NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX; i++)
+                       nfs_pageio_mirror_init(&desc->pg_mirrors[i], bsize);
+       } else {
+               desc->pg_mirrors_dynamic = NULL;
+               desc->pg_mirrors = desc->pg_mirrors_static;
+               nfs_pageio_mirror_init(&desc->pg_mirrors[0], bsize);
+       }
  }
  EXPORT_SYMBOL_GPL(nfs_pageio_init);
  
@@@ -737,14 -791,16 +791,16 @@@ static void nfs_pgio_result(struct rpc_
  int nfs_generic_pgio(struct nfs_pageio_descriptor *desc,
                     struct nfs_pgio_header *hdr)
  {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
        struct nfs_page         *req;
        struct page             **pages,
                                *last_page;
-       struct list_head *head = &desc->pg_list;
+       struct list_head *head = &mirror->pg_list;
        struct nfs_commit_info cinfo;
        unsigned int pagecount, pageused;
  
-       pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count);
+       pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count);
        if (!nfs_pgarray_set(&hdr->page_array, pagecount))
                return nfs_pgio_error(desc, hdr);
  
                desc->pg_ioflags &= ~FLUSH_COND_STABLE;
  
        /* Set up the argument struct */
-       nfs_pgio_rpcsetup(hdr, desc->pg_count, 0, desc->pg_ioflags, &cinfo);
+       nfs_pgio_rpcsetup(hdr, mirror->pg_count, 0, desc->pg_ioflags, &cinfo);
        desc->pg_rpc_callops = &nfs_pgio_common_ops;
        return 0;
  }
@@@ -780,23 -836,74 +836,74 @@@ EXPORT_SYMBOL_GPL(nfs_generic_pgio)
  
  static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc)
  {
+       struct nfs_pgio_mirror *mirror;
        struct nfs_pgio_header *hdr;
        int ret;
  
+       mirror = nfs_pgio_current_mirror(desc);
        hdr = nfs_pgio_header_alloc(desc->pg_rw_ops);
        if (!hdr) {
-               desc->pg_completion_ops->error_cleanup(&desc->pg_list);
+               /* TODO: make sure this is right with mirroring - or
+                *       should it back out all mirrors? */
+               desc->pg_completion_ops->error_cleanup(&mirror->pg_list);
                return -ENOMEM;
        }
        nfs_pgheader_init(desc, hdr, nfs_pgio_header_free);
        ret = nfs_generic_pgio(desc, hdr);
        if (ret == 0)
                ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode),
-                                       hdr, desc->pg_rpc_callops,
+                                       hdr,
+                                       hdr->cred,
+                                       NFS_PROTO(hdr->inode),
+                                       desc->pg_rpc_callops,
                                        desc->pg_ioflags, 0);
        return ret;
  }
  
+ /*
+  * nfs_pageio_setup_mirroring - determine if mirroring is to be used
+  *                            by calling the pg_get_mirror_count op
+  */
+ static int nfs_pageio_setup_mirroring(struct nfs_pageio_descriptor *pgio,
+                                      struct nfs_page *req)
+ {
+       int mirror_count = 1;
+       if (!pgio->pg_ops->pg_get_mirror_count)
+               return 0;
+       mirror_count = pgio->pg_ops->pg_get_mirror_count(pgio, req);
+       if (!mirror_count || mirror_count > NFS_PAGEIO_DESCRIPTOR_MIRROR_MAX)
+               return -EINVAL;
+       if (WARN_ON_ONCE(!pgio->pg_mirrors_dynamic))
+               return -EINVAL;
+       pgio->pg_mirror_count = mirror_count;
+       return 0;
+ }
+ /*
+  * nfs_pageio_stop_mirroring - stop using mirroring (set mirror count to 1)
+  */
+ void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio)
+ {
+       pgio->pg_mirror_count = 1;
+       pgio->pg_mirror_idx = 0;
+ }
+ static void nfs_pageio_cleanup_mirroring(struct nfs_pageio_descriptor *pgio)
+ {
+       pgio->pg_mirror_count = 1;
+       pgio->pg_mirror_idx = 0;
+       pgio->pg_mirrors = pgio->pg_mirrors_static;
+       kfree(pgio->pg_mirrors_dynamic);
+       pgio->pg_mirrors_dynamic = NULL;
+ }
  static bool nfs_match_open_context(const struct nfs_open_context *ctx1,
                const struct nfs_open_context *ctx2)
  {
@@@ -826,15 -933,11 +933,15 @@@ static bool nfs_can_coalesce_requests(s
                                      struct nfs_pageio_descriptor *pgio)
  {
        size_t size;
 +      struct file_lock_context *flctx;
  
        if (prev) {
                if (!nfs_match_open_context(req->wb_context, prev->wb_context))
                        return false;
 -              if (req->wb_context->dentry->d_inode->i_flock != NULL &&
 +              flctx = req->wb_context->dentry->d_inode->i_flctx;
 +              if (flctx != NULL &&
 +                  !(list_empty_careful(&flctx->flc_posix) &&
 +                    list_empty_careful(&flctx->flc_flock)) &&
                    !nfs_match_lock_context(req->wb_lock_context,
                                            prev->wb_lock_context))
                        return false;
  static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc,
                                     struct nfs_page *req)
  {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
        struct nfs_page *prev = NULL;
-       if (desc->pg_count != 0) {
-               prev = nfs_list_entry(desc->pg_list.prev);
+       if (mirror->pg_count != 0) {
+               prev = nfs_list_entry(mirror->pg_list.prev);
        } else {
                if (desc->pg_ops->pg_init)
                        desc->pg_ops->pg_init(desc, req);
-               desc->pg_base = req->wb_pgbase;
+               mirror->pg_base = req->wb_pgbase;
        }
        if (!nfs_can_coalesce_requests(prev, req, desc))
                return 0;
        nfs_list_remove_request(req);
-       nfs_list_add_request(req, &desc->pg_list);
-       desc->pg_count += req->wb_bytes;
+       nfs_list_add_request(req, &mirror->pg_list);
+       mirror->pg_count += req->wb_bytes;
        return 1;
  }
  
   */
  static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc)
  {
-       if (!list_empty(&desc->pg_list)) {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
+       if (!list_empty(&mirror->pg_list)) {
                int error = desc->pg_ops->pg_doio(desc);
                if (error < 0)
                        desc->pg_error = error;
                else
-                       desc->pg_bytes_written += desc->pg_count;
+                       mirror->pg_bytes_written += mirror->pg_count;
        }
-       if (list_empty(&desc->pg_list)) {
-               desc->pg_count = 0;
-               desc->pg_base = 0;
+       if (list_empty(&mirror->pg_list)) {
+               mirror->pg_count = 0;
+               mirror->pg_base = 0;
        }
  }
  
  static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
                           struct nfs_page *req)
  {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
        struct nfs_page *subreq;
        unsigned int bytes_left = 0;
        unsigned int offset, pgbase;
                        nfs_pageio_doio(desc);
                        if (desc->pg_error < 0)
                                return 0;
-                       if (desc->pg_recoalesce)
+                       if (mirror->pg_recoalesce)
                                return 0;
                        /* retry add_request for this subreq */
                        nfs_page_group_lock(req, false);
@@@ -976,14 -1087,16 +1091,16 @@@ err_ptr
  
  static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc)
  {
+       struct nfs_pgio_mirror *mirror = nfs_pgio_current_mirror(desc);
        LIST_HEAD(head);
  
        do {
-               list_splice_init(&desc->pg_list, &head);
-               desc->pg_bytes_written -= desc->pg_count;
-               desc->pg_count = 0;
-               desc->pg_base = 0;
-               desc->pg_recoalesce = 0;
+               list_splice_init(&mirror->pg_list, &head);
+               mirror->pg_bytes_written -= mirror->pg_count;
+               mirror->pg_count = 0;
+               mirror->pg_base = 0;
+               mirror->pg_recoalesce = 0;
                desc->pg_moreio = 0;
  
                while (!list_empty(&head)) {
                                return 0;
                        break;
                }
-       } while (desc->pg_recoalesce);
+       } while (mirror->pg_recoalesce);
        return 1;
  }
  
int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
static int nfs_pageio_add_request_mirror(struct nfs_pageio_descriptor *desc,
                struct nfs_page *req)
  {
        int ret;
                        break;
                ret = nfs_do_recoalesce(desc);
        } while (ret);
        return ret;
  }
  
+ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc,
+                          struct nfs_page *req)
+ {
+       u32 midx;
+       unsigned int pgbase, offset, bytes;
+       struct nfs_page *dupreq, *lastreq;
+       pgbase = req->wb_pgbase;
+       offset = req->wb_offset;
+       bytes = req->wb_bytes;
+       nfs_pageio_setup_mirroring(desc, req);
+       for (midx = 0; midx < desc->pg_mirror_count; midx++) {
+               if (midx) {
+                       nfs_page_group_lock(req, false);
+                       /* find the last request */
+                       for (lastreq = req->wb_head;
+                            lastreq->wb_this_page != req->wb_head;
+                            lastreq = lastreq->wb_this_page)
+                               ;
+                       dupreq = nfs_create_request(req->wb_context,
+                                       req->wb_page, lastreq, pgbase, bytes);
+                       if (IS_ERR(dupreq)) {
+                               nfs_page_group_unlock(req);
+                               return 0;
+                       }
+                       nfs_lock_request(dupreq);
+                       nfs_page_group_unlock(req);
+                       dupreq->wb_offset = offset;
+                       dupreq->wb_index = req->wb_index;
+               } else
+                       dupreq = req;
+               if (nfs_pgio_has_mirroring(desc))
+                       desc->pg_mirror_idx = midx;
+               if (!nfs_pageio_add_request_mirror(desc, dupreq))
+                       return 0;
+       }
+       return 1;
+ }
+ /*
+  * nfs_pageio_complete_mirror - Complete I/O on the current mirror of an
+  *                            nfs_pageio_descriptor
+  * @desc: pointer to io descriptor
+  */
+ static void nfs_pageio_complete_mirror(struct nfs_pageio_descriptor *desc,
+                                      u32 mirror_idx)
+ {
+       struct nfs_pgio_mirror *mirror = &desc->pg_mirrors[mirror_idx];
+       u32 restore_idx = desc->pg_mirror_idx;
+       if (nfs_pgio_has_mirroring(desc))
+               desc->pg_mirror_idx = mirror_idx;
+       for (;;) {
+               nfs_pageio_doio(desc);
+               if (!mirror->pg_recoalesce)
+                       break;
+               if (!nfs_do_recoalesce(desc))
+                       break;
+       }
+       desc->pg_mirror_idx = restore_idx;
+ }
  /*
   * nfs_pageio_resend - Transfer requests to new descriptor and resend
   * @hdr - the pgio header to move request from
@@@ -1050,18 -1234,19 +1238,19 @@@ int nfs_pageio_resend(struct nfs_pageio
  EXPORT_SYMBOL_GPL(nfs_pageio_resend);
  
  /**
-  * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor
+  * nfs_pageio_complete - Complete I/O then cleanup an nfs_pageio_descriptor
   * @desc: pointer to io descriptor
   */
  void nfs_pageio_complete(struct nfs_pageio_descriptor *desc)
  {
-       for (;;) {
-               nfs_pageio_doio(desc);
-               if (!desc->pg_recoalesce)
-                       break;
-               if (!nfs_do_recoalesce(desc))
-                       break;
-       }
+       u32 midx;
+       for (midx = 0; midx < desc->pg_mirror_count; midx++)
+               nfs_pageio_complete_mirror(desc, midx);
+       if (desc->pg_ops->pg_cleanup)
+               desc->pg_ops->pg_cleanup(desc);
+       nfs_pageio_cleanup_mirroring(desc);
  }
  
  /**
   */
  void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
  {
-       if (!list_empty(&desc->pg_list)) {
-               struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev);
-               if (index != prev->wb_index + 1)
-                       nfs_pageio_complete(desc);
+       struct nfs_pgio_mirror *mirror;
+       struct nfs_page *prev;
+       u32 midx;
+       for (midx = 0; midx < desc->pg_mirror_count; midx++) {
+               mirror = &desc->pg_mirrors[midx];
+               if (!list_empty(&mirror->pg_list)) {
+                       prev = nfs_list_entry(mirror->pg_list.prev);
+                       if (index != prev->wb_index + 1)
+                               nfs_pageio_complete_mirror(desc, midx);
+               }
        }
  }
  
diff --combined fs/nfs/write.c
index 4ae66f416eb906670248dc9c3ef0d16fe2a3956f,ceacfeeb28c26fa128d4025f5a3919368a442753..bcf83e535f29a0060f4abb03f8c3f43684eb4880
@@@ -473,13 -473,18 +473,18 @@@ try_again
        do {
                /*
                 * Subrequests are always contiguous, non overlapping
-                * and in order. If not, it's a programming error.
+                * and in order - but may be repeated (mirrored writes).
                 */
-               WARN_ON_ONCE(subreq->wb_offset !=
-                    (head->wb_offset + total_bytes));
-               /* keep track of how many bytes this group covers */
-               total_bytes += subreq->wb_bytes;
+               if (subreq->wb_offset == (head->wb_offset + total_bytes)) {
+                       /* keep track of how many bytes this group covers */
+                       total_bytes += subreq->wb_bytes;
+               } else if (WARN_ON_ONCE(subreq->wb_offset < head->wb_offset ||
+                           ((subreq->wb_offset + subreq->wb_bytes) >
+                            (head->wb_offset + total_bytes)))) {
+                       nfs_page_group_unlock(head);
+                       spin_unlock(&inode->i_lock);
+                       return ERR_PTR(-EIO);
+               }
  
                if (!nfs_lock_request(subreq)) {
                        /* releases page group bit lock and
@@@ -842,9 -847,9 +847,9 @@@ EXPORT_SYMBOL_GPL(nfs_init_cinfo)
   */
  void
  nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg,
-                       struct nfs_commit_info *cinfo)
+                       struct nfs_commit_info *cinfo, u32 ds_commit_idx)
  {
-       if (pnfs_mark_request_commit(req, lseg, cinfo))
+       if (pnfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx))
                return;
        nfs_request_add_commit_list(req, &cinfo->mds->list, cinfo);
  }
@@@ -900,7 -905,8 +905,8 @@@ static void nfs_write_completion(struc
                }
                if (nfs_write_need_commit(hdr)) {
                        memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf));
-                       nfs_mark_request_commit(req, hdr->lseg, &cinfo);
+                       nfs_mark_request_commit(req, hdr->lseg, &cinfo,
+                               hdr->pgio_mirror_idx);
                        goto next;
                }
  remove_req:
@@@ -1091,7 -1097,6 +1097,7 @@@ int nfs_flush_incompatible(struct file 
  {
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct nfs_lock_context *l_ctx;
 +      struct file_lock_context *flctx = file_inode(file)->i_flctx;
        struct nfs_page *req;
        int do_flush, status;
        /*
                do_flush = req->wb_page != page || req->wb_context != ctx;
                /* for now, flush if more than 1 request in page_group */
                do_flush |= req->wb_this_page != req;
 -              if (l_ctx && ctx->dentry->d_inode->i_flock != NULL) {
 +              if (l_ctx && flctx &&
 +                  !(list_empty_careful(&flctx->flc_posix) &&
 +                    list_empty_careful(&flctx->flc_flock))) {
                        do_flush |= l_ctx->lockowner.l_owner != current->files
                                || l_ctx->lockowner.l_pid != current->tgid;
                }
        return PageUptodate(page) != 0;
  }
  
 +static bool
 +is_whole_file_wrlock(struct file_lock *fl)
 +{
 +      return fl->fl_start == 0 && fl->fl_end == OFFSET_MAX &&
 +                      fl->fl_type == F_WRLCK;
 +}
 +
  /* If we know the page is up to date, and we're not using byte range locks (or
   * if we have the whole file locked for writing), it may be more efficient to
   * extend the write to cover the entire page in order to avoid fragmentation
   */
  static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
  {
 +      int ret;
 +      struct file_lock_context *flctx = inode->i_flctx;
 +      struct file_lock *fl;
 +
        if (file->f_flags & O_DSYNC)
                return 0;
        if (!nfs_write_pageuptodate(page, inode))
                return 0;
        if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
                return 1;
 -      if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 &&
 -                      inode->i_flock->fl_end == OFFSET_MAX &&
 -                      inode->i_flock->fl_type != F_RDLCK))
 -              return 1;
 -      return 0;
 +      if (!flctx || (list_empty_careful(&flctx->flc_flock) &&
 +                     list_empty_careful(&flctx->flc_posix)))
 +              return 0;
 +
 +      /* Check to see if there are whole file write locks */
 +      ret = 0;
 +      spin_lock(&flctx->flc_lock);
 +      if (!list_empty(&flctx->flc_posix)) {
 +              fl = list_first_entry(&flctx->flc_posix, struct file_lock,
 +                                      fl_list);
 +              if (is_whole_file_wrlock(fl))
 +                      ret = 1;
 +      } else if (!list_empty(&flctx->flc_flock)) {
 +              fl = list_first_entry(&flctx->flc_flock, struct file_lock,
 +                                      fl_list);
 +              if (fl->fl_type == F_WRLCK)
 +                      ret = 1;
 +      }
 +      spin_unlock(&flctx->flc_lock);
 +      return ret;
  }
  
  /*
@@@ -1269,15 -1246,15 +1275,15 @@@ static int flush_task_priority(int how
  
  static void nfs_initiate_write(struct nfs_pgio_header *hdr,
                               struct rpc_message *msg,
+                              const struct nfs_rpc_ops *rpc_ops,
                               struct rpc_task_setup *task_setup_data, int how)
  {
-       struct inode *inode = hdr->inode;
        int priority = flush_task_priority(how);
  
        task_setup_data->priority = priority;
-       NFS_PROTO(inode)->write_setup(hdr, msg);
+       rpc_ops->write_setup(hdr, msg);
  
-       nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client,
+       nfs4_state_protect_write(NFS_SERVER(hdr->inode)->nfs_client,
                                 &task_setup_data->rpc_client, msg, hdr);
  }
  
@@@ -1327,8 -1304,14 +1333,14 @@@ EXPORT_SYMBOL_GPL(nfs_pageio_init_write
  
  void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio)
  {
+       struct nfs_pgio_mirror *mirror;
        pgio->pg_ops = &nfs_pgio_rw_ops;
-       pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize;
+       nfs_pageio_stop_mirroring(pgio);
+       mirror = &pgio->pg_mirrors[0];
+       mirror->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize;
  }
  EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds);
  
@@@ -1494,6 -1477,7 +1506,7 @@@ void nfs_commitdata_release(struct nfs_
  EXPORT_SYMBOL_GPL(nfs_commitdata_release);
  
  int nfs_initiate_commit(struct rpc_clnt *clnt, struct nfs_commit_data *data,
+                       const struct nfs_rpc_ops *nfs_ops,
                        const struct rpc_call_ops *call_ops,
                        int how, int flags)
  {
                .priority = priority,
        };
        /* Set up the initial task struct.  */
-       NFS_PROTO(data->inode)->commit_setup(data, &msg);
+       nfs_ops->commit_setup(data, &msg);
  
        dprintk("NFS: %5u initiated commit call\n", data->task.tk_pid);
  
@@@ -1583,14 -1567,15 +1596,15 @@@ EXPORT_SYMBOL_GPL(nfs_init_commit)
  
  void nfs_retry_commit(struct list_head *page_list,
                      struct pnfs_layout_segment *lseg,
-                     struct nfs_commit_info *cinfo)
+                     struct nfs_commit_info *cinfo,
+                     u32 ds_commit_idx)
  {
        struct nfs_page *req;
  
        while (!list_empty(page_list)) {
                req = nfs_list_entry(page_list->next);
                nfs_list_remove_request(req);
-               nfs_mark_request_commit(req, lseg, cinfo);
+               nfs_mark_request_commit(req, lseg, cinfo, ds_commit_idx);
                if (!cinfo->dreq) {
                        dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
                        dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,
@@@ -1618,10 -1603,10 +1632,10 @@@ nfs_commit_list(struct inode *inode, st
        /* Set up the argument struct */
        nfs_init_commit(data, head, NULL, cinfo);
        atomic_inc(&cinfo->mds->rpcs_out);
-       return nfs_initiate_commit(NFS_CLIENT(inode), data, data->mds_ops,
-                                  how, 0);
+       return nfs_initiate_commit(NFS_CLIENT(inode), data, NFS_PROTO(inode),
+                                  data->mds_ops, how, 0);
   out_bad:
-       nfs_retry_commit(head, NULL, cinfo);
+       nfs_retry_commit(head, NULL, cinfo, 0);
        cinfo->completion_ops->error_cleanup(NFS_I(inode));
        return -ENOMEM;
  }