All of lore.kernel.org
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
To: linux-kernel@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	stable@vger.kernel.org, Esben Haabendal <esben@geanix.com>,
	"David S. Miller" <davem@davemloft.net>,
	Sasha Levin <sashal@kernel.org>
Subject: [PATCH 5.4 30/60] net: ll_temac: Fix RX buffer descriptor handling on GFP_ATOMIC pressure
Date: Thu, 19 Mar 2020 14:04:08 +0100	[thread overview]
Message-ID: <20200319123929.044989757@linuxfoundation.org> (raw)
In-Reply-To: <20200319123919.441695203@linuxfoundation.org>

From: Esben Haabendal <esben@geanix.com>

[ Upstream commit 770d9c67974c4c71af4beb786dc43162ad2a15ba ]

Failures caused by GFP_ATOMIC memory pressure have been observed, and
due to the missing error handling, results in kernel crash such as

[1876998.350133] kernel BUG at mm/slub.c:3952!
[1876998.350141] invalid opcode: 0000 [#1] PREEMPT SMP PTI
[1876998.350147] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 5.3.0-scnxt #1
[1876998.350150] Hardware name: N/A N/A/COMe-bIP2, BIOS CCR2R920 03/01/2017
[1876998.350160] RIP: 0010:kfree+0x1ca/0x220
[1876998.350164] Code: 85 db 74 49 48 8b 95 68 01 00 00 48 31 c2 48 89 10 e9 d7 fe ff ff 49 8b 04 24 a9 00 00 01 00 75 0b 49 8b 44 24 08 a8 01 75 02 <0f> 0b 49 8b 04 24 31 f6 a9 00 00 01 00 74 06 41 0f b6 74 24
 5b
[1876998.350172] RSP: 0018:ffffc900000f0df0 EFLAGS: 00010246
[1876998.350177] RAX: ffffea00027f0708 RBX: ffff888008d78000 RCX: 0000000000391372
[1876998.350181] RDX: 0000000000000000 RSI: ffffe8ffffd01400 RDI: ffff888008d78000
[1876998.350185] RBP: ffff8881185a5d00 R08: ffffc90000087dd8 R09: 000000000000280a
[1876998.350189] R10: 0000000000000002 R11: 0000000000000000 R12: ffffea0000235e00
[1876998.350193] R13: ffff8881185438a0 R14: 0000000000000000 R15: ffff888118543870
[1876998.350198] FS:  0000000000000000(0000) GS:ffff88811f300000(0000) knlGS:0000000000000000
[1876998.350203] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
s#1 Part1
[1876998.350206] CR2: 00007f8dac7b09f0 CR3: 000000011e20a006 CR4: 00000000001606e0
[1876998.350210] Call Trace:
[1876998.350215]  <IRQ>
[1876998.350224]  ? __netif_receive_skb_core+0x70a/0x920
[1876998.350229]  kfree_skb+0x32/0xb0
[1876998.350234]  __netif_receive_skb_core+0x70a/0x920
[1876998.350240]  __netif_receive_skb_one_core+0x36/0x80
[1876998.350245]  process_backlog+0x8b/0x150
[1876998.350250]  net_rx_action+0xf7/0x340
[1876998.350255]  __do_softirq+0x10f/0x353
[1876998.350262]  irq_exit+0xb2/0xc0
[1876998.350265]  do_IRQ+0x77/0xd0
[1876998.350271]  common_interrupt+0xf/0xf
[1876998.350274]  </IRQ>

In order to handle such failures more graceful, this change splits the
receive loop into one for consuming the received buffers, and one for
allocating new buffers.

When GFP_ATOMIC allocations fail, the receive will continue with the
buffers that is still there, and with the expectation that the allocations
will succeed in a later call to receive.

Fixes: 92744989533c ("net: add Xilinx ll_temac device driver")
Signed-off-by: Esben Haabendal <esben@geanix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
 drivers/net/ethernet/xilinx/ll_temac.h      |   1 +
 drivers/net/ethernet/xilinx/ll_temac_main.c | 112 ++++++++++++++------
 2 files changed, 82 insertions(+), 31 deletions(-)

diff --git a/drivers/net/ethernet/xilinx/ll_temac.h b/drivers/net/ethernet/xilinx/ll_temac.h
index 276292bca334d..99fe059e5c7f3 100644
--- a/drivers/net/ethernet/xilinx/ll_temac.h
+++ b/drivers/net/ethernet/xilinx/ll_temac.h
@@ -375,6 +375,7 @@ struct temac_local {
 	int tx_bd_next;
 	int tx_bd_tail;
 	int rx_bd_ci;
+	int rx_bd_tail;
 
 	/* DMA channel control setup */
 	u32 tx_chnl_ctrl;
diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c
index fd4231493449b..2e3f59dae586e 100644
--- a/drivers/net/ethernet/xilinx/ll_temac_main.c
+++ b/drivers/net/ethernet/xilinx/ll_temac_main.c
@@ -389,12 +389,13 @@ static int temac_dma_bd_init(struct net_device *ndev)
 	lp->tx_bd_next = 0;
 	lp->tx_bd_tail = 0;
 	lp->rx_bd_ci = 0;
+	lp->rx_bd_tail = RX_BD_NUM - 1;
 
 	/* Enable RX DMA transfers */
 	wmb();
 	lp->dma_out(lp, RX_CURDESC_PTR,  lp->rx_bd_p);
 	lp->dma_out(lp, RX_TAILDESC_PTR,
-		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * (RX_BD_NUM - 1)));
+		       lp->rx_bd_p + (sizeof(*lp->rx_bd_v) * lp->rx_bd_tail));
 
 	/* Prepare for TX DMA transfer */
 	lp->dma_out(lp, TX_CURDESC_PTR, lp->tx_bd_p);
@@ -923,27 +924,41 @@ temac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 static void ll_temac_recv(struct net_device *ndev)
 {
 	struct temac_local *lp = netdev_priv(ndev);
-	struct sk_buff *skb, *new_skb;
-	unsigned int bdstat;
-	struct cdmac_bd *cur_p;
-	dma_addr_t tail_p, skb_dma_addr;
-	int length;
 	unsigned long flags;
+	int rx_bd;
+	bool update_tail = false;
 
 	spin_lock_irqsave(&lp->rx_lock, flags);
 
-	tail_p = lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_ci;
-	cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-
-	bdstat = be32_to_cpu(cur_p->app0);
-	while ((bdstat & STS_CTRL_APP0_CMPLT)) {
+	/* Process all received buffers, passing them on network
+	 * stack.  After this, the buffer descriptors will be in an
+	 * un-allocated stage, where no skb is allocated for it, and
+	 * they are therefore not available for TEMAC/DMA.
+	 */
+	do {
+		struct cdmac_bd *bd = &lp->rx_bd_v[lp->rx_bd_ci];
+		struct sk_buff *skb = lp->rx_skb[lp->rx_bd_ci];
+		unsigned int bdstat = be32_to_cpu(bd->app0);
+		int length;
+
+		/* While this should not normally happen, we can end
+		 * here when GFP_ATOMIC allocations fail, and we
+		 * therefore have un-allocated buffers.
+		 */
+		if (!skb)
+			break;
 
-		skb = lp->rx_skb[lp->rx_bd_ci];
-		length = be32_to_cpu(cur_p->app4) & 0x3FFF;
+		/* Loop over all completed buffer descriptors */
+		if (!(bdstat & STS_CTRL_APP0_CMPLT))
+			break;
 
-		dma_unmap_single(ndev->dev.parent, be32_to_cpu(cur_p->phys),
+		dma_unmap_single(ndev->dev.parent, be32_to_cpu(bd->phys),
 				 XTE_MAX_JUMBO_FRAME_SIZE, DMA_FROM_DEVICE);
+		/* The buffer is not valid for DMA anymore */
+		bd->phys = 0;
+		bd->len = 0;
 
+		length = be32_to_cpu(bd->app4) & 0x3FFF;
 		skb_put(skb, length);
 		skb->protocol = eth_type_trans(skb, ndev);
 		skb_checksum_none_assert(skb);
@@ -958,39 +973,74 @@ static void ll_temac_recv(struct net_device *ndev)
 			 * (back) for proper IP checksum byte order
 			 * (be16).
 			 */
-			skb->csum = htons(be32_to_cpu(cur_p->app3) & 0xFFFF);
+			skb->csum = htons(be32_to_cpu(bd->app3) & 0xFFFF);
 			skb->ip_summed = CHECKSUM_COMPLETE;
 		}
 
 		if (!skb_defer_rx_timestamp(skb))
 			netif_rx(skb);
+		/* The skb buffer is now owned by network stack above */
+		lp->rx_skb[lp->rx_bd_ci] = NULL;
 
 		ndev->stats.rx_packets++;
 		ndev->stats.rx_bytes += length;
 
-		new_skb = netdev_alloc_skb_ip_align(ndev,
-						XTE_MAX_JUMBO_FRAME_SIZE);
-		if (!new_skb) {
-			spin_unlock_irqrestore(&lp->rx_lock, flags);
-			return;
+		rx_bd = lp->rx_bd_ci;
+		if (++lp->rx_bd_ci >= RX_BD_NUM)
+			lp->rx_bd_ci = 0;
+	} while (rx_bd != lp->rx_bd_tail);
+
+	/* Allocate new buffers for those buffer descriptors that were
+	 * passed to network stack.  Note that GFP_ATOMIC allocations
+	 * can fail (e.g. when a larger burst of GFP_ATOMIC
+	 * allocations occurs), so while we try to allocate all
+	 * buffers in the same interrupt where they were processed, we
+	 * continue with what we could get in case of allocation
+	 * failure.  Allocation of remaining buffers will be retried
+	 * in following calls.
+	 */
+	while (1) {
+		struct sk_buff *skb;
+		struct cdmac_bd *bd;
+		dma_addr_t skb_dma_addr;
+
+		rx_bd = lp->rx_bd_tail + 1;
+		if (rx_bd >= RX_BD_NUM)
+			rx_bd = 0;
+		bd = &lp->rx_bd_v[rx_bd];
+
+		if (bd->phys)
+			break;	/* All skb's allocated */
+
+		skb = netdev_alloc_skb_ip_align(ndev, XTE_MAX_JUMBO_FRAME_SIZE);
+		if (!skb) {
+			dev_warn(&ndev->dev, "skb alloc failed\n");
+			break;
 		}
 
-		cur_p->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
-		skb_dma_addr = dma_map_single(ndev->dev.parent, new_skb->data,
+		skb_dma_addr = dma_map_single(ndev->dev.parent, skb->data,
 					      XTE_MAX_JUMBO_FRAME_SIZE,
 					      DMA_FROM_DEVICE);
-		cur_p->phys = cpu_to_be32(skb_dma_addr);
-		cur_p->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
-		lp->rx_skb[lp->rx_bd_ci] = new_skb;
+		if (WARN_ON_ONCE(dma_mapping_error(ndev->dev.parent,
+						   skb_dma_addr))) {
+			dev_kfree_skb_any(skb);
+			break;
+		}
 
-		lp->rx_bd_ci++;
-		if (lp->rx_bd_ci >= RX_BD_NUM)
-			lp->rx_bd_ci = 0;
+		bd->phys = cpu_to_be32(skb_dma_addr);
+		bd->len = cpu_to_be32(XTE_MAX_JUMBO_FRAME_SIZE);
+		bd->app0 = cpu_to_be32(STS_CTRL_APP0_IRQONEND);
+		lp->rx_skb[rx_bd] = skb;
+
+		lp->rx_bd_tail = rx_bd;
+		update_tail = true;
+	}
 
-		cur_p = &lp->rx_bd_v[lp->rx_bd_ci];
-		bdstat = be32_to_cpu(cur_p->app0);
+	/* Move tail pointer when buffers have been allocated */
+	if (update_tail) {
+		lp->dma_out(lp, RX_TAILDESC_PTR,
+			lp->rx_bd_p + sizeof(*lp->rx_bd_v) * lp->rx_bd_tail);
 	}
-	lp->dma_out(lp, RX_TAILDESC_PTR, tail_p);
 
 	spin_unlock_irqrestore(&lp->rx_lock, flags);
 }
-- 
2.20.1




  parent reply	other threads:[~2020-03-19 13:22 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-19 13:03 [PATCH 5.4 00/60] 5.4.27-rc1 review Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 01/60] netfilter: hashlimit: do not use indirect calls during gc Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 02/60] netfilter: xt_hashlimit: unregister proc file before releasing mutex Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 03/60] drm/amdgpu: Fix TLB invalidation request when using semaphore Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 04/60] mmc: core: Default to generic_cmd6_time as timeout in __mmc_switch() Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 05/60] mmc: core: Allow host controllers to require R1B for CMD6 Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 06/60] mmc: sdhci-tegra: Fix busy detection by enabling MMC_CAP_NEED_RSP_BUSY Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 07/60] mmc: sdhci-omap: " Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 08/60] mmc: core: Respect MMC_CAP_NEED_RSP_BUSY for eMMC sleep command Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 09/60] mmc: core: Respect MMC_CAP_NEED_RSP_BUSY for erase/trim/discard Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 10/60] ACPI: watchdog: Allow disabling WDAT at boot Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 11/60] HID: apple: Add support for recent firmware on Magic Keyboards Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 12/60] ACPI: watchdog: Set default timeout in probe Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 13/60] HID: i2c-hid: add Trekstor Surfbook E11B to descriptor override Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 14/60] mips: vdso: fix jalr t9 crash in vdso code Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 15/60] MIPS: Disable VDSO time functionality on microMIPS Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 16/60] mips: vdso: add build time check that no jalr t9 calls left Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 17/60] HID: hid-bigbenff: fix general protection fault caused by double kfree Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 18/60] HID: hid-bigbenff: call hid_hw_stop() in case of error Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 19/60] HID: hid-bigbenff: fix race condition for scheduled work during removal Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 20/60] MIPS: vdso: Wrap -mexplicit-relocs in cc-option Greg Kroah-Hartman
2020-03-19 13:03 ` [PATCH 5.4 21/60] selftests/rseq: Fix out-of-tree compilation Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 22/60] tracing: Fix number printing bug in print_synth_event() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 23/60] cfg80211: check reg_rule for NULL in handle_channel_custom() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 24/60] scsi: libfc: free response frame from GPN_ID Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 25/60] net: usb: qmi_wwan: restore mtu min/max values after raw_ip switch Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 26/60] net: ks8851-ml: Fix IRQ handling and locking Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 27/60] mac80211: rx: avoid RCU list traversal under mutex Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 28/60] net: ll_temac: Fix race condition causing TX hang Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 29/60] net: ll_temac: Add more error handling of dma_map_single() calls Greg Kroah-Hartman
2020-03-19 13:04 ` Greg Kroah-Hartman [this message]
2020-03-19 13:04 ` [PATCH 5.4 31/60] net: ll_temac: Handle DMA halt condition caused by buffer underrun Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 32/60] blk-mq: insert passthrough request into hctx->dispatch directly Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 33/60] drm/amdgpu: fix memory leak during TDR test(v2) Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 34/60] kbuild: add dtbs_check to PHONY Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 35/60] kbuild: add dt_binding_check to PHONY in a correct place Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 36/60] signal: avoid double atomic counter increments for user accounting Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 37/60] slip: not call free_netdev before rtnl_unlock in slip_open Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 38/60] net: phy: mscc: fix firmware paths Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 39/60] hinic: fix a irq affinity bug Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 40/60] hinic: fix a bug of setting hw_ioctxt Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 41/60] hinic: fix a bug of rss configuration Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 42/60] net: rmnet: fix NULL pointer dereference in rmnet_newlink() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 43/60] net: rmnet: fix NULL pointer dereference in rmnet_changelink() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 44/60] net: rmnet: fix suspicious RCU usage Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 45/60] net: rmnet: remove rcu_read_lock in rmnet_force_unassociate_device() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 46/60] net: rmnet: do not allow to change mux id if mux id is duplicated Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 47/60] net: rmnet: use upper/lower device infrastructure Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 48/60] net: rmnet: fix bridge mode bugs Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 49/60] net: rmnet: fix packet forwarding in rmnet bridge mode Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 50/60] sfc: fix timestamp reconstruction at 16-bit rollover points Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 51/60] jbd2: fix data races at struct journal_head Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 52/60] blk-mq: insert flush request to the front of dispatch queue Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 53/60] net: qrtr: fix len of skb_put_padto in qrtr_node_enqueue Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 54/60] ARM: 8957/1: VDSO: Match ARMv8 timer in cntvct_functional() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 55/60] ARM: 8958/1: rename missed uaccess .fixup section Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 56/60] mm: slub: add missing TID bump in kmem_cache_alloc_bulk() Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 57/60] HID: google: add moonball USB id Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 58/60] HID: add ALWAYS_POLL quirk to lenovo pixart mouse Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 59/60] ARM: 8961/2: Fix Kbuild issue caused by per-task stack protector GCC plugin Greg Kroah-Hartman
2020-03-19 13:04 ` [PATCH 5.4 60/60] ipv4: ensure rcu_read_lock() in cipso_v4_error() Greg Kroah-Hartman
2020-03-19 21:59 ` [PATCH 5.4 00/60] 5.4.27-rc1 review Naresh Kamboju
2020-03-20  7:12   ` Greg Kroah-Hartman
2020-03-21 18:18     ` Naresh Kamboju
2020-03-19 23:55 ` Guenter Roeck
2020-03-20 10:55   ` Greg Kroah-Hartman
2020-03-20 11:23     ` Naresh Kamboju
2020-03-20 11:31       ` Greg Kroah-Hartman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200319123929.044989757@linuxfoundation.org \
    --to=gregkh@linuxfoundation.org \
    --cc=davem@davemloft.net \
    --cc=esben@geanix.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=sashal@kernel.org \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.