DMA Mapping Error Analysis
Contents |
DMA Mapping Error Check Analysis
I analyzed all calls to dma_map_single() and dma_map_page() in the kernel, to see if callers check for mapping errors, before using the returned address. The goal of this analysis is to find drivers that currently do not check dma mapping errors, and fix them. I did a grep for dma_map_single() and dma_map_page() and looked at the code that calls these routines. As a side note, this analysis stemmed from the discussion on my patch that disables swiotlb overflow as a first step towards removing the support all together.
linux-next August 6 2012 is used as the base for this analysis.
I classified the results into three categories, Broken, Partially Broken, Unmap Broken, and Good. Details below:
Broken
- Broken - No dma mapping error checks done on the returned address.
- Partially Broken - In that source file, not all calls are followed by mapping error checks.
- Unmap broken - Checks dma mapping errors, however doesn't unmap already mapped pages when mapping error occurs in the middle of a multiple page mapping attempt.
The first two categories Broken, and Partially Broken are classified as severe and need fixing. The third one needs fixing, since it leaves dangling mapped pages, and holds on to them which is equivalent to a memory leak condition. Some drivers release all mapped pages when the device closes, but others don't. Not doing unmap might be harmless on some architectures going by the comments I found in some source files.
Good
- Checks dma mapping errors and unmaps already mapped pages when mapping error occurs in the middle of a multiple page mapping attempt.
- Checks dma mapping errors without unlikely()
- Checks dma mapping errors with unlikely()
I grouped the above three cases as good cases. Using unlikely() is icing on the cake, and something we don't need to be concerned about considering the other more serious problems in this area.
dmap_map_single() - results
- Broken - 195 (46%)
- Partially broken - 46 (11%)
- Unmap broken: 26 (6%)
- Good: 147 (35%)
dma_map_page() - results
- Broken: 61 (59%)
- Partially broken: 7 (.06%)
- Unmap broken: 15 (14.5%)
- Good: 20 (19%)
In summary, a large % of the cases (> 50%) go unchecked. This raises the following questions:
- When do mapping errors get detected?
- How often do these errors occur?
- Why don't we see failures related to missing dma mapping error checks?
- Are they silent failures?
I propose the following next steps to gather more information and understand the severity of the problem.
Next Steps
- Enhance swiotlb or dma-debug infrastructure to track how often overflow buffer is triggered. I am working on this change. [V1 patch https://lkml.org/lkml/2012/8/31/376]
- Enhance dma-debug infrastructure to track dma map and unmap errors - I am working on this change. [V1 Patch https://lkml.org/lkml/2012/9/2/80]
- Assess severity and fix drivers and modules as needed.
- Circle back to where I started - remove swiotlb overflow buffer support to make it consistent with the rest of the iotlb implementations. Removing support will be done in phases starting with deprecation notice, before removing the feature. [V1 patch https://lkml.org/lkml/2012/8/24/426]
In addition to the above, I am sharing the information with the community at large, so individual driver and module owners can take a look at this analysis and assess the severity of the reported problems. I propose that, we use this page to record comments and track progress made on fixing the problem drivers and modules. If you have comments, questions etc. please contact [Shuah Khan]
Detailed Analysis
The following is the detailed information on the nature of problems with dma mapping error checking, ranging from not checking mapping errors, doing partial checks, not unmapping, and checking and unmapping correctly.
dma_map_single() usages and error checking status
The following table lists the source files that call dma_map_single() and whether or not dma mapping errors are checked on the returned address. Also includes the status that indicates the cases that are broken and need fixing. Observations and open issues if any are captured in the Notes column. Individual driver and module owners can assess the severity of the broken cases.
| File Name | # of calls | Status | Notes |
|---|---|---|---|
| arch/arm/mach-rpc/dma.c | 1 | Broken | |
| arch/arm/kernel/dma-isa.c | 1 | Broken | |
| drivers/parport/parport_pc.c | 1 | Broken | |
| drivers/parport/parport_ip32.c | 1 | Broken | |
| drivers/infiniband/core/mad.c | 3 | Broken | |
| drivers/atm/fore200e.c | 1 | Broken | |
| drivers/tty/serial/msm_serial_hs.c | 5 | Broken | |
| drivers/tty/serial/atmel_serial.c | 2 | Broken | |
| drivers/tty/serial/mfd.c | 2 | Broken | |
| drivers/spi/spi-stmp.c | 1 | Broken | |
| drivers/dma/mv_xor.c | 2 | Broken | |
| drivers/dma/dmaengine.c | 3 | Broken | |
| drivers/dma/iop-adma.c | 2 | Broken | |
| drivers/dma/dw_dmac.c | 1 | Broken | |
| drivers/dma/ioat/dma.c | 2 | Broken | |
| drivers/dma/dmatest.c | 2 | Broken | |
| drivers/dma/txx9dmac.c | 1 | Broken | |
| drivers/mtd/nand/fsmc_nand.c | 1 | Broken | |
| drivers/scsi/initio.c | 1 | Broken | |
| drivers/scsi/isci/request.c | 1 | Broken | |
| drivers/scsi/sgiwd93.c | 1 | Broken | |
| drivers/scsi/sun_esp.c | 1 | Broken | |
| drivers/scsi/jazz_esp.c | 1 | Broken | |
| drivers/scsi/53c700.c | 2 | Broken | |
| drivers/scsi/sun3x_esp.c | 1 | Broken | do sun3x_esp_map_single() callers check errors? |
| drivers/scsi/qla4xxx/ql4_os.c | 1 | Broken | |
| drivers/usb/host/whci/qset.c | 3 | Broken | |
| drivers/usb/musb/tusb6010_omap.c | 2 | Broken | |
| drivers/usb/musb/musb_gadget.c | 1 | Broken | |
| drivers/usb/core/usb.c | 1 | Broken | |
| drivers/usb/gadget/atmel_usba_udc.c | 1 | Broken | |
| drivers/usb/gadget/mv_udc_core.c | 2 | Broken | |
| drivers/usb/gadget/fsl_udc_core.c | 3 | Broken | |
| drivers/usb/gadget/lpc32xx_udc.c | 1 | Broken | |
| drivers/usb/gadget/mv_u3d_core.c | 1 | Broken | |
| drivers/usb/gadget/pch_udc.c | 5 | Broken | |
| drivers/usb/gadget/fsl_qe_udc.c | 3 | Broken | |
| drivers/video/grvga.c | 1 | Broken | |
| drivers/staging/et131x/et131x.c | 9 | Broken | |
| drivers/mmc/host/mmc_spi.c | 2 | Broken | |
| drivers/media/video/vino.c | 3 | Broken | |
| drivers/gpu/drm/via/via_dmablit.c | 1 | Broken | |
| drivers/vme/bridges/vme_tsi148.c | 2 | Broken | |
| drivers/message/i2o/memory.c | 4 | Broken | i2o_dma_map_single() checks mapping error, but returns bad address - couldn't find any i2o_dma_map_single() callers. |
| drivers/net/wireless/rt2x00/rt2x00queue.c | 2 | Broken | |
| drivers/net/wireless/brcm80211/brcmsmac/dma.c | 2 | Broken | |
| drivers/net/ethernet/ibm/emac/core.c | 6 | Broken | |
| drivers/net/ethernet/sun/sunbmac.c | 3 | Broken | |
| drivers/net/ethernet/sun/niu.c | 1 | Broken | [Fixed https://lkml.org/lkml/2012/7/20/401] |
| drivers/net/ethernet/sun/sunhme.c | 5 | Broken | |
| drivers/net/ethernet/sgi/meth.c | 5 | Broken | |
| drivers/net/ethernet/smsc/smc91x.h | 2 | Broken | |
| drivers/net/ethernet/smsc/smc911x.h | 2 | Broken | |
| drivers/net/ethernet/tundra/tsi108_eth.c | 2 | Broken | |
| drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 3 | Broken | |
| drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 3 | Broken | |
| drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 | Broken | |
| drivers/net/ethernet/brocade/bna/bnad.c | 2 | Broken | |
| drivers/net/ethernet/ti/cpmac.c | 3 | Broken | |
| drivers/net/ethernet/ti/davinci_cpdma.c | 1 | Broken | |
| drivers/net/ethernet/mellanox/mlx4/en_tx.c | 1 | Broken | |
| drivers/net/ethernet/seeq/sgiseeq.c | 3 | Broken | |
| drivers/net/ethernet/intel/e1000/e1000_ethtool.c | 2 | Broken | |
| drivers/net/ethernet/freescale/fec_mpc52xx.c | 2 | Broken | |
| drivers/net/ethernet/freescale/fec.c | 3 | Broken | |
| drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c | 4 | Broken | |
| drivers/net/ethernet/freescale/ucc_geth.c | 2 | Broken | |
| drivers/net/ethernet/freescale/gianfar.c | 2 | Broken | |
| drivers/net/ethernet/xilinx/ll_temac_main.c | 4 | Broken | |
| drivers/net/ethernet/xilinx/xilinx_axienet_main.c | 4 | Broken | |
| drivers/net/ethernet/lantiq_etop.c | 2 | Broken | |
| drivers/net/ethernet/renesas/sh_eth.c | 3 | Broken | |
| drivers/net/ethernet/realtek/8139cp.c | 5 | Broken | |
| drivers/net/ethernet/marvell/mv643xx_eth.c | 2 | Broken | |
| drivers/net/ethernet/marvell/pxa168_eth.c | 2 | Broken | |
| drivers/net/ethernet/cadence/at91_ether.c | 1 | Broken | |
| drivers/net/ethernet/cadence/macb.c | 1 | Broken | |
| drivers/net/ethernet/dec/tulip/de4x5.c | 1 | Broken | |
| drivers/net/ethernet/i825xx/lib82596.c | 3 | Broken | |
| drivers/net/ethernet/octeon/octeon_mgmt.c | 4 | Broken | |
| drivers/net/ethernet/broadcom/bcm63xx_enet.c | 2 | Broken | |
| drivers/net/fddi/defxx.c | 3 | Broken | |
| drivers/crypto/talitos.c | 3 | Broken | |
| drivers/crypto/ixp4xx_crypto.c | 1 | Broken | |
| drivers/crypto/picoxcell_crypto.c | 1 | Broken | |
| drivers/crypto/bfin_crc.c | 2 | Broken | |
| drivers/crypto/caam/ctrl.c | 1 | Broken | |
| drivers/crypto/caam/caamrng.c | 2 | Broken | |
| include/asm-generic/pci-dma-compat.h | 1 | Broken | do pci_map_single() callers check errors? |
| sound/soc/sh/fsi.c | 1 | Broken | |
| sound/sparc/dbri.c | 1 | Broken | |
| drivers/scsi/advansys.c | 2 | Partially Broken | |
| drivers/mmc/host/wbsd.c | 1 | Partially Broken | Checks returned address is aligned on 64k - however doesn't call dma_mapping_error() |
| drivers/net/ethernet/intel/ixgb/ixgb_main.c | 2 | Partially Broken | |
| drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c | 2 | Partially Broken | |
| drivers/net/ethernet/intel/igbvf/netdev.c | 2 | Partially Broken | |
| drivers/net/ethernet/calxeda/xgmac.c | 2 | Partially Broken | |
| drivers/crypto/caam/caamhash.c | 20 | Partially Broken | |
| drivers/crypto/caam/caamalg.c | 13 | Partially Broken | |
| net/sunrpc/xprtrdma/verbs.c | 1 | Partially Broken | |
| drivers/infiniband/ulp/iser/iser_verbs.c | 2 | Unmap Broken | |
| drivers/mtd/onenand/omap2.c | 4 | Unmap Broken | |
| drivers/net/ethernet/ibm/ibmveth.c | 6 | Unmap Broken | |
| drivers/net/ethernet/intel/e1000e/netdev.c | 3 | Unmap Broken | |
| drivers/net/ethernet/dlink/sundance.c | 3 | Unmap Broken | |
| drivers/net/ethernet/xscale/ixp4xx_eth.c | 3 | Unmap Broken | |
| drivers/net/ethernet/sfc/rx.c | 1 | Unmap Broken | |
| drivers/net/ethernet/oki-semi/pch_gbe/pch_gbe_main.c | 2 | Unmap Broken | |
| drivers/net/wan/ixp4xx_hss.c | 3 | Unmap Broken | |
| arch/powerpc/platforms/cell/celleb_scc_pciex.c | 1 | Good | |
| arch/powerpc/platforms/cell/spider-pci.c | 1 | Good | |
| arch/c6x/include/asm/dma-mapping.h | 1 | Good | |
| arch/c6x/kernel/dma.c | 1 | Good | |
| drivers/infiniband/hw/qib/qib_sdma.c | 1 | Good | |
| drivers/infiniband/hw/qib/qib_verbs.c | 1 | Good | |
| drivers/infiniband/hw/ipath/ipath_sdma.c | 2 | Good | |
| drivers/infiniband/ulp/ipoib/ipoib_ib.c | 2 | Good | |
| drivers/infiniband/ulp/ipoib/ipoib_cm.c | 2 | Good | |
| drivers/infiniband/ulp/srpt/ib_srpt.c | 1 | Good | |
| drivers/infiniband/ulp/iser/iser_initiator.c | 1 | Good | |
| drivers/infiniband/ulp/iser/iscsi_iser.c | 1 | Good | |
| drivers/infiniband/ulp/srp/ib_srp.c | 2 | Good | |
| drivers/spi/spi-au1550.c | 3 | Good | |
| drivers/spi/spi-atmel.c | 2 | Good | |
| drivers/spi/spi-omap2-mcspi.c | 2 | Good | |
| drivers/spi/spi-davinci.c | 2 | Good | |
| drivers/spi/spi-fsl-spi.c | 4 | Good | |
| drivers/spi/spi-pxa2xx.c | 2 | Good | |
| drivers/spi/spi-s3c64xx.c | 4 | Good | |
| drivers/dma/ste_dma40.c | 2 | Good | |
| drivers/dma/timb_dma.c | 1 | Good | |
| drivers/mtd/onenand/samsung.c | 1 | Good | |
| drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 2 | Good | |
| drivers/mtd/nand/atmel_nand.c | 2 | Good | |
| drivers/mtd/nand/denali.c | 1 | Good | |
| drivers/scsi/ibmvscsi/ibmvstgt.c | 1 | Good | |
| drivers/scsi/ibmvscsi/ibmvfc.c | 2 | Good | |
| drivers/scsi/ibmvscsi/rpa_vscsi.c | 1 | Good | |
| drivers/scsi/ibmvscsi/ibmvscsi.c | 3 | Good | |
| drivers/scsi/aha1740.c | 1 | Good | |
| drivers/usb/host/imx21-hcd.c | 1 | Good | |
| drivers/usb/core/hcd.c | 2 | Good | |
| drivers/usb/gadget/fusb300_udc.c | 1 | Good | |
| drivers/usb/gadget/s3c-hsotg.c | 2 | Good | |
| drivers/usb/gadget/udc-core.c | 1 | Good | |
| drivers/staging/rts_pstor/rtsx_transport.c | 1 | Good | |
| drivers/mmc/host/sdhci.c | 2 | Good | |
| drivers/media/video/videobuf-dma-contig.c | 2 | Good | |
| drivers/media/video/omap/omap_vout.c | 2 | Good | |
| drivers/firewire/ohci.c | 1 | Good | |
| drivers/firewire/sbp2.c | 4 | Good | |
| drivers/message/i2o/iop.c | 1 | Good | |
| drivers/net/wireless/ath/ath9k/xmit.c | 1 | Good | |
| drivers/net/wireless/ath/ath9k/beacon.c | 1 | Good | |
| drivers/net/wireless/ath/ath9k/recv.c | 3 | Good | |
| drivers/net/wireless/ath/ath5k/base.c | 3 | Good | |
| drivers/net/wireless/b43legacy/dma.c | 4 | Good | |
| drivers/net/wireless/b43/dma.c | 4 | Good | |
| drivers/net/wireless/iwlwifi/pcie/trans.c | 2 | Good | |
| drivers/net/wireless/iwlwifi/pcie/tx.c | 2 | Good | |
| drivers/net/ethernet/aeroflex/greth.c | 5 | Good | |
| drivers/net/ethernet/natsemi/sonic.c | 3 | Good | |
| drivers/net/ethernet/cirrus/ep93xx_eth.c | 2 | Good | |
| drivers/net/ethernet/faraday/ftmac100.c | 1 | Good | |
| drivers/net/ethernet/micrel/ks8842.c | 2 | Good | |
| drivers/net/ethernet/micrel/ks8695net.c | 2 | Good | |
| drivers/net/ethernet/intel/e1000e/ethtool.c | 2 | Good | |
| drivers/net/ethernet/intel/igb/igb_main.c | 2 | Good | |
| drivers/net/ethernet/intel/e1000/e1000_main.c | 2 | Good | |
| drivers/net/ethernet/intel/ixgbe/ixgbe_fcoe.c | 1 | Good | |
| drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 1 | Good | |
| drivers/net/ethernet/toshiba/ps3_gelic_net.c | 3 | Good | |
| drivers/net/ethernet/realtek/r8169.c | 3 | Good | |
| drivers/net/ethernet/sfc/tx.c | 4 | Good | |
| drivers/net/ethernet/emulex/benet/be_main.c | 1 | Good | |
| drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 2 | Good | |
| drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 3 | Good | |
| drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 1 | Good | |
| drivers/net/ethernet/broadcom/bnx2.c | 3 | Good | |
| drivers/net/ethernet/broadcom/b44.c | 6 | Good | |
| drivers/ps3/ps3stor_lib.c | 1 | Good | |
| drivers/crypto/atmel-tdes.c | 2 | Good | |
| drivers/crypto/atmel-sha.c | 2 | Good | |
| drivers/crypto/omap-aes.c | 2 | Good | |
| drivers/crypto/omap-sham.c | 1 | Good | |
| drivers/crypto/caam/jr.c | 1 | Good | |
| drivers/crypto/caam/key_gen.c | 2 | Good | |
| net/9p/trans_rdma.c | 2 | Good |
dma_map_page() usages and error checking status
The following table lists the source files that call dma_map_page() and whether or not dma mapping errors are checked on the returned address. Also includes the status that indicates the cases that are broken and need fixing. Observations and open issues if any are captured in the Notes column. Individual driver and module owners can assess the severity of the broken cases.
| File Name | # of calls | Status | Notes |
|---|---|---|---|
| crypto/async_tx/async_pq.c | 7 | Broken | |
| crypto/async_tx/async_memcpy.c | 2 | Broken | |
| crypto/async_tx/async_memset.c | 4 | Broken | |
| crypto/async_tx/async_raid6_recov.c | 5 | Broken | |
| drivers/dma/mv_xor.c | 2 | Broken | |
| drivers/dma/dmaengine.c | 3 | Broken | |
| drivers/dma/iop-adma.c | 10 | Broken | |
| drivers/dma/ioat/dma_v3.c | 5 | Broken | |
| drivers/dma/ppc4xx/adma.c | 3 | Broken | |
| drivers/mtd/onenand/samsung.c | 1 | Broken | |
| drivers/staging/omapdrm/omap_gem.c | 2 | Broken | |
| drivers/staging/et131x/et131x.c | 2 | Broken | |
| drivers/staging/sep/sep_main.c | 1 | Broken | |
| drivers/mmc/host/mmc_spi.c | 1 | Broken | |
| drivers/gpu/drm/via/via_dmablit.c | 1 | Broken | |
| drivers/net/wireless/iwlwifi/pcie/rx.c | 2 | Broken | |
| drivers/net/ethernet/ibm/emac/core.c | 2 | Broken | |
| drivers/net/ethernet/intel/igbvf/netdev.c | 1 | Broken | |
| drivers/net/ethernet/emulex/benet/be_main.c | 1 | Broken | |
| drivers/crypto/amcc/crypto4xx_core.c | 5 | Broken | |
| net/sunrpc/xprtrdma/verbs.c | 1 | Broken | |
| drivers/net/ethernet/intel/e1000e/netdev.c | 2 | Partially Broken | |
| net/sunrpc/xprtrdma/svc_rdma_sendto.c | 5 | Partially Broken | |
| drivers/infiniband/hw/qib/qib_user_sdma.c | 3 | Unmap Broken | |
| drivers/infiniband/hw/ipath/ipath_user_sdma.c | 3 | Unmap Broken | |
| drivers/firewire/core-iso.c | 1 | Unmap Broken | |
| drivers/firewire/ohci.c | 1 | Unmap Broken | |
| drivers/net/ethernet/sfc/rx.c | 1 | Unmap Broken | |
| drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 2 | Unmap Broken | |
| drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 | Unmap Broken | |
| net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 2 | Unmap Broken | |
| drivers/infiniband/ulp/ipoib/ipoib_ib.c | 2 | Good | |
| drivers/infiniband/ulp/ipoib/ipoib_cm.c | 1 | Good | |
| drivers/scsi/cxgbi/libcxgbi.c | 1 | Good | |
| drivers/usb/core/hcd.c | 1 | Good | |
| drivers/staging/media/go7007/saa7134-go7007.c | 2 | Good | |
| drivers/net/ethernet/faraday/ftmac100.c | 2 | Good | |
| drivers/net/ethernet/mellanox/mlx4/en_rx.c | 2 | Good | |
| drivers/net/ethernet/intel/igb/igb_main.c | 1 | Good | |
| drivers/net/ethernet/intel/e1000/e1000_main.c | 1 | Good | |
| drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 1 | Good | |
| drivers/net/ethernet/sfc/tx.c | 1 | Good | |
| drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 1 | Good | |
| drivers/net/ethernet/broadcom/bnx2.c | 1 | Good | |
| net/rds/iw_recv.c | 1 | Good | |
| net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 | Good |