linux/drivers/dma
Dan Williams b69ec58913 net_dma: mark broken
commit 7787380336 upstream.

net_dma can cause data to be copied to a stale mapping if a
copy-on-write fault occurs during dma.  The application sees missing
data.

The following trace is triggered by modifying the kernel to WARN if it
ever triggers copy-on-write on a page that is undergoing dma:

 WARNING: CPU: 24 PID: 2529 at lib/dma-debug.c:485 debug_dma_assert_idle+0xd2/0x120()
 ioatdma 0000:00:04.0: DMA-API: cpu touching an active dma mapped page [pfn=0x16bcd9]
 Modules linked in: iTCO_wdt iTCO_vendor_support ioatdma lpc_ich pcspkr dca
 CPU: 24 PID: 2529 Comm: linbug Tainted: G        W    3.13.0-rc1+ #353
  00000000000001e5 ffff88016f45f688 ffffffff81751041 ffff88017ab0ef70
  ffff88016f45f6d8 ffff88016f45f6c8 ffffffff8104ed9c ffffffff810f3646
  ffff8801768f4840 0000000000000282 ffff88016f6cca10 00007fa2bb699349
 Call Trace:
  [<ffffffff81751041>] dump_stack+0x46/0x58
  [<ffffffff8104ed9c>] warn_slowpath_common+0x8c/0xc0
  [<ffffffff810f3646>] ? ftrace_pid_func+0x26/0x30
  [<ffffffff8104ee86>] warn_slowpath_fmt+0x46/0x50
  [<ffffffff8139c062>] debug_dma_assert_idle+0xd2/0x120
  [<ffffffff81154a40>] do_wp_page+0xd0/0x790
  [<ffffffff811582ac>] handle_mm_fault+0x51c/0xde0
  [<ffffffff813830b9>] ? copy_user_enhanced_fast_string+0x9/0x20
  [<ffffffff8175fc2c>] __do_page_fault+0x19c/0x530
  [<ffffffff8175c196>] ? _raw_spin_lock_bh+0x16/0x40
  [<ffffffff810f3539>] ? trace_clock_local+0x9/0x10
  [<ffffffff810fa1f4>] ? rb_reserve_next_event+0x64/0x310
  [<ffffffffa0014c00>] ? ioat2_dma_prep_memcpy_lock+0x60/0x130 [ioatdma]
  [<ffffffff8175ffce>] do_page_fault+0xe/0x10
  [<ffffffff8175c862>] page_fault+0x22/0x30
  [<ffffffff81643991>] ? __kfree_skb+0x51/0xd0
  [<ffffffff813830b9>] ? copy_user_enhanced_fast_string+0x9/0x20
  [<ffffffff81388ea2>] ? memcpy_toiovec+0x52/0xa0
  [<ffffffff8164770f>] skb_copy_datagram_iovec+0x5f/0x2a0
  [<ffffffff8169d0f4>] tcp_rcv_established+0x674/0x7f0
  [<ffffffff816a68c5>] tcp_v4_do_rcv+0x2e5/0x4a0
  [..]
 ---[ end trace e30e3b01191b7617 ]---
 Mapped at:
  [<ffffffff8139c169>] debug_dma_map_page+0xb9/0x160
  [<ffffffff8142bf47>] dma_async_memcpy_pg_to_pg+0x127/0x210
  [<ffffffff8142cce9>] dma_memcpy_pg_to_iovec+0x119/0x1f0
  [<ffffffff81669d3c>] dma_skb_copy_datagram_iovec+0x11c/0x2b0
  [<ffffffff8169d1ca>] tcp_rcv_established+0x74a/0x7f0:

...the problem is that the receive path falls back to cpu-copy in
several locations and this trace is just one of the areas.  A few
options were considered to fix this:

1/ sync all dma whenever a cpu copy branch is taken

2/ modify the page fault handler to hold off while dma is in-flight

Option 1 adds yet more cpu overhead to an "offload" that struggles to compete
with cpu-copy.  Option 2 adds checks for behavior that is already documented as
broken when using get_user_pages().  At a minimum a debug mode is warranted to
catch and flag these violations of the dma-api vs get_user_pages().

Thanks to David for his reproducer.

Cc: Dave Jiang <dave.jiang@intel.com>
Cc: Vinod Koul <vinod.koul@intel.com>
Cc: Alexander Duyck <alexander.h.duyck@intel.com>
Reported-by: David Whipple <whipple@securedatainnovations.ch>
Acked-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2014-01-09 12:24:21 -08:00
..
bestcomm Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc 2013-02-23 17:09:55 -08:00
ioat ioatdma: fix selection of 16 vs 8 source path 2013-12-04 10:56:45 -08:00
ipu dma: ipu: ipu_idmac: Fix section mismatch 2013-04-15 09:51:18 +05:30
ppc4xx Drivers: dma: remove __dev* attributes. 2013-01-03 15:57:15 -08:00
sh sudmac: add support for SUDMAC 2013-04-30 15:50:12 +05:30
acpi-dma.c dma: acpi-dma: parse CSRT to extract additional resources 2013-05-14 10:23:57 +05:30
amba-pl08x.c pl080.h: moved from arm/include/asm/hardware to include/linux/amba/ 2013-01-13 05:19:45 -08:00
at_hdmac_regs.h at_hdmac: move to generic DMA binding 2013-04-30 14:17:41 +05:30
at_hdmac.c Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma 2013-05-09 09:46:45 -07:00
coh901318_lli.c Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma 2013-02-26 09:24:48 -08:00
coh901318.c dma: Remove erroneous __exit and __exit_p() references 2013-04-15 09:51:16 +05:30
coh901318.h dma: coh901318: merge header files 2013-01-07 17:36:37 +01:00
dmaengine.c Merge branch 'topic/of' into for-linus 2013-05-02 21:52:26 +05:30
dmaengine.h dmaengine: consolidate initialization of cookies 2012-03-13 11:37:22 +05:30
dmatest.c dmatest: do not allow to interrupt ongoing tests 2013-06-08 02:13:44 +05:30
dw_dmac_regs.h dw_dmac: add ACPI support 2013-04-15 22:04:19 +05:30
dw_dmac.c dw_dmac: add ACPI support 2013-04-15 22:04:19 +05:30
edma.c Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma 2013-02-26 09:24:48 -08:00
ep93xx_dma.c dma: ep93xx_dma: reuse is_slave_direction helper 2013-01-12 05:07:22 -08:00
fsldma.c dma: remove use of __devinit 2012-11-28 12:42:36 -08:00
fsldma.h dmaengine: move last completed cookie into generic dma_chan structure 2012-03-13 11:36:06 +05:30
imx-dma.c dmaengine: imx-dma: fix slow path issue in prep_dma_cyclic 2013-10-13 16:08:34 -07:00
imx-sdma.c dma: Remove erroneous __exit and __exit_p() references 2013-04-15 09:51:16 +05:30
intel_mid_dma_regs.h dma: fix comments 2012-09-01 08:57:12 -07:00
intel_mid_dma.c Drivers: dma: remove __dev* attributes. 2013-01-03 15:57:15 -08:00
iop-adma.c Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma 2013-02-26 09:24:48 -08:00
iovlock.c include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h 2010-03-30 22:02:32 +09:00
Kconfig net_dma: mark broken 2014-01-09 12:24:21 -08:00
Makefile dma: sh: add Kconfig 2013-04-30 15:50:12 +05:30
mmp_pdma.c Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma 2013-02-26 09:24:48 -08:00
mmp_tdma.c dma: Convert to devm_ioremap_resource() 2013-01-25 12:21:46 -08:00
mpc512x_dma.c Drivers: dma: remove __dev* attributes. 2013-01-03 15:57:15 -08:00
mv_xor.c Merge branch 'next' of git://git.infradead.org/users/vkoul/slave-dma 2013-02-26 09:24:48 -08:00
mv_xor.h dma: mv_xor: clear the window override control registers 2012-11-22 18:16:37 +01:00
mxs-dma.c dma: mxs-dma: move to generic device tree binding 2013-04-04 21:22:43 +08:00
of-dma.c dma:of: Use a mutex to protect the of_dma_list 2013-05-02 21:50:38 +05:30
omap-dma.c dmaengine: OMAP: Register SDMA controller with Device Tree DMA driver 2013-04-15 09:51:19 +05:30
pch_dma.c pch_dma: Use GFP_ATOMIC because called from interrupt context 2013-04-15 09:51:16 +05:30
pl330.c dma: pl330: Fix cyclic transfers 2013-08-11 18:35:21 -07:00
sa11x0-dma.c Drivers: dma: remove __dev* attributes. 2013-01-03 15:57:15 -08:00
sirf-dma.c dmaengine: sirf: move driver init from module_init to subsys_initcall 2013-05-02 20:48:23 +05:30
ste_dma40_ll.c dmaengine: ste_dma40: minor cosmetic fixes 2013-01-14 10:51:01 +01:00
ste_dma40_ll.h dmaengine: ste_dma40: support more than 128 event lines 2013-01-14 10:50:48 +01:00
ste_dma40.c dmaengine: ste_dma40: fix pm runtime ref counting 2013-05-27 19:50:32 +05:30
tegra20-apb-dma.c drivers/dma: don't check resource with devm_ioremap_resource 2013-05-18 11:54:55 +02:00
timb_dma.c dma: timb_dma: Fix compiler warning 2013-04-15 09:51:16 +05:30
TODO dmaengine: remove ste_dma40 from issue_pending TODO 2011-07-14 04:02:08 +05:30
txx9dmac.c dma: Remove erroneous __exit and __exit_p() references 2013-04-15 09:51:16 +05:30
txx9dmac.h dmaengine: move last completed cookie into generic dma_chan structure 2012-03-13 11:36:06 +05:30
virt-dma.c dmaengine: virt-dma: add support for cyclic DMA periodic callbacks 2012-07-01 14:15:23 +01:00
virt-dma.h dmaengine: virt-dma: add support for cyclic DMA periodic callbacks 2012-07-01 14:15:23 +01:00