[kernel] Fix forcedeth DMA check error (rhbz 928024)

Justin M. Forbes jforbes at fedoraproject.org
Fri Apr 12 14:19:49 UTC 2013


commit e98edb5c673c95676ff26dd50d9d2b2fcb96de88
Author: Justin M. Forbes <jforbes at redhat.com>
Date:   Fri Apr 12 09:12:04 2013 -0500

    Fix forcedeth DMA check error (rhbz 928024)

 forcedeth-dma-error-check.patch |  132 +++++++++++++++++++++++++++++++++++++++
 kernel.spec                     |    9 +++
 2 files changed, 141 insertions(+), 0 deletions(-)
---
diff --git a/forcedeth-dma-error-check.patch b/forcedeth-dma-error-check.patch
new file mode 100644
index 0000000..0baee2a
--- /dev/null
+++ b/forcedeth-dma-error-check.patch
@@ -0,0 +1,132 @@
+This backtrace was recently reported on a 3.9 kernel:
+
+Actual results: from syslog /var/log/messsages:
+kernel: [17539.340285] ------------[ cut here ]------------
+kernel: [17539.341012] WARNING: at lib/dma-debug.c:937 check_unmap+0x493/0x960()
+kernel: [17539.341012] Hardware name: MS-7125
+kernel: [17539.341012] forcedeth 0000:00:0a.0: DMA-API: device driver failed to
+check map error[device address=0x0000000013c88000] [size=544 bytes] [mapped as
+page]
+kernel: [17539.341012] Modules linked in: fuse ebtable_nat ipt_MASQUERADE
+nf_conntrack_netbios_ns nf_conntrack_broadcast ip6table_nat nf_nat_ipv6
+ip6table_mangle ip6t_REJECT nf_conntrack_ipv6 nf_defrag_ipv6 iptable_nat
+nf_nat_ipv4 nf_nat iptable_mangle nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack
+nf_conntrack bnep bluetooth rfkill ebtable_filter ebtables ip6table_filter
+ip6_tables snd_hda_codec_hdmi snd_cmipci snd_mpu401_uart snd_hda_intel
+snd_intel8x0 snd_opl3_lib snd_ac97_codec gameport snd_hda_codec snd_rawmidi
+ac97_bus snd_hwdep snd_seq snd_seq_device snd_pcm snd_page_alloc snd_timer snd
+k8temp soundcore serio_raw i2c_nforce2 forcedeth ata_generic pata_acpi nouveau
+video mxm_wmi wmi i2c_algo_bit drm_kms_helper ttm drm i2c_core sata_sil pata_amd
+sata_nv uinput
+kernel: [17539.341012] Pid: 17340, comm: sshd Not tainted
+3.9.0-0.rc4.git0.1.fc19.i686.PAE #1
+kernel: [17539.341012] Call Trace:
+kernel: [17539.341012]  [<c045573c>] warn_slowpath_common+0x6c/0xa0
+kernel: [17539.341012]  [<c0701953>] ? check_unmap+0x493/0x960
+kernel: [17539.341012]  [<c0701953>] ? check_unmap+0x493/0x960
+kernel: [17539.341012]  [<c04557a3>] warn_slowpath_fmt+0x33/0x40
+kernel: [17539.341012]  [<c0701953>] check_unmap+0x493/0x960
+kernel: [17539.341012]  [<c049238f>] ? sched_clock_cpu+0xdf/0x150
+kernel: [17539.341012]  [<c0701e87>] debug_dma_unmap_page+0x67/0x70
+kernel: [17539.341012]  [<f7eae8f2>] nv_unmap_txskb.isra.32+0x92/0x100
+
+Its pretty plainly the result of an skb fragment getting unmapped without having
+its initial mapping operation checked for errors.  This patch corrects that.
+
+Signed-off-by: Neil Horman <nhorman at tuxdriver.com>
+CC: "David S. Miller" <davem at davemloft.net>
+---
+ drivers/net/ethernet/nvidia/forcedeth.c | 41 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 40 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
+index b62262c..5ae1247 100644
+--- a/drivers/net/ethernet/nvidia/forcedeth.c
++++ b/drivers/net/ethernet/nvidia/forcedeth.c
+@@ -2200,6 +2200,7 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 	struct ring_desc *start_tx;
+ 	struct ring_desc *prev_tx;
+ 	struct nv_skb_map *prev_tx_ctx;
++	struct nv_skb_map *tmp_tx_ctx = NULL, *start_tx_ctx = NULL;
+ 	unsigned long flags;
+ 
+ 	/* add fragments to entries count */
+@@ -2261,12 +2262,31 @@ static netdev_tx_t nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ 		do {
+ 			prev_tx = put_tx;
+ 			prev_tx_ctx = np->put_tx_ctx;
++			if (!start_tx_ctx)
++				start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx;
++
+ 			bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size;
+ 			np->put_tx_ctx->dma = skb_frag_dma_map(
+ 							&np->pci_dev->dev,
+ 							frag, offset,
+ 							bcnt,
+ 							DMA_TO_DEVICE);
++			if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) {
++
++				/* Unwind the mapped fragments */
++				do {
++					nv_unmap_txskb(np, start_tx_ctx);
++					if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
++						tmp_tx_ctx = np->first_tx_ctx;
++				} while (tmp_tx_ctx != np->put_tx_ctx);
++				kfree_skb(skb);
++				np->put_tx_ctx = start_tx_ctx;
++				u64_stats_update_begin(&np->swstats_tx_syncp);
++				np->stat_tx_dropped++;
++				u64_stats_update_end(&np->swstats_tx_syncp);
++				return NETDEV_TX_OK;
++			}
++
+ 			np->put_tx_ctx->dma_len = bcnt;
+ 			np->put_tx_ctx->dma_single = 0;
+ 			put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+@@ -2327,7 +2347,8 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
+ 	struct ring_desc_ex *start_tx;
+ 	struct ring_desc_ex *prev_tx;
+ 	struct nv_skb_map *prev_tx_ctx;
+-	struct nv_skb_map *start_tx_ctx;
++	struct nv_skb_map *start_tx_ctx = NULL;
++	struct nv_skb_map *tmp_tx_ctx = NULL;
+ 	unsigned long flags;
+ 
+ 	/* add fragments to entries count */
+@@ -2392,11 +2413,29 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
+ 			prev_tx = put_tx;
+ 			prev_tx_ctx = np->put_tx_ctx;
+ 			bcnt = (frag_size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : frag_size;
++			if (!start_tx_ctx)
++				start_tx_ctx = tmp_tx_ctx = np->put_tx_ctx;
+ 			np->put_tx_ctx->dma = skb_frag_dma_map(
+ 							&np->pci_dev->dev,
+ 							frag, offset,
+ 							bcnt,
+ 							DMA_TO_DEVICE);
++
++			if (dma_mapping_error(&np->pci_dev->dev, np->put_tx_ctx->dma)) {
++
++				/* Unwind the mapped fragments */
++				do {
++					nv_unmap_txskb(np, start_tx_ctx);
++					if (unlikely(tmp_tx_ctx++ == np->last_tx_ctx))
++						tmp_tx_ctx = np->first_tx_ctx;
++				} while (tmp_tx_ctx != np->put_tx_ctx);
++				kfree_skb(skb);
++				np->put_tx_ctx = start_tx_ctx;
++				u64_stats_update_begin(&np->swstats_tx_syncp);
++				np->stat_tx_dropped++;
++				u64_stats_update_end(&np->swstats_tx_syncp);
++				return NETDEV_TX_OK;
++			}
+ 			np->put_tx_ctx->dma_len = bcnt;
+ 			np->put_tx_ctx->dma_single = 0;
+ 			put_tx->bufhigh = cpu_to_le32(dma_high(np->put_tx_ctx->dma));
+-- 
+1.7.11.7
+
+--
+To unsubscribe from this list: send the line "unsubscribe netdev" in
+the body of a message to majordomo at vger.kernel.org
+More majordomo info at  http://vger.kernel.org/majordomo-info.html
\ No newline at end of file
diff --git a/kernel.spec b/kernel.spec
index b0aa13f..5c8a8e5 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -749,6 +749,9 @@ Patch23006: fix-child-thread-introspection.patch
 #rhbz 949875
 Patch23007: libsas-use-right-function-to-alloc-smp-response.patch
 
+#rhbz 928024
+Patch23008: forcedeth-dma-error-check.patch
+
 # END OF PATCH DEFINITIONS
 
 %endif
@@ -1448,6 +1451,9 @@ ApplyPatch fix-child-thread-introspection.patch
 #rhbz 949875
 ApplyPatch libsas-use-right-function-to-alloc-smp-response.patch
 
+#rhbz 928024
+ApplyPatch forcedeth-dma-error-check.patch
+
 # END OF PATCH APPLICATIONS
 
 %endif
@@ -2281,6 +2287,9 @@ fi
 #                 ||----w |
 #                 ||     ||
 %changelog
+* Fri Apr 12 2013 Justin M. Forbes <jforbes at redhat.com>
+- Fix forcedeth DMA check error (rhbz 928024)
+
 * Thu Apr 11 2013 Dave Jones <davej at redhat.com>
 - Print out some extra debug information when we hit bad page tables.
 


More information about the scm-commits mailing list