* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 20:41 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <20120517121800.GA18052@1wt.eu>
On Thu, 2012-05-17 at 14:18 +0200, Willy Tarreau wrote:
> Hi Eric,
>
> I'm facing a regression in stable 3.2.17 and 3.0.31 which is
> exhibited by your patch 'tcp: allow splice() to build full TSO
> packets' which unfortunately I am very interested in !
>
> What I'm observing is that TCP transmits using splice() stall
> quite quickly if I'm using pipes larger than 64kB (even 65537
> is enough to reliably observe the stall).
>
> I'm seeing this on haproxy running on a small ARM machine (a
> dockstar), which exchanges data through a gig switch with my
> development PC. The NIC (mv643xx) doesn't support TSO but has
> GSO enabled. If I disable GSO, the problem remains. I can however
> make the problem disappear by disabling SG or Tx checksumming.
> BTW, using recv/send() instead of splice() also gets rid of the
> problem.
>
> I can also reduce the risk of seeing the problem by increasing
> the default TCP buffer sizes in tcp_wmem. By default I'm running
> at 16kB, but if I increase the output buffer size above the pipe
> size, the problem *seems* to disappear though I can't be certain,
> since larger buffers generally means the problem takes longer to
> appear, probably due to the fact that the buffers don't need to
> be filled. Still I'm certain that with 64k TCP buffers and 128k
> pipes I'm still seeing it.
>
> With strace, I'm seeing data fill up the pipe with the splice()
> call responsible for pushing the data to the output socket returing
> -1 EAGAIN. During this time, the client receives no data.
>
> Something bugs me, I have tested with a dummy server of mine,
> httpterm, which uses tee+splice() to push data outside, and it
> has no problem filling the gig pipe, and correctly recoverers
> from the EAGAIN :
>
> send(13, "HTTP/1.1 200\r\nConnection: close\r"..., 160, MSG_DONTWAIT|MSG_NOSIGNAL) = 160
> tee(0x3, 0x6, 0x10000, 0x2) = 42552
> splice(0x5, 0, 0xd, 0, 0xa00000, 0x2) = 14440
> tee(0x3, 0x6, 0x10000, 0x2) = 13880
> splice(0x5, 0, 0xd, 0, 0x9fc798, 0x2) = -1 EAGAIN (Resource temporarily unavailable)
> ...
> tee(0x3, 0x6, 0x10000, 0x2) = 13880
> splice(0x5, 0, 0xd, 0, 0x9fc798, 0x2) = 51100
> tee(0x3, 0x6, 0x10000, 0x2) = 50744
> splice(0x5, 0, 0xd, 0, 0x9efffc, 0x2) = 32120
> tee(0x3, 0x6, 0x10000, 0x2) = 30264
> splice(0x5, 0, 0xd, 0, 0x9e8284, 0x2) = -1 EAGAIN (Resource temporarily unavailable)
>
> etc...
>
> It's only with haproxy which uses splice() to copy data between
> two sockets that I'm getting the issue (data forwarded from fd 0xe
> to fd 0x6) :
>
> 16:03:17.797144 pipe([36, 37]) = 0
> 16:03:17.797318 fcntl64(36, 0x407 /* F_??? */, 0x20000) = 131072 ## note: fcntl(F_SETPIPE_SZ, 128k)
> 16:03:17.797473 splice(0xe, 0, 0x25, 0, 0x9f2234, 0x3) = 10220
> 16:03:17.797706 splice(0x24, 0, 0x6, 0, 0x27ec, 0x3) = 10220
> 16:03:17.802036 gettimeofday({1324652597, 802093}, NULL) = 0
> 16:03:17.802200 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 7
> 16:03:17.802363 gettimeofday({1324652597, 802419}, NULL) = 0
> 16:03:17.802530 splice(0xe, 0, 0x25, 0, 0x9efa48, 0x3) = 16060
> 16:03:17.802789 splice(0x24, 0, 0x6, 0, 0x3ebc, 0x3) = 16060
> 16:03:17.806593 gettimeofday({1324652597, 806651}, NULL) = 0
> 16:03:17.806759 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 4
> 16:03:17.806919 gettimeofday({1324652597, 806974}, NULL) = 0
> 16:03:17.807087 splice(0xe, 0, 0x25, 0, 0x9ebb8c, 0x3) = 17520
> 16:03:17.807356 splice(0x24, 0, 0x6, 0, 0x4470, 0x3) = 17520
> 16:03:17.809565 gettimeofday({1324652597, 809620}, NULL) = 0
> 16:03:17.809726 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 1
> 16:03:17.809883 gettimeofday({1324652597, 809937}, NULL) = 0
> 16:03:17.810047 splice(0xe, 0, 0x25, 0, 0x9e771c, 0x3) = 36500
> 16:03:17.810399 splice(0x24, 0, 0x6, 0, 0x8e94, 0x3) = 23360
> 16:03:17.810629 epoll_ctl(0x3, 0x1, 0x6, 0x85378) = 0 ## note: epoll_ctl(ADD, fd=6, dir=OUT).
> 16:03:17.810792 gettimeofday({1324652597, 810848}, NULL) = 0
> 16:03:17.810954 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 1
> 16:03:17.811188 gettimeofday({1324652597, 811246}, NULL) = 0
> 16:03:17.811356 splice(0xe, 0, 0x25, 0, 0x9de888, 0x3) = 21900
> 16:03:17.811651 splice(0x24, 0, 0x6, 0, 0x88e0, 0x3) = -1 EAGAIN (Resource temporarily unavailable)
>
Willy you say output to fd 6 hangs, but splice() returns EAGAIN here ?
(because socket buffer is full)
> So output fd 6 hangs here and will not appear anymore until
> here where I pressed Ctrl-C to stop the test :
>
I just want to make sure its not a userland error that triggers now much
faster than with prior kernels.
You drain bytes from fd 0xe to pipe buffers, but I dont see you check
write ability on destination socket prior the splice(pipe -> socket)
^ permalink raw reply
* [PATCH] STA2X11 CAN: CAN driver for the STA2X11 board
From: Federico Vaga @ 2012-05-17 20:59 UTC (permalink / raw)
To: Wolfgang Grandegger, Marc Kleine-Budde, linux-can, netdev,
linux-kernel
Cc: Federico vaga, Giancarlo Asnaghi, Alan Cox
Signed-off-by: Federico Vaga <federico.vaga@gmail.com>
Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi@st.com>
Cc: Alan Cox <alan@linux.intel.com>
---
drivers/net/can/Kconfig | 11 +
drivers/net/can/Makefile | 1 +
drivers/net/can/sta2x11_can.c | 1085 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 1097 insertions(+), 0 deletions(-)
create mode 100644 drivers/net/can/sta2x11_can.c
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index bb709fd..5b1baef 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -122,6 +122,17 @@ source "drivers/net/can/usb/Kconfig"
source "drivers/net/can/softing/Kconfig"
+config CAN_STA2X11
+ depends on CAN_DEV && HAS_IOMEM && MFD_STA2X11
+ tristate "CAN STA2X11"
+ ---help---
+ Driver for the STA2x11 CAN controller
+ Supports CAN protocol version 2.0 part A and B
+ Bit rates up to 1 MBit/s
+ 32 Message Objects
+ Programmable loop-back mode for self-test operation
+ 8-bit non-multiplex Motorola HC08 compatible module interface
+
config CAN_DEBUG_DEVICES
bool "CAN devices debugging messages"
depends on CAN
diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile
index 938be37..00474b6 100644
--- a/drivers/net/can/Makefile
+++ b/drivers/net/can/Makefile
@@ -22,5 +22,6 @@ obj-$(CONFIG_CAN_BFIN) += bfin_can.o
obj-$(CONFIG_CAN_JANZ_ICAN3) += janz-ican3.o
obj-$(CONFIG_CAN_FLEXCAN) += flexcan.o
obj-$(CONFIG_PCH_CAN) += pch_can.o
+obj-$(CONFIG_CAN_STA2X11) += sta2x11_can.o
ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
diff --git a/drivers/net/can/sta2x11_can.c b/drivers/net/can/sta2x11_can.c
new file mode 100644
index 0000000..9194b02
--- /dev/null
+++ b/drivers/net/can/sta2x11_can.c
@@ -0,0 +1,1085 @@
+/*
+ * Copyright (c) 2010-2011 Wind River Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/mfd/sta2x11-mfd.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#define PCI_DEVICE_ID_STMICRO_CAN 0xCC11
+
+#define CAN_CR 0x0 /* Control Register */
+#define CAN_CR_INI 0x01 /* Initialization */
+#define CAN_CR_IE 0x02 /* Interrupt Enable */
+#define CAN_CR_SIE 0x04 /* Status Interrupt Enable */
+#define CAN_CR_EIE 0x08 /* Error Interrupt Enable */
+#define CAN_CR_DAR 0x20 /* Disable Automatic Re-transmission */
+#define CAN_CR_CCE 0x40 /* Change Configuration Enable */
+#define CAN_CR_TME 0x80 /* Test Mode Enable */
+
+#define CAN_SR 0x04 /* Status Register */
+#define CAN_SR_LEC 0x07 /* Last Error Code */
+#define CAN_SR_LEC_STUFF 0x01 /* Stuff error */
+#define CAN_SR_LEC_FORM 0x02 /* Form error */
+#define CAN_SR_LEC_ACK 0x03 /* Acknowledgement error */
+#define CAN_SR_LEC_BIT1 0x04 /* Bit1 error */
+#define CAN_SR_LEC_BIT0 0x05 /* Bit0 error */
+#define CAN_SR_LEC_CRC 0x06 /* CRC error */
+#define CAN_SR_TXOK 0x08 /* Transmit Message Successfully */
+#define CAN_SR_RXOK 0x10 /* Receive Message Successfully */
+#define CAN_SR_EPAS 0x20 /* Error Passive */
+#define CAN_SR_WARN 0x40 /* Warning Status */
+#define CAN_SR_BOFF 0x80 /* Bus Off Status */
+
+#define CAN_ERR 0x08 /* Error Counter Register */
+#define CAN_ERR_TEC 0xFF /* Transmit Error Counter */
+#define CAN_ERR_REC 0x7F00 /* Receive Error Counter */
+#define CAN_ERR_RP 0x8000 /* Receive Error Passive */
+
+#define CAN_BTR 0x0C /* Bit Timing Register */
+
+#define CAN_BRPR 0x18 /* BRP Extension Register */
+
+#define CAN_IDR 0x10 /* Interrupt Identifier Register */
+#define CAN_IDR_STATUS 0x8000 /* Status Interrupt Identifier */
+
+#define CAN_TXR1R 0x100 /* Transmission Request Register */
+#define CAN_TXR2R 0x104 /* Transmission Request Register */
+
+#define CAN_ND1R 0x120 /* New Data Register */
+#define CAN_ND2R 0x124 /* New Data Register */
+
+#define CAN_IP1R 0x140 /* Interrupt Pending Register */
+#define CAN_IP2R 0x144 /* Interrupt Pending Register */
+
+#define CAN_MV1R 0x160 /* Message Valid Register */
+#define CAN_MV2R 0x164 /* Message Valid Register */
+
+#define CAN_IF1_CRR 0x20 /* Command Request Register */
+#define CAN_IF2_CRR 0x80 /* Command Request Register */
+#define CAN_IF_CRR_BUSY 0x8000 /* Busy Flag */
+#define CAN_IF_CRR_MSG 0x3F /* Message Number */
+
+#define CAN_IF1_CMR 0x24 /* Command Mask Register */
+#define CAN_IF2_CMR 0x84 /* Command Mask Register */
+#define CAN_IF_CMR_WR 0x80 /* Write/Read to/from Message Object */
+#define CAN_IF_CMR_MSK 0x40 /* Transfer Mask Bits */
+#define CAN_IF_CMR_AR 0x20 /* Transfer Arbitration Bits */
+#define CAN_IF_CMR_CTL 0x10 /* Transfer Control Bits */
+#define CAN_IF_CMR_CPI 0x08 /* Clear Interrupt Pending Bit */
+#define CAN_IF_CMR_TXR 0x04 /* Clear TxRqst/NewDat Bit */
+#define CAN_IF_CMR_CND 0x04 /* Clear TxRqst/NewDat Bit */
+#define CAN_IF_CMR_D30 0x02 /* Transfer Data Bytes 3:0 */
+#define CAN_IF_CMR_C74 0x01 /* Transfer Data Bytes 7:4 */
+
+#define CAN_IF1_M1R 0x28 /* Mask Register */
+#define CAN_IF2_M1R 0x88 /* Mask Register */
+
+#define CAN_IF1_M2R 0x2C /* Mask Register */
+#define CAN_IF2_M2R 0x8C /* Mask Register */
+#define CAN_IF_M2R_MXTD 0x8000
+#define CAN_IF_M2R_MDIR 0x4000
+
+#define CAN_IF1_A1R 0x30 /* Message Arbitration Register */
+#define CAN_IF2_A1R 0x90 /* Message Arbitration Register */
+
+#define CAN_IF1_A2R 0x34 /* Message Arbitration Register */
+#define CAN_IF2_A2R 0x94 /* Message Arbitration Register */
+#define CAN_IF_A2R_MSGVAL 0x8000
+#define CAN_IF_A2R_XTD 0x4000
+#define CAN_IF_A2R_DIR 0x2000
+
+#define CAN_IF1_MCR 0x38 /* Message Control Register */
+#define CAN_IF2_MCR 0x98 /* Message Control Register */
+#define CAN_IF_MCR_NEWD 0x8000
+#define CAN_IF_MCR_MSGL 0x4000
+#define CAN_IF_MCR_INTP 0x2000
+#define CAN_IF_MCR_UMSK 0x1000
+#define CAN_IF_MCR_TXIE 0x800
+#define CAN_IF_MCR_RXIE 0x400
+#define CAN_IF_MCR_RMT 0x200
+#define CAN_IF_MCR_TXR 0x100
+#define CAN_IF_MCR_EOB 0x80
+
+#define CAN_IF1_DATA1 0x3C /* Buffer Register */
+#define CAN_IF1_DATA2 0x40 /* Buffer Register */
+#define CAN_IF1_DATB1 0x44 /* Buffer Register */
+#define CAN_IF1_DATB2 0x48 /* Buffer Register */
+#define CAN_IF1_DATAV {CAN_IF1_DATA1, CAN_IF1_DATA2, \
+ CAN_IF1_DATB1, CAN_IF1_DATB2}
+
+#define CAN_IF2_DATA1 0x9C /* Buffer Register */
+#define CAN_IF2_DATA2 0xA0 /* Buffer Register */
+#define CAN_IF2_DATB1 0xA4 /* Buffer Register */
+#define CAN_IF2_DATB2 0xA8 /* Buffer Register */
+#define CAN_IF2_DATAV {CAN_IF2_DATA1, CAN_IF2_DATA2, \
+ CAN_IF2_DATB1, CAN_IF2_DATB2}
+
+#define STA2X11_ECHO_SKB_MAX 1
+
+#define MSGOBJ_FIRST 0x01
+#define MSGOBJ_LAST 0x20
+
+/* max. number of interrupts handled in ISR */
+#define STA2X11_MAX_IRQ 20
+
+/*
+ * STA2X11 private data structure
+ */
+struct sta2x11_priv {
+ struct can_priv can; /* must be the first member */
+ int open_time;
+ struct net_device *dev;
+ void __iomem *reg_base; /* ioremap'ed address to registers */
+ struct dentry *dentry;
+ struct timer_list txtimer;
+};
+
+#define STA2X11_APB_FREQ 104000000
+
+/*
+ * 32 messages are available, but only 2 messages are used.
+ * TX and RX message objects
+ */
+#define STA2X11_OBJ_TX 1
+#define STA2X11_OBJ_RX 2
+
+static struct can_bittiming_const sta2x11_can_bittiming_const = {
+ .name = KBUILD_MODNAME,
+ .tseg1_min = 2,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+};
+
+static void sta2x11_can_write_reg(struct sta2x11_priv *priv, uint32_t val, int reg)
+{
+ writel(val, priv->reg_base + reg);
+}
+
+static uint32_t sta2x11_can_read_reg(struct sta2x11_priv *priv, int reg)
+{
+ return readl(priv->reg_base + reg);
+}
+
+static void sta2x11_can_clear_interrupts(struct sta2x11_priv *priv)
+{
+ uint32_t mo;
+
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_CPI, CAN_IF1_CMR);
+ for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++)
+ sta2x11_can_write_reg(priv, mo, CAN_IF1_CRR);
+}
+
+static void sta2x11_can_enable_objs(const struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+ /* RX message object */
+ /* command mask */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR |
+ CAN_IF_CMR_MSK | CAN_IF_CMR_CTL,
+ CAN_IF1_CMR);
+ /* mask */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_M1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_M2R);
+ /* arb */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, CAN_IF_A2R_MSGVAL, CAN_IF1_A2R);
+ /* control */
+ sta2x11_can_write_reg(priv, CAN_IF_MCR_RXIE | CAN_IF_MCR_UMSK |
+ CAN_IF_MCR_EOB, CAN_IF1_MCR);
+
+ sta2x11_can_write_reg(priv, STA2X11_OBJ_RX, CAN_IF1_CRR);
+
+ /* TX message object */
+ /* command mask */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR |
+ CAN_IF_CMR_CTL, CAN_IF1_CMR);
+ /* arb */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A2R);
+ /* control */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_MCR);
+ /* Write to RAM */
+ sta2x11_can_write_reg(priv, STA2X11_OBJ_TX, CAN_IF1_CRR);
+}
+
+static void sta2x11_can_disable_objs(struct sta2x11_priv *priv)
+{
+ /* RX message object */
+ /* command mask */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR |
+ CAN_IF_CMR_CTL, CAN_IF1_CMR);
+ /* arb */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A2R);
+ /* control */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_MCR);
+ /* command */
+ sta2x11_can_write_reg(priv, STA2X11_OBJ_RX, CAN_IF1_CRR);
+
+ /* TX message object */
+ /* command mask */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR |
+ CAN_IF_CMR_CTL, CAN_IF1_CMR);
+ /* arb */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A2R);
+ /* control */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_MCR);
+ /* command */
+ sta2x11_can_write_reg(priv, STA2X11_OBJ_TX, CAN_IF1_CRR);
+}
+
+static void sta2x11_can_reset_mode(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) {
+ /* cancel timer handling tx request poll */
+ del_timer_sync(&priv->txtimer);
+ }
+
+ /* enable configuration and puts chip in bus-off, disable interrupts */
+ sta2x11_can_write_reg(priv, CAN_CR_CCE | CAN_CR_INI, CAN_CR);
+
+ priv->can.state = CAN_STATE_STOPPED;
+
+ sta2x11_can_clear_interrupts(priv);
+
+ /* clear status interrupt */
+ sta2x11_can_read_reg(priv, CAN_SR);
+ /* clear status register */
+ sta2x11_can_write_reg(priv, 0x0, CAN_SR);
+
+ /* disable all used message objects */
+ sta2x11_can_disable_objs(priv);
+}
+
+static void sta2x11_can_normal_mode(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ uint32_t ctrl;
+
+ sta2x11_can_clear_interrupts(priv);
+
+ /* clear status interrupt */
+ sta2x11_can_read_reg(priv, CAN_SR);
+ /* clear status register */
+ sta2x11_can_write_reg(priv, CAN_SR_LEC, CAN_SR);
+
+ /* enable all used message objects */
+ sta2x11_can_enable_objs(dev);
+
+ /* clear bus-off */
+ ctrl = CAN_CR_IE | CAN_CR_EIE;
+ if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
+ ctrl |= CAN_CR_SIE;
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ ctrl |= CAN_CR_DAR;
+
+ sta2x11_can_write_reg(priv, ctrl, CAN_CR);
+
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+}
+
+static void sta2x11_can_chipset_init(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct pci_dev *pdev = to_pci_dev(dev->dev.parent);
+ int data_reg[] = CAN_IF1_DATAV;
+ uint32_t mo;
+ unsigned int i;
+
+
+ /* config clock and release device from reset */
+ sta2x11_apbreg_mask(pdev, APBREG_PCG, APBREG_CAN, 0);
+ sta2x11_apbreg_mask(pdev, APBREG_PUR, APBREG_CAN, 0);
+ msleep_interruptible(100);
+ sta2x11_apbreg_mask(pdev, APBREG_PCG, APBREG_CAN, APBREG_CAN);
+ sta2x11_apbreg_mask(pdev, APBREG_PUR, APBREG_CAN, APBREG_CAN);
+ msleep_interruptible(100);
+
+ /* enable configuration and put chip in bus-off, disable interrupts */
+ sta2x11_can_write_reg(priv, CAN_CR_CCE | CAN_CR_INI, CAN_CR);
+
+ /* clear status interrupt */
+ sta2x11_can_read_reg(priv, CAN_SR);
+ /* clear status register */
+ sta2x11_can_write_reg(priv, CAN_SR_LEC, CAN_SR);
+
+ sta2x11_can_clear_interrupts(priv);
+
+ /* Invalidate message objects */
+ /* command mask */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_MSK |
+ CAN_IF_CMR_AR | CAN_IF_CMR_CTL |
+ CAN_IF_CMR_D30 | CAN_IF_CMR_C74,
+ CAN_IF1_CMR);
+ /* mask */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_M1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_M2R);
+ /* arb */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A2R);
+ /* control */
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_MCR);
+ /* data */
+ for (i = 0; i < 4; i++)
+ sta2x11_can_write_reg(priv, 0x0, data_reg[i]);
+
+ /* send command to all 32 messages */
+ for (mo = MSGOBJ_FIRST; mo <= MSGOBJ_LAST; mo++)
+ sta2x11_can_write_reg(priv, mo, CAN_IF1_CRR);
+}
+
+static void sta2x11_can_start(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+ if (priv->can.state != CAN_STATE_STOPPED)
+ sta2x11_can_reset_mode(dev);
+
+ sta2x11_can_normal_mode(dev);
+}
+
+static void sta2x11_can_write_data(struct sta2x11_priv *priv,
+ struct can_frame *cf, u8 dlc)
+{
+ int data_reg[] = CAN_IF1_DATAV;
+ uint32_t val = 0;
+ int i;
+
+ for (i = 0; i < dlc; i++) {
+ if (i & 0x1) {
+ val |= cf->data[i] << 8;
+ sta2x11_can_write_reg(priv, val, data_reg[i / 2]);
+ } else {
+ val = cf->data[i];
+ }
+ }
+ /* if dlc is an even number the last byte must be write */
+ if (i & 0x1)
+ sta2x11_can_write_reg(priv, val, data_reg[i / 2]);
+
+}
+
+static void sta2x11_can_ar_config(struct sta2x11_priv *priv, uint32_t id,
+ uint32_t dir)
+{
+ /* Arbitration configuration */
+ if (id & CAN_EFF_FLAG) { /* extended identifier */
+ id &= CAN_EFF_MASK;
+ sta2x11_can_write_reg(priv, id & 0xFFFF, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, CAN_IF_A2R_MSGVAL | CAN_IF_A2R_XTD |
+ dir | (id >> 16), CAN_IF1_A2R);
+ } else { /* standard identifier */
+ id &= CAN_SFF_MASK;
+ sta2x11_can_write_reg(priv, 0X0, CAN_IF1_A1R);
+ sta2x11_can_write_reg(priv, CAN_IF_A2R_MSGVAL | dir | (id << 2),
+ CAN_IF1_A2R);
+ }
+}
+
+static int sta2x11_can_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf = (struct can_frame *)skb->data;
+ uint32_t dlc, id, dir = 0, cmr, ctrl;
+
+ if (can_dropped_invalid_skb(dev, skb))
+ return NETDEV_TX_OK;
+
+ if ((sta2x11_can_read_reg(priv, CAN_TXR1R) & STA2X11_OBJ_TX)) {
+ dev_err(dev->dev.parent, "TX register is still occupied!\n");
+ return NETDEV_TX_BUSY;
+ }
+
+ /* It doesn't accept new message during transmission */
+ netif_stop_queue(dev);
+
+ dlc = cf->can_dlc & 0x0f;
+ id = cf->can_id;
+
+ /* Message Control Register configuration */
+ cmr = CAN_IF_CMR_WR | CAN_IF_CMR_AR | CAN_IF_CMR_CTL;
+ if (!(id & CAN_RTR_FLAG)) {
+ /* transmission */
+ dir = CAN_IF_A2R_DIR;
+ cmr |= CAN_IF_CMR_D30 | CAN_IF_CMR_C74;
+ }
+ sta2x11_can_write_reg(priv, cmr, CAN_IF1_CMR);
+
+ sta2x11_can_ar_config(priv, id, dir);
+
+ /* control */
+ ctrl = CAN_IF_MCR_TXR | CAN_IF_MCR_EOB;
+
+ if (dir) {
+ /* control */
+ ctrl |= dlc;
+ /* Write data to IF1 data registers */
+ sta2x11_can_write_data(priv, cf, dlc);
+ }
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
+ /* use polling in one-shot mode */
+ ctrl |= CAN_IF_MCR_NEWD;
+ else
+ ctrl |= CAN_IF_MCR_TXIE;
+
+ sta2x11_can_write_reg(priv, ctrl, CAN_IF1_MCR);
+
+ /* start data transfer to RAM by writing on CRR the destination */
+ sta2x11_can_write_reg(priv, STA2X11_OBJ_TX, CAN_IF1_CRR);
+
+ stats->tx_bytes += dlc;
+ dev->trans_start = jiffies;
+
+ can_put_echo_skb(skb, dev, 0);
+
+ if (priv->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT) {
+ /*
+ * when automatic re-transmission mode is disabled the txRqst
+ * bit of the respective message buffer is not set,
+ * we don't know if the transmission started or not ...
+ */
+ mod_timer(&priv->txtimer, jiffies + HZ / 100);
+ }
+ return NETDEV_TX_OK;
+}
+
+static int sta2x11_can_err(struct net_device *dev, uint32_t status)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *pcf;
+ struct sk_buff *skb;
+ uint32_t err, rec, tec, lec;
+ uint32_t can_data[4] = {0};
+ canid_t can_id = 0;
+ int i;
+
+ dev_dbg(dev->dev.parent, "status interrupt (0x%04x)\n", status);
+
+ if (status & CAN_SR_BOFF) {
+ if (priv->can.state != CAN_STATE_BUS_OFF) {
+ dev_dbg(dev->dev.parent, "entering busoff state\n");
+ /* disable interrupts */
+ sta2x11_can_write_reg(priv, CAN_CR_INI, CAN_CR);
+ can_id |= CAN_ERR_BUSOFF;
+ priv->can.state = CAN_STATE_BUS_OFF;
+ can_bus_off(dev);
+ }
+ } else if (status & CAN_SR_EPAS) {
+ if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
+ dev_dbg(dev->dev.parent,
+ "entering error passive state\n");
+ can_id |= CAN_ERR_CRTL;
+
+ err = sta2x11_can_read_reg(priv, CAN_ERR);
+ tec = (err & CAN_ERR_TEC);
+ rec = (err & CAN_ERR_REC) >> 8;
+
+ if (tec > rec)
+ can_data[1] |= CAN_ERR_CRTL_TX_PASSIVE;
+ else
+ can_data[1] |= CAN_ERR_CRTL_RX_PASSIVE;
+
+ priv->can.state = CAN_STATE_ERROR_PASSIVE;
+ priv->can.can_stats.error_passive++;
+ }
+ } else if (status & CAN_SR_WARN) {
+ if (priv->can.state != CAN_STATE_ERROR_WARNING) {
+ dev_dbg(dev->dev.parent,
+ "entering error warning state\n");
+ can_id |= CAN_ERR_CRTL;
+
+ err = sta2x11_can_read_reg(priv, CAN_ERR);
+ tec = (err & CAN_ERR_TEC);
+ rec = (err & CAN_ERR_REC) >> 8;
+
+ if (tec > rec)
+ can_data[1] |= CAN_ERR_CRTL_TX_WARNING;
+ else
+ can_data[1] |= CAN_ERR_CRTL_RX_WARNING;
+
+ priv->can.state = CAN_STATE_ERROR_WARNING;
+ priv->can.can_stats.error_warning++;
+ }
+ } else if (priv->can.state != CAN_STATE_ERROR_ACTIVE) {
+ dev_dbg(dev->dev.parent, "entering error active state\n");
+ priv->can.state = CAN_STATE_ERROR_ACTIVE;
+ }
+
+ lec = status & CAN_SR_LEC;
+
+ if (lec && (lec != CAN_SR_LEC)) {
+ if (lec == CAN_SR_LEC_ACK) {
+ dev_dbg(dev->dev.parent, "ack error\n");
+ can_id |= CAN_ERR_ACK;
+ stats->tx_errors++;
+ } else {
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+
+ can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
+ switch (lec) {
+ case CAN_SR_LEC_STUFF:
+ dev_dbg(dev->dev.parent, "stuff error\n");
+ can_data[2] |= CAN_ERR_PROT_STUFF;
+ break;
+ case CAN_SR_LEC_FORM:
+ dev_dbg(dev->dev.parent, "form error\n");
+ can_data[2] |= CAN_ERR_PROT_FORM;
+ break;
+ case CAN_SR_LEC_BIT1:
+ dev_dbg(dev->dev.parent, "bit1 error\n");
+ can_data[2] |= CAN_ERR_PROT_BIT1;
+ break;
+ case CAN_SR_LEC_BIT0:
+ dev_dbg(dev->dev.parent, "bit0 error\n");
+ can_data[2] |= CAN_ERR_PROT_BIT0;
+ break;
+ case CAN_SR_LEC_CRC:
+ dev_dbg(dev->dev.parent, "crc error\n");
+ can_data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+ break;
+ }
+ }
+ }
+
+ if (can_id) {
+ skb = alloc_can_err_skb(dev, &pcf);
+ if (unlikely(!skb))
+ return -ENOMEM;
+ pcf->can_id |= can_id;
+ for (i = 0; i < 4; i++)
+ pcf->data[i] = can_data[i];
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += pcf->can_dlc;
+ }
+ return 0;
+}
+
+static int sta2x11_can_status_interrupt(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ uint32_t status;
+
+ /* get status */
+ status = sta2x11_can_read_reg(priv, CAN_SR);
+ /* reset the status register including RXOK and TXOK */
+ sta2x11_can_write_reg(priv, CAN_SR_LEC, CAN_SR);
+
+ return sta2x11_can_err(dev, status);
+}
+
+/*
+ * Reading data from the Interface Register 2
+ */
+static void sta2x11_can_read_data(struct sta2x11_priv *priv,
+ struct can_frame *cf, u8 dlc)
+{
+ int data_reg[] = CAN_IF2_DATAV;
+ uint32_t val = 0;
+ int i;
+
+ for (i = 0; i < dlc; i++) {
+ if (i & 0x1) {
+ cf->data[i] = val >> 8;
+ } else {
+ val = sta2x11_can_read_reg(priv, data_reg[i / 2]);
+ cf->data[i] = val & 0xFF;
+ }
+ }
+}
+
+static void sta2x11_can_rx(struct net_device *dev, unsigned int mo, uint32_t ctrl)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+ uint32_t arb1, arb2;
+
+ skb = alloc_can_skb(dev, &cf);
+ if (skb == NULL)
+ return;
+
+ /* Read Arbitration 2 Register */
+ arb2 = sta2x11_can_read_reg(priv, CAN_IF2_A2R);
+ if (arb2 & CAN_IF_A2R_XTD) {
+ /* Massage has an extended identifier */
+ arb1 = sta2x11_can_read_reg(priv, CAN_IF2_A1R);
+ cf->can_id = (((arb2 & 0x1FFF) << 16) | arb1 | CAN_EFF_FLAG);
+ } else {
+ /* Massage hasn't an extended identifier */
+ cf->can_id = ((arb2 & 0x1FFF) >> 2);
+ }
+
+ if (arb2 & CAN_IF_A2R_DIR) {
+ cf->can_id |= CAN_RTR_FLAG;
+ cf->can_dlc = 0;
+ } else {
+ cf->can_dlc = get_can_dlc(ctrl & 0xF);
+ sta2x11_can_read_data(priv, cf, cf->can_dlc);
+ }
+
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+}
+
+static void sta2x11_can_rx_interrupt(struct net_device *dev, unsigned int mo)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+ struct can_frame *pcf;
+ struct sk_buff *skb;
+ uint32_t ctrl;
+
+ /* clear interrupt, read control, data, arbitration */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_CPI | CAN_IF_CMR_CND |
+ CAN_IF_CMR_AR | CAN_IF_CMR_CTL |
+ CAN_IF_CMR_D30 | CAN_IF_CMR_C74,
+ CAN_IF2_CMR);
+ sta2x11_can_write_reg(priv, mo, CAN_IF2_CRR);
+
+ ctrl = sta2x11_can_read_reg(priv, CAN_IF2_MCR);
+
+ if (ctrl & CAN_IF_MCR_MSGL) {
+ dev_dbg(dev->dev.parent, "rx overrun error\n");
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+ skb = alloc_can_err_skb(dev, &pcf);
+ if (likely(skb)) {
+ pcf->can_id |= CAN_ERR_CRTL;
+ pcf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
+ netif_rx(skb);
+
+ stats->rx_packets++;
+ stats->rx_bytes += pcf->can_dlc;
+ }
+ }
+
+ sta2x11_can_rx(dev, mo, ctrl);
+
+ /* reset message object */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR |
+ CAN_IF_CMR_CTL, CAN_IF2_CMR);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF2_M1R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF2_M2R);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF2_A1R);
+ sta2x11_can_write_reg(priv, CAN_IF_A2R_MSGVAL, CAN_IF2_A2R);
+ sta2x11_can_write_reg(priv, CAN_IF_MCR_RXIE | CAN_IF_MCR_UMSK |
+ CAN_IF_MCR_EOB, CAN_IF2_MCR);
+ sta2x11_can_write_reg(priv, mo, CAN_IF2_CRR);
+}
+
+static void sta2x11_can_tx_interrupt(struct net_device *dev, unsigned int mo)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+
+ /* clear interrupt */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_CPI | CAN_IF_CMR_CTL,
+ CAN_IF2_CMR);
+ sta2x11_can_write_reg(priv, mo, CAN_IF2_CRR);
+
+ /* invalidate */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR,
+ CAN_IF2_CMR);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF2_A2R);
+ sta2x11_can_write_reg(priv, mo, CAN_IF2_CRR);
+
+ stats->tx_packets++;
+ can_get_echo_skb(dev, 0);
+ netif_wake_queue(dev);
+}
+
+static irqreturn_t sta2x11_can_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ uint32_t intid;
+ int n = 0;
+
+ /* shared interrupts and IRQ off? */
+ if (priv->can.state == CAN_STATE_STOPPED)
+ return IRQ_NONE;
+
+ while (n < STA2X11_MAX_IRQ) {
+
+ /* read the highest pending interrupt request */
+ intid = sta2x11_can_read_reg(priv, CAN_IDR);
+ if (!intid)
+ break;
+
+ switch (intid) {
+ case CAN_IDR_STATUS:
+ sta2x11_can_status_interrupt(dev);
+ break;
+ case STA2X11_OBJ_RX:
+ sta2x11_can_rx_interrupt(dev, intid);
+ break;
+ case STA2X11_OBJ_TX:
+ sta2x11_can_tx_interrupt(dev, intid);
+ break;
+ default:
+ dev_err(dev->dev.parent, "Unexpected interrupt %i",
+ intid);
+ sta2x11_can_clear_interrupts(priv);
+ break;
+ }
+
+ n++;
+ }
+
+ return n ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static int sta2x11_can_open(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ int err;
+
+ sta2x11_can_reset_mode(dev);
+
+ err = open_candev(dev);
+ if (err)
+ return err;
+
+ err = request_irq(dev->irq, &sta2x11_can_interrupt, 0 /* FIXME */,
+ dev->name, (void *)dev);
+ if (err) {
+ close_candev(dev);
+ return -EAGAIN;
+ }
+
+ sta2x11_can_start(dev);
+ priv->open_time = jiffies;
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static int sta2x11_can_close(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+ netif_stop_queue(dev);
+ sta2x11_can_reset_mode(dev);
+
+ free_irq(dev->irq, (void *)dev);
+ close_candev(dev);
+
+ priv->open_time = 0;
+
+ return 0;
+}
+
+static int sta2x11_can_set_bittiming(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct can_bittiming *bt = &priv->can.bittiming;
+ uint32_t reg;
+
+ reg = ((bt->prop_seg + bt->phase_seg1 - 1) & 0xf) |
+ (((bt->phase_seg2 - 1) & 0x7) << 4);
+ reg <<= 8;
+ reg |= ((bt->brp - 1) & 0x3f) | (((bt->sjw - 1) & 0x3) << 6);
+ sta2x11_can_write_reg(priv, reg, CAN_BTR);
+
+ reg = ((bt->brp - 1) >> 6) & 0xf;
+ sta2x11_can_write_reg(priv, reg, CAN_BRPR);
+
+ return 0;
+}
+
+static int sta2x11_can_set_mode(struct net_device *dev, enum can_mode mode)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+ if (!priv->open_time)
+ return -EINVAL;
+
+ switch (mode) {
+ case CAN_MODE_START:
+ sta2x11_can_start(dev);
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static struct net_device *sta2x11_can_alloc(void)
+{
+ struct net_device *dev;
+ struct sta2x11_priv *priv;
+
+ dev = alloc_candev(sizeof(struct sta2x11_priv), STA2X11_ECHO_SKB_MAX);
+ if (!dev)
+ return NULL;
+
+ priv = netdev_priv(dev);
+
+ priv->dev = dev;
+
+ /* Configuring CAN */
+ priv->can.bittiming_const = &sta2x11_can_bittiming_const;
+ priv->can.do_set_bittiming = sta2x11_can_set_bittiming;
+ priv->can.do_set_mode = sta2x11_can_set_mode;
+ priv->can.clock.freq = STA2X11_APB_FREQ / 2;
+ priv->can.ctrlmode_supported = CAN_CTRLMODE_ONE_SHOT |
+ CAN_CTRLMODE_BERR_REPORTING;
+
+ return dev;
+}
+
+static void sta2x11_can_free(struct net_device *dev)
+{
+ free_candev(dev);
+}
+
+static const struct net_device_ops sta2x11_can_netdev_ops = {
+ .ndo_open = sta2x11_can_open,
+ .ndo_stop = sta2x11_can_close,
+ .ndo_start_xmit = sta2x11_can_start_xmit,
+};
+
+static void sta2x11_can_tx_poll(unsigned long xdev)
+{
+ struct net_device *dev = (struct net_device *)xdev;
+ struct sta2x11_priv *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &dev->stats;
+
+ if (sta2x11_can_read_reg(priv, CAN_ND1R) & STA2X11_OBJ_TX) {
+ dev_dbg(dev->dev.parent, "one-shot tx failed\n");
+ stats->tx_errors++;
+ stats->tx_dropped++;
+ can_free_echo_skb(dev, 0);
+ } else {
+ stats->tx_packets++;
+ can_get_echo_skb(dev, 0);
+ }
+
+ /* invalidate */
+ sta2x11_can_write_reg(priv, CAN_IF_CMR_WR | CAN_IF_CMR_AR,
+ CAN_IF1_CMR);
+ sta2x11_can_write_reg(priv, 0x0, CAN_IF1_A2R);
+ sta2x11_can_write_reg(priv, STA2X11_OBJ_TX, CAN_IF1_CRR);
+
+ netif_wake_queue(dev);
+}
+
+static int sta2x11_can_register(struct net_device *dev)
+{
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+ /* local echo */
+ dev->flags |= IFF_ECHO;
+ dev->netdev_ops = &sta2x11_can_netdev_ops;
+
+ /* init timer handling tx request poll for one-shot mode */
+ init_timer(&priv->txtimer);
+ priv->txtimer.data = (unsigned long)dev;
+ priv->txtimer.function = sta2x11_can_tx_poll;
+
+ sta2x11_can_chipset_init(dev);
+ sta2x11_can_reset_mode(dev);
+
+ return register_candev(dev);
+}
+
+static void sta2x11_can_unregister(struct net_device *dev)
+{
+ sta2x11_can_reset_mode(dev);
+ unregister_candev(dev);
+}
+
+DEFINE_PCI_DEVICE_TABLE(sta2x11_can_pci_tbl) = {
+ {
+ PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_CAN),
+ .driver_data = 0,
+ },
+ {},
+};
+
+/*
+ * Static definition of debugfs 32bit registers, on sta2x11 there is only
+ * one CAN bus
+ */
+#define REG(regname) {.name = #regname, .offset = regname}
+static struct debugfs_reg32 sta2x11_can_regs[] = {
+ REG(CAN_CR), REG(CAN_SR), REG(CAN_ERR), REG(CAN_BTR),
+ REG(CAN_BRPR), REG(CAN_IDR), REG(CAN_TXR1R), REG(CAN_TXR2R),
+ REG(CAN_ND1R), REG(CAN_ND2R), REG(CAN_IP1R), REG(CAN_IP2R),
+ REG(CAN_MV1R), REG(CAN_MV2R),
+};
+#undef REG
+static struct debugfs_regset32 sta2x11_can_regset = {
+ .regs = sta2x11_can_regs,
+ .nregs = ARRAY_SIZE(sta2x11_can_regs),
+};
+
+static int __devinit
+sta2x11_can_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ struct sta2x11_priv *priv;
+ int rc = 0;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ dev_err(&pdev->dev, "pci_enable_device FAILED\n");
+ goto out;
+ }
+
+ rc = pci_request_regions(pdev, KBUILD_MODNAME);
+ if (rc) {
+ dev_err(&pdev->dev, "pci_request_regions FAILED\n");
+ goto out_disable_device;
+ }
+
+ pci_set_master(pdev);
+ pci_enable_msi(pdev);
+
+ dev = sta2x11_can_alloc();
+ if (!dev) {
+ rc = -ENOMEM;
+ goto out_release_regions;
+ }
+
+ dev->irq = pdev->irq;
+ priv = netdev_priv(dev);
+
+ priv->reg_base = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+
+ if (!priv->reg_base) {
+ dev_err(&pdev->dev,
+ "device has no PCI memory resources, "
+ "failing adapter\n");
+ rc = -ENOMEM;
+ goto out_kfree_sta2x11;
+ }
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ rc = sta2x11_can_register(dev);
+ if (rc) {
+ dev_err(&pdev->dev, "registering %s failed (err=%d)\n",
+ KBUILD_MODNAME, rc);
+ goto out_iounmap;
+ }
+
+ pci_set_drvdata(pdev, dev);
+
+ /* Configure debugfs */
+ sta2x11_can_regset.base = priv->reg_base;
+ priv->dentry = debugfs_create_regset32("sta2x11_can", S_IFREG | S_IRUGO,
+ NULL, &sta2x11_can_regset);
+
+ return 0;
+
+out_iounmap:
+ pci_iounmap(pdev, priv->reg_base);
+out_kfree_sta2x11:
+ sta2x11_can_free(dev);
+out_release_regions:
+ pci_disable_msi(pdev);
+ pci_release_regions(pdev);
+out_disable_device:
+ /*
+ * do not call pci_disable_device on sta2x11 because it
+ * break all other Bus masters on this EP
+ */
+out:
+ return rc;
+}
+
+static void __devexit sta2x11_can_pci_remove(struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct sta2x11_priv *priv = netdev_priv(dev);
+
+
+ if (priv->dentry)
+ debugfs_remove(priv->dentry);
+
+ pci_set_drvdata(pdev, NULL);
+
+ sta2x11_can_unregister(dev);
+ pci_iounmap(pdev, priv->reg_base);
+ sta2x11_can_free(dev);
+
+ pci_disable_msi(pdev);
+ pci_release_regions(pdev);
+ /*
+ * do not call pci_disable_device on sta2x11 because it
+ * break all other Bus masters on this EP
+ */
+}
+
+static struct pci_driver sta2x11_pci_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = sta2x11_can_pci_tbl,
+ .probe = sta2x11_can_pci_probe,
+ .remove = __devexit_p(sta2x11_can_pci_remove),
+};
+
+static __init int sta2x11_can_init(void)
+{
+ return pci_register_driver(&sta2x11_pci_driver);
+}
+
+/* needs to be started after the sta2x11_apbreg driver */
+late_initcall(sta2x11_can_init);
+
+static __exit void sta2x11_can_exit(void)
+{
+ pci_unregister_driver(&sta2x11_pci_driver);
+}
+
+module_exit(sta2x11_can_exit);
+
+MODULE_AUTHOR("Wind River");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION(KBUILD_MODNAME "CAN netdevice driver");
+MODULE_DEVICE_TABLE(pci, sta2x11_pci_tbl);
--
1.7.7.6
^ permalink raw reply related
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 21:14 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1337287279.3403.44.camel@edumazet-glaptop>
On Thu, May 17, 2012 at 10:41:19PM +0200, Eric Dumazet wrote:
> On Thu, 2012-05-17 at 14:18 +0200, Willy Tarreau wrote:
> > Hi Eric,
> >
> > I'm facing a regression in stable 3.2.17 and 3.0.31 which is
> > exhibited by your patch 'tcp: allow splice() to build full TSO
> > packets' which unfortunately I am very interested in !
> >
> > What I'm observing is that TCP transmits using splice() stall
> > quite quickly if I'm using pipes larger than 64kB (even 65537
> > is enough to reliably observe the stall).
> >
> > I'm seeing this on haproxy running on a small ARM machine (a
> > dockstar), which exchanges data through a gig switch with my
> > development PC. The NIC (mv643xx) doesn't support TSO but has
> > GSO enabled. If I disable GSO, the problem remains. I can however
> > make the problem disappear by disabling SG or Tx checksumming.
> > BTW, using recv/send() instead of splice() also gets rid of the
> > problem.
> >
> > I can also reduce the risk of seeing the problem by increasing
> > the default TCP buffer sizes in tcp_wmem. By default I'm running
> > at 16kB, but if I increase the output buffer size above the pipe
> > size, the problem *seems* to disappear though I can't be certain,
> > since larger buffers generally means the problem takes longer to
> > appear, probably due to the fact that the buffers don't need to
> > be filled. Still I'm certain that with 64k TCP buffers and 128k
> > pipes I'm still seeing it.
> >
> > With strace, I'm seeing data fill up the pipe with the splice()
> > call responsible for pushing the data to the output socket returing
> > -1 EAGAIN. During this time, the client receives no data.
> >
> > Something bugs me, I have tested with a dummy server of mine,
> > httpterm, which uses tee+splice() to push data outside, and it
> > has no problem filling the gig pipe, and correctly recoverers
> > from the EAGAIN :
> >
> > send(13, "HTTP/1.1 200\r\nConnection: close\r"..., 160, MSG_DONTWAIT|MSG_NOSIGNAL) = 160
> > tee(0x3, 0x6, 0x10000, 0x2) = 42552
> > splice(0x5, 0, 0xd, 0, 0xa00000, 0x2) = 14440
> > tee(0x3, 0x6, 0x10000, 0x2) = 13880
> > splice(0x5, 0, 0xd, 0, 0x9fc798, 0x2) = -1 EAGAIN (Resource temporarily unavailable)
> > ...
> > tee(0x3, 0x6, 0x10000, 0x2) = 13880
> > splice(0x5, 0, 0xd, 0, 0x9fc798, 0x2) = 51100
> > tee(0x3, 0x6, 0x10000, 0x2) = 50744
> > splice(0x5, 0, 0xd, 0, 0x9efffc, 0x2) = 32120
> > tee(0x3, 0x6, 0x10000, 0x2) = 30264
> > splice(0x5, 0, 0xd, 0, 0x9e8284, 0x2) = -1 EAGAIN (Resource temporarily unavailable)
> >
> > etc...
> >
> > It's only with haproxy which uses splice() to copy data between
> > two sockets that I'm getting the issue (data forwarded from fd 0xe
> > to fd 0x6) :
> >
> > 16:03:17.797144 pipe([36, 37]) = 0
> > 16:03:17.797318 fcntl64(36, 0x407 /* F_??? */, 0x20000) = 131072 ## note: fcntl(F_SETPIPE_SZ, 128k)
> > 16:03:17.797473 splice(0xe, 0, 0x25, 0, 0x9f2234, 0x3) = 10220
> > 16:03:17.797706 splice(0x24, 0, 0x6, 0, 0x27ec, 0x3) = 10220
> > 16:03:17.802036 gettimeofday({1324652597, 802093}, NULL) = 0
> > 16:03:17.802200 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 7
> > 16:03:17.802363 gettimeofday({1324652597, 802419}, NULL) = 0
> > 16:03:17.802530 splice(0xe, 0, 0x25, 0, 0x9efa48, 0x3) = 16060
> > 16:03:17.802789 splice(0x24, 0, 0x6, 0, 0x3ebc, 0x3) = 16060
> > 16:03:17.806593 gettimeofday({1324652597, 806651}, NULL) = 0
> > 16:03:17.806759 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 4
> > 16:03:17.806919 gettimeofday({1324652597, 806974}, NULL) = 0
> > 16:03:17.807087 splice(0xe, 0, 0x25, 0, 0x9ebb8c, 0x3) = 17520
> > 16:03:17.807356 splice(0x24, 0, 0x6, 0, 0x4470, 0x3) = 17520
> > 16:03:17.809565 gettimeofday({1324652597, 809620}, NULL) = 0
> > 16:03:17.809726 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 1
> > 16:03:17.809883 gettimeofday({1324652597, 809937}, NULL) = 0
> > 16:03:17.810047 splice(0xe, 0, 0x25, 0, 0x9e771c, 0x3) = 36500
> > 16:03:17.810399 splice(0x24, 0, 0x6, 0, 0x8e94, 0x3) = 23360
> > 16:03:17.810629 epoll_ctl(0x3, 0x1, 0x6, 0x85378) = 0 ## note: epoll_ctl(ADD, fd=6, dir=OUT).
> > 16:03:17.810792 gettimeofday({1324652597, 810848}, NULL) = 0
> > 16:03:17.810954 epoll_wait(0x3, 0x99250, 0x16, 0x3e8) = 1
> > 16:03:17.811188 gettimeofday({1324652597, 811246}, NULL) = 0
> > 16:03:17.811356 splice(0xe, 0, 0x25, 0, 0x9de888, 0x3) = 21900
> > 16:03:17.811651 splice(0x24, 0, 0x6, 0, 0x88e0, 0x3) = -1 EAGAIN (Resource temporarily unavailable)
> >
>
> Willy you say output to fd 6 hangs, but splice() returns EAGAIN here ?
> (because socket buffer is full)
Exactly.
> > So output fd 6 hangs here and will not appear anymore until
> > here where I pressed Ctrl-C to stop the test :
> >
>
> I just want to make sure its not a userland error that triggers now much
> faster than with prior kernels.
I understand and that could be possible indeed. Still, this precise code
has been used for a few years now in prod at 10+ Gbps, so while that does
not mean it's exempt from any race condition or bug, we have not observed
this behaviour earlier. In fact, what I've not tested much was the small
ARM based machine which is just a convenient development system to try to
optimize network performance. Among the differences I see with usual
deployments is that the NIC doesn't support TSO, while I've been used to
enable splicing only where TSO was supported, because before your recent
optimizations, it was less performant than recv/send.
> You drain bytes from fd 0xe to pipe buffers, but I dont see you check
> write ability on destination socket prior the splice(pipe -> socket)
I don't, I only rely on EAGAIN to re-enable polling for write (otherwise
it becomes a real mess of epoll_ctl which sensibly hurts performance). I
only re-enable polling if FDs can't move anymore.
Before doing a splice(read), if any data are left pending in the pipe, I
first try a splice(write) to try to flush the pipe, then I perform the
splice(read) then try to flush the pipe again using a splice(write).
Then polling is enabled if we block on EAGAIN.
I could fix the issue here by reworking my first patch. I think I was
too much conservative, because if we leave do_tcp_sendpages() on OOM
with copied == 0, in my opinion we never push. My first attempt tried
to call tcp_push() only once but it seems like this is a wrong idea
because it doesn't allow new attempts if for example tcp_write_xmit()
cannot send upon first attempt.
After calling tcp_push() inconditionnally on OOM, I cannot reproduce
the issue at all, and the traffic reaches a steady 950 Mbps in each
direction.
I'm appending the patch, you'll know better than me if it's correct or
not.
Best regards,
Willy
---
>From 39c3f73176118a274ec9dea9c22c83d97a7fbfe0 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Thu, 17 May 2012 22:43:20 +0200
Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
Since recent changes on TCP splicing (starting with commits 2f533844
and 35f9c09f), I started seeing massive stalls when forwarding traffic
between two sockets using splice() when pipe buffers were larger than
socket buffers.
Latest changes (net: netdev_alloc_skb() use build_skb()) made the
problem even more apparent.
The reason seems to be that if do_tcp_sendpages() fails on out of memory
condition without being able to send at least one byte, tcp_push() is not
called and the buffers cannot be flushed.
After applying the attached patch, I cannot reproduce the stalls at all
and the data rate it perfectly stable and steady under any condition
which previously caused the problem to be permanent.
The issue seems to have been there since before the kernel migrated to
git, which makes me think that the stalls I occasionally experienced
with tux during stress-tests years ago were probably related to the
same issue.
This issue was first encountered on 3.0.31 and 3.2.17, so please backport
to -stable.
Signed-off-by: Willy Tarreau <w@1wt.eu>
Cc: <stable@vger.kernel.org>
---
net/ipv4/tcp.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 63ddaee..231fe53 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -917,8 +917,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied)
- tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+ tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
goto do_error;
--
1.7.2.1.45.g54fbc
^ permalink raw reply related
* Re: [RFC] API to modify /proc/sys/net/ipv4/ip_local_reserved_ports
From: Helge Deller @ 2012-05-17 21:18 UTC (permalink / raw)
To: Eric W. Biederman
Cc: Cong Wang, Octavian Purdila, netdev, David Miller, Andrew Morton,
Frank Danapfel, Laszlo Ersek, shemminger
In-Reply-To: <m18vi3w7zd.fsf@fess.ebiederm.org>
On 04/11/2012 12:13 AM, Eric W. Biederman wrote:
> Helge Deller <deller@gmx.de> writes:
>
>> On 04/09/2012 10:43 AM, Cong Wang wrote:
>>> On Wed, 2012-04-04 at 22:24 +0200, Helge Deller wrote:
>>>> I would like to follow up on my last patch series to be able to modify
>>>> the contents of the /proc/sys/net/ipv4/ip_local_reserved_ports port list
>>>> from userspace.
>>>>
>>>> My last patch (https://lkml.org/lkml/2012/3/10/187) was based on
>>>> modifications to the proc interface, which - based on the feedback here
>>>> on the list - seemed to not be the right way to go (although I personally
>>>> still like the idea very much :-)).
>>>>
>>>> Anyway, with this RFC I would like to get feedback about a new proposed
>>>> API and attached kernel patch.
>>>>
>>>> The idea is to introduce a new<optname> value for get/setsockopt()
>>>> named SO_RESERVED_PORTS to get/set the ip_local_reserved_ports
>>>> bitmap via standard get/setsockopt() syscalls.
>>>> As far as I understand this seems to be similiar to how iptables works.
>>>>
>>>> An untested kernel patch for review and feedback is attached below.
>>>>
>>>> In userspace it then would be possible to write a new tool or to extend
>>>> for example the "ip" tool to accept commands like:
>>>> $> ip reserved_ports add 100-2000
>>>> $> ip reserved_ports remove 50-60
>>>> $> ip reserved_ports list (to show current reserved port list)
>>>>
>>>> This userspace tool could then read the port bitmap from kernel via
>>>> a) socket(PF_INET, SOCK_RAW, IPPROTO_RAW)
>>>> b) getsockopt(3, SOL_SOCKET, SO_RESERVED_PORTS,<bitmaplist>)
>>>> and write back the results after modification via
>>>> c) setsockopt(3, SOL_SOCKET, SO_RESERVED_PORTS,<bitmaplist>)
>>>>
>>>> Would that be an acceptable solution?
>>> Hmm, it is indeed that bitmap fits for syscall rather than /proc file.
>>>
>>> But it seems that using getsockopt()/setsockopt() makes it like it is a
>>> per-socket setting, actually it is a system-wide setting.
>> Yes, that's the reason why I used SOL_SOCKET which configures at least
>> a few system-wide settings too.
>>
>>> So I am
>>> wondering if exporting a binary /proc file for this is a better
>>> solution.
>> Yeah - that's another solution, but (65536 ports)/(8 bits per byte) = 8 KByte,
>> so we
>> may again hit the 4k limit of /proc (unless you do binary reads which should
>> be done with a binary /proc-entry anyway).
>>
>> Again, I'm open to develop any kind of solution which would get an OK
>> here.
>
> Just looking at proc_do_large_bitmap, it does appear that there is a
> very local 4k limit on writes.
>
> Can you please just modify proc_do_large_bitmap so that there is not a
> 4k limit on writes. Ideally the code would just read another 4k from
> userspace when it is getting close to the end of it's 4k buffer, or
> perhaps we just read everything directly from userspace and run slowly.
Hi Eric,
sorry for the very late reply.
Yes, you are right- this is only a local 4K limit. Increasing it allowed me
to write more ports at once.
With your tips I was now able to build a simple solution which fits my needs.
Based on standard tools like echo and dd (with the seek option) I can
block all ports which I need.
Nevertheless, the current kernel interface is not very flexible.
So, my proposal for a new interface (with tools) still stands. I just need
and advise what would be acceptable. Without any advise I will just leave
everything as is (since I'm now fine with it).
Helge
^ permalink raw reply
* Re: [PATCH 2/5] drivers/net: delete all code/drivers depending on CONFIG_MCA
From: Paul Gortmaker @ 2012-05-17 21:20 UTC (permalink / raw)
To: linux-kernel, JBottomley, David S. Miller, netdev
In-Reply-To: <4FB52C99.6010303@windriver.com>
[Re: [PATCH 2/5] drivers/net: delete all code/drivers depending on CONFIG_MCA] On 17/05/2012 (Thu 12:51) Paul Gortmaker wrote:
> On 12-05-17 12:40 PM, Paul Gortmaker wrote:
>
> [..]
>
> > 18 files changed, 18 insertions(+), 5288 deletions(-)
> > delete mode 100644 drivers/net/ethernet/8390/ne2.c
> > delete mode 100644 drivers/net/ethernet/8390/smc-mca.c
> > delete mode 100644 drivers/net/ethernet/i825xx/3c523.c
> > delete mode 100644 drivers/net/ethernet/i825xx/3c523.h
> > delete mode 100644 drivers/net/ethernet/i825xx/3c527.c
>
> I can also obviously delete 3c527.h too. Not sure why I didn't
> notice that until just now... :(
I've layered the above commit (with 3c527.h deleted) onto today's
net-next, did a quick re-test of x86_64 allmodconfig and put it
on a branch as per below (vs sending a 5000+ line patch).
Thanks,
Paul.
---
The following changes since commit bc6a4744b827c5a78ca591acca81809bddb8b2db:
net/mlx4_en: num cores tx rings for every UP (2012-05-17 16:17:50 -0400)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux.git delete-mca-net-drivers
for you to fetch changes up to a5e371f61ad33c07b28e7c9b60c78d71fdd34e2a:
drivers/net: delete all code/drivers depending on CONFIG_MCA (2012-05-17 16:37:41 -0400)
----------------------------------------------------------------
Paul Gortmaker (1):
drivers/net: delete all code/drivers depending on CONFIG_MCA
Documentation/networking/3c509.txt | 1 -
Documentation/networking/fore200e.txt | 6 +-
drivers/net/Space.c | 16 +-
drivers/net/ethernet/3com/3c509.c | 123 +---
drivers/net/ethernet/8390/Kconfig | 24 -
drivers/net/ethernet/8390/Makefile | 1 -
drivers/net/ethernet/8390/ne2.c | 798 ---------------
drivers/net/ethernet/8390/smc-mca.c | 575 -----------
drivers/net/ethernet/amd/depca.c | 210 +----
drivers/net/ethernet/fujitsu/at1700.c | 120 +---
drivers/net/ethernet/i825xx/3c523.c | 1312 -------------------------
drivers/net/ethernet/i825xx/3c523.h | 355 -------
drivers/net/ethernet/i825xx/3c527.c | 1660 --------------------------------
drivers/net/ethernet/i825xx/3c527.h | 81 --
drivers/net/ethernet/i825xx/Kconfig | 22 -
drivers/net/ethernet/i825xx/Makefile | 2 -
drivers/net/ethernet/i825xx/eexpress.c | 60 +--
drivers/net/ethernet/natsemi/Kconfig | 20 +-
drivers/net/ethernet/natsemi/Makefile | 1 -
19 files changed, 18 insertions(+), 5369 deletions(-)
delete mode 100644 drivers/net/ethernet/8390/ne2.c
delete mode 100644 drivers/net/ethernet/8390/smc-mca.c
delete mode 100644 drivers/net/ethernet/i825xx/3c523.c
delete mode 100644 drivers/net/ethernet/i825xx/3c523.h
delete mode 100644 drivers/net/ethernet/i825xx/3c527.c
delete mode 100644 drivers/net/ethernet/i825xx/3c527.h
^ permalink raw reply
* Re: [RFC] API to modify /proc/sys/net/ipv4/ip_local_reserved_ports
From: Stephen Hemminger @ 2012-05-17 21:22 UTC (permalink / raw)
To: Helge Deller
Cc: Eric W. Biederman, Cong Wang, Octavian Purdila, netdev,
David Miller, Andrew Morton, Frank Danapfel, Laszlo Ersek
In-Reply-To: <4FB56B1A.6010208@gmx.de>
On Thu, 17 May 2012 23:18:18 +0200
Helge Deller <deller@gmx.de> wrote:
> On 04/11/2012 12:13 AM, Eric W. Biederman wrote:
> > Helge Deller <deller@gmx.de> writes:
> >
> >> On 04/09/2012 10:43 AM, Cong Wang wrote:
> >>> On Wed, 2012-04-04 at 22:24 +0200, Helge Deller wrote:
> >>>> I would like to follow up on my last patch series to be able to modify
> >>>> the contents of the /proc/sys/net/ipv4/ip_local_reserved_ports port list
> >>>> from userspace.
> >>>>
> >>>> My last patch (https://lkml.org/lkml/2012/3/10/187) was based on
> >>>> modifications to the proc interface, which - based on the feedback here
> >>>> on the list - seemed to not be the right way to go (although I personally
> >>>> still like the idea very much :-)).
> >>>>
> >>>> Anyway, with this RFC I would like to get feedback about a new proposed
> >>>> API and attached kernel patch.
> >>>>
> >>>> The idea is to introduce a new<optname> value for get/setsockopt()
> >>>> named SO_RESERVED_PORTS to get/set the ip_local_reserved_ports
> >>>> bitmap via standard get/setsockopt() syscalls.
> >>>> As far as I understand this seems to be similiar to how iptables works.
> >>>>
> >>>> An untested kernel patch for review and feedback is attached below.
> >>>>
> >>>> In userspace it then would be possible to write a new tool or to extend
> >>>> for example the "ip" tool to accept commands like:
> >>>> $> ip reserved_ports add 100-2000
> >>>> $> ip reserved_ports remove 50-60
> >>>> $> ip reserved_ports list (to show current reserved port list)
> >>>>
> >>>> This userspace tool could then read the port bitmap from kernel via
> >>>> a) socket(PF_INET, SOCK_RAW, IPPROTO_RAW)
> >>>> b) getsockopt(3, SOL_SOCKET, SO_RESERVED_PORTS,<bitmaplist>)
> >>>> and write back the results after modification via
> >>>> c) setsockopt(3, SOL_SOCKET, SO_RESERVED_PORTS,<bitmaplist>)
> >>>>
> >>>> Would that be an acceptable solution?
> >>> Hmm, it is indeed that bitmap fits for syscall rather than /proc file.
> >>>
> >>> But it seems that using getsockopt()/setsockopt() makes it like it is a
> >>> per-socket setting, actually it is a system-wide setting.
> >> Yes, that's the reason why I used SOL_SOCKET which configures at least
> >> a few system-wide settings too.
> >>
> >>> So I am
> >>> wondering if exporting a binary /proc file for this is a better
> >>> solution.
> >> Yeah - that's another solution, but (65536 ports)/(8 bits per byte) = 8 KByte,
> >> so we
> >> may again hit the 4k limit of /proc (unless you do binary reads which should
> >> be done with a binary /proc-entry anyway).
> >>
> >> Again, I'm open to develop any kind of solution which would get an OK
> >> here.
> >
> > Just looking at proc_do_large_bitmap, it does appear that there is a
> > very local 4k limit on writes.
> >
> > Can you please just modify proc_do_large_bitmap so that there is not a
> > 4k limit on writes. Ideally the code would just read another 4k from
> > userspace when it is getting close to the end of it's 4k buffer, or
> > perhaps we just read everything directly from userspace and run slowly.
>
> Hi Eric,
>
> sorry for the very late reply.
> Yes, you are right- this is only a local 4K limit. Increasing it allowed me
> to write more ports at once.
>
> With your tips I was now able to build a simple solution which fits my needs.
> Based on standard tools like echo and dd (with the seek option) I can
> block all ports which I need.
>
> Nevertheless, the current kernel interface is not very flexible.
> So, my proposal for a new interface (with tools) still stands. I just need
> and advise what would be acceptable. Without any advise I will just leave
> everything as is (since I'm now fine with it).
>
> Helge
Sounds like an ideal case for providing an mmap interface to the
bitmap?
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 21:40 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <20120517211414.GP14498@1wt.eu>
On Thu, 2012-05-17 at 23:14 +0200, Willy Tarreau wrote:
> I understand and that could be possible indeed. Still, this precise code
> has been used for a few years now in prod at 10+ Gbps, so while that does
> not mean it's exempt from any race condition or bug, we have not observed
> this behaviour earlier. In fact, what I've not tested much was the small
> ARM based machine which is just a convenient development system to try to
> optimize network performance. Among the differences I see with usual
> deployments is that the NIC doesn't support TSO, while I've been used to
> enable splicing only where TSO was supported, because before your recent
> optimizations, it was less performant than recv/send.
>
> > You drain bytes from fd 0xe to pipe buffers, but I dont see you check
> > write ability on destination socket prior the splice(pipe -> socket)
>
> I don't, I only rely on EAGAIN to re-enable polling for write (otherwise
> it becomes a real mess of epoll_ctl which sensibly hurts performance). I
> only re-enable polling if FDs can't move anymore.
>
> Before doing a splice(read), if any data are left pending in the pipe, I
> first try a splice(write) to try to flush the pipe, then I perform the
> splice(read) then try to flush the pipe again using a splice(write).
> Then polling is enabled if we block on EAGAIN.
>
> I could fix the issue here by reworking my first patch. I think I was
> too much conservative, because if we leave do_tcp_sendpages() on OOM
> with copied == 0, in my opinion we never push. My first attempt tried
> to call tcp_push() only once but it seems like this is a wrong idea
> because it doesn't allow new attempts if for example tcp_write_xmit()
> cannot send upon first attempt.
>
> After calling tcp_push() inconditionnally on OOM, I cannot reproduce
> the issue at all, and the traffic reaches a steady 950 Mbps in each
> direction.
>
> I'm appending the patch, you'll know better than me if it's correct or
> not.
>
> Best regards,
> Willy
>
> ---
>
> From 39c3f73176118a274ec9dea9c22c83d97a7fbfe0 Mon Sep 17 00:00:00 2001
> From: Willy Tarreau <w@1wt.eu>
> Date: Thu, 17 May 2012 22:43:20 +0200
> Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
>
> Since recent changes on TCP splicing (starting with commits 2f533844
> and 35f9c09f), I started seeing massive stalls when forwarding traffic
> between two sockets using splice() when pipe buffers were larger than
> socket buffers.
>
> Latest changes (net: netdev_alloc_skb() use build_skb()) made the
> problem even more apparent.
>
> The reason seems to be that if do_tcp_sendpages() fails on out of memory
> condition without being able to send at least one byte, tcp_push() is not
> called and the buffers cannot be flushed.
>
> After applying the attached patch, I cannot reproduce the stalls at all
> and the data rate it perfectly stable and steady under any condition
> which previously caused the problem to be permanent.
>
> The issue seems to have been there since before the kernel migrated to
> git, which makes me think that the stalls I occasionally experienced
> with tux during stress-tests years ago were probably related to the
> same issue.
>
> This issue was first encountered on 3.0.31 and 3.2.17, so please backport
> to -stable.
>
> Signed-off-by: Willy Tarreau <w@1wt.eu>
> Cc: <stable@vger.kernel.org>
> ---
> net/ipv4/tcp.c | 3 +--
> 1 files changed, 1 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 63ddaee..231fe53 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -917,8 +917,7 @@ new_segment:
> wait_for_sndbuf:
> set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> wait_for_memory:
> - if (copied)
> - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
> + tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
>
> if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
> goto do_error;
I dont understand why we should tcp_push() if we sent 0 bytes in this
splice() call.
The push() should have be done already by prior splice() call, dont you
think ?
out:
if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
tcp_push(sk, flags, mss_now, tp->nonagle);
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 21:47 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <20120517211414.GP14498@1wt.eu>
On Thu, May 17, 2012 at 11:14:14PM +0200, Willy Tarreau wrote:
> On Thu, May 17, 2012 at 10:41:19PM +0200, Eric Dumazet wrote:
> > You drain bytes from fd 0xe to pipe buffers, but I dont see you check
> > write ability on destination socket prior the splice(pipe -> socket)
>
> I don't, I only rely on EAGAIN to re-enable polling for write (otherwise
> it becomes a real mess of epoll_ctl which sensibly hurts performance). I
> only re-enable polling if FDs can't move anymore.
>
> Before doing a splice(read), if any data are left pending in the pipe, I
> first try a splice(write) to try to flush the pipe, then I perform the
> splice(read) then try to flush the pipe again using a splice(write).
> Then polling is enabled if we block on EAGAIN.
Just for the sake of documentation, I have rebuilt an up-to-date strace
so that we get the details of the epoll_ctl(). I've restarted with only
the classical epoll (without the events cache) so that it's easier to
trace event status with strace.
Here we clearly see that the output FD (6) was not reported as being
writable for a long period, until haproxy's timeout struck :
15:07:50.130499 gettimeofday({1324652870, 130772}, NULL) = 0
15:07:50.130937 gettimeofday({1324652870, 131071}, NULL) = 0
15:07:50.131195 epoll_wait(3, {}, 6, 1000) = 0
15:07:51.132529 gettimeofday({1324652871, 132654}, NULL) = 0
15:07:51.132777 gettimeofday({1324652871, 132895}, NULL) = 0
15:07:51.133013 epoll_wait(3, {{EPOLLIN, {u32=4, u64=4}}}, 6, 1000) = 1
15:07:51.561594 gettimeofday({1324652871, 561723}, NULL) = 0
15:07:51.561866 accept(4, {sa_family=AF_INET, sin_port=htons(56441), sin_addr=inet_addr("192.168.0.31")}, [16]) = 6
15:07:51.562249 fcntl64(6, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
15:07:51.562582 setsockopt(6, SOL_TCP, TCP_NODELAY, [1], 4) = 0
15:07:51.562844 accept(4, 0x7ea65a64, [128]) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.563142 epoll_ctl(3, EPOLL_CTL_ADD, 6, {EPOLLIN, {u32=6, u64=6}}) = 0
15:07:51.563421 gettimeofday({1324652871, 563540}, NULL) = 0
15:07:51.563657 epoll_wait(3, {{EPOLLIN, {u32=6, u64=6}}}, 7, 1000) = 1
15:07:51.563923 gettimeofday({1324652871, 564041}, NULL) = 0
15:07:51.564180 recv(6, "GET /?s=1g HTTP/1.0\r\nUser-Agent:"..., 7000, 0) = 126
15:07:51.564574 socket(PF_INET, SOCK_STREAM, IPPROTO_TCP) = 7
15:07:51.564817 fcntl64(7, F_SETFL, O_RDONLY|O_NONBLOCK) = 0
15:07:51.565040 setsockopt(7, SOL_TCP, TCP_NODELAY, [1], 4) = 0
15:07:51.565277 setsockopt(7, SOL_TCP, TCP_QUICKACK, [0], 4) = 0
15:07:51.565524 connect(7, {sa_family=AF_INET, sin_port=htons(8000), sin_addr=inet_addr("192.168.0.31")}, 16) = -1 EINPROGRESS (Operation now in progress)
15:07:51.565955 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLOUT, {u32=7, u64=7}}) = 0
15:07:51.566235 epoll_ctl(3, EPOLL_CTL_DEL, 6, {0, {u32=6, u64=6}}) = 0
15:07:51.566494 gettimeofday({1324652871, 566613}, NULL) = 0
15:07:51.566730 epoll_wait(3, {{EPOLLOUT, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.566994 gettimeofday({1324652871, 567114}, NULL) = 0
15:07:51.567246 send(7, "GET /?s=1g HTTP/1.0\r\nUser-Agent:"..., 107, MSG_DONTWAIT|MSG_NOSIGNAL) = 107
15:07:51.567589 epoll_ctl(3, EPOLL_CTL_MOD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0
15:07:51.567907 gettimeofday({1324652871, 568031}, NULL) = 0
15:07:51.568148 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.568471 gettimeofday({1324652871, 568593}, NULL) = 0
15:07:51.568715 recv(7, "HTTP/1.1 200\r\nConnection: close\r"..., 7000, 0) = 4380
15:07:51.569057 recv(7, "89.12345678\n.123456789.123456789"..., 2620, 0) = 2620
15:07:51.569425 epoll_ctl(3, EPOLL_CTL_DEL, 7, {0, {u32=7, u64=7}}) = 0
15:07:51.569745 epoll_ctl(3, EPOLL_CTL_ADD, 6, {EPOLLOUT, {u32=6, u64=6}}) = 0
15:07:51.570013 gettimeofday({1324652871, 570133}, NULL) = 0
15:07:51.570251 epoll_wait(3, {{EPOLLOUT, {u32=6, u64=6}}}, 8, 1000) = 1
15:07:51.570514 gettimeofday({1324652871, 570634}, NULL) = 0
15:07:51.570754 send(6, "HTTP/1.1 200\r\nConnection: close\r"..., 7000, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE) = 7000
15:07:51.571244 epoll_ctl(3, EPOLL_CTL_DEL, 6, {0, {u32=6, u64=6}}) = 0
15:07:51.571518 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0
15:07:51.571825 gettimeofday({1324652871, 571947}, NULL) = 0
15:07:51.572064 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.572355 gettimeofday({1324652871, 572476}, NULL) = 0
15:07:51.572617 pipe([8, 9]) = 0
15:07:51.572863 fcntl64(8, 0x407 /* F_??? */, 0x40000) = 262144
15:07:51.573107 splice(7, NULL, 9, NULL, 1073734988, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 9060
15:07:51.573408 splice(7, NULL, 9, NULL, 1073725928, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 1460
15:07:51.573696 splice(7, NULL, 9, NULL, 1073724468, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.573942 splice(8, NULL, 6, NULL, 10520, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 10520
15:07:51.574328 gettimeofday({1324652871, 574452}, NULL) = 0
15:07:51.574572 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.574988 gettimeofday({1324652871, 575112}, NULL) = 0
15:07:51.575235 splice(7, NULL, 9, NULL, 1073724468, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 16060
15:07:51.575513 splice(8, NULL, 6, NULL, 16060, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 16060
15:07:51.575878 gettimeofday({1324652871, 576003}, NULL) = 0
15:07:51.576142 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.576510 gettimeofday({1324652871, 576631}, NULL) = 0
15:07:51.576753 splice(7, NULL, 9, NULL, 1073708408, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 11680
15:07:51.577027 splice(8, NULL, 6, NULL, 11680, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 11680
15:07:51.577358 gettimeofday({1324652871, 577480}, NULL) = 0
15:07:51.577614 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.577959 gettimeofday({1324652871, 578080}, NULL) = 0
15:07:51.578201 splice(7, NULL, 9, NULL, 1073696728, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 13140
15:07:51.578492 splice(8, NULL, 6, NULL, 13140, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 13140
15:07:51.578799 gettimeofday({1324652871, 578921}, NULL) = 0
15:07:51.579057 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.579413 gettimeofday({1324652871, 579534}, NULL) = 0
15:07:51.579654 splice(7, NULL, 9, NULL, 1073683588, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 14600
15:07:51.579927 splice(8, NULL, 6, NULL, 14600, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 14600
15:07:51.580260 gettimeofday({1324652871, 580389}, NULL) = 0
15:07:51.580526 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.580952 gettimeofday({1324652871, 581073}, NULL) = 0
15:07:51.581195 splice(7, NULL, 9, NULL, 1073668988, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 16060
15:07:51.581491 splice(8, NULL, 6, NULL, 16060, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 16060
15:07:51.581801 gettimeofday({1324652871, 581930}, NULL) = 0
15:07:51.582173 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.582475 gettimeofday({1324652871, 582597}, NULL) = 0
15:07:51.582719 splice(7, NULL, 9, NULL, 1073652928, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 17520
15:07:51.582998 splice(8, NULL, 6, NULL, 17520, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 17520
15:07:51.583345 gettimeofday({1324652871, 583476}, NULL) = 0
15:07:51.583725 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.584001 gettimeofday({1324652871, 584131}, NULL) = 0
15:07:51.584329 splice(7, NULL, 9, NULL, 1073635408, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 29200
15:07:51.584599 splice(8, NULL, 6, NULL, 29200, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 24820
15:07:51.584968 epoll_ctl(3, EPOLL_CTL_ADD, 6, {EPOLLOUT, {u32=6, u64=6}}) = 0
Here FD6 was enabled on output since some data remained in the pipe.
15:07:51.585244 gettimeofday({1324652871, 585374}, NULL) = 0
15:07:51.585583 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.585852 gettimeofday({1324652871, 585972}, NULL) = 0
15:07:51.586093 splice(7, NULL, 9, NULL, 1073606208, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 45260
15:07:51.586384 splice(8, NULL, 6, NULL, 49640, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.586668 gettimeofday({1324652871, 586789}, NULL) = 0
15:07:51.586908 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.587246 gettimeofday({1324652871, 587367}, NULL) = 0
15:07:51.587488 splice(7, NULL, 9, NULL, 1073560948, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 20440
15:07:51.587764 splice(8, NULL, 6, NULL, 70080, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.588045 gettimeofday({1324652871, 588166}, NULL) = 0
15:07:51.588284 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.588641 gettimeofday({1324652871, 588762}, NULL) = 0
15:07:51.588882 splice(7, NULL, 9, NULL, 1073540508, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 23360
15:07:51.589157 splice(8, NULL, 6, NULL, 93440, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.589438 gettimeofday({1324652871, 589558}, NULL) = 0
15:07:51.589677 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.590041 gettimeofday({1324652871, 590163}, NULL) = 0
15:07:51.590284 splice(7, NULL, 9, NULL, 1073517148, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.590533 splice(8, NULL, 6, NULL, 93440, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.590781 epoll_ctl(3, EPOLL_CTL_DEL, 7, {0, {u32=7, u64=7}}) = 0
15:07:51.591054 gettimeofday({1324652871, 591173}, NULL) = 0
15:07:51.591290 epoll_wait(3, {{EPOLLOUT, {u32=6, u64=6}}}, 8, 1000) = 1
write reported on FD6
15:07:51.623172 gettimeofday({1324652871, 623304}, NULL) = 0
15:07:51.623430 splice(8, NULL, 6, NULL, 93440, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 74460
74kB sent, 18980 bytes remaining, FD status not changed.
15:07:51.623739 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0
15:07:51.624009 gettimeofday({1324652871, 624128}, NULL) = 0
15:07:51.624246 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.624510 gettimeofday({1324652871, 624629}, NULL) = 0
15:07:51.624749 splice(7, NULL, 9, NULL, 1073517148, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 59860
15:07:51.625067 splice(8, NULL, 6, NULL, 78840, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.625357 gettimeofday({1324652871, 625479}, NULL) = 0
15:07:51.625597 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.625970 gettimeofday({1324652871, 626092}, NULL) = 0
15:07:51.626213 splice(7, NULL, 9, NULL, 1073457288, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = 14600
15:07:51.626490 splice(8, NULL, 6, NULL, 93440, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.626773 gettimeofday({1324652871, 626894}, NULL) = 0
15:07:51.627013 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 1000) = 1
15:07:51.627387 gettimeofday({1324652871, 627509}, NULL) = 0
15:07:51.627630 splice(7, NULL, 9, NULL, 1073442688, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.627883 splice(8, NULL, 6, NULL, 93440, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:51.628131 epoll_ctl(3, EPOLL_CTL_DEL, 7, {0, {u32=7, u64=7}}) = 0
And here we're blocked on both FDs. We disable polling for reads on the input
FD since the pipe is full. We have still not disabled events on FD6, which is
not reported anymore.
15:07:51.628389 gettimeofday({1324652871, 628508}, NULL) = 0
15:07:51.628625 epoll_wait(3, {}, 8, 1000) = 0
15:07:52.629938 gettimeofday({1324652872, 630103}, NULL) = 0
15:07:52.630232 gettimeofday({1324652872, 630364}, NULL) = 0
15:07:52.630481 epoll_wait(3, {}, 8, 1000) = 0
15:07:53.631760 gettimeofday({1324652873, 631895}, NULL) = 0
15:07:53.632018 gettimeofday({1324652873, 632146}, NULL) = 0
15:07:53.632289 epoll_wait(3, {}, 8, 1000) = 0
15:07:54.633641 gettimeofday({1324652874, 633770}, NULL) = 0
15:07:54.633896 gettimeofday({1324652874, 634017}, NULL) = 0
15:07:54.634135 epoll_wait(3, {}, 8, 1000) = 0
15:07:55.635457 gettimeofday({1324652875, 635582}, NULL) = 0
15:07:55.635705 gettimeofday({1324652875, 635824}, NULL) = 0
15:07:55.635943 epoll_wait(3, {}, 8, 930) = 0
15:07:56.567197 gettimeofday({1324652876, 567322}, NULL) = 0
15:07:56.567448 gettimeofday({1324652876, 567568}, NULL) = 0
15:07:56.567685 epoll_wait(3, {}, 8, 1000) = 0
15:07:57.568855 gettimeofday({1324652877, 569012}, NULL) = 0
15:07:57.569145 gettimeofday({1324652877, 569278}, NULL) = 0
15:07:57.569396 epoll_wait(3, {}, 8, 1000) = 0
15:07:58.570760 gettimeofday({1324652878, 570899}, NULL) = 0
15:07:58.571023 gettimeofday({1324652878, 571154}, NULL) = 0
15:07:58.571270 epoll_wait(3, {}, 8, 999) = 0
15:07:59.571418 gettimeofday({1324652879, 571546}, NULL) = 0
Timeout strikes, we're about to close. It happens that the FD is re-enabled
at this point. That doesn't really matter anyway.
15:07:59.571688 epoll_ctl(3, EPOLL_CTL_ADD, 7, {EPOLLIN, {u32=7, u64=7}}) = 0
15:07:59.571964 gettimeofday({1324652879, 572084}, NULL) = 0
15:07:59.572227 epoll_wait(3, {{EPOLLIN, {u32=7, u64=7}}}, 8, 57) = 1
15:07:59.572499 gettimeofday({1324652879, 572619}, NULL) = 0
15:07:59.572742 splice(7, NULL, 9, NULL, 1073442688, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
15:07:59.573010 splice(8, NULL, 6, NULL, 93440, SPLICE_F_MOVE|SPLICE_F_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
The FD 6 was still blocked.
15:07:59.573269 epoll_ctl(3, EPOLL_CTL_DEL, 7, {0, {u32=7, u64=7}}) = 0
15:07:59.573529 gettimeofday({1324652879, 573649}, NULL) = 0
15:07:59.573766 epoll_wait(3, {}, 8, 56) = 0
15:07:59.630081 gettimeofday({1324652879, 630202}, NULL) = 0
15:07:59.630327 setsockopt(6, SOL_SOCKET, SO_LINGER, {onoff=1, linger=0}, 8) = 0
15:07:59.630594 close(6) = 0
15:07:59.630909 close(7) = 0
FDs are closed.
15:07:59.631424 close(9) = 0
15:07:59.631746 close(8) = 0
And pipe is killed because it contains remaining data.
Regards,
Willy
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 21:50 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <1337290822.3403.47.camel@edumazet-glaptop>
On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
> I dont understand why we should tcp_push() if we sent 0 bytes in this
> splice() call.
>
> The push() should have be done already by prior splice() call, dont you
> think ?
>
> out:
> if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> tcp_push(sk, flags, mss_now, tp->nonagle);
>
I think I now understand
One splice() syscall actually calls do_tcp_sendpages() several times
(N).
Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
And last one with MSG_SENDPAGE_NOTLAST unset
So maybe we should replace this test by :
if (!(flags & MSG_SENDPAGE_NOTLAST))
tcp_push(...);
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 21:54 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1337290822.3403.47.camel@edumazet-glaptop>
On Thu, May 17, 2012 at 11:40:22PM +0200, Eric Dumazet wrote:
> > diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> > index 63ddaee..231fe53 100644
> > --- a/net/ipv4/tcp.c
> > +++ b/net/ipv4/tcp.c
> > @@ -917,8 +917,7 @@ new_segment:
> > wait_for_sndbuf:
> > set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> > wait_for_memory:
> > - if (copied)
> > - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
> > + tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
> >
> > if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
> > goto do_error;
>
>
> I dont understand why we should tcp_push() if we sent 0 bytes in this
> splice() call.
>
> The push() should have be done already by prior splice() call, dont you
> think ?
>
> out:
> if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> tcp_push(sk, flags, mss_now, tp->nonagle);
>
I do think so, but my guess is that something fails below us at some point.
I tracked the tcp_push() chain down to tcp_write_xmit() which I *think* might
fail. I'm not certain about the conditions which can make this happen though.
However what I'm almost sure is that if we fail one tcp_write_xmit() from a
call to tcp_push(), next time we come here in do_tcp_sendpages(), the buffers
won't have moved and this second splice() will immediately go to out with
copied == 0.
Maybe I just worked around the consequence of a deeper issue and something
else needs to enable tcp_push() when we fail, but it's not very clear to me.
I felt like the call to tcp_check_probe_timer() in __tcp_push_pending_frames()
is there for this purpose, but I'm not sure.
Willy
^ permalink raw reply
* Re: [IPROUTE2 0/2] Add ECN support to tc-netem
From: Stephen Hemminger @ 2012-05-17 21:54 UTC (permalink / raw)
To: Vijay Subramanian; +Cc: netdev, Eric Dumazet
In-Reply-To: <1337212318-2100-1-git-send-email-subramanian.vijay@gmail.com>
On Wed, 16 May 2012 16:51:56 -0700
Vijay Subramanian <subramanian.vijay@gmail.com> wrote:
> Recent patch to net-next kernel from Eric Dumazet (e4ae004b84b netem: add ECN
> capability) made it possible for netem to mark packets with ECN instead of
> dropping them. These two patches add support to iproute2/tc and update the
> manpage.
>
> Vijay Subramanian (2):
> Update tc-netem manpage to add ecn capability
> tc-netem: Add support for ECN packet marking
>
> include/linux/pkt_sched.h | 1 +
> man/man8/tc-netem.8 | 8 ++++++--
> tc/q_netem.c | 25 +++++++++++++++++++++++++
> 3 files changed, 32 insertions(+), 2 deletions(-)
>
I am holding these until 3.5 merge window, since they depend
on the feature still in net-next
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 21:57 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1337291410.3403.52.camel@edumazet-glaptop>
On Thu, May 17, 2012 at 11:50:10PM +0200, Eric Dumazet wrote:
> On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
>
> > I dont understand why we should tcp_push() if we sent 0 bytes in this
> > splice() call.
> >
> > The push() should have be done already by prior splice() call, dont you
> > think ?
> >
> > out:
> > if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > tcp_push(sk, flags, mss_now, tp->nonagle);
> >
>
> I think I now understand
>
> One splice() syscall actually calls do_tcp_sendpages() several times
> (N).
>
> Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
>
> And last one with MSG_SENDPAGE_NOTLAST unset
>
> So maybe we should replace this test by :
>
> if (!(flags & MSG_SENDPAGE_NOTLAST))
> tcp_push(...);
Just tested, and it unfortunately does not fix the issue :-(
I'll see if I can log errors from lower layers.
Willy
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 22:01 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <1337291410.3403.52.camel@edumazet-glaptop>
On Thu, 2012-05-17 at 23:50 +0200, Eric Dumazet wrote:
> On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
>
> > I dont understand why we should tcp_push() if we sent 0 bytes in this
> > splice() call.
> >
> > The push() should have be done already by prior splice() call, dont you
> > think ?
> >
> > out:
> > if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > tcp_push(sk, flags, mss_now, tp->nonagle);
> >
>
> I think I now understand
>
> One splice() syscall actually calls do_tcp_sendpages() several times
> (N).
>
> Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
>
> And last one with MSG_SENDPAGE_NOTLAST unset
>
> So maybe we should replace this test by :
>
> if (!(flags & MSG_SENDPAGE_NOTLAST))
> tcp_push(...);
>
>
Its more tricky than that.
If we return 0 from do_tcp_sendpages(), __splice_from_pipe() wont call
us again, but we need to flush(). (This bug is indeed very old)
So maybe use :
if ((copied && !(flags & MSG_SENDPAGE_NOTLAST)) ||
!copied)
tcp_push(...);
^ permalink raw reply
* [RFC PATCH net-next] hp100: delete VG/AnyLAN hp100
From: Joe Perches @ 2012-05-17 22:09 UTC (permalink / raw)
To: Paul Gortmaker; +Cc: linux-kernel, JBottomley, David S. Miller, netdev
In-Reply-To: <20120517212039.GC27789@windriver.com>
On Thu, 2012-05-17 at 17:20 -0400, Paul Gortmaker wrote:
> [Re: [PATCH 2/5] drivers/net: delete all code/drivers depending on CONFIG_MCA
If we're removing really old and unused stuff,
how about the VG/AnyLAN driver too?
---
drivers/net/ethernet/Kconfig | 1 -
drivers/net/ethernet/Makefile | 1 -
drivers/net/ethernet/hp/Kconfig | 32 -
drivers/net/ethernet/hp/Makefile | 5 -
drivers/net/ethernet/hp/hp100.c | 3066 --------------------------------------
drivers/net/ethernet/hp/hp100.h | 615 --------
6 files changed, 0 insertions(+), 3720 deletions(-)
delete mode 100644 drivers/net/ethernet/hp/Kconfig
delete mode 100644 drivers/net/ethernet/hp/Makefile
delete mode 100644 drivers/net/ethernet/hp/hp100.c
delete mode 100644 drivers/net/ethernet/hp/hp100.h
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index a11af5c..0896c8f 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -52,7 +52,6 @@ source "drivers/net/ethernet/neterion/Kconfig"
source "drivers/net/ethernet/faraday/Kconfig"
source "drivers/net/ethernet/freescale/Kconfig"
source "drivers/net/ethernet/fujitsu/Kconfig"
-source "drivers/net/ethernet/hp/Kconfig"
source "drivers/net/ethernet/ibm/Kconfig"
source "drivers/net/ethernet/intel/Kconfig"
source "drivers/net/ethernet/i825xx/Kconfig"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index 878ad32..756ebd3 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -27,7 +27,6 @@ obj-$(CONFIG_NET_VENDOR_EXAR) += neterion/
obj-$(CONFIG_NET_VENDOR_FARADAY) += faraday/
obj-$(CONFIG_NET_VENDOR_FREESCALE) += freescale/
obj-$(CONFIG_NET_VENDOR_FUJITSU) += fujitsu/
-obj-$(CONFIG_NET_VENDOR_HP) += hp/
obj-$(CONFIG_NET_VENDOR_IBM) += ibm/
obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
^ permalink raw reply related
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 22:10 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <1337292119.3403.60.camel@edumazet-glaptop>
On Fri, 2012-05-18 at 00:02 +0200, Eric Dumazet wrote:
> On Thu, 2012-05-17 at 23:50 +0200, Eric Dumazet wrote:
> > On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
> >
> > > I dont understand why we should tcp_push() if we sent 0 bytes in this
> > > splice() call.
> > >
> > > The push() should have be done already by prior splice() call, dont you
> > > think ?
> > >
> > > out:
> > > if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > > tcp_push(sk, flags, mss_now, tp->nonagle);
> > >
> >
> > I think I now understand
> >
> > One splice() syscall actually calls do_tcp_sendpages() several times
> > (N).
> >
> > Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
> >
> > And last one with MSG_SENDPAGE_NOTLAST unset
> >
> > So maybe we should replace this test by :
> >
> > if (!(flags & MSG_SENDPAGE_NOTLAST))
> > tcp_push(...);
> >
> >
>
> Its more tricky than that.
>
> If we return 0 from do_tcp_sendpages(), __splice_from_pipe() wont call
> us again, but we need to flush(). (This bug is indeed very old)
>
> So maybe use :
>
> if ((copied && !(flags & MSG_SENDPAGE_NOTLAST)) ||
> !copied)
> tcp_push(...);
But then your patch is equivalentm so I'm going to Ack it ;)
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 22:14 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <20120517211414.GP14498@1wt.eu>
On Thu, 2012-05-17 at 23:14 +0200, Willy Tarreau wrote:
> ---
>
> From 39c3f73176118a274ec9dea9c22c83d97a7fbfe0 Mon Sep 17 00:00:00 2001
> From: Willy Tarreau <w@1wt.eu>
> Date: Thu, 17 May 2012 22:43:20 +0200
> Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
>
> Since recent changes on TCP splicing (starting with commits 2f533844
> and 35f9c09f), I started seeing massive stalls when forwarding traffic
> between two sockets using splice() when pipe buffers were larger than
> socket buffers.
>
> Latest changes (net: netdev_alloc_skb() use build_skb()) made the
> problem even more apparent.
>
> The reason seems to be that if do_tcp_sendpages() fails on out of memory
> condition without being able to send at least one byte, tcp_push() is not
> called and the buffers cannot be flushed.
>
> After applying the attached patch, I cannot reproduce the stalls at all
> and the data rate it perfectly stable and steady under any condition
> which previously caused the problem to be permanent.
>
> The issue seems to have been there since before the kernel migrated to
> git, which makes me think that the stalls I occasionally experienced
> with tux during stress-tests years ago were probably related to the
> same issue.
>
> This issue was first encountered on 3.0.31 and 3.2.17, so please backport
> to -stable.
>
> Signed-off-by: Willy Tarreau <w@1wt.eu>
> Cc: <stable@vger.kernel.org>
> ---
> net/ipv4/tcp.c | 3 +--
> 1 files changed, 1 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 63ddaee..231fe53 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -917,8 +917,7 @@ new_segment:
> wait_for_sndbuf:
> set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> wait_for_memory:
> - if (copied)
> - tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
> + tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
>
> if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
> goto do_error;
Acked-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 22:16 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1337292119.3403.60.camel@edumazet-glaptop>
On Fri, May 18, 2012 at 12:01:59AM +0200, Eric Dumazet wrote:
> On Thu, 2012-05-17 at 23:50 +0200, Eric Dumazet wrote:
> > On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
> >
> > > I dont understand why we should tcp_push() if we sent 0 bytes in this
> > > splice() call.
> > >
> > > The push() should have be done already by prior splice() call, dont you
> > > think ?
> > >
> > > out:
> > > if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > > tcp_push(sk, flags, mss_now, tp->nonagle);
> > >
> >
> > I think I now understand
> >
> > One splice() syscall actually calls do_tcp_sendpages() several times
> > (N).
> >
> > Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
> >
> > And last one with MSG_SENDPAGE_NOTLAST unset
> >
> > So maybe we should replace this test by :
> >
> > if (!(flags & MSG_SENDPAGE_NOTLAST))
> > tcp_push(...);
> >
> >
>
> Its more tricky than that.
>
> If we return 0 from do_tcp_sendpages(), __splice_from_pipe() wont call
> us again, but we need to flush(). (This bug is indeed very old)
>
> So maybe use :
>
> if ((copied && !(flags & MSG_SENDPAGE_NOTLAST)) ||
> !copied)
> tcp_push(...);
That's what I wanted to do at first but was still worried about the
situations where we fail upon first call due to lack of memory. And
indeed that did not fix the issue either :-(
At least now I've checked that we fail here in do_tcp_sendpages() :
if (!sk_stream_memory_free(sk)) {
printk(KERN_DEBUG "%s:%d copied=%d\n", __FUNCTION__, __LINE__, copied);
goto wait_for_sndbuf;
}
Well, finally I just put the same test as yours above for the call to
tcp_push() upon out of memory and it fixed it too. I have simplified
the expression, since ((A && !B) || !A) == !(A & B).
With the updated patch here it works for me. I don't know if it's
better.
Willy
-----
>From 1f26263bd4f8827bbca4cef77a99fac128cf8ccc Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Thu, 17 May 2012 22:43:20 +0200
Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
Since recent changes on TCP splicing (starting with commits 2f533844
and 35f9c09f), I started seeing massive stalls when forwarding traffic
between two sockets using splice() when pipe buffers were larger than
socket buffers.
Latest changes (net: netdev_alloc_skb() use build_skb()) made the
problem even more apparent.
The reason seems to be that if do_tcp_sendpages() fails on out of memory
condition without being able to send at least one byte, tcp_push() is not
called and the buffers cannot be flushed.
After applying the attached patch, I cannot reproduce the stalls at all
and the data rate it perfectly stable and steady under any condition
which previously caused the problem to be permanent.
The issue seems to have been there since before the kernel migrated to
git, which makes me think that the stalls I occasionally experienced
with tux during stress-tests years ago were probably related to the
same issue.
This issue was first encountered on 3.0.31 and 3.2.17, so please backport
to -stable.
Signed-off-by: Willy Tarreau <w@1wt.eu>
Cc: <stable@vger.kernel.org>
---
net/ipv4/tcp.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 63ddaee..cfe47c1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -917,7 +917,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied)
+ if (!(copied && (flags & MSG_SENDPAGE_NOTLAST)))
tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
@@ -927,7 +927,7 @@ wait_for_memory:
}
out:
- if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
+ if (!(copied && (flags & MSG_SENDPAGE_NOTLAST)))
tcp_push(sk, flags, mss_now, tp->nonagle);
return copied;
--
1.7.2.1.45.g54fbc
^ permalink raw reply related
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Eric Dumazet @ 2012-05-17 22:22 UTC (permalink / raw)
To: Willy Tarreau; +Cc: netdev
In-Reply-To: <20120517221641.GS14498@1wt.eu>
On Fri, 2012-05-18 at 00:16 +0200, Willy Tarreau wrote:
> On Fri, May 18, 2012 at 12:01:59AM +0200, Eric Dumazet wrote:
> > On Thu, 2012-05-17 at 23:50 +0200, Eric Dumazet wrote:
> > > On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
> > >
> > > > I dont understand why we should tcp_push() if we sent 0 bytes in this
> > > > splice() call.
> > > >
> > > > The push() should have be done already by prior splice() call, dont you
> > > > think ?
> > > >
> > > > out:
> > > > if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > > > tcp_push(sk, flags, mss_now, tp->nonagle);
> > > >
> > >
> > > I think I now understand
> > >
> > > One splice() syscall actually calls do_tcp_sendpages() several times
> > > (N).
> > >
> > > Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
> > >
> > > And last one with MSG_SENDPAGE_NOTLAST unset
> > >
> > > So maybe we should replace this test by :
> > >
> > > if (!(flags & MSG_SENDPAGE_NOTLAST))
> > > tcp_push(...);
> > >
> > >
> >
> > Its more tricky than that.
> >
> > If we return 0 from do_tcp_sendpages(), __splice_from_pipe() wont call
> > us again, but we need to flush(). (This bug is indeed very old)
> >
> > So maybe use :
> >
> > if ((copied && !(flags & MSG_SENDPAGE_NOTLAST)) ||
> > !copied)
> > tcp_push(...);
>
> That's what I wanted to do at first but was still worried about the
> situations where we fail upon first call due to lack of memory. And
> indeed that did not fix the issue either :-(
>
> At least now I've checked that we fail here in do_tcp_sendpages() :
>
> if (!sk_stream_memory_free(sk)) {
> printk(KERN_DEBUG "%s:%d copied=%d\n", __FUNCTION__, __LINE__, copied);
> goto wait_for_sndbuf;
> }
>
> Well, finally I just put the same test as yours above for the call to
> tcp_push() upon out of memory and it fixed it too. I have simplified
> the expression, since ((A && !B) || !A) == !(A & B).
>
> With the updated patch here it works for me. I don't know if it's
> better.
>
> Willy
>
> -----
>
> From 1f26263bd4f8827bbca4cef77a99fac128cf8ccc Mon Sep 17 00:00:00 2001
> From: Willy Tarreau <w@1wt.eu>
> Date: Thu, 17 May 2012 22:43:20 +0200
> Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
>
> Since recent changes on TCP splicing (starting with commits 2f533844
> and 35f9c09f), I started seeing massive stalls when forwarding traffic
> between two sockets using splice() when pipe buffers were larger than
> socket buffers.
>
> Latest changes (net: netdev_alloc_skb() use build_skb()) made the
> problem even more apparent.
>
> The reason seems to be that if do_tcp_sendpages() fails on out of memory
> condition without being able to send at least one byte, tcp_push() is not
> called and the buffers cannot be flushed.
>
> After applying the attached patch, I cannot reproduce the stalls at all
> and the data rate it perfectly stable and steady under any condition
> which previously caused the problem to be permanent.
>
> The issue seems to have been there since before the kernel migrated to
> git, which makes me think that the stalls I occasionally experienced
> with tux during stress-tests years ago were probably related to the
> same issue.
>
> This issue was first encountered on 3.0.31 and 3.2.17, so please backport
> to -stable.
>
> Signed-off-by: Willy Tarreau <w@1wt.eu>
> Cc: <stable@vger.kernel.org>
> ---
> net/ipv4/tcp.c | 4 ++--
> 1 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 63ddaee..cfe47c1 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -917,7 +917,7 @@ new_segment:
> wait_for_sndbuf:
> set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> wait_for_memory:
> - if (copied)
> + if (!(copied && (flags & MSG_SENDPAGE_NOTLAST)))
> tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
>
> if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
> @@ -927,7 +927,7 @@ wait_for_memory:
> }
>
> out:
> - if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> + if (!(copied && (flags & MSG_SENDPAGE_NOTLAST)))
> tcp_push(sk, flags, mss_now, tp->nonagle);
> return copied;
>
Hmm... I believe I prefer your prior patch ( the one I Acked)
^ permalink raw reply
* Re: [PATCH 2/5] drivers/net: delete all code/drivers depending on CONFIG_MCA
From: David Miller @ 2012-05-17 22:23 UTC (permalink / raw)
To: paul.gortmaker; +Cc: linux-kernel, JBottomley, netdev
In-Reply-To: <20120517212039.GC27789@windriver.com>
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Thu, 17 May 2012 17:20:39 -0400
> I've layered the above commit (with 3c527.h deleted) onto today's
> net-next, did a quick re-test of x86_64 allmodconfig and put it
> on a branch as per below (vs sending a 5000+ line patch).
...
> git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux.git delete-mca-net-drivers
Pulled, thanks Paul.
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 22:24 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1337293351.3403.67.camel@edumazet-glaptop>
On Fri, May 18, 2012 at 12:22:31AM +0200, Eric Dumazet wrote:
> On Fri, 2012-05-18 at 00:16 +0200, Willy Tarreau wrote:
> > On Fri, May 18, 2012 at 12:01:59AM +0200, Eric Dumazet wrote:
> > > On Thu, 2012-05-17 at 23:50 +0200, Eric Dumazet wrote:
> > > > On Thu, 2012-05-17 at 23:40 +0200, Eric Dumazet wrote:
> > > >
> > > > > I dont understand why we should tcp_push() if we sent 0 bytes in this
> > > > > splice() call.
> > > > >
> > > > > The push() should have be done already by prior splice() call, dont you
> > > > > think ?
> > > > >
> > > > > out:
> > > > > if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > > > > tcp_push(sk, flags, mss_now, tp->nonagle);
> > > > >
> > > >
> > > > I think I now understand
> > > >
> > > > One splice() syscall actually calls do_tcp_sendpages() several times
> > > > (N).
> > > >
> > > > Problem is N-1 calls are done with MSG_SENDPAGE_NOTLAST set
> > > >
> > > > And last one with MSG_SENDPAGE_NOTLAST unset
> > > >
> > > > So maybe we should replace this test by :
> > > >
> > > > if (!(flags & MSG_SENDPAGE_NOTLAST))
> > > > tcp_push(...);
> > > >
> > > >
> > >
> > > Its more tricky than that.
> > >
> > > If we return 0 from do_tcp_sendpages(), __splice_from_pipe() wont call
> > > us again, but we need to flush(). (This bug is indeed very old)
> > >
> > > So maybe use :
> > >
> > > if ((copied && !(flags & MSG_SENDPAGE_NOTLAST)) ||
> > > !copied)
> > > tcp_push(...);
> >
> > That's what I wanted to do at first but was still worried about the
> > situations where we fail upon first call due to lack of memory. And
> > indeed that did not fix the issue either :-(
> >
> > At least now I've checked that we fail here in do_tcp_sendpages() :
> >
> > if (!sk_stream_memory_free(sk)) {
> > printk(KERN_DEBUG "%s:%d copied=%d\n", __FUNCTION__, __LINE__, copied);
> > goto wait_for_sndbuf;
> > }
> >
> > Well, finally I just put the same test as yours above for the call to
> > tcp_push() upon out of memory and it fixed it too. I have simplified
> > the expression, since ((A && !B) || !A) == !(A & B).
> >
> > With the updated patch here it works for me. I don't know if it's
> > better.
> >
> > Willy
> >
> > -----
> >
> > From 1f26263bd4f8827bbca4cef77a99fac128cf8ccc Mon Sep 17 00:00:00 2001
> > From: Willy Tarreau <w@1wt.eu>
> > Date: Thu, 17 May 2012 22:43:20 +0200
> > Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
> >
> > Since recent changes on TCP splicing (starting with commits 2f533844
> > and 35f9c09f), I started seeing massive stalls when forwarding traffic
> > between two sockets using splice() when pipe buffers were larger than
> > socket buffers.
> >
> > Latest changes (net: netdev_alloc_skb() use build_skb()) made the
> > problem even more apparent.
> >
> > The reason seems to be that if do_tcp_sendpages() fails on out of memory
> > condition without being able to send at least one byte, tcp_push() is not
> > called and the buffers cannot be flushed.
> >
> > After applying the attached patch, I cannot reproduce the stalls at all
> > and the data rate it perfectly stable and steady under any condition
> > which previously caused the problem to be permanent.
> >
> > The issue seems to have been there since before the kernel migrated to
> > git, which makes me think that the stalls I occasionally experienced
> > with tux during stress-tests years ago were probably related to the
> > same issue.
> >
> > This issue was first encountered on 3.0.31 and 3.2.17, so please backport
> > to -stable.
> >
> > Signed-off-by: Willy Tarreau <w@1wt.eu>
> > Cc: <stable@vger.kernel.org>
> > ---
> > net/ipv4/tcp.c | 4 ++--
> > 1 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> > index 63ddaee..cfe47c1 100644
> > --- a/net/ipv4/tcp.c
> > +++ b/net/ipv4/tcp.c
> > @@ -917,7 +917,7 @@ new_segment:
> > wait_for_sndbuf:
> > set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
> > wait_for_memory:
> > - if (copied)
> > + if (!(copied && (flags & MSG_SENDPAGE_NOTLAST)))
> > tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
> >
> > if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
> > @@ -927,7 +927,7 @@ wait_for_memory:
> > }
> >
> > out:
> > - if (copied && !(flags & MSG_SENDPAGE_NOTLAST))
> > + if (!(copied && (flags & MSG_SENDPAGE_NOTLAST)))
> > tcp_push(sk, flags, mss_now, tp->nonagle);
> > return copied;
> >
>
>
> Hmm... I believe I prefer your prior patch ( the one I Acked)
I too, less changes are better :-)
Thanks,
Willy
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: David Miller @ 2012-05-17 22:25 UTC (permalink / raw)
To: w; +Cc: eric.dumazet, netdev
In-Reply-To: <20120517222431.GT14498@1wt.eu>
From: Willy Tarreau <w@1wt.eu>
Date: Fri, 18 May 2012 00:24:31 +0200
> On Fri, May 18, 2012 at 12:22:31AM +0200, Eric Dumazet wrote:
>> Hmm... I believe I prefer your prior patch ( the one I Acked)
>
> I too, less changes are better :-)
And I think that's the one I'm going to apply after I audit this
code a little bit myself.
Thanks!
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Joe Perches @ 2012-05-17 22:27 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Willy Tarreau, netdev
In-Reply-To: <1337293351.3403.67.camel@edumazet-glaptop>
On Fri, 2012-05-18 at 00:22 +0200, Eric Dumazet wrote:
> On Fri, 2012-05-18 at 00:16 +0200, Willy Tarreau wrote:
> > I have simplified the expression,
> > since ((A && !B) || !A) == !(A & B).
Perhaps it's clearer for a reader the first way and
any decent compiler (even gcc) could probably do that
optimization.
^ permalink raw reply
* Re: [RFC PATCH net-next] hp100: delete VG/AnyLAN hp100
From: Francois Romieu @ 2012-05-17 22:28 UTC (permalink / raw)
To: Joe Perches
Cc: Paul Gortmaker, linux-kernel, JBottomley, David S. Miller, netdev,
Joel Soete
In-Reply-To: <1337292547.8872.20.camel@joe2Laptop>
Joe Perches <joe@perches.com> :
> On Thu, 2012-05-17 at 17:20 -0400, Paul Gortmaker wrote:
> > [Re: [PATCH 2/5] drivers/net: delete all code/drivers depending on CONFIG_MCA
>
> If we're removing really old and unused stuff,
> how about the VG/AnyLAN driver too?
Joel Soete appeared to actively use a PCI one with recent kernels back
in 2007.
--
Ueimor
^ permalink raw reply
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 22:29 UTC (permalink / raw)
To: David Miller; +Cc: Eric Dumazet, netdev
In-Reply-To: <1337292894.3403.66.camel@edumazet-glaptop>
David,
After several tests, we finally agreed on this one. I can't make the
transfers fail anymore. And they're damn fast thanks to Eric's recent
work!
Best regards,
Willy
---
>From 39c3f73176118a274ec9dea9c22c83d97a7fbfe0 Mon Sep 17 00:00:00 2001
From: Willy Tarreau <w@1wt.eu>
Date: Thu, 17 May 2012 22:43:20 +0200
Subject: [PATCH] tcp: do_tcp_sendpages() must try to push data out on oom conditions
Since recent changes on TCP splicing (starting with commits 2f533844
and 35f9c09f), I started seeing massive stalls when forwarding traffic
between two sockets using splice() when pipe buffers were larger than
socket buffers.
Latest changes (net: netdev_alloc_skb() use build_skb()) made the
problem even more apparent.
The reason seems to be that if do_tcp_sendpages() fails on out of memory
condition without being able to send at least one byte, tcp_push() is not
called and the buffers cannot be flushed.
After applying the attached patch, I cannot reproduce the stalls at all
and the data rate it perfectly stable and steady under any condition
which previously caused the problem to be permanent.
The issue seems to have been there since before the kernel migrated to
git, which makes me think that the stalls I occasionally experienced
with tux during stress-tests years ago were probably related to the
same issue.
This issue was first encountered on 3.0.31 and 3.2.17, so please backport
to -stable.
Signed-off-by: Willy Tarreau <w@1wt.eu>
Cc: <stable@vger.kernel.org>
Acked-by: Eric Dumazet <edumazet@google.com>
---
net/ipv4/tcp.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 63ddaee..231fe53 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -917,8 +917,7 @@ new_segment:
wait_for_sndbuf:
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
wait_for_memory:
- if (copied)
- tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
+ tcp_push(sk, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH);
if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
goto do_error;
^ permalink raw reply related
* Re: Stable regression with 'tcp: allow splice() to build full TSO packets'
From: Willy Tarreau @ 2012-05-17 22:30 UTC (permalink / raw)
To: David Miller; +Cc: eric.dumazet, netdev
In-Reply-To: <20120517.182545.91312407467980757.davem@davemloft.net>
On Thu, May 17, 2012 at 06:25:45PM -0400, David Miller wrote:
> From: Willy Tarreau <w@1wt.eu>
> Date: Fri, 18 May 2012 00:24:31 +0200
>
> > On Fri, May 18, 2012 at 12:22:31AM +0200, Eric Dumazet wrote:
> >> Hmm... I believe I prefer your prior patch ( the one I Acked)
> >
> > I too, less changes are better :-)
>
> And I think that's the one I'm going to apply after I audit this
> code a little bit myself.
>
> Thanks!
Sorry for the double mail, I didn't know if you were following the thread
when I forwarded it to you.
Cheers,
Willy
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox